From 78e8b67b801ee2c22cb24e0bf21707e164939dbf Mon Sep 17 00:00:00 2001 From: MrBounty Date: Sat, 25 Jan 2025 19:11:01 +0100 Subject: [PATCH] Moved benchmark and test to src. Implemented array without testing yet --- build.zig | 18 +- lib/types/stringToType.zig | 241 ------------- schema/benchmark | 2 + benchmark.zig => src/benchmark.zig | 90 ++++- src/dataStructure/filter.zig | 65 +++- src/file/entityWriter.zig | 2 +- src/schema/parser.zig | 1 - test.zig => src/test.zig | 15 +- test_runner.zig => src/test_runner.zig | 0 src/ziql/parser.zig | 1 - src/ziql/parts/condition.zig | 96 +++++- src/ziql/parts/value.zig | 448 +++++++++++++++++-------- src/ziql/utils.zig | 122 ------- 13 files changed, 554 insertions(+), 547 deletions(-) rename benchmark.zig => src/benchmark.zig (74%) rename test.zig => src/test.zig (94%) rename test_runner.zig => src/test_runner.zig (100%) delete mode 100644 src/ziql/utils.zig diff --git a/build.zig b/build.zig index 7d9b3b0..f7f1b96 100644 --- a/build.zig +++ b/build.zig @@ -34,7 +34,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "CLI tokenizer", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); tests1.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") })); const run_tests1 = b.addRunArtifact(tests1); @@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "CLI tokenizer", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); const run_tests2 = b.addRunArtifact(tests2); @@ -53,7 +53,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "ZiQL tokenizer", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); const run_tests3 = b.addRunArtifact(tests3); @@ -62,18 +62,18 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "Schema tokenizer", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); tests4.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") })); tests4.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") })); const run_tests4 = b.addRunArtifact(tests4); const tests5 = b.addTest(.{ - .root_source_file = b.path("test.zig"), + .root_source_file = b.path("src/test.zig"), .target = target, .optimize = optimize, .name = "ZiQL parser", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); tests5.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") })); tests5.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") })); @@ -86,7 +86,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "Filter tree", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); tests6.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") })); tests6.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") })); @@ -111,7 +111,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, .name = "File parsing", - .test_runner = b.path("test_runner.zig"), + .test_runner = b.path("src/test_runner.zig"), }); const run_tests1 = b.addRunArtifact(tests1); @@ -124,7 +124,7 @@ pub fn build(b: *std.Build) void { { const benchmark = b.addExecutable(.{ .name = "benchmark", - .root_source_file = b.path("benchmark.zig"), + .root_source_file = b.path("src/benchmark.zig"), .target = target, .optimize = optimize, }); diff --git a/lib/types/stringToType.zig b/lib/types/stringToType.zig index 8e6e7e9..0b6ef14 100644 --- a/lib/types/stringToType.zig +++ b/lib/types/stringToType.zig @@ -6,34 +6,10 @@ pub fn parseInt(value_str: []const u8) i32 { return std.fmt.parseInt(i32, value_str, 10) catch return 0; } -pub fn parseArrayInt(allocator: std.mem.Allocator, array_str: []const u8) ![]const i32 { - var array = std.ArrayList(i32).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseInt(x)); - } - - return try array.toOwnedSlice(); -} - pub fn parseFloat(value_str: []const u8) f64 { return std.fmt.parseFloat(f64, value_str) catch return 0; } -pub fn parseArrayFloat(allocator: std.mem.Allocator, array_str: []const u8) ![]const f64 { - var array = std.ArrayList(f64).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseFloat(x)); - } - - return try array.toOwnedSlice(); -} - pub fn parseBool(value_str: []const u8) bool { return (value_str[0] != '0'); } @@ -48,30 +24,6 @@ pub fn parseDate(value_str: []const u8) DateTime { return DateTime.init(year, month - 1, day - 1, 0, 0, 0, 0); } -pub fn parseArrayDate(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime { - var array = std.ArrayList(DateTime).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseDate(x)); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayDateUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 { - var array = std.ArrayList(u64).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseDate(x).toUnix()); - } - - return array.toOwnedSlice(); -} - pub fn parseTime(value_str: []const u8) DateTime { if (std.mem.eql(u8, value_str, "NOW")) return DateTime.now(); @@ -83,30 +35,6 @@ pub fn parseTime(value_str: []const u8) DateTime { return DateTime.init(0, 0, 0, hours, minutes, seconds, milliseconds); } -pub fn parseArrayTime(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime { - var array = std.ArrayList(DateTime).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseTime(x)); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayTimeUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 { - var array = std.ArrayList(u64).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseTime(x).toUnix()); - } - - return try array.toOwnedSlice(); -} - pub fn parseDatetime(value_str: []const u8) DateTime { if (std.mem.eql(u8, value_str, "NOW")) return DateTime.now(); @@ -121,155 +49,31 @@ pub fn parseDatetime(value_str: []const u8) DateTime { return DateTime.init(year, month - 1, day - 1, hours, minutes, seconds, milliseconds); } -pub fn parseArrayDatetime(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime { - var array = std.ArrayList(DateTime).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseDatetime(x)); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayDatetimeUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 { - var array = std.ArrayList(u64).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseDatetime(x).toUnix()); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayBool(allocator: std.mem.Allocator, array_str: []const u8) ![]const bool { - var array = std.ArrayList(bool).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(parseBool(x)); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayUUID(allocator: std.mem.Allocator, array_str: []const u8) ![]const UUID { - var array = std.ArrayList(UUID).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - const uuid = try UUID.parse(x); - try array.append(uuid); - } - - return try array.toOwnedSlice(); -} - -pub fn parseArrayUUIDBytes(allocator: std.mem.Allocator, array_str: []const u8) ![]const [16]u8 { - var array = std.ArrayList([16]u8).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - const uuid = try UUID.parse(x); - try array.append(uuid.bytes); - } - - return try array.toOwnedSlice(); -} - -// FIXME: I think it will not work if there is a ' inside the string, even \', need to fix that -pub fn parseArrayStr(allocator: std.mem.Allocator, array_str: []const u8) ![]const []const u8 { - var array = std.ArrayList([]const u8).init(allocator); - - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], "'"); - _ = it.next(); // SSkip first token that is empty - while (it.next()) |x| { - if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue; - try array.append(x); - } - - if (array.items.len > 0) allocator.free(array.pop()); // Remove the last because empty like the first one - - return try array.toOwnedSlice(); -} - test "Value parsing: Int" { - const allocator = std.testing.allocator; - - // Int const values: [3][]const u8 = .{ "1", "42", "Hello" }; const expected_values: [3]i32 = .{ 1, 42, 0 }; for (values, 0..) |value, i| { try std.testing.expect(parseInt(value) == expected_values[i]); } - - // Int array - const array_str = "[1 14 44 42 hello]"; - const array = try parseArrayInt(allocator, array_str); - defer allocator.free(array); - const expected_array: [5]i32 = .{ 1, 14, 44, 42, 0 }; - try std.testing.expect(std.mem.eql(i32, array, &expected_array)); } test "Value parsing: Float" { - const allocator = std.testing.allocator; - // Float const values: [3][]const u8 = .{ "1.3", "65.991", "Hello" }; const expected_values: [3]f64 = .{ 1.3, 65.991, 0 }; for (values, 0..) |value, i| { try std.testing.expect(parseFloat(value) == expected_values[i]); } - - // Float array - const array_str = "[1.5 14.3 44.9999 42 hello]"; - const array = try parseArrayFloat(allocator, array_str); - defer allocator.free(array); - const expected_array: [5]f64 = .{ 1.5, 14.3, 44.9999, 42, 0 }; - try std.testing.expect(std.mem.eql(f64, array, &expected_array)); -} - -test "Value parsing: String" { - // Note that I dont parse string because I dont need to, a string is a string - - const allocator = std.testing.allocator; - - // string array - const array_str = "['Hello' 'How are you doing ?' '']"; - const array = try parseArrayStr(allocator, array_str); - defer allocator.free(array); - const expected_array: [3][]const u8 = .{ "Hello", "How are you doing ?", "" }; - for (array, expected_array) |parsed, expected| { - std.debug.print("{s} : {s}\n", .{ parsed, expected }); - try std.testing.expect(std.mem.eql(u8, parsed, expected)); - } } test "Value parsing: Bool array" { - const allocator = std.testing.allocator; - const values: [3][]const u8 = .{ "1", "Hello", "0" }; const expected_values: [3]bool = .{ true, true, false }; for (values, 0..) |value, i| { try std.testing.expect(parseBool(value) == expected_values[i]); } - - // Bool array - const array_str = "[1 0 0 1 1]"; - const array = try parseArrayBool(allocator, array_str); - defer allocator.free(array); - const expected_array: [5]bool = .{ true, false, false, true, true }; - try std.testing.expect(std.mem.eql(bool, array, &expected_array)); } test "Value parsing: Date" { - const allocator = std.testing.allocator; - // Date const values: [3][]const u8 = .{ "1920/01/01", "1998/01/21", "2024/12/31" }; const expected_values: [3]DateTime = .{ DateTime.init(1920, 0, 0, 0, 0, 0, 0), @@ -279,24 +83,9 @@ test "Value parsing: Date" { for (values, 0..) |value, i| { try std.testing.expect(expected_values[i].compareDate(parseDate(value))); } - - // Date array - const array_str = "[1920/01/01 1998/01/21 2024/12/31]"; - const array = try parseArrayDate(allocator, array_str); - defer allocator.free(array); - const expected_array: [3]DateTime = .{ - DateTime.init(1920, 0, 0, 0, 0, 0, 0), - DateTime.init(1998, 0, 20, 0, 0, 0, 0), - DateTime.init(2024, 11, 30, 0, 0, 0, 0), - }; - for (array, expected_array) |parsed, expected| { - try std.testing.expect(expected.compareDate(parsed)); - } } test "Value parsing: Time" { - const allocator = std.testing.allocator; - const values: [4][]const u8 = .{ "12:45:00.0000", "18:12:53.7491", "02:30:10", "12:30" }; const expected_values: [4]DateTime = .{ DateTime.init(0, 0, 0, 12, 45, 0, 0), @@ -307,25 +96,9 @@ test "Value parsing: Time" { for (values, 0..) |value, i| { try std.testing.expect(expected_values[i].compareTime(parseTime(value))); } - - // Time array - const array_str = "[12:45:00.0000 18:12:53.7491 02:30:10 12:30]"; - const array = try parseArrayTime(allocator, array_str); - defer allocator.free(array); - const expected_array: [4]DateTime = .{ - DateTime.init(0, 0, 0, 12, 45, 0, 0), - DateTime.init(0, 0, 0, 18, 12, 53, 7491), - DateTime.init(0, 0, 0, 2, 30, 10, 0), - DateTime.init(0, 0, 0, 12, 30, 0, 0), - }; - for (array, expected_array) |parsed, expected| { - try std.testing.expect(expected.compareTime(parsed)); - } } test "Value parsing: Datetime" { - const allocator = std.testing.allocator; - const values: [4][]const u8 = .{ "1920/01/01-12:45:00.0000", "1920/01/01-18:12:53.7491", "1920/01/01-02:30:10", "1920/01/01-12:30" }; const expected_values: [4]DateTime = .{ DateTime.init(1920, 0, 0, 12, 45, 0, 0), @@ -336,18 +109,4 @@ test "Value parsing: Datetime" { for (values, 0..) |value, i| { try std.testing.expect(expected_values[i].compareDatetime(parseDatetime(value))); } - - // Time array - const array_str = "[1920/01/01-12:45:00.0000 1920/01/01-18:12:53.7491 1920/01/01-02:30:10 1920/01/01-12:30]"; - const array = try parseArrayDatetime(allocator, array_str); - defer allocator.free(array); - const expected_array: [4]DateTime = .{ - DateTime.init(1920, 0, 0, 12, 45, 0, 0), - DateTime.init(1920, 0, 0, 18, 12, 53, 7491), - DateTime.init(1920, 0, 0, 2, 30, 10, 0), - DateTime.init(1920, 0, 0, 12, 30, 0, 0), - }; - for (array, expected_array) |parsed, expected| { - try std.testing.expect(expected.compareDatetime(parsed)); - } } diff --git a/schema/benchmark b/schema/benchmark index 1c6f6ed..55fc5e6 100644 --- a/schema/benchmark +++ b/schema/benchmark @@ -1,6 +1,8 @@ User ( name: str, email: str, + age: int, + address: str, ) Order ( diff --git a/benchmark.zig b/src/benchmark.zig similarity index 74% rename from benchmark.zig rename to src/benchmark.zig index 3aeda2c..0a62509 100644 --- a/benchmark.zig +++ b/src/benchmark.zig @@ -1,6 +1,6 @@ const std = @import("std"); const dtype = @import("dtype"); -const DBEngine = @import("src/cli/core.zig"); +const DBEngine = @import("cli/core.zig"); const ZipponError = @import("error").ZipponError; const names = [_][]const u8{ "Alice", "Bob", "Charlie", "Dave", "Eve" }; @@ -8,13 +8,15 @@ const emails = [_][]const u8{ "alice@email.com", "bob@email.com", "charlie@email const dates = [_][]const u8{ "2000/01/01", "1954/04/02", "1998/01/21", "1977/12/31" }; const times = [_][]const u8{ "12:04", "20:45:11", "03:11:13", "03:00:01.0152" }; const datetimes = [_][]const u8{ "2000/01/01-12:04", "1954/04/02-20:45:11", "1998/01/21-03:11:13", "1977/12/31-03:00:01.0153" }; -const scores = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; +const ages = [_][]const u8{ "15", "11", "53", "34", "96", "64" }; +const address = [_][]const u8{ "01 rue Notre Dame", "11 street St Bob", "Route to Heaven bis", "Here", "Not here", "Maybe here" }; pub const std_options = std.Options{ .log_level = .info, .logFn = myLog, }; +const NUMBER_OF_RUN: usize = 10; var date_buffer: [64]u8 = undefined; var date_fa = std.heap.FixedBufferAllocator.init(&date_buffer); const date_allocator = date_fa.allocator(); @@ -144,19 +146,23 @@ pub fn benchmark(allocator: std.mem.Allocator) !void { var writer = array.writer(); try writer.print( - "ADD User (name = '{s}', email='{s}', orders=none)", + "ADD User (name = '{s}', email='{s}', age={s}, address='{s}')", .{ names[rng.uintAtMost(usize, names.len - 1)], emails[rng.uintAtMost(usize, emails.len - 1)], + ages[rng.uintAtMost(usize, ages.len - 1)], + address[rng.uintAtMost(usize, address.len - 1)], }, ); for (0..users_count - 1) |_| { try writer.print( - "('{s}', '{s}', none)", + "('{s}', '{s}', {s}, '{s}')", .{ names[rng.uintAtMost(usize, names.len - 1)], emails[rng.uintAtMost(usize, emails.len - 1)], + ages[rng.uintAtMost(usize, ages.len - 1)], + address[rng.uintAtMost(usize, address.len - 1)], }, ); } @@ -173,7 +179,7 @@ pub fn benchmark(allocator: std.mem.Allocator) !void { } // Order - { + if (false) { // Linked array not yet implemented and array manipulation not tested const null_term_query_str = try std.fmt.bufPrintZ( &line_buffer, // I dont like 'category = {name='Book'}'. Maybe att a IS keyword ? @@ -203,6 +209,8 @@ pub fn benchmark(allocator: std.mem.Allocator) !void { // Run query { + var read_time: f64 = 0; + var read_write_time: f64 = 0; const queries = [_][]const u8{ "GRAB User {}", "GRAB User {name='asd'}", @@ -212,24 +220,78 @@ pub fn benchmark(allocator: std.mem.Allocator) !void { "GRAB Category {}", "GRAB Item {}", "GRAB Order {}", - "GRAB Order [from, items, quantity, at] {at > 2024}", + "GRAB Order [from, items, quantity, at] {}", "DELETE User {}", }; // Run benchmarks - for (queries) |query| { - const start_time = std.time.nanoTimestamp(); + for (queries, 0..) |query, j| { + var time_buff: [NUMBER_OF_RUN]f64 = undefined; + for (0..NUMBER_OF_RUN) |i| { + const start_time = std.time.nanoTimestamp(); - // Execute the query here - const null_term_query_str = try std.fmt.bufPrintZ(&line_buffer, "{s}", .{query}); - db_engine.runQuery(null_term_query_str); + // Execute the query here + const null_term_query_str = try std.fmt.bufPrintZ(&line_buffer, "{s}", .{query}); + db_engine.runQuery(null_term_query_str); - const end_time = std.time.nanoTimestamp(); - const duration = @as(f64, @floatFromInt(end_time - start_time)) / 1e6; + const end_time = std.time.nanoTimestamp(); + time_buff[i] = @as(f64, @floatFromInt(end_time - start_time)) / 1e6; + } + std.debug.print( + "Query: \t{s}\nTime: \t{d:>6.2} ± {d:<6.2}ms | Min {d:>8.2}ms | Max {d:>8.2}ms\n\n", + .{ query, mean(time_buff), std_dev(time_buff), min(time_buff), max(time_buff) }, + ); - std.debug.print("Query: \t\t{s}\nDuration: \t{d:.6} ms\n\n", .{ query, duration }); + if (j == 0) read_write_time = mean(time_buff); + if (j == 1) read_time = mean(time_buff); } + std.debug.print( + "Read: \t{d:.0} Entity/second\t*Include small condition\n", + .{@as(f64, @floatFromInt(users_count)) / (read_time / 1000)}, + ); + std.debug.print( + "Write: \t{d:.0} Entity/second\n", + .{@as(f64, @floatFromInt(users_count)) / ((read_write_time - read_time) / 1000)}, + ); } } std.debug.print("=====================================\n\n", .{}); } + +fn min(array: [NUMBER_OF_RUN]f64) f64 { + var current_min: f64 = 999999999999; + for (array) |value| { + if (value < current_min) current_min = value; + } + return current_min; +} + +fn max(array: [NUMBER_OF_RUN]f64) f64 { + var current_max: f64 = 0; + for (array) |value| { + if (value > current_max) current_max = value; + } + return current_max; +} + +fn mean(array: [NUMBER_OF_RUN]f64) f64 { + var total: f64 = 0; + for (array) |value| { + total += value; + } + return total / @as(f64, @floatFromInt(NUMBER_OF_RUN)); +} + +fn variance(array: [NUMBER_OF_RUN]f64) f64 { + const m = mean(array); + var square_diff: f64 = 0; + for (array) |value| { + square_diff += (value - m) * (value - m); + } + return square_diff / @as(f64, @floatFromInt(NUMBER_OF_RUN)); +} + +fn std_dev(array: [NUMBER_OF_RUN]f64) f64 { + const vari = variance(array); + return @sqrt(vari); +} diff --git a/src/dataStructure/filter.zig b/src/dataStructure/filter.zig index 733e9e0..fd19a6d 100644 --- a/src/dataStructure/filter.zig +++ b/src/dataStructure/filter.zig @@ -69,6 +69,18 @@ pub const ConditionValue = union(enum) { link: *std.AutoHashMap(UUID, void), link_array: *std.AutoHashMap(UUID, void), + pub fn init(dtype: DataType, value: []const u8) ConditionValue { + return switch (dtype) { + .int => ConditionValue.initInt(value), + .float => ConditionValue.initFloat(value), + .bool => ConditionValue.initBool(value), + .date => ConditionValue.initDate(value), + .time => ConditionValue.initTime(value), + .datetime => ConditionValue.initDateTime(value), + .str => ConditionValue.initStr(value[1 .. value.len - 1]), + }; + } + pub fn initInt(value: []const u8) ConditionValue { return ConditionValue{ .int = s2t.parseInt(value) }; } @@ -102,32 +114,24 @@ pub const ConditionValue = union(enum) { } // Array - pub fn initArrayInt(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .int_array = s2t.parseArrayInt(allocator, value) catch return ZipponError.ParsingValueError }; + pub fn initArrayInt(value: []const i32) ZipponError!ConditionValue { + return ConditionValue{ .int_array = value }; } - pub fn initArrayFloat(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .float_array = s2t.parseArrayFloat(allocator, value) catch return ZipponError.ParsingValueError }; + pub fn initArrayFloat(value: []const f64) ZipponError!ConditionValue { + return ConditionValue{ .float_array = value }; } - pub fn initArrayStr(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .str_array = s2t.parseArrayStr(allocator, value) catch return ZipponError.ParsingValueError }; + pub fn initArrayStr(value: []const []const u8) ZipponError!ConditionValue { + return ConditionValue{ .str_array = value }; } - pub fn initArrayBool(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .bool_array = s2t.parseArrayBool(allocator, value) catch return ZipponError.ParsingValueError }; + pub fn initArrayBool(value: []const bool) ZipponError!ConditionValue { + return ConditionValue{ .bool_array = value }; } - pub fn initArrayDate(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .unix_array = s2t.parseArrayDateUnix(allocator, value) catch return ZipponError.ParsingValueError }; - } - - pub fn initArrayTime(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .unix_array = s2t.parseArrayTimeUnix(allocator, value) catch return ZipponError.ParsingValueError }; - } - - pub fn initArrayDateTime(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue { - return ConditionValue{ .unix_array = s2t.parseArrayDatetimeUnix(allocator, value) catch return ZipponError.ParsingValueError }; + pub fn initArrayUnix(value: []const u64) ZipponError!ConditionValue { + return ConditionValue{ .unix_array = value }; } pub fn initLink(value: *std.AutoHashMap(UUID, void)) ConditionValue { @@ -308,13 +312,28 @@ pub const Filter = struct { else => unreachable, }, + // TODO: Add stuff to compare array, now condition with value as int, operator as in and to compare as []int should exist .in => switch (condition.data_type) { .link => condition.value.link.contains(UUID{ .bytes = row_value.UUID }), + .int => in(i32, row_value.Int, condition.value.int_array), + .float => in(f64, row_value.Float, condition.value.float_array), + .str => inStr(row_value.Str, condition.value.str_array), + .bool => in(bool, row_value.Bool, condition.value.bool_array), + .date => in(u64, row_value.Unix, condition.value.unix_array), + .time => in(u64, row_value.Unix, condition.value.unix_array), + .datetime => in(u64, row_value.Unix, condition.value.unix_array), else => unreachable, }, .not_in => switch (condition.data_type) { .link => !condition.value.link.contains(UUID{ .bytes = row_value.UUID }), + .int => !in(i32, row_value.Int, condition.value.int_array), + .float => !in(f64, row_value.Float, condition.value.float_array), + .str => !inStr(row_value.Str, condition.value.str_array), + .bool => !in(bool, row_value.Bool, condition.value.bool_array), + .date => !in(u64, row_value.Unix, condition.value.unix_array), + .time => !in(u64, row_value.Unix, condition.value.unix_array), + .datetime => !in(u64, row_value.Unix, condition.value.unix_array), else => unreachable, }, }; @@ -343,6 +362,16 @@ pub const Filter = struct { .empty => std.debug.print("Empty", .{}), } } + + fn in(comptime T: type, value: T, array: []const T) bool { + for (array) |v| if (v == value) return true; + return false; + } + + fn inStr(value: []const u8, array: []const []const u8) bool { + for (array) |v| if (std.mem.eql(u8, v, value)) return true; + return false; + } }; test "Evaluate" { diff --git a/src/file/entityWriter.zig b/src/file/entityWriter.zig index bf070fa..c90b37e 100644 --- a/src/file/entityWriter.zig +++ b/src/file/entityWriter.zig @@ -8,7 +8,7 @@ const DataType = dtype.DataType; const DateTime = dtype.DateTime; const UUID = dtype.UUID; -// TODO: Move this from FileEngine +// TODO: Move this outside of FileEngine and make it faster const ZipponError = @import("error").ZipponError; diff --git a/src/schema/parser.zig b/src/schema/parser.zig index a5eddf8..e218865 100644 --- a/src/schema/parser.zig +++ b/src/schema/parser.zig @@ -61,7 +61,6 @@ pub fn parse(self: *Parser, allocator: Allocator, struct_array: *std.ArrayList(S }, .eof => state = .end, else => { - std.debug.print("{s}\n", .{self.toker.getTokenSlice(token)}); return printError( "Error parsing schema: Expected a struct name", ZipponError.SynthaxError, diff --git a/test.zig b/src/test.zig similarity index 94% rename from test.zig rename to src/test.zig index 748e381..eb69c34 100644 --- a/test.zig +++ b/src/test.zig @@ -1,8 +1,8 @@ const std = @import("std"); const Allocator = std.mem.Allocator; -const Parser = @import("src/ziql/parser.zig"); -const Tokenizer = @import("src/ziql/tokenizer.zig").Tokenizer; -const DBEngine = @import("src/cli/core.zig"); +const Parser = @import("ziql/parser.zig"); +const Tokenizer = @import("ziql/tokenizer.zig").Tokenizer; +const DBEngine = @import("cli/core.zig"); const ZipponError = @import("error").ZipponError; const DB = struct { @@ -124,6 +124,11 @@ test "GRAB Relationship AdditionalData Filtered" { try testParsing(db, "GRAB User [2; name, best_friend] {best_friend !IN {}}"); } +test "GRAB name IN" { + const db = DB{ .path = "test1", .schema = "schema/test" }; + try testParsing(db, "GRAB User {name IN ['Bob' 'Bobinou']}"); +} + test "GRAB Relationship dot" { // DO I add this ? I'm not sure about this feature const db = DB{ .path = "test1", .schema = "schema/test" }; @@ -174,7 +179,9 @@ fn testParsing(db: DB, source: [:0]const u8) !void { &db_engine.schema_engine, ); + std.debug.print("Running: {s}\n", .{source}); try parser.parse(allocator, source); + std.debug.print("\n\n-------------------------------\n\n", .{}); } fn expectParsingError(db: DB, source: [:0]const u8, err: ZipponError) !void { @@ -187,5 +194,7 @@ fn expectParsingError(db: DB, source: [:0]const u8, err: ZipponError) !void { &db_engine.schema_engine, ); + std.debug.print("Running: {s}\n", .{source}); try std.testing.expectError(err, parser.parse(allocator, source)); + std.debug.print("\n\n-------------------------------\n\n", .{}); } diff --git a/test_runner.zig b/src/test_runner.zig similarity index 100% rename from test_runner.zig rename to src/test_runner.zig diff --git a/src/ziql/parser.zig b/src/ziql/parser.zig index ef22a47..425875c 100644 --- a/src/ziql/parser.zig +++ b/src/ziql/parser.zig @@ -67,7 +67,6 @@ pub usingnamespace @import("parts/newData.zig"); pub usingnamespace @import("parts/value.zig"); pub usingnamespace @import("parts/filter.zig"); pub usingnamespace @import("parts/additionalData.zig"); -pub usingnamespace @import("utils.zig"); toker: *Tokenizer = undefined, file_engine: *FileEngine, diff --git a/src/ziql/parts/condition.zig b/src/ziql/parts/condition.zig index a18abc8..d9b6f1f 100644 --- a/src/ziql/parts/condition.zig +++ b/src/ziql/parts/condition.zig @@ -71,11 +71,21 @@ pub fn parseCondition( .expect_operation => { condition.operation = try self.parseComparisonOperator(token); + if (condition.operation == .in) condition.data_type = switch (condition.data_type) { + .int => .int_array, + .float => .float_array, + .str => .str_array, + .bool => .bool_array, + .date => .date_array, + .time => .time_array, + .datetime => .datetime_array, + else => condition.data_type, + }; + log.debug("Condition operation {any}\n", .{condition.operation}); state = .expect_value; }, .expect_value => { - log.debug("Parse condition value of member {s}", .{member_name}); condition.value = try self.parseConditionValue(allocator, struct_name, member_name, condition.data_type, &token); state = .end; }, @@ -87,3 +97,87 @@ pub fn parseCondition( return condition; } + +pub fn checkConditionValidity( + self: Self, + condition: Condition, + token: Token, +) ZipponError!void { + switch (condition.operation) { + .equal => switch (condition.data_type) { + .int, .float, .str, .bool, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, str, bool, date, time, datetime can be compare with =", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .different => switch (condition.data_type) { + .int, .float, .str, .bool, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, str, bool, date, time, datetime can be compare with !=", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .superior_or_equal => switch (condition.data_type) { + .int, .float, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, date, time, datetime can be compare with >=", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .superior => switch (condition.data_type) { + .int, .float, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, date, time, datetime can be compare with >", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .inferior_or_equal => switch (condition.data_type) { + .int, .float, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, date, time, datetime can be compare with <=", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .inferior => switch (condition.data_type) { + .int, .float, .date, .time, .datetime => {}, + else => return printError( + "Error: Only int, float, date, time, datetime can be compare with <", + ZipponError.ConditionError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), + }, + + .in => switch (condition.data_type) { + .link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {}, + else => unreachable, + }, + + .not_in => switch (condition.data_type) { + .link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {}, + else => unreachable, + }, + } +} diff --git a/src/ziql/parts/value.zig b/src/ziql/parts/value.zig index 2d8d9a4..f6ae922 100644 --- a/src/ziql/parts/value.zig +++ b/src/ziql/parts/value.zig @@ -1,5 +1,6 @@ const std = @import("std"); const dtype = @import("dtype"); +const s2t = dtype.s2t; const UUID = dtype.UUID; const Allocator = std.mem.Allocator; const Token = @import("../tokenizer.zig").Token; @@ -12,9 +13,10 @@ const ZipponError = @import("error").ZipponError; var buff: [1024]u8 = undefined; -var zero_map_buf: [1024 * 4]u8 = undefined; +var zero_map_buf: [200]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&zero_map_buf); var zero_map = std.AutoHashMap(UUID, void).init(fba.allocator()); +var empty_map = std.AutoHashMap(UUID, void).init(fba.allocator()); const Self = @import("../parser.zig"); @@ -23,148 +25,324 @@ pub fn initZeroMap() ZipponError!void { } /// To run just after a condition like = or > or >= to get the corresponding ConditionValue that you need to compare -pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []const u8, member_name: []const u8, data_type: dtype.DataType, token: *Token) ZipponError!ConditionValue { +pub fn parseConditionValue( + self: Self, + allocator: Allocator, + struct_name: []const u8, + member_name: []const u8, + data_type: dtype.DataType, + token: *Token, +) ZipponError!ConditionValue { const start_index = token.loc.start; - const expected_tag: ?Token.Tag = switch (data_type) { - .int => .int_literal, - .float => .float_literal, - .str => .string_literal, - .self => .uuid_literal, - .int_array => .int_literal, - .float_array => .float_literal, - .str_array => .string_literal, - .bool, .bool_array, .link, .link_array, .date, .time, .datetime, .date_array, .time_array, .datetime_array => null, // handle separately + + if (data_type.is_array()) switch (token.tag) { + .l_bracket => token.* = self.toker.next(), + else => return printError( + "Error: expecting [ to start array.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ), }; - // Check if the all next tokens are the right one - if (expected_tag) |tag| { - if (data_type.is_array()) { - token.* = try self.checkTokensInArray(tag); + switch (data_type) { + .self => unreachable, + + .int => if (token.tag != .int_literal) { + return printError( + "Error: Wrong type. Expected: int.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); } else { - if (token.tag != tag) { - const msg = std.fmt.bufPrint(&buff, "Error: Wrong type. Expected: {any}", .{tag}) catch return ZipponError.MemoryError; - return printError( - msg, + return ConditionValue.initInt(self.toker.buffer[start_index..token.loc.end]); + }, + + .float => if (token.tag != .float_literal) { + return printError( + "Error: Wrong type. Expected: float.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initFloat(self.toker.buffer[start_index..token.loc.end]); + }, + + .str => if (token.tag != .string_literal) { + return printError( + "Error: Wrong type. Expected: string.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initStr(self.toker.buffer[start_index..token.loc.end]); + }, + + .bool => if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) { + return printError( + "Error: Wrong type. Expected: bool.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]); + }, + + .date => if (token.tag != .date_literal and token.tag != .keyword_now) { + return printError( + "Error: Wrong type. Expected: date.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initDate(self.toker.buffer[start_index..token.loc.end]); + }, + + .time => if (token.tag != .time_literal and token.tag != .keyword_now) { + return printError( + "Error: Wrong type. Expected: time.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]); + }, + + .datetime => if (token.tag != .date_literal and token.tag != .datetime_literal and token.tag != .keyword_now) { + return printError( + "Error: Wrong type. Expected: datetime.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + } else { + return ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]); + }, + + .int_array => { + var array = std.ArrayList(i32).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .int_literal) return printError( + "Error: Wrong type. Expected int.", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ); + array.append(s2t.parseInt(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError; } - } - } else switch (data_type) { - .bool => if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) { - return printError( - "Error: Expected bool", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - }, - .bool_array => { - token.* = self.toker.next(); - while (token.tag != .r_bracket) : (token.* = self.toker.next()) { - if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) { - return printError( - "Error: Expected bool or ]", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - } - } - }, - .date => if (token.tag != .date_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected date", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - }, - .date_array => { - token.* = self.toker.next(); - while (token.tag != .r_bracket) : (token.* = self.toker.next()) { - if (token.tag != .date_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected date", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - } - } - }, - .time => if (token.tag != .time_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected time", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - }, - .time_array => { - token.* = self.toker.next(); - while (token.tag != .r_bracket) : (token.* = self.toker.next()) { - if (token.tag != .time_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected time", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - } - } - }, - .datetime => if (token.tag != .datetime_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected datetime", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - }, - .datetime_array => { - token.* = self.toker.next(); - while (token.tag != .r_bracket) : (token.* = self.toker.next()) { - if (token.tag != .datetime_literal and token.tag != .keyword_now) { - return printError( - "Error: Expected datetime", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - } - } - }, - .link, .link_array => {}, - else => unreachable, - } - // And finally create the ConditionValue - switch (data_type) { - .int => return ConditionValue.initInt(self.toker.buffer[start_index..token.loc.end]), - .float => return ConditionValue.initFloat(self.toker.buffer[start_index..token.loc.end]), - .str => return ConditionValue.initStr(self.toker.buffer[start_index + 1 .. token.loc.end - 1]), - .date => return ConditionValue.initDate(self.toker.buffer[start_index..token.loc.end]), - .time => return ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]), - .datetime => return ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]), - .bool => return ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]), - .int_array => return try ConditionValue.initArrayInt(allocator, self.toker.buffer[start_index..token.loc.end]), - .str_array => return try ConditionValue.initArrayStr(allocator, self.toker.buffer[start_index..token.loc.end]), - .bool_array => return try ConditionValue.initArrayBool(allocator, self.toker.buffer[start_index..token.loc.end]), - .float_array => return try ConditionValue.initArrayFloat(allocator, self.toker.buffer[start_index..token.loc.end]), - .date_array => return try ConditionValue.initArrayDate(allocator, self.toker.buffer[start_index..token.loc.end]), - .time_array => return try ConditionValue.initArrayTime(allocator, self.toker.buffer[start_index..token.loc.end]), - .datetime_array => return try ConditionValue.initArrayDateTime(allocator, self.toker.buffer[start_index..token.loc.end]), + return try ConditionValue.initArrayInt(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .float_array => { + var array = std.ArrayList(f64).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .float_literal) return printError( + "Error: Wrong type. Expected float.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(s2t.parseFloat(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayFloat(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .bool_array => { + var array = std.ArrayList(bool).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .bool_literal_false and token.tag != .bool_literal_true) return printError( + "Error: Wrong type. Expected bool.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(s2t.parseBool(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayBool(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .str_array => { + var array = std.ArrayList([]const u8).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .string_literal) return printError( + "Error: Wrong type. Expected str.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(self.toker.getTokenSlice(token.*)) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayStr(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .date_array => { + var array = std.ArrayList(u64).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .date_literal and token.tag != .keyword_now) return printError( + "Error: Wrong type. Expected date.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(s2t.parseDate(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .time_array => { + var array = std.ArrayList(u64).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .time_literal and token.tag != .keyword_now) return printError( + "Error: Wrong type. Expected time.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(s2t.parseTime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + + .datetime_array => { + var array = std.ArrayList(u64).init(allocator); + errdefer array.deinit(); + + var first = true; + while (token.tag != .r_bracket) : (token.* = self.toker.next()) { + if (!first) { + if (token.tag != .comma) return printError( + "Error: Expected comma.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + token.* = self.toker.next(); + } else first = false; + + if (token.tag != .datetime_literal and token.tag != .date_literal and token.tag != .keyword_now) return printError( + "Error: Wrong type. Expected datetime.", + ZipponError.SynthaxError, + self.toker.buffer, + token.loc.start, + token.loc.end, + ); + array.append(s2t.parseDatetime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError; + } + + return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError); + }, + .link => switch (token.tag) { .keyword_none => { _ = self.toker.next(); @@ -239,12 +417,11 @@ pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []cons token.loc.end, ), }, + .link_array => switch (token.tag) { .keyword_none => { - const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError; - map.* = std.AutoHashMap(UUID, void).init(allocator); _ = self.toker.next(); - return ConditionValue.initArrayLink(map); + return ConditionValue.initArrayLink(&empty_map); }, .l_brace, .l_bracket => { var filter: ?Filter = null; @@ -292,6 +469,5 @@ pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []cons token.loc.end, ), }, - .self => unreachable, } } diff --git a/src/ziql/utils.zig b/src/ziql/utils.zig deleted file mode 100644 index c343add..0000000 --- a/src/ziql/utils.zig +++ /dev/null @@ -1,122 +0,0 @@ -const std = @import("std"); -const config = @import("config"); -const Allocator = std.mem.Allocator; -const Token = @import("tokenizer.zig").Token; -const Condition = @import("../dataStructure/filter.zig").Condition; -const printError = @import("../utils.zig").printError; - -const ZipponError = @import("error").ZipponError; - -const Self = @import("parser.zig"); - -/// Check if all token in an array is of one specific type -pub fn checkTokensInArray(self: Self, tag: Token.Tag) ZipponError!Token { - var token = self.toker.next(); - while (token.tag != .r_bracket) : (token = self.toker.next()) { - if (token.tag != tag) return printError( - "Error: Wrong type.", - ZipponError.SynthaxError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ); - } - return token; -} - -/// Will check if what is compared is ok, like comparing if a string is superior to another string is not for example. -pub fn checkConditionValidity( - self: Self, - condition: Condition, - token: Token, -) ZipponError!void { - switch (condition.operation) { - .equal => switch (condition.data_type) { - .int, .float, .str, .bool, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, str, bool, date, time, datetime can be compare with =", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .different => switch (condition.data_type) { - .int, .float, .str, .bool, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, str, bool, date, time, datetime can be compare with !=", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .superior_or_equal => switch (condition.data_type) { - .int, .float, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, date, time, datetime can be compare with >=", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .superior => switch (condition.data_type) { - .int, .float, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, date, time, datetime can be compare with >", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .inferior_or_equal => switch (condition.data_type) { - .int, .float, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, date, time, datetime can be compare with <=", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .inferior => switch (condition.data_type) { - .int, .float, .date, .time, .datetime => {}, - else => return printError( - "Error: Only int, float, date, time, datetime can be compare with <", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .in => switch (condition.data_type) { - .link => {}, - else => return printError( - "Error: Only link can be compare with IN.", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - - .not_in => switch (condition.data_type) { - .link => {}, - else => return printError( - "Error: Only link can be compare with !IN.", - ZipponError.ConditionError, - self.toker.buffer, - token.loc.start, - token.loc.end, - ), - }, - } -}