diff --git a/src/fileEngine.zig b/src/fileEngine.zig index df6a802..24b68b4 100644 --- a/src/fileEngine.zig +++ b/src/fileEngine.zig @@ -329,6 +329,9 @@ pub const FileEngine = struct { /// Take a filter, parse all file and if one struct if validate by the filter, write it in a JSON format to the writer /// filter can be null. This will return all of them + /// TODO: For relationship, if they are in additional_data and I need to return it with the other members, I will need to parse the file + /// This is difficult, because that mean I need to parse file while parsing files ? I dont like that because it may be the same struct + /// And because of multi thread, I can read the same file at the same time... pub fn parseEntities( self: *FileEngine, struct_name: []const u8, @@ -475,7 +478,14 @@ pub const FileEngine = struct { .Float => |v| try writer.print("{d}", .{v}), .Int => |v| try writer.print("{d}", .{v}), .Str => |v| try writer.print("\"{s}\"", .{v}), - .UUID => |v| try writer.print("\"{s}\"", .{UUID.format_bytes(v)}), + .UUID => |v| { + 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}\"", .{UUID.format_bytes(v)}); + } else { + try writer.print("{{}}", .{}); + } + }, .Bool => |v| try writer.print("{any}", .{v}), .Unix => |v| { const datetime = DateTime.initUnix(v); diff --git a/src/main.zig b/src/main.zig index 61a5dc1..2051f84 100644 --- a/src/main.zig +++ b/src/main.zig @@ -49,6 +49,10 @@ pub const DBEngine = struct { pub fn init(allocator: std.mem.Allocator, potential_main_path: ?[]const u8, potential_schema_path: ?[]const u8) DBEngine { var self = DBEngine{ .allocator = allocator }; const potential_main_path_or_environment_variable = potential_main_path orelse utils.getEnvVariable(allocator, "ZIPPONDB_PATH"); + defer { + log.debug("{s} {any}\n", .{ potential_main_path_or_environment_variable.?, potential_schema_path }); + if (potential_main_path_or_environment_variable != null and potential_main_path == null) allocator.free(potential_main_path_or_environment_variable.?); + } if (potential_main_path_or_environment_variable) |main_path| { log_path = std.fmt.bufPrint(&log_buff, "{s}/LOG/log", .{main_path}) catch ""; @@ -100,6 +104,7 @@ pub const DBEngine = struct { log.info("Database don't have any schema yet, trying to add one.", .{}); const potential_schema_path_or_environment_variable = potential_schema_path orelse utils.getEnvVariable(allocator, "ZIPPONDB_SCHEMA"); + if (potential_schema_path_or_environment_variable != null and potential_schema_path == null) allocator.free(potential_main_path_or_environment_variable.?); if (potential_schema_path_or_environment_variable) |schema_path| { log.info("Found schema path {s}.", .{schema_path}); self.schema_engine = SchemaEngine.init(self.allocator, schema_path) catch |err| { diff --git a/src/stuffs/filter.zig b/src/stuffs/filter.zig index a35ebdc..d3eaa9c 100644 --- a/src/stuffs/filter.zig +++ b/src/stuffs/filter.zig @@ -59,12 +59,13 @@ pub const ConditionValue = union(enum) { bool_: bool, self: UUID, unix: u64, + link: UUID, int_array: std.ArrayList(i32), str_array: std.ArrayList([]const u8), float_array: std.ArrayList(f64), bool_array: std.ArrayList(bool), unix_array: std.ArrayList(u64), - link: *std.AutoHashMap([16]u8, void), + link_array: *std.AutoHashMap([16]u8, void), pub fn deinit(self: ConditionValue) void { switch (self) { @@ -73,6 +74,7 @@ pub const ConditionValue = union(enum) { .float_array => self.float_array.deinit(), .bool_array => self.bool_array.deinit(), .unix_array => self.unix_array.deinit(), + .link_array => self.link_array.deinit(), else => {}, } } @@ -109,6 +111,14 @@ pub const ConditionValue = union(enum) { return ConditionValue{ .unix = s2t.parseDatetime(value).toUnix() }; } + pub fn initLink(value: []const u8) ConditionValue { + const uuid = UUID.parse(value) catch { + std.debug.print("Error: {s}", .{value}); + @panic("WFT ?"); + }; + return ConditionValue{ .link = uuid }; + } + // Array pub fn initArrayInt(allocator: std.mem.Allocator, value: []const u8) ConditionValue { return ConditionValue{ .int_array = s2t.parseArrayInt(allocator, value) }; @@ -138,8 +148,8 @@ pub const ConditionValue = union(enum) { return ConditionValue{ .unix_array = s2t.parseArrayDatetimeUnix(allocator, value) }; } - pub fn initLink(value: *std.AutoHashMap([16]u8, void)) ConditionValue { - return ConditionValue{ .link = value }; + pub fn initLinkArray(value: *std.AutoHashMap([16]u8, void)) ConditionValue { + return ConditionValue{ .link_array = value }; } }; @@ -386,12 +396,12 @@ test "ConditionValue: link" { try hash_map.put(uuid2.bytes, {}); // Create a ConditionValue with the link - var value = ConditionValue.initLink(&hash_map); + var value = ConditionValue.initLinkArray(&hash_map); // Check that the hash map contains the correct number of UUIDs - try std.testing.expectEqual(@as(usize, 2), value.link.count()); + try std.testing.expectEqual(@as(usize, 2), value.link_array.count()); // Check that specific UUIDs are in the hash map - try std.testing.expect(value.link.contains(uuid1.bytes)); - try std.testing.expect(value.link.contains(uuid2.bytes)); + try std.testing.expect(value.link_array.contains(uuid1.bytes)); + try std.testing.expect(value.link_array.contains(uuid2.bytes)); } diff --git a/src/ziqlParser.zig b/src/ziqlParser.zig index b69dc8c..b3f9cc8 100644 --- a/src/ziqlParser.zig +++ b/src/ziqlParser.zig @@ -564,7 +564,9 @@ pub const Parser = struct { }; var filter: ?Filter = null; + defer if (filter != null) filter.?.deinit(); var additional_data = AdditionalData.init(self.allocator); + defer additional_data.deinit(); if (expected_tag) |tag| { if (condition.data_type.is_array()) { @@ -607,6 +609,33 @@ pub const Parser = struct { } } else if (condition.data_type == .link) { switch (token.tag) { + .l_bracket => { + try self.parseAdditionalData( + &additional_data, + struct_name, + ); + }, + .uuid_literal => {}, + else => {}, + } + + additional_data.entity_count_to_find = 1; + + switch (token.tag) { + .l_brace => { + filter = try self.parseFilter(struct_name, false); + }, + .uuid_literal => {}, + else => return printError( + "Error: Expected new filter or UUID", + ZiQlParserError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + } + } else if (condition.data_type == .link_array) { + switch (token.tag) { // TODO: Also be able to do an array of UUID like [00000-00000-00000 000000-000000-0000001] .l_bracket => { try self.parseAdditionalData( &additional_data, @@ -639,7 +668,7 @@ pub const Parser = struct { .time => condition.value = ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]), .datetime => condition.value = ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]), .bool => condition.value = ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]), - .link => { + .link_array => { var map = std.AutoHashMap([16]u8, void).init(self.allocator); try self.file_engine.populateUUIDMap( struct_name, @@ -647,7 +676,20 @@ pub const Parser = struct { &map, &additional_data, ); - condition.value = ConditionValue.initLink(&map); + condition.value = ConditionValue.initLinkArray(&map); + }, + .link => switch (token.tag) { + .l_brace, .l_bracket => {}, // Get the first entity using a filter + .uuid_literal => { + condition.value = ConditionValue.initLink(self.toker.buffer[start_index..token.loc.end]); + }, + else => return printError( + "Error: Expected filter or UUID", + ZiQlParserError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), }, else => unreachable, // TODO: Make for link and array =/ } @@ -1108,9 +1150,9 @@ test "Specific query" { try testParsing("GRAB User [1]"); } -//test "Relationship" { -// try testParsing("GRAB User {best_friend IN {name = 'Bob'}}"); -//} +test "Relationship" { + try testParsing("GRAB User {best_friend IN {name = 'Bob'}}"); +} test "DELETE" { try testParsing("DELETE User {name='Bob'}");