From b757e01b64a954cfedb451771a848c7bb0d159a8 Mon Sep 17 00:00:00 2001 From: MrBounty Date: Fri, 31 Jan 2025 10:05:55 +0100 Subject: [PATCH] Array and link are empty by default if not in ADD action. Also can use * to return everything execpt link The * is to be use like that GRAB User [*, friends] Because if I just do GRAB User [friends], I only get friends So I would of need to specify all of them like GRAB User [name, age, email, .., friends] --- src/dataStructure/additionalData.zig | 4 +- src/dataStructure/filter.zig | 8 ++-- src/file/read.zig | 2 +- src/schema/utils.zig | 71 ++++++++++++++++++---------- src/test.zig | 20 ++++---- src/ziql/parser.zig | 6 ++- src/ziql/parts/additionalData.zig | 6 +++ src/ziql/tokenizer.zig | 6 +++ 8 files changed, 80 insertions(+), 43 deletions(-) diff --git a/src/dataStructure/additionalData.zig b/src/dataStructure/additionalData.zig index 1738cef..b713ceb 100644 --- a/src/dataStructure/additionalData.zig +++ b/src/dataStructure/additionalData.zig @@ -20,10 +20,10 @@ pub fn init(allocator: Allocator) AdditionalData { }; } -pub fn populateWithEverythingExceptLink(self: *AdditionalData, members: [][]const u8, dtypes: []DataType) !void { +pub fn populateWithEverythingExceptLink(self: *AdditionalData, members: [][]const u8, dtypes: []DataType) ZipponError!void { for (members, dtypes, 0..) |member, dt, i| { if (dt == .link or dt == .link_array) continue; - try self.childrens.append(AdditionalDataMember.init(self.allocator, member, i)); + self.childrens.append(AdditionalDataMember.init(self.allocator, member, i)) catch return ZipponError.MemoryError; } } diff --git a/src/dataStructure/filter.zig b/src/dataStructure/filter.zig index 66648b6..c7b6514 100644 --- a/src/dataStructure/filter.zig +++ b/src/dataStructure/filter.zig @@ -66,8 +66,8 @@ pub const ConditionValue = union(enum) { float_array: []const f64, bool_array: []const bool, unix_array: []const u64, - link: *std.AutoHashMap(UUID, void), - link_array: *std.AutoHashMap(UUID, void), + link: *const std.AutoHashMap(UUID, void), + link_array: *const std.AutoHashMap(UUID, void), pub fn init(dtype: DataType, value: []const u8) ConditionValue { return switch (dtype) { @@ -134,11 +134,11 @@ pub const ConditionValue = union(enum) { return ConditionValue{ .unix_array = value }; } - pub fn initLink(value: *std.AutoHashMap(UUID, void)) ConditionValue { + pub fn initLink(value: *const std.AutoHashMap(UUID, void)) ConditionValue { return ConditionValue{ .link = value }; } - pub fn initArrayLink(value: *std.AutoHashMap(UUID, void)) ConditionValue { + pub fn initArrayLink(value: *const std.AutoHashMap(UUID, void)) ConditionValue { return ConditionValue{ .link_array = value }; } }; diff --git a/src/file/read.zig b/src/file/read.zig index 31c4e14..e8b2d4d 100644 --- a/src/file/read.zig +++ b/src/file/read.zig @@ -366,7 +366,7 @@ pub fn parseEntitiesRelationMap( dir, sstruct.zid_schema, relation_map.additional_data, - try self.schema_engine.structName2DataType(struct_name), + sstruct.types, &sync_context, }, ); diff --git a/src/schema/utils.zig b/src/schema/utils.zig index 63c5aa6..a5fc3af 100644 --- a/src/schema/utils.zig +++ b/src/schema/utils.zig @@ -13,14 +13,27 @@ const JsonString = RelationMap.JsonString; const ZipponError = @import("error").ZipponError; +var empty_map_buf: [20]u8 = undefined; +var fa = std.heap.FixedBufferAllocator.init(&empty_map_buf); +const empty_map_allocator = fa.allocator(); + +const empty_int: [0]i32 = .{}; +const empty_float: [0]f64 = .{}; +const empty_unix: [0]u64 = .{}; +const empty_bool: [0]bool = .{}; +const empty_str: [0][]const u8 = .{}; +const zero_link = std.AutoHashMap(UUID, void).init(empty_map_allocator); +const empty_link = std.AutoHashMap(UUID, void).init(empty_map_allocator); + // I need to redo how SchemaStruct work because it is a mess // I mean I use wayyyyyyyyyyyyyyyyyyyyyyy too much structName2SchemaStruct or stuff like that // I mean that not good to always for loop and compare when a map would work pub fn memberName2DataType(self: *Self, struct_name: []const u8, member_name: []const u8) ZipponError!DataType { - for (try self.structName2structMembers(struct_name), 0..) |mn, i| { - const dtypes = try self.structName2DataType(struct_name); - if (std.mem.eql(u8, mn, member_name)) return dtypes[i]; + const sstruct = try self.structName2SchemaStruct(struct_name); + + for (sstruct.members, 0..) |mn, i| { + if (std.mem.eql(u8, mn, member_name)) return sstruct.types[i]; } return ZipponError.MemberNotFound; @@ -47,7 +60,7 @@ pub fn structName2structMembers(self: Self, struct_name: []const u8) ZipponError return self.struct_array[i].members; } -// TODO: This is the first one I want to change to use a map +// Return the SchemaStruct based on it's name pub fn structName2SchemaStruct(self: Self, struct_name: []const u8) ZipponError!SchemaStruct { var i: usize = 0; @@ -60,20 +73,6 @@ pub fn structName2SchemaStruct(self: Self, struct_name: []const u8) ZipponError! return self.struct_array[i]; } -pub fn structName2DataType(self: Self, struct_name: []const u8) ZipponError![]const DataType { - var i: u16 = 0; - - while (i < self.struct_array.len) : (i += 1) { - if (std.mem.eql(u8, self.struct_array[i].name, struct_name)) break; - } - - if (i == self.struct_array.len and !std.mem.eql(u8, self.struct_array[i].name, struct_name)) { - return ZipponError.StructNotFound; - } - - return self.struct_array[i].types; -} - /// Chech if the name of a struct is in the current schema pub fn isStructNameExists(self: Self, struct_name: []const u8) bool { var i: u16 = 0; @@ -98,23 +97,43 @@ pub fn linkedStructName(self: Self, struct_name: []const u8, member_name: []cons return sstruct; } -pub fn checkIfAllMemberInMap( +/// Use with NewData to check if all member are in the map, otherwise write the missing one to be send with the error +/// Also if array and link are missing, to make them empty instead +pub fn checkIfAllMemberInMapAndAddEmptyMissingArray( self: Self, struct_name: []const u8, map: *std.StringHashMap(ValueOrArray), - error_message_buffer: *std.ArrayList(u8), + writer: std.ArrayList(u8).Writer, ) ZipponError!bool { - const all_struct_member = try self.structName2structMembers(struct_name); + const sstruct = try self.structName2SchemaStruct(struct_name); var count: u16 = 0; - const writer = error_message_buffer.writer(); - - for (all_struct_member) |mn| { + for (sstruct.members, sstruct.types) |mn, dt| { if (std.mem.eql(u8, mn, "id")) continue; - if (map.contains(mn)) count += 1 else writer.print(" {s},", .{mn}) catch return ZipponError.WriteError; + if (map.contains(mn)) count += 1 else { + if (dt.is_array() or dt == .link) { + map.put( + mn, + switch (dt) { + .int_array => ValueOrArray{ .value = try ConditionValue.initArrayInt(&empty_int) }, + .float_array => ValueOrArray{ .value = try ConditionValue.initArrayFloat(&empty_float) }, + .str_array => ValueOrArray{ .value = try ConditionValue.initArrayStr(&empty_str) }, + .bool_array => ValueOrArray{ .value = try ConditionValue.initArrayBool(&empty_bool) }, + .date_array => ValueOrArray{ .value = try ConditionValue.initArrayUnix(&empty_unix) }, + .time_array => ValueOrArray{ .value = try ConditionValue.initArrayUnix(&empty_unix) }, + .datetime_array => ValueOrArray{ .value = try ConditionValue.initArrayUnix(&empty_unix) }, + .link_array => ValueOrArray{ .value = ConditionValue.initArrayLink(&empty_link) }, + .link => ValueOrArray{ .value = ConditionValue.initLink(&zero_link) }, + else => unreachable, + }, + ) catch return ZipponError.MemoryError; + count += 1; + } + writer.print(" {s},", .{mn}) catch return ZipponError.WriteError; + } } - return ((count == all_struct_member.len - 1) and (count == map.count())); + return ((count == sstruct.members.len - 1) and (count == map.count())); } pub fn isUUIDExist(self: Self, struct_name: []const u8, uuid: UUID) bool { diff --git a/src/test.zig b/src/test.zig index 9ab3a24..a4790e6 100644 --- a/src/test.zig +++ b/src/test.zig @@ -89,11 +89,21 @@ test "GRAB filter with date" { // OK try testParsing(db, "GRAB User {last_order > 2000/01/01-12:45}"); } -test "Specific query" { // OK +// FIXME: GRAB User [1] return nothing +test "Specific query" { // NOT OK const db = DB{ .path = "test1", .schema = "schema/test" }; try testParsing(db, "GRAB User"); try testParsing(db, "GRAB User {}"); try testParsing(db, "GRAB User [1]"); + try testParsing(db, "GRAB User [*, friends]"); +} + +test "Specific query ADD" { // OK + const db = DB{ .path = "test1", .schema = "schema/test" }; + try testParsing(db, "ADD User (name = 'Bob1', email='bob@email.com', age=55, best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)"); + try testParsing(db, "ADD User (name = 'Bob2', email='bob@email.com', age=55, best_friend=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)"); + try testParsing(db, "ADD User (name = 'Bob3', email='bob@email.com', age=55, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)"); + try testParsing(db, "GRAB User {name IN ['Bob1', 'Bob2', 'Bob3']}"); } // Array manipulation @@ -188,14 +198,6 @@ test "GRAB Relationship dot" { // TODO: Make this a reality try testParsing(db, "GRAB User [1] {}"); } -// Cleaning -// =============================================================== - -test "DELETE" { - const db = DB{ .path = "test1", .schema = "schema/test" }; - try testParsing(db, "DELETE User {}"); -} - // 3 Struct Relationship // =============================================================== diff --git a/src/ziql/parser.zig b/src/ziql/parser.zig index 70d7b21..fc2be2f 100644 --- a/src/ziql/parser.zig +++ b/src/ziql/parser.zig @@ -353,7 +353,11 @@ pub fn parse(self: *Self, parent_allocator: Allocator, buffer: [:0]const u8) Zip const error_message_buffer_writer = error_message_buffer.writer(); error_message_buffer_writer.writeAll("Error missing: ") catch return ZipponError.WriteError; - if (!(self.schema_engine.checkIfAllMemberInMap(struct_name, &data_map, &error_message_buffer) catch { + if (!(self.schema_engine.checkIfAllMemberInMapAndAddEmptyMissingArray( + struct_name, + &data_map, + error_message_buffer.writer(), + ) catch { return ZipponError.StructNotFound; })) { _ = error_message_buffer.pop(); diff --git a/src/ziql/parts/additionalData.zig b/src/ziql/parts/additionalData.zig index e147388..9084cdc 100644 --- a/src/ziql/parts/additionalData.zig +++ b/src/ziql/parts/additionalData.zig @@ -85,6 +85,12 @@ pub fn parseAdditionalData( state = .expect_comma_OR_r_bracket_OR_l_bracket; }, + .star => { + const sstruct = try self.schema_engine.structName2SchemaStruct(struct_name); + try additional_data.populateWithEverythingExceptLink(sstruct.members, sstruct.types); + last_member = undefined; + state = .expect_comma_OR_r_bracket_OR_l_bracket; + }, else => return printError( "Error: Expected a member name.", ZipponError.SynthaxError, diff --git a/src/ziql/tokenizer.zig b/src/ziql/tokenizer.zig index 78fad37..b0163d0 100644 --- a/src/ziql/tokenizer.zig +++ b/src/ziql/tokenizer.zig @@ -76,6 +76,7 @@ pub const Token = struct { uuid_literal, identifier, equal, + star, // * bang, // ! pipe, // | l_paren, // ( @@ -171,6 +172,11 @@ pub const Tokenizer = struct { '=' => { state = .equal; }, + '*' => { + result.tag = .star; + self.index += 1; + break; + }, '!' => { state = .bang; },