const std = @import("std"); const utils = @import("utils.zig"); const zid = @import("ZipponData"); const AdditionalData = @import("dataStructure/additionalData.zig").AdditionalData; const JsonString = @import("dataStructure/relationMap.zig").JsonString; const dtype = @import("dtype"); const DataType = dtype.DataType; const DateTime = dtype.DateTime; const UUID = dtype.UUID; const ZipponError = @import("error").ZipponError; pub fn writeEntityTable( writer: anytype, row: []zid.Data, additional_data: AdditionalData, data_types: []const DataType, ) !void { try writer.writeAll("| "); for (additional_data.childrens.items) |member| { try writeValue(writer, row[member.index], data_types[member.index]); try writer.writeAll(" \t| "); } try writer.writeByte('\n'); } pub fn writeHeaderCsv( writer: anytype, members: [][]const u8, delimiter: u8, ) !void { for (members, 0..) |member, i| { try writer.writeAll(member); if (i < members.len - 1) try writer.writeByte(delimiter); } try writer.writeByte('\n'); } pub fn writeEntityCsv( // FIXME: I think if one value str have a \n this will broke. I need to use like """ writer: anytype, row: []zid.Data, data_types: []const DataType, delimiter: u8, ) !void { for (0..row.len) |i| { try writeValue(writer, row[i], data_types[i]); if (i < row.len - 1) try writer.writeByte(delimiter); } try writer.writeByte('\n'); } pub fn writeEntityJSON( writer: anytype, row: []zid.Data, additional_data: AdditionalData, data_types: []const DataType, ) !void { try writer.writeByte('{'); for (additional_data.childrens.items) |member| { try writer.print("{s}: ", .{member.name}); try writeValue(writer, row[member.index], data_types[member.index]); try writer.writeAll(", "); } try writer.writeAll("}, "); } fn writeValue(writer: anytype, value: zid.Data, data_type: DataType) !void { switch (value) { .Float => |v| try writer.print("{d}", .{v}), .Int => |v| try writer.print("{d}", .{v}), .Str => |v| try writer.print("\"{s}\"", .{v}), .UUID => |v| { if (data_type == .self) { try writer.print("\"{s}\"", .{UUID.format_bytes(v)}); return; } const uuid = try UUID.parse("00000000-0000-0000-0000-000000000000"); // Maybe pass that comptime to prevent parsing it everytime if (!std.meta.eql(v, uuid.bytes)) { try writer.print("{{|<{s}>|}}", .{v}); } else { try writer.print("{{}}", .{}); } }, .Bool => |v| try writer.print("{any}", .{v}), .Unix => |v| { const datetime = DateTime.initUnix(v); try writer.writeByte('"'); switch (data_type) { .date => try datetime.format("YYYY/MM/DD", writer), .time => try datetime.format("HH:mm:ss.SSSS", writer), .datetime => try datetime.format("YYYY/MM/DD-HH:mm:ss.SSSS", writer), else => unreachable, } try writer.writeByte('"'); }, .IntArray, .FloatArray, .StrArray, .UUIDArray, .BoolArray, .UnixArray => try writeArray(writer, value, data_type), } } fn writeArray(writer: anytype, data: zid.Data, data_type: DataType) ZipponError!void { writer.writeByte('[') catch return ZipponError.WriteError; var iter = zid.ArrayIterator.init(data) catch return ZipponError.ZipponDataError; switch (data) { .IntArray => while (iter.next()) |v| writer.print("{d}, ", .{v.Int}) catch return ZipponError.WriteError, .FloatArray => while (iter.next()) |v| writer.print("{d}", .{v.Float}) catch return ZipponError.WriteError, .StrArray => while (iter.next()) |v| writer.print("\"{s}\"", .{v.Str}) catch return ZipponError.WriteError, .UUIDArray => while (iter.next()) |v| writer.print("{{|<{s}>|}},", .{v.UUID}) catch return ZipponError.WriteError, .BoolArray => while (iter.next()) |v| writer.print("{any}", .{v.Bool}) catch return ZipponError.WriteError, .UnixArray => while (iter.next()) |v| { const datetime = DateTime.initUnix(v.Unix); writer.writeByte('"') catch return ZipponError.WriteError; switch (data_type) { .date => datetime.format("YYYY/MM/DD", writer) catch return ZipponError.WriteError, .time => datetime.format("HH:mm:ss.SSSS", writer) catch return ZipponError.WriteError, .datetime => datetime.format("YYYY/MM/DD-HH:mm:ss.SSSS", writer) catch return ZipponError.WriteError, else => unreachable, } writer.writeAll("\", ") catch return ZipponError.WriteError; }, else => unreachable, } writer.writeByte(']') catch return ZipponError.WriteError; } /// Take a string in the JSON format and look for {|<[16]u8>|}, then will look into the map and check if it can find this UUID /// If it find it, it ill replace the {|<[16]u8>|} will the value pub fn updateWithRelation(writer: anytype, input: []const u8, map: std.AutoHashMap([16]u8, JsonString)) ZipponError!void { var uuid_bytes: [16]u8 = undefined; var start: usize = 0; while (std.mem.indexOf(u8, input[start..], "{|<")) |pos| { const pattern_start = start + pos + 3; const pattern_end = pattern_start + 16; // Write the text before the pattern writer.writeAll(input[start .. pattern_start - 3]) catch return ZipponError.WriteError; if (input[pattern_start - 4] == '[') { start = try updateArray(writer, input, map, pattern_start - 3); continue; } @memcpy(uuid_bytes[0..], input[pattern_start..pattern_end]); if (map.get(uuid_bytes)) |json_string| { writer.writeAll(json_string.slice) catch return ZipponError.WriteError; } else { writer.writeAll(input[pattern_start - 3 .. pattern_end + 3]) catch return ZipponError.WriteError; } start = pattern_end + 5; } // Write any remaining text writer.writeAll(input[start..]) catch return ZipponError.WriteError; } fn updateArray(writer: anytype, input: []const u8, map: std.AutoHashMap([16]u8, JsonString), origin: usize) ZipponError!usize { var uuid_bytes: [16]u8 = undefined; var start = origin; while (input.len > start + 23 and std.mem.eql(u8, input[start .. start + 3], "{|<") and std.mem.eql(u8, input[start + 19 .. start + 23], ">|},")) : (start += 23) { @memcpy(uuid_bytes[0..], input[start + 3 .. start + 19]); if (map.get(uuid_bytes)) |json_string| { writer.writeAll(json_string.slice) catch return ZipponError.WriteError; } else { writer.writeAll(input[start .. start + 23]) catch return ZipponError.WriteError; } } return start; }