Passe basic GRAB query !
This commit is contained in:
parent
84495e831f
commit
cda2ee16a8
@ -7,6 +7,17 @@ const ziqlTokenizer = @import("tokenizers/ziql.zig").Tokenizer;
|
|||||||
const ziqlToken = @import("tokenizers/ziql.zig").Token;
|
const ziqlToken = @import("tokenizers/ziql.zig").Token;
|
||||||
const ziqlParser = @import("ziqlParser.zig").Parser;
|
const ziqlParser = @import("ziqlParser.zig").Parser;
|
||||||
|
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
|
fn send(comptime format: []const u8, args: anytype) void {
|
||||||
|
stdout.print(format, args) catch |err| {
|
||||||
|
std.log.err("Can't send: {any}", .{err});
|
||||||
|
stdout.print("\x03\n", .{}) catch {};
|
||||||
|
};
|
||||||
|
|
||||||
|
stdout.print("\x03\n", .{}) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
// TODO: Use an environment variable for the path of the DB
|
// TODO: Use an environment variable for the path of the DB
|
||||||
checkAndCreateDirectories();
|
checkAndCreateDirectories();
|
||||||
@ -16,11 +27,8 @@ pub fn main() !void {
|
|||||||
|
|
||||||
defer {
|
defer {
|
||||||
switch (gpa.deinit()) {
|
switch (gpa.deinit()) {
|
||||||
.ok => std.debug.print("No memory leak baby !\n", .{}),
|
.ok => std.log.debug("No memory leak baby !\n", .{}),
|
||||||
.leak => {
|
.leak => std.log.debug("We fucked it up bro...\n", .{}),
|
||||||
std.debug.print("We fucked it up bro...\n", .{});
|
|
||||||
@panic("=(");
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +41,8 @@ pub fn main() !void {
|
|||||||
const line = try std.io.getStdIn().reader().readUntilDelimiterOrEof(line_buf, '\n');
|
const line = try std.io.getStdIn().reader().readUntilDelimiterOrEof(line_buf, '\n');
|
||||||
|
|
||||||
if (line) |line_str| {
|
if (line) |line_str| {
|
||||||
|
const time_initial = std.time.microTimestamp();
|
||||||
|
|
||||||
const null_term_line_str = try allocator.dupeZ(u8, line_str[0..line_str.len]);
|
const null_term_line_str = try allocator.dupeZ(u8, line_str[0..line_str.len]);
|
||||||
defer allocator.free(null_term_line_str);
|
defer allocator.free(null_term_line_str);
|
||||||
|
|
||||||
@ -47,20 +57,19 @@ pub fn main() !void {
|
|||||||
defer allocator.free(null_term_query_str);
|
defer allocator.free(null_term_query_str);
|
||||||
try runCommand(null_term_query_str);
|
try runCommand(null_term_query_str);
|
||||||
},
|
},
|
||||||
.keyword_help => std.debug.print("The run command will take a ZiQL query between \" and run it. eg: run \"GRAB User\"\n", .{}),
|
.keyword_help => send("The run command will take a ZiQL query between \" and run it. eg: run \"GRAB User\"\n", .{}),
|
||||||
else => std.debug.print("After command run, need a string of a query, eg: \"GRAB User\"\n", .{}),
|
else => send("After command run, need a string of a query, eg: \"GRAB User\"\n", .{}),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.keyword_schema => {
|
.keyword_schema => {
|
||||||
const second_token = cliToker.next();
|
const second_token = cliToker.next();
|
||||||
|
|
||||||
switch (second_token.tag) {
|
switch (second_token.tag) {
|
||||||
.keyword_describe => std.debug.print("{s}\n", .{ // TODO: Change that to use the SchemaEngine
|
.keyword_describe => send("{s}\n", .{ // TODO: Change that to use the SchemaEngine
|
||||||
\\User (
|
\\User (
|
||||||
\\ name: str,
|
\\ name: str,
|
||||||
\\ email: str,
|
\\ email: str,
|
||||||
\\)
|
\\)
|
||||||
\\
|
|
||||||
\\Message (
|
\\Message (
|
||||||
\\ content: str,
|
\\ content: str,
|
||||||
\\)
|
\\)
|
||||||
@ -70,7 +79,7 @@ pub fn main() !void {
|
|||||||
try data_engine.initDataFolder();
|
try data_engine.initDataFolder();
|
||||||
},
|
},
|
||||||
.keyword_help => {
|
.keyword_help => {
|
||||||
std.debug.print("{s}", .{
|
send("{s}", .{
|
||||||
\\Here are all available options to use with the schema command:
|
\\Here are all available options to use with the schema command:
|
||||||
\\
|
\\
|
||||||
\\describe Print the schema use by the current engine.
|
\\describe Print the schema use by the current engine.
|
||||||
@ -82,7 +91,7 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.keyword_help => {
|
.keyword_help => {
|
||||||
std.debug.print("{s}", .{
|
send("{s}", .{
|
||||||
\\Welcome to ZipponDB!
|
\\Welcome to ZipponDB!
|
||||||
\\
|
\\
|
||||||
\\run To run a query. Args => query: str, the query to execute.
|
\\run To run a query. Args => query: str, the query to execute.
|
||||||
@ -95,8 +104,12 @@ pub fn main() !void {
|
|||||||
},
|
},
|
||||||
.keyword_quit => break,
|
.keyword_quit => break,
|
||||||
.eof => {},
|
.eof => {},
|
||||||
else => std.debug.print("Command need to start with a keyword, including: run, schema, help and quit\n", .{}),
|
else => send("Command need to start with a keyword, including: run, schema, help and quit\n", .{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const time_final = std.time.microTimestamp();
|
||||||
|
const duration = time_final - time_initial;
|
||||||
|
std.debug.print("Time: {d:.2}ms\n", .{@as(f64, @floatFromInt(duration)) / 1000.0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ const DataType = @import("types/dataType.zig").DataType;
|
|||||||
pub const FileEngine = struct {
|
pub const FileEngine = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
path_to_DATA_dir: []const u8, // The path to the DATA folder
|
path_to_DATA_dir: []const u8, // The path to the DATA folder
|
||||||
max_file_size: usize = 1e+7, // 10mb
|
max_file_size: usize = 5e+4, // 50kb TODO: Change
|
||||||
|
|
||||||
const DataEngineError = error{
|
const DataEngineError = error{
|
||||||
ErrorCreateDataFolder,
|
ErrorCreateDataFolder,
|
||||||
@ -57,31 +57,26 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Take a condition and an array of UUID and fill the array with all UUID that match the condition
|
/// Take a condition and an array of UUID and fill the array with all UUID that match the condition
|
||||||
pub fn getUUIDListUsingCondition(self: FileEngine, condition: Condition, uuid_array: *std.ArrayList(UUID)) !void {
|
pub fn getUUIDListUsingCondition(self: *FileEngine, condition: Condition, uuid_array: *std.ArrayList(UUID)) !void {
|
||||||
var file_names = std.ArrayList([]const u8).init(self.allocator);
|
var file_names = std.ArrayList([]const u8).init(self.allocator);
|
||||||
self.getFilesNames(condition.struct_name, condition.member_name, &file_names) catch @panic("Can't get list of files");
|
self.getFilesNames(condition.struct_name, condition.member_name, &file_names) catch @panic("Can't get list of files");
|
||||||
defer {
|
defer file_names.deinit();
|
||||||
for (file_names.items) |elem| {
|
|
||||||
self.allocator.free(elem);
|
|
||||||
}
|
|
||||||
file_names.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
const sub_path = std.fmt.allocPrint(self.allocator, "{s}/{s}/{s}/{s}", .{ self.path_to_DATA_dir, condition.struct_name, condition.member_name, file_names.items[0] }) catch @panic("Can't create sub_path for init a DataIterator");
|
var current_file = file_names.pop();
|
||||||
|
|
||||||
|
var sub_path = std.fmt.allocPrint(self.allocator, "{s}/{s}/{s}/{s}", .{ self.path_to_DATA_dir, condition.struct_name, condition.member_name, current_file }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
defer self.allocator.free(sub_path);
|
defer self.allocator.free(sub_path);
|
||||||
|
|
||||||
var file = std.fs.cwd().openFile(sub_path, .{}) catch @panic("Can't open first file to init a data iterator");
|
var file = std.fs.cwd().openFile(sub_path, .{}) catch @panic("Can't open first file to init a data iterator");
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
var output: [1024 * 50]u8 = undefined; // Maybe need to increase that as it limit the size of a line in files
|
var output: [1024 * 50]u8 = undefined; // Maybe need to increase that as it limit the size of a line in a file
|
||||||
var output_fbs = std.io.fixedBufferStream(&output);
|
var output_fbs = std.io.fixedBufferStream(&output);
|
||||||
const writer = output_fbs.writer();
|
const writer = output_fbs.writer();
|
||||||
|
|
||||||
var buffered = std.io.bufferedReader(file.reader());
|
var buffered = std.io.bufferedReader(file.reader());
|
||||||
var reader = buffered.reader();
|
var reader = buffered.reader();
|
||||||
|
|
||||||
var file_index: usize = 0;
|
|
||||||
|
|
||||||
var compare_value: ComparisonValue = undefined;
|
var compare_value: ComparisonValue = undefined;
|
||||||
switch (condition.data_type) {
|
switch (condition.data_type) {
|
||||||
.int => compare_value = ComparisonValue{ .int = dataParsing.parseInt(condition.value) },
|
.int => compare_value = ComparisonValue{ .int = dataParsing.parseInt(condition.value) },
|
||||||
@ -108,14 +103,23 @@ pub const FileEngine = struct {
|
|||||||
reader.streamUntilDelimiter(writer, '\n', null) catch |err| switch (err) {
|
reader.streamUntilDelimiter(writer, '\n', null) catch |err| switch (err) {
|
||||||
error.EndOfStream => {
|
error.EndOfStream => {
|
||||||
output_fbs.reset(); // clear buffer before exit
|
output_fbs.reset(); // clear buffer before exit
|
||||||
file_index += 1;
|
self.allocator.free(current_file);
|
||||||
|
|
||||||
if (file_index == file_names.items.len) break;
|
if (file_names.items.len == 0) break;
|
||||||
|
|
||||||
// FIXME: Update the file and reader to be the next file of the list
|
current_file = file_names.pop();
|
||||||
std.debug.print("End of stream\n", .{});
|
|
||||||
|
|
||||||
break;
|
// Do I leak memory here ? Do I deinit every time ?
|
||||||
|
self.allocator.free(sub_path);
|
||||||
|
sub_path = std.fmt.allocPrint(self.allocator, "{s}/{s}/{s}/{s}", .{ self.path_to_DATA_dir, condition.struct_name, condition.member_name, current_file }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
// Same here, do I close everytime ?
|
||||||
|
file.close();
|
||||||
|
file = std.fs.cwd().openFile(sub_path, .{}) catch @panic("Can't open first file to init a data iterator");
|
||||||
|
|
||||||
|
buffered = std.io.bufferedReader(file.reader());
|
||||||
|
reader = buffered.reader();
|
||||||
|
continue;
|
||||||
}, // file read till the end
|
}, // file read till the end
|
||||||
else => {
|
else => {
|
||||||
std.debug.print("Error while reading file: {any}\n", .{err});
|
std.debug.print("Error while reading file: {any}\n", .{err});
|
||||||
@ -185,13 +189,9 @@ pub const FileEngine = struct {
|
|||||||
|
|
||||||
// TODO: Clean a bit the code
|
// TODO: Clean a bit the code
|
||||||
// Do I need multiple files too ? I mean it duplicate UUID a lot, if it's just to save a name like 'Bob', storing a long UUID is overkill
|
// Do I need multiple files too ? I mean it duplicate UUID a lot, if it's just to save a name like 'Bob', storing a long UUID is overkill
|
||||||
// I could just use a tabular data format with separator using space
|
// I could just use a tabular data format with separator using space - Or maybe I encode the uuid to take a minimum space as I always know it size
|
||||||
pub fn writeEntity(self: FileEngine, struct_name: []const u8, data_map: std.StringHashMap([]const u8)) !void {
|
pub fn writeEntity(self: FileEngine, struct_name: []const u8, data_map: std.StringHashMap([]const u8)) !UUID {
|
||||||
const uuid_str = UUID.init().format_uuid();
|
const uuid_str = UUID.init().format_uuid();
|
||||||
defer std.debug.print("Added new {s} successfully using UUID: {s}\n", .{
|
|
||||||
struct_name,
|
|
||||||
uuid_str,
|
|
||||||
});
|
|
||||||
|
|
||||||
const member_names = schemaEngine.structName2structMembers(struct_name);
|
const member_names = schemaEngine.structName2structMembers(struct_name);
|
||||||
for (member_names) |member_name| {
|
for (member_names) |member_name| {
|
||||||
@ -207,7 +207,7 @@ pub const FileEngine = struct {
|
|||||||
.mode = .read_write,
|
.mode = .read_write,
|
||||||
}) catch {
|
}) catch {
|
||||||
std.debug.print("Error opening data file.", .{});
|
std.debug.print("Error opening data file.", .{});
|
||||||
return;
|
continue; // TODO: Error handeling
|
||||||
};
|
};
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
@ -219,14 +219,14 @@ pub const FileEngine = struct {
|
|||||||
const new_file_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}/{s}/{d}.zippondata", .{ self.path_to_DATA_dir, struct_name, member_name, max_index + 1 });
|
const new_file_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}/{s}/{d}.zippondata", .{ self.path_to_DATA_dir, struct_name, member_name, max_index + 1 });
|
||||||
defer self.allocator.free(new_file_path);
|
defer self.allocator.free(new_file_path);
|
||||||
|
|
||||||
std.debug.print("new file path: {s}\n", .{new_file_path});
|
|
||||||
|
|
||||||
const new_file = std.fs.cwd().createFile(new_file_path, .{}) catch @panic("Error creating new data file");
|
const new_file = std.fs.cwd().createFile(new_file_path, .{}) catch @panic("Error creating new data file");
|
||||||
defer new_file.close();
|
defer new_file.close();
|
||||||
|
|
||||||
try new_file.writer().print("{s} {s}\n", .{ &uuid_str, data_map.get(member_name).? });
|
try new_file.writer().print("{s} {s}\n", .{ &uuid_str, data_map.get(member_name).? });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return UUID.parse(&uuid_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a filename in the format 1.zippondata and return the 1
|
/// Use a filename in the format 1.zippondata and return the 1
|
||||||
@ -245,6 +245,7 @@ pub const FileEngine = struct {
|
|||||||
defer member_dir.close();
|
defer member_dir.close();
|
||||||
|
|
||||||
var iter = member_dir.iterate();
|
var iter = member_dir.iterate();
|
||||||
|
defer iter.reset();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
if ((entry.kind != std.fs.Dir.Entry.Kind.file) or (std.mem.eql(u8, "main.zippondata", entry.name))) continue;
|
if ((entry.kind != std.fs.Dir.Entry.Kind.file) or (std.mem.eql(u8, "main.zippondata", entry.name))) continue;
|
||||||
try file_names.*.append(try self.allocator.dupe(u8, entry.name));
|
try file_names.*.append(try self.allocator.dupe(u8, entry.name));
|
||||||
@ -281,10 +282,10 @@ pub const FileEngine = struct {
|
|||||||
|
|
||||||
var iter = member_dir.iterate();
|
var iter = member_dir.iterate();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
if ((entry.kind != std.fs.Dir.Entry.Kind.file) or (std.mem.eql(u8, "main.zippondata", entry.name))) continue;
|
if (entry.kind != std.fs.Dir.Entry.Kind.file) continue;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
return count;
|
return count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Give the option to keep , dump or erase the data
|
// TODO: Give the option to keep , dump or erase the data
|
||||||
|
@ -7,6 +7,17 @@ const Token = @import("tokenizers/ziql.zig").Token;
|
|||||||
const UUID = @import("types/uuid.zig").UUID;
|
const UUID = @import("types/uuid.zig").UUID;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
|
fn send(comptime format: []const u8, args: anytype) void {
|
||||||
|
stdout.print(format, args) catch |err| {
|
||||||
|
std.log.err("Can't send: {any}", .{err});
|
||||||
|
stdout.print("\x03\n", .{}) catch {};
|
||||||
|
};
|
||||||
|
|
||||||
|
stdout.print("\x03\n", .{}) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Parser = struct {
|
pub const Parser = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
state: State,
|
state: State,
|
||||||
@ -31,6 +42,7 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
pub fn deinit(self: *Parser) void {
|
pub fn deinit(self: *Parser) void {
|
||||||
self.additional_data.deinit();
|
self.additional_data.deinit();
|
||||||
|
self.allocator.free(self.struct_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Options = struct {
|
const Options = struct {
|
||||||
@ -50,7 +62,7 @@ pub const Parser = struct {
|
|||||||
// For the main parse function
|
// For the main parse function
|
||||||
expect_struct_name,
|
expect_struct_name,
|
||||||
expect_filter,
|
expect_filter,
|
||||||
expect_additional_data,
|
parse_additional_data,
|
||||||
expect_filter_or_additional_data,
|
expect_filter_or_additional_data,
|
||||||
expect_new_data,
|
expect_new_data,
|
||||||
expect_right_arrow,
|
expect_right_arrow,
|
||||||
@ -121,23 +133,23 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.keyword_grab => {
|
.keyword_grab => {
|
||||||
self.action = .GRAB;
|
self.action = .GRAB;
|
||||||
self.state = State.expect_struct_name;
|
self.state = .expect_struct_name;
|
||||||
},
|
},
|
||||||
.keyword_add => {
|
.keyword_add => {
|
||||||
self.action = .ADD;
|
self.action = .ADD;
|
||||||
self.state = State.expect_struct_name;
|
self.state = .expect_struct_name;
|
||||||
},
|
},
|
||||||
.keyword_update => {
|
.keyword_update => {
|
||||||
self.action = .UPDATE;
|
self.action = .UPDATE;
|
||||||
self.state = State.expect_struct_name;
|
self.state = .expect_struct_name;
|
||||||
},
|
},
|
||||||
.keyword_delete => {
|
.keyword_delete => {
|
||||||
self.action = .DELETE;
|
self.action = .DELETE;
|
||||||
self.state = State.expect_struct_name;
|
self.state = .expect_struct_name;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
self.printError("Error: Expected action keyword. Available: GRAB ADD DELETE UPDATE", &token);
|
self.printError("Error: Expected action keyword. Available: GRAB ADD DELETE UPDATE", &token);
|
||||||
self.state = State.end;
|
self.state = .end;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -146,34 +158,34 @@ pub const Parser = struct {
|
|||||||
self.struct_name = try self.allocator.dupe(u8, self.toker.getTokenSlice(token));
|
self.struct_name = try self.allocator.dupe(u8, self.toker.getTokenSlice(token));
|
||||||
if (!schemaEngine.isStructNameExists(self.struct_name)) self.printError("Error: struct name not found in schema.", &token);
|
if (!schemaEngine.isStructNameExists(self.struct_name)) self.printError("Error: struct name not found in schema.", &token);
|
||||||
switch (self.action) {
|
switch (self.action) {
|
||||||
.ADD => self.state = State.expect_new_data,
|
.ADD => self.state = .expect_new_data,
|
||||||
else => self.state = State.expect_filter_or_additional_data,
|
else => self.state = .expect_filter_or_additional_data,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_filter_or_additional_data => {
|
.expect_filter_or_additional_data => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.l_bracket => self.state = State.expect_additional_data,
|
.l_bracket => self.state = .parse_additional_data,
|
||||||
.l_brace => self.state = State.filter_and_send,
|
.l_brace => self.state = .filter_and_send,
|
||||||
else => self.printError("Error: Expect [ for additional data or { for a filter", &token),
|
else => self.printError("Error: Expect [ for additional data or { for a filter", &token),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_additional_data => {
|
.parse_additional_data => {
|
||||||
try self.parseAdditionalData(&self.additional_data);
|
try self.parseAdditionalData(&self.additional_data);
|
||||||
self.state = State.filter_and_send;
|
self.state = .filter_and_send;
|
||||||
},
|
},
|
||||||
.filter_and_send => {
|
.filter_and_send => {
|
||||||
var array = std.ArrayList(UUID).init(self.allocator);
|
var array = std.ArrayList(UUID).init(self.allocator);
|
||||||
defer array.deinit();
|
defer array.deinit();
|
||||||
try self.parseFilter(&array, self.struct_name, true);
|
try self.parseFilter(&array, self.struct_name, true);
|
||||||
self.sendEntity(array.items);
|
self.sendEntity(array.items);
|
||||||
self.state = State.end;
|
self.state = .end;
|
||||||
},
|
},
|
||||||
.expect_new_data => {
|
.expect_new_data => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.l_paren => {
|
.l_paren => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.state = State.parse_new_data_and_add_data;
|
self.state = .parse_new_data_and_add_data;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expecting new data starting with (", &token),
|
else => self.printError("Error: Expecting new data starting with (", &token),
|
||||||
}
|
}
|
||||||
@ -187,8 +199,12 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
// TODO: Print the list of missing
|
// TODO: Print the list of missing
|
||||||
if (!schemaEngine.checkIfAllMemberInMap(self.struct_name, &data_map)) self.printError("Error: Missing member", &token);
|
if (!schemaEngine.checkIfAllMemberInMap(self.struct_name, &data_map)) self.printError("Error: Missing member", &token);
|
||||||
try self.data_engine.writeEntity(self.struct_name, data_map);
|
const uuid = self.data_engine.writeEntity(self.struct_name, data_map) catch {
|
||||||
self.state = State.end;
|
send("ZipponDB error: Couln't write new data to file", .{});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
send("Successfully added new {s} with UUID: {s}", .{ self.struct_name, uuid.format_uuid() });
|
||||||
|
self.state = .end;
|
||||||
},
|
},
|
||||||
.UPDATE => {}, // TODO:
|
.UPDATE => {}, // TODO:
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -204,8 +220,9 @@ pub const Parser = struct {
|
|||||||
// Maybe to a struct Communicator to handle all communication between use and cli
|
// Maybe to a struct Communicator to handle all communication between use and cli
|
||||||
fn sendEntity(self: *Parser, uuid_array: []UUID) void {
|
fn sendEntity(self: *Parser, uuid_array: []UUID) void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
_ = uuid_array;
|
||||||
|
|
||||||
std.debug.print("Number of uuid to send: {d}\n", .{uuid_array.len});
|
//send("Number of uuid to send: {d}\n", .{uuid_array.len});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The parser that check what is between ||
|
// TODO: The parser that check what is between ||
|
||||||
@ -414,10 +431,10 @@ pub const Parser = struct {
|
|||||||
fn parseAdditionalData(self: *Parser, additional_data: *AdditionalData) !void {
|
fn parseAdditionalData(self: *Parser, additional_data: *AdditionalData) !void {
|
||||||
var token = self.toker.next();
|
var token = self.toker.next();
|
||||||
var keep_next = false;
|
var keep_next = false;
|
||||||
self.state = State.expect_count_of_entity_to_find;
|
self.state = .expect_count_of_entity_to_find;
|
||||||
|
|
||||||
while (self.state != State.end) : ({
|
while (self.state != .end) : ({
|
||||||
token = if (!keep_next) self.toker.next() else token;
|
token = if ((!keep_next) and (self.state != .end)) self.toker.next() else token;
|
||||||
keep_next = false;
|
keep_next = false;
|
||||||
}) {
|
}) {
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
@ -441,7 +458,7 @@ pub const Parser = struct {
|
|||||||
.expect_semicolon_OR_right_bracket => {
|
.expect_semicolon_OR_right_bracket => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.semicolon => self.state = .expect_member,
|
.semicolon => self.state = .expect_member,
|
||||||
.r_bracket => self.state = State.end,
|
.r_bracket => self.state = .end,
|
||||||
else => self.printError("Error: Expect ';' or ']'.", &token),
|
else => self.printError("Error: Expect ';' or ']'.", &token),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -464,10 +481,7 @@ pub const Parser = struct {
|
|||||||
.expect_comma_OR_r_bracket_OR_l_bracket => {
|
.expect_comma_OR_r_bracket_OR_l_bracket => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.comma => self.state = .expect_member,
|
.comma => self.state = .expect_member,
|
||||||
.r_bracket => {
|
.r_bracket => self.state = .end,
|
||||||
self.state = State.end;
|
|
||||||
keep_next = true;
|
|
||||||
},
|
|
||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
try self.parseAdditionalData(
|
try self.parseAdditionalData(
|
||||||
&additional_data.member_to_find.items[additional_data.member_to_find.items.len - 1].additional_data,
|
&additional_data.member_to_find.items[additional_data.member_to_find.items.len - 1].additional_data,
|
||||||
@ -480,10 +494,7 @@ pub const Parser = struct {
|
|||||||
.expect_comma_OR_r_bracket => {
|
.expect_comma_OR_r_bracket => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.comma => self.state = .expect_member,
|
.comma => self.state = .expect_member,
|
||||||
.r_bracket => {
|
.r_bracket => self.state = .end,
|
||||||
self.state = State.end;
|
|
||||||
keep_next = true;
|
|
||||||
},
|
|
||||||
else => self.printError("Error: Expected , or ]", &token),
|
else => self.printError("Error: Expected , or ]", &token),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -499,9 +510,9 @@ pub const Parser = struct {
|
|||||||
var token = self.toker.next();
|
var token = self.toker.next();
|
||||||
var keep_next = false;
|
var keep_next = false;
|
||||||
var member_name: []const u8 = undefined; // Maybe use allocator.alloc
|
var member_name: []const u8 = undefined; // Maybe use allocator.alloc
|
||||||
self.state = State.expect_member;
|
self.state = .expect_member;
|
||||||
|
|
||||||
while (self.state != State.end) : ({
|
while (self.state != .end) : ({
|
||||||
token = if (!keep_next) self.toker.next() else token;
|
token = if (!keep_next) self.toker.next() else token;
|
||||||
keep_next = false;
|
keep_next = false;
|
||||||
}) {
|
}) {
|
||||||
@ -511,7 +522,7 @@ pub const Parser = struct {
|
|||||||
.identifier => {
|
.identifier => {
|
||||||
member_name = self.toker.getTokenSlice(token);
|
member_name = self.toker.getTokenSlice(token);
|
||||||
if (!schemaEngine.isMemberNameInStruct(self.struct_name, member_name)) self.printError("Member not found in struct.", &token);
|
if (!schemaEngine.isMemberNameInStruct(self.struct_name, member_name)) self.printError("Member not found in struct.", &token);
|
||||||
self.state = State.expect_equal;
|
self.state = .expect_equal;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected member name.", &token),
|
else => self.printError("Error: Expected member name.", &token),
|
||||||
}
|
}
|
||||||
@ -519,7 +530,7 @@ pub const Parser = struct {
|
|||||||
.expect_equal => {
|
.expect_equal => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
// TODO: Add more comparison like IN or other stuff
|
// TODO: Add more comparison like IN or other stuff
|
||||||
.equal => self.state = State.expect_new_value,
|
.equal => self.state = .expect_new_value,
|
||||||
else => self.printError("Error: Expected =", &token),
|
else => self.printError("Error: Expected =", &token),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -530,7 +541,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.int_literal, .keyword_null => {
|
.int_literal, .keyword_null => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.state = State.add_member_to_map;
|
self.state = .add_member_to_map;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected int", &token),
|
else => self.printError("Error: Expected int", &token),
|
||||||
}
|
}
|
||||||
@ -539,7 +550,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.float_literal, .keyword_null => {
|
.float_literal, .keyword_null => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.state = State.add_member_to_map;
|
self.state = .add_member_to_map;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected float", &token),
|
else => self.printError("Error: Expected float", &token),
|
||||||
}
|
}
|
||||||
@ -548,7 +559,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.bool_literal_true, .bool_literal_false, .keyword_null => {
|
.bool_literal_true, .bool_literal_false, .keyword_null => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.state = State.add_member_to_map;
|
self.state = .add_member_to_map;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected bool: true false", &token),
|
else => self.printError("Error: Expected bool: true false", &token),
|
||||||
}
|
}
|
||||||
@ -557,7 +568,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.string_literal, .keyword_null => {
|
.string_literal, .keyword_null => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.state = State.add_member_to_map;
|
self.state = .add_member_to_map;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected string between ''", &token),
|
else => self.printError("Error: Expected string between ''", &token),
|
||||||
}
|
}
|
||||||
@ -568,7 +579,7 @@ pub const Parser = struct {
|
|||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
const start_index = token.loc.start;
|
const start_index = token.loc.start;
|
||||||
token = self.toker.next();
|
token = self.toker.next();
|
||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != .r_bracket) : (token = self.toker.next()) {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.int_literal => continue,
|
.int_literal => continue,
|
||||||
else => self.printError("Error: Expected int or ].", &token),
|
else => self.printError("Error: Expected int or ].", &token),
|
||||||
@ -576,7 +587,7 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
// Maybe change that as it just recreate a string that is already in the buffer
|
// Maybe change that as it just recreate a string that is already in the buffer
|
||||||
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
||||||
self.state = State.expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => self.printError("Error: Expected [ to start an array", &token),
|
||||||
}
|
}
|
||||||
@ -586,7 +597,7 @@ pub const Parser = struct {
|
|||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
const start_index = token.loc.start;
|
const start_index = token.loc.start;
|
||||||
token = self.toker.next();
|
token = self.toker.next();
|
||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != .r_bracket) : (token = self.toker.next()) {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.float_literal => continue,
|
.float_literal => continue,
|
||||||
else => self.printError("Error: Expected float or ].", &token),
|
else => self.printError("Error: Expected float or ].", &token),
|
||||||
@ -594,7 +605,7 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
// Maybe change that as it just recreate a string that is already in the buffer
|
// Maybe change that as it just recreate a string that is already in the buffer
|
||||||
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
||||||
self.state = State.expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => self.printError("Error: Expected [ to start an array", &token),
|
||||||
}
|
}
|
||||||
@ -604,7 +615,7 @@ pub const Parser = struct {
|
|||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
const start_index = token.loc.start;
|
const start_index = token.loc.start;
|
||||||
token = self.toker.next();
|
token = self.toker.next();
|
||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != .r_bracket) : (token = self.toker.next()) {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.bool_literal_false, .bool_literal_true => continue,
|
.bool_literal_false, .bool_literal_true => continue,
|
||||||
else => self.printError("Error: Expected bool or ].", &token),
|
else => self.printError("Error: Expected bool or ].", &token),
|
||||||
@ -612,7 +623,7 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
// Maybe change that as it just recreate a string that is already in the buffer
|
// Maybe change that as it just recreate a string that is already in the buffer
|
||||||
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
||||||
self.state = State.expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => self.printError("Error: Expected [ to start an array", &token),
|
||||||
}
|
}
|
||||||
@ -622,7 +633,7 @@ pub const Parser = struct {
|
|||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
const start_index = token.loc.start;
|
const start_index = token.loc.start;
|
||||||
token = self.toker.next();
|
token = self.toker.next();
|
||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != .r_bracket) : (token = self.toker.next()) {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.string_literal => continue,
|
.string_literal => continue,
|
||||||
else => self.printError("Error: Expected str or ].", &token),
|
else => self.printError("Error: Expected str or ].", &token),
|
||||||
@ -630,7 +641,7 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
// Maybe change that as it just recreate a string that is already in the buffer
|
// Maybe change that as it just recreate a string that is already in the buffer
|
||||||
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
member_map.put(member_name, self.toker.buffer[start_index..token.loc.end]) catch @panic("Couln't add string of array in data map");
|
||||||
self.state = State.expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => self.printError("Error: Expected [ to start an array", &token),
|
||||||
}
|
}
|
||||||
@ -639,13 +650,13 @@ pub const Parser = struct {
|
|||||||
},
|
},
|
||||||
.add_member_to_map => {
|
.add_member_to_map => {
|
||||||
member_map.put(member_name, self.toker.getTokenSlice(token)) catch @panic("Could not add member name and value to map in getMapOfMember");
|
member_map.put(member_name, self.toker.getTokenSlice(token)) catch @panic("Could not add member name and value to map in getMapOfMember");
|
||||||
self.state = State.expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
.add_array_to_map => {},
|
.add_array_to_map => {},
|
||||||
.expect_comma_OR_end => {
|
.expect_comma_OR_end => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.r_paren => self.state = State.end,
|
.r_paren => self.state = .end,
|
||||||
.comma => self.state = State.expect_member,
|
.comma => self.state = .expect_member,
|
||||||
else => self.printError("Error: Expect , or )", &token),
|
else => self.printError("Error: Expect , or )", &token),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -654,29 +665,28 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Stop panicking !
|
|
||||||
fn printError(self: *Parser, message: []const u8, token: *Token) void {
|
fn printError(self: *Parser, message: []const u8, token: *Token) void {
|
||||||
std.debug.print("\n", .{});
|
stdout.print("\n", .{}) catch {};
|
||||||
std.debug.print("{s}\n", .{self.toker.buffer});
|
stdout.print("{s}\n", .{self.toker.buffer}) catch {};
|
||||||
|
|
||||||
// Calculate the number of spaces needed to reach the start position.
|
// Calculate the number of spaces needed to reach the start position.
|
||||||
var spaces: usize = 0;
|
var spaces: usize = 0;
|
||||||
while (spaces < token.loc.start) : (spaces += 1) {
|
while (spaces < token.loc.start) : (spaces += 1) {
|
||||||
std.debug.print(" ", .{});
|
stdout.print(" ", .{}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the '^' characters for the error span.
|
// Print the '^' characters for the error span.
|
||||||
var i: usize = token.loc.start;
|
var i: usize = token.loc.start;
|
||||||
while (i < token.loc.end) : (i += 1) {
|
while (i < token.loc.end) : (i += 1) {
|
||||||
std.debug.print("^", .{});
|
stdout.print("^", .{}) catch {};
|
||||||
}
|
}
|
||||||
std.debug.print(" \n", .{}); // Align with the message
|
stdout.print(" \n", .{}) catch {}; // Align with the message
|
||||||
|
|
||||||
std.debug.print("{s}\n", .{message});
|
stdout.print("{s}\n", .{message}) catch {};
|
||||||
|
|
||||||
std.debug.print("{any}\n{any}\n", .{ token.tag, token.loc });
|
stdout.print("{any}\n{any}\n", .{ token.tag, token.loc }) catch {};
|
||||||
|
|
||||||
@panic("");
|
send("", .{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -770,6 +780,38 @@ fn compareUUIDArray(arr1: std.ArrayList(UUID), arr2: std.ArrayList(UUID)) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "GRAB with additional data" {
|
||||||
|
try testParsing("GRAB User [1] {age < 18}");
|
||||||
|
try testParsing("GRAB User [name] {age < 18}");
|
||||||
|
try testParsing("GRAB User [100; name] {age < 18}");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "GRAB filter with string" {
|
||||||
|
// TODO: Use a fixe dataset for testing, to choose in the build.zig
|
||||||
|
// It should check if the right number of entity is found too
|
||||||
|
try testParsing("GRAB User {name = 'Brittany Rogers'}");
|
||||||
|
try testParsing("GRAB User {name != 'Brittany Rogers'}");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "GRAB filter with int" {
|
||||||
|
// TODO: Use a fixe dataset for testing, to choose in the build.zig
|
||||||
|
// It should check if the right number of entity is found too
|
||||||
|
try testParsing("GRAB User {age = 18}");
|
||||||
|
try testParsing("GRAB User {age > 18}");
|
||||||
|
try testParsing("GRAB User {age < 18}");
|
||||||
|
try testParsing("GRAB User {age <= 18}");
|
||||||
|
try testParsing("GRAB User {age >= 18}");
|
||||||
|
try testParsing("GRAB User {age != 18}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testParsing(source: [:0]const u8) !void {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var tokenizer = Tokenizer.init(source);
|
||||||
|
var parser = Parser.init(allocator, &tokenizer);
|
||||||
|
defer parser.deinit();
|
||||||
|
try parser.parse();
|
||||||
|
}
|
||||||
|
|
||||||
test "Parse condition" {
|
test "Parse condition" {
|
||||||
const condition1 = Condition{ .data_type = .int, .member_name = "age", .operation = .superior_or_equal, .struct_name = "User", .value = "26" };
|
const condition1 = Condition{ .data_type = .int, .member_name = "age", .operation = .superior_or_equal, .struct_name = "User", .value = "26" };
|
||||||
try testConditionParsing("age >= 26", condition1);
|
try testConditionParsing("age >= 26", condition1);
|
||||||
@ -821,7 +863,6 @@ fn testNewDataParsing(source: [:0]const u8, expected_member_map: std.StringHashM
|
|||||||
var parser = Parser.init(allocator, &tokenizer);
|
var parser = Parser.init(allocator, &tokenizer);
|
||||||
parser.struct_name = allocator.dupe(u8, "User") catch @panic("Cant alloc struct name");
|
parser.struct_name = allocator.dupe(u8, "User") catch @panic("Cant alloc struct name");
|
||||||
defer parser.deinit();
|
defer parser.deinit();
|
||||||
defer allocator.free(parser.struct_name);
|
|
||||||
|
|
||||||
var data_map = std.StringHashMap([]const u8).init(allocator);
|
var data_map = std.StringHashMap([]const u8).init(allocator);
|
||||||
defer data_map.deinit();
|
defer data_map.deinit();
|
||||||
@ -857,6 +898,8 @@ test "Parse filter" {
|
|||||||
|
|
||||||
var tokenizer = Tokenizer.init("{name = 'Adrien'}");
|
var tokenizer = Tokenizer.init("{name = 'Adrien'}");
|
||||||
var parser = Parser.init(allocator, &tokenizer);
|
var parser = Parser.init(allocator, &tokenizer);
|
||||||
|
parser.struct_name = allocator.dupe(u8, "User") catch @panic("Cant alloc struct name"); // Otherwise get an error trying to free this when deinit
|
||||||
|
|
||||||
defer parser.deinit();
|
defer parser.deinit();
|
||||||
_ = tokenizer.next(); // Start at name
|
_ = tokenizer.next(); // Start at name
|
||||||
|
|
||||||
@ -913,7 +956,6 @@ fn testAdditionalData(source: [:0]const u8, expected_AdditionalData: Parser.Addi
|
|||||||
var parser = Parser.init(allocator, &tokenizer);
|
var parser = Parser.init(allocator, &tokenizer);
|
||||||
parser.struct_name = allocator.dupe(u8, "User") catch @panic("Cant alloc struct name");
|
parser.struct_name = allocator.dupe(u8, "User") catch @panic("Cant alloc struct name");
|
||||||
defer parser.deinit();
|
defer parser.deinit();
|
||||||
defer allocator.free(parser.struct_name);
|
|
||||||
|
|
||||||
_ = tokenizer.next();
|
_ = tokenizer.next();
|
||||||
parser.parseAdditionalData(&parser.additional_data) catch |err| {
|
parser.parseAdditionalData(&parser.additional_data) catch |err| {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user