Implemented UPDATE and error for ZiQL Parser
Created a function that is use by UPDATE to take a list of uuids and a map of new value. Can be optimize later but work rn. Also started to creat more proper error handeling with custom error starting with ZiQLError
This commit is contained in:
parent
fbcca0dc09
commit
94e3905009
11
src/cli.zig
11
src/cli.zig
@ -92,7 +92,7 @@ pub fn main() !void {
|
|||||||
.string_literal => {
|
.string_literal => {
|
||||||
const null_term_query_str = try allocator.dupeZ(u8, line_str[token.loc.start + 1 .. token.loc.end - 1]);
|
const null_term_query_str = try allocator.dupeZ(u8, line_str[token.loc.start + 1 .. token.loc.end - 1]);
|
||||||
defer allocator.free(null_term_query_str);
|
defer allocator.free(null_term_query_str);
|
||||||
try runQuery(null_term_query_str, &file_engine);
|
runQuery(null_term_query_str, &file_engine);
|
||||||
state = .end;
|
state = .end;
|
||||||
},
|
},
|
||||||
.keyword_help => {
|
.keyword_help => {
|
||||||
@ -165,7 +165,7 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runQuery(null_term_query_str: [:0]const u8, file_engine: *FileEngine) !void {
|
pub fn runQuery(null_term_query_str: [:0]const u8, file_engine: *FileEngine) void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
@ -175,12 +175,15 @@ pub fn runQuery(null_term_query_str: [:0]const u8, file_engine: *FileEngine) !vo
|
|||||||
defer {
|
defer {
|
||||||
parser.deinit();
|
parser.deinit();
|
||||||
switch (gpa.deinit()) {
|
switch (gpa.deinit()) {
|
||||||
.ok => std.log.debug("No memory leak baby !\n", .{}),
|
.ok => {},
|
||||||
.leak => std.log.debug("We fucked it up bro...\n", .{}),
|
.leak => std.log.debug("We fucked it up bro...\n", .{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try parser.parse();
|
parser.parse() catch |err| switch (err) {
|
||||||
|
error.SynthaxError => {},
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Put that in the FileEngine
|
// TODO: Put that in the FileEngine
|
||||||
|
@ -54,10 +54,12 @@ pub const FileEngine = struct {
|
|||||||
float: f64,
|
float: f64,
|
||||||
str: []const u8,
|
str: []const u8,
|
||||||
bool_: bool,
|
bool_: bool,
|
||||||
|
id: UUID,
|
||||||
int_array: std.ArrayList(i64),
|
int_array: std.ArrayList(i64),
|
||||||
str_array: std.ArrayList([]const u8),
|
str_array: std.ArrayList([]const u8),
|
||||||
float_array: std.ArrayList(f64),
|
float_array: std.ArrayList(f64),
|
||||||
bool_array: std.ArrayList(bool),
|
bool_array: std.ArrayList(bool),
|
||||||
|
id_array: std.ArrayList(UUID),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// use to parse file. It take a struct name and member name to know what to parse.
|
/// use to parse file. It take a struct name and member name to know what to parse.
|
||||||
@ -67,7 +69,7 @@ pub const FileEngine = struct {
|
|||||||
struct_name: []const u8,
|
struct_name: []const u8,
|
||||||
member_name: []const u8 = undefined,
|
member_name: []const u8 = undefined,
|
||||||
value: []const u8 = undefined,
|
value: []const u8 = undefined,
|
||||||
operation: enum { equal, different, superior, superior_or_equal, inferior, inferior_or_equal } = undefined, // Add more stuff like IN
|
operation: enum { equal, different, superior, superior_or_equal, inferior, inferior_or_equal, in } = undefined, // Add more stuff like IN
|
||||||
data_type: DataType = undefined,
|
data_type: DataType = undefined,
|
||||||
|
|
||||||
pub fn init(struct_name: []const u8) Condition {
|
pub fn init(struct_name: []const u8) Condition {
|
||||||
@ -76,20 +78,25 @@ 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
|
||||||
|
/// TODO: Change the UUID function to be a B+Tree
|
||||||
/// TODO: Optimize the shit out of this, it it way too slow rn. Here some ideas
|
/// TODO: Optimize the shit out of this, it it way too slow rn. Here some ideas
|
||||||
/// - Array can take a very long time to parse, maybe put them in a seperate file. But string can be too...
|
/// - Array can take a very long time to parse, maybe put them in a seperate file. But string can be too...
|
||||||
/// - Use the stream directly in the tokenizer
|
/// - Use the stream directly in the tokenizer
|
||||||
/// - Use a fixed size and split into other file. Like one file for one member (Because very long, like an array of 1000 value) and another one for everything else
|
/// - Use a fixed size and split into other file. Like one file for one member (Because very long, like an array of 1000 value) and another one for everything else
|
||||||
/// The threselhold can be like if the average len is > 400 character. So UUID would take less that 10% of the storage
|
/// The threselhold can be like if the average len is > 400 character. So UUID would take less that 10% of the storage
|
||||||
/// - Save data in a more compact way
|
/// - Save data in a more compact way
|
||||||
|
/// - Multithreading, each thread take a list of files and we mix them at the end
|
||||||
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 {
|
||||||
const max_file_index = try self.maxFileIndex(condition.struct_name);
|
const max_file_index = try self.maxFileIndex(condition.struct_name);
|
||||||
var current_index: usize = 0;
|
var current_index: usize = 0;
|
||||||
|
|
||||||
var sub_path = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, condition.struct_name, current_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
var path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, condition.struct_name, current_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
defer self.allocator.free(sub_path);
|
defer self.allocator.free(path_buff);
|
||||||
|
|
||||||
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(path_buff, .{}) catch {
|
||||||
|
std.debug.print("Path: {s}", .{path_buff});
|
||||||
|
@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 a file
|
var output: [1024 * 50]u8 = undefined; // Maybe need to increase that as it limit the size of a line in a file
|
||||||
@ -105,10 +112,12 @@ pub const FileEngine = struct {
|
|||||||
.str => compare_value = ComparisonValue{ .str = condition.value },
|
.str => compare_value = ComparisonValue{ .str = condition.value },
|
||||||
.float => compare_value = ComparisonValue{ .float = parseFloat(condition.value) },
|
.float => compare_value = ComparisonValue{ .float = parseFloat(condition.value) },
|
||||||
.bool => compare_value = ComparisonValue{ .bool_ = parseBool(condition.value) },
|
.bool => compare_value = ComparisonValue{ .bool_ = parseBool(condition.value) },
|
||||||
|
.id => compare_value = ComparisonValue{ .id = try UUID.parse(condition.value) },
|
||||||
.int_array => compare_value = ComparisonValue{ .int_array = parseArrayInt(self.allocator, condition.value) },
|
.int_array => compare_value = ComparisonValue{ .int_array = parseArrayInt(self.allocator, condition.value) },
|
||||||
.str_array => compare_value = ComparisonValue{ .str_array = parseArrayStr(self.allocator, condition.value) },
|
.str_array => compare_value = ComparisonValue{ .str_array = parseArrayStr(self.allocator, condition.value) },
|
||||||
.float_array => compare_value = ComparisonValue{ .float_array = parseArrayFloat(self.allocator, condition.value) },
|
.float_array => compare_value = ComparisonValue{ .float_array = parseArrayFloat(self.allocator, condition.value) },
|
||||||
.bool_array => compare_value = ComparisonValue{ .bool_array = parseArrayBool(self.allocator, condition.value) },
|
.bool_array => compare_value = ComparisonValue{ .bool_array = parseArrayBool(self.allocator, condition.value) },
|
||||||
|
.id_array => compare_value = ComparisonValue{ .id_array = parseArrayUUID(self.allocator, condition.value) },
|
||||||
}
|
}
|
||||||
defer {
|
defer {
|
||||||
switch (condition.data_type) {
|
switch (condition.data_type) {
|
||||||
@ -116,6 +125,7 @@ pub const FileEngine = struct {
|
|||||||
.str_array => compare_value.str_array.deinit(),
|
.str_array => compare_value.str_array.deinit(),
|
||||||
.float_array => compare_value.float_array.deinit(),
|
.float_array => compare_value.float_array.deinit(),
|
||||||
.bool_array => compare_value.bool_array.deinit(),
|
.bool_array => compare_value.bool_array.deinit(),
|
||||||
|
.id_array => compare_value.id_array.deinit(),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,19 +137,21 @@ pub const FileEngine = struct {
|
|||||||
output_fbs.reset();
|
output_fbs.reset();
|
||||||
reader.streamUntilDelimiter(writer, '\n', null) catch |err| switch (err) {
|
reader.streamUntilDelimiter(writer, '\n', null) catch |err| switch (err) {
|
||||||
error.EndOfStream => {
|
error.EndOfStream => {
|
||||||
|
// When end of file, check if all file was parse, if not update the reader to the next file
|
||||||
|
// TODO: Be able to give an array of file index from the B+Tree to only parse them
|
||||||
output_fbs.reset(); // clear buffer before exit
|
output_fbs.reset(); // clear buffer before exit
|
||||||
|
|
||||||
if (current_index == max_file_index) break;
|
if (current_index == max_file_index) break;
|
||||||
|
|
||||||
current_index += 1;
|
current_index += 1;
|
||||||
|
|
||||||
self.allocator.free(sub_path);
|
self.allocator.free(path_buff);
|
||||||
sub_path = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, condition.struct_name, current_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, condition.struct_name, current_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
file.close(); // Do I need to close ? I think so
|
file.close(); // Do I need to close ? I think so
|
||||||
file = std.fs.cwd().openFile(sub_path, .{}) catch {
|
file = std.fs.cwd().openFile(path_buff, .{}) catch {
|
||||||
std.debug.print("Error trying to open {s}\n", .{sub_path});
|
std.debug.print("Error trying to open {s}\n", .{path_buff});
|
||||||
@panic("Can't open first file to init a data iterator");
|
@panic("Can't open file to update a data iterator");
|
||||||
};
|
};
|
||||||
|
|
||||||
buffered = std.io.bufferedReader(file.reader());
|
buffered = std.io.bufferedReader(file.reader());
|
||||||
@ -167,64 +179,63 @@ pub const FileEngine = struct {
|
|||||||
|
|
||||||
token = data_toker.next();
|
token = data_toker.next();
|
||||||
|
|
||||||
// TODO: Add error for wrong condition like superior between 2 string or array
|
// TODO: Make sure in amount that the rest is unreachable by sending an error for wrong condition like superior between 2 string or array
|
||||||
switch (condition.operation) {
|
switch (condition.operation) {
|
||||||
.equal => {
|
.equal => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int == parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int == parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float == parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float == parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.str => if (std.mem.eql(u8, compare_value.str, data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.str => if (std.mem.eql(u8, compare_value.str, data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.bool => if (compare_value.bool_ == parseBool(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.bool => if (compare_value.bool_ == parseBool(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.id => if (compare_value.id.compare(uuid)) try uuid_array.append(uuid),
|
||||||
// TODO: Implement for array too
|
// TODO: Implement for array too
|
||||||
else => {},
|
else => unreachable,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.different => {
|
.different => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int != parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int != parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float != parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float != parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.str => if (!std.mem.eql(u8, compare_value.str, data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.str => if (!std.mem.eql(u8, compare_value.str, data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.bool => if (compare_value.bool_ != parseBool(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.bool => if (compare_value.bool_ != parseBool(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
// TODO: Implement for array too
|
||||||
// TODO: Implement for array too
|
else => unreachable,
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.superior_or_equal => {
|
.superior_or_equal => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int <= parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int <= parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float <= parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float <= parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
// TODO: Implement for array too
|
||||||
// TODO: Implement for array too
|
else => unreachable,
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.superior => {
|
.superior => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int < parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int < parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float < parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float < parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
// TODO: Implement for array too
|
||||||
// TODO: Implement for array too
|
else => unreachable,
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.inferior_or_equal => {
|
.inferior_or_equal => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int >= parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int >= parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float >= parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float >= parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
// TODO: Implement for array too
|
||||||
// TODO: Implement for array too
|
else => unreachable,
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.inferior => {
|
.inferior => switch (condition.data_type) {
|
||||||
switch (condition.data_type) {
|
.int => if (compare_value.int > parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.int => if (compare_value.int > parseInt(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
.float => if (compare_value.float > parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
||||||
.float => if (compare_value.float > parseFloat(data_toker.getTokenSlice(token))) try uuid_array.append(uuid),
|
// TODO: Implement for array too
|
||||||
// TODO: Implement for array too
|
else => unreachable,
|
||||||
else => {},
|
},
|
||||||
}
|
|
||||||
|
// TODO: Do it for other array
|
||||||
|
.in => switch (condition.data_type) {
|
||||||
|
.id_array => {
|
||||||
|
for (compare_value.id_array.items) |elem| {
|
||||||
|
if (elem.compare(uuid)) try uuid_array.append(uuid);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,6 +276,161 @@ pub const FileEngine = struct {
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Function to update the file with updated data. Take a list of uuid and a list of string map. The map is in the format key: member; value: new value.
|
||||||
|
/// It create a new index.zippondata.new file in the same folder, stream the output of the old file to it until a uuid is found, then write the new row and continue until the end
|
||||||
|
/// TODO: Optmize a lot, I did that quickly to work but it is far from optimized. Idea:
|
||||||
|
/// - Once all uuid found, stream until the end of the file without delimiter or uuid compare
|
||||||
|
/// - Change map to array
|
||||||
|
pub fn updateEntities(self: *FileEngine, struct_name: []const u8, uuids: std.ArrayList(UUID), new_data_map: std.StringHashMap([]const u8)) !void {
|
||||||
|
const max_file_index = self.maxFileIndex(struct_name) catch @panic("Cant get max index file when updating");
|
||||||
|
var current_file_index: usize = 0;
|
||||||
|
|
||||||
|
var path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
defer self.allocator.free(path_buff);
|
||||||
|
|
||||||
|
var path_buff2 = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
defer self.allocator.free(path_buff2);
|
||||||
|
|
||||||
|
var old_file = std.fs.cwd().openFile(path_buff, .{}) catch {
|
||||||
|
std.debug.print("Path: {s}", .{path_buff});
|
||||||
|
@panic("Can't open first file to init a data iterator");
|
||||||
|
};
|
||||||
|
|
||||||
|
self.allocator.free(path_buff);
|
||||||
|
path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata.new", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
var new_file = std.fs.cwd().createFile(path_buff, .{}) catch {
|
||||||
|
std.debug.print("Path: {s}", .{path_buff});
|
||||||
|
@panic("Can't create new file to init a data iterator");
|
||||||
|
};
|
||||||
|
defer new_file.close();
|
||||||
|
|
||||||
|
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);
|
||||||
|
const writer = output_fbs.writer();
|
||||||
|
|
||||||
|
var buffered = std.io.bufferedReader(old_file.reader());
|
||||||
|
var reader = buffered.reader();
|
||||||
|
var founded = false;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
output_fbs.reset();
|
||||||
|
reader.streamUntilDelimiter(writer, ' ', null) catch |err| switch (err) {
|
||||||
|
error.EndOfStream => {
|
||||||
|
// When end of file, check if all file was parse, if not update the reader to the next file
|
||||||
|
// TODO: Be able to give an array of file index from the B+Tree to only parse them
|
||||||
|
output_fbs.reset(); // clear buffer before exit
|
||||||
|
|
||||||
|
// Start by deleting and renaming the new file
|
||||||
|
self.allocator.free(path_buff);
|
||||||
|
path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
self.allocator.free(path_buff2);
|
||||||
|
path_buff2 = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata.new", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
old_file.close();
|
||||||
|
try std.fs.cwd().deleteFile(path_buff);
|
||||||
|
try std.fs.cwd().rename(path_buff2, path_buff);
|
||||||
|
|
||||||
|
if (current_file_index == max_file_index) break;
|
||||||
|
|
||||||
|
current_file_index += 1;
|
||||||
|
|
||||||
|
self.allocator.free(path_buff);
|
||||||
|
path_buff = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
self.allocator.free(path_buff2);
|
||||||
|
path_buff2 = std.fmt.allocPrint(self.allocator, "{s}/DATA/{s}/{d}.zippondata.new", .{ self.path_to_ZipponDB_dir, struct_name, current_file_index }) catch @panic("Can't create sub_path for init a DataIterator");
|
||||||
|
|
||||||
|
old_file = std.fs.cwd().openFile(path_buff, .{}) catch {
|
||||||
|
std.debug.print("Error trying to open {s}\n", .{path_buff});
|
||||||
|
@panic("Can't open file to update entities");
|
||||||
|
};
|
||||||
|
|
||||||
|
new_file = std.fs.cwd().createFile(path_buff2, .{}) catch {
|
||||||
|
std.debug.print("Error trying to create {s}\n", .{path_buff2});
|
||||||
|
@panic("Can't create file to update entities");
|
||||||
|
};
|
||||||
|
|
||||||
|
buffered = std.io.bufferedReader(old_file.reader());
|
||||||
|
reader = buffered.reader();
|
||||||
|
continue;
|
||||||
|
}, // file read till the end
|
||||||
|
else => {
|
||||||
|
std.debug.print("Error while reading file: {any}\n", .{err});
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try new_file.writeAll(output_fbs.getWritten());
|
||||||
|
|
||||||
|
// THis is the uuid of the current row
|
||||||
|
const uuid = try UUID.parse(output_fbs.getWritten()[0..36]); // FIXME: After the first loop, the first char is \n, which is invalid
|
||||||
|
founded = false;
|
||||||
|
|
||||||
|
// Optimize this
|
||||||
|
for (uuids.items) |elem| {
|
||||||
|
if (elem.compare(uuid)) {
|
||||||
|
founded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (founded) {
|
||||||
|
for (self.structName2structMembers(struct_name), self.structName2DataType(struct_name)) |member_name, member_type| {
|
||||||
|
// For all collum in the right order, check if the key is in the map, if so use it to write the new value, otherwise use the old file
|
||||||
|
output_fbs.reset();
|
||||||
|
switch (member_type) {
|
||||||
|
.str => {
|
||||||
|
try reader.streamUntilDelimiter(writer, '\'', null);
|
||||||
|
try reader.streamUntilDelimiter(writer, '\'', null);
|
||||||
|
},
|
||||||
|
.int_array, .float_array, .bool_array, .id_array => try reader.streamUntilDelimiter(writer, ']', null),
|
||||||
|
.str_array => try reader.streamUntilDelimiter(writer, ']', null), // FIXME: If the string itself contain ], this will be a problem
|
||||||
|
else => {
|
||||||
|
try reader.streamUntilDelimiter(writer, ' ', null);
|
||||||
|
try reader.streamUntilDelimiter(writer, ' ', null);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_data_map.contains(self.locToSlice(member_name))) {
|
||||||
|
// Write the new data
|
||||||
|
try new_file.writer().print(" {s}", .{new_data_map.get(self.locToSlice(member_name)).?});
|
||||||
|
} else {
|
||||||
|
// Write the old data
|
||||||
|
switch (member_type) {
|
||||||
|
.str => try new_file.writeAll(" \'"),
|
||||||
|
.int_array => try new_file.writeAll(" "),
|
||||||
|
.float_array => try new_file.writeAll(" "),
|
||||||
|
.str_array => try new_file.writeAll(" "),
|
||||||
|
.bool_array => try new_file.writeAll(" "),
|
||||||
|
.id_array => try new_file.writeAll(" "),
|
||||||
|
else => try new_file.writeAll(" "),
|
||||||
|
}
|
||||||
|
|
||||||
|
try new_file.writeAll(output_fbs.getWritten());
|
||||||
|
|
||||||
|
switch (member_type) {
|
||||||
|
.str => try new_file.writeAll("\'"),
|
||||||
|
.int_array, .float_array, .bool_array, .id_array => try new_file.writeAll("]"),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try reader.streamUntilDelimiter(writer, '\n', null);
|
||||||
|
try new_file.writeAll("\n");
|
||||||
|
} else {
|
||||||
|
// stream until the delimiter
|
||||||
|
output_fbs.reset();
|
||||||
|
try new_file.writeAll(" ");
|
||||||
|
try reader.streamUntilDelimiter(writer, '\n', null);
|
||||||
|
try new_file.writeAll(output_fbs.getWritten());
|
||||||
|
try new_file.writeAll("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use a filename in the format 1.zippondata and return the 1
|
/// Use a filename in the format 1.zippondata and return the 1
|
||||||
/// Note that if I change the extension of the data file, I need to update that as it use a fixed len for the extension
|
/// Note that if I change the extension of the data file, I need to update that as it use a fixed len for the extension
|
||||||
fn fileName2Index(_: FileEngine, file_name: []const u8) usize {
|
fn fileName2Index(_: FileEngine, file_name: []const u8) usize {
|
||||||
@ -535,6 +701,18 @@ pub fn parseArrayBool(allocator: std.mem.Allocator, array_str: []const u8) std.A
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parseArrayUUID(allocator: std.mem.Allocator, array_str: []const u8) std.ArrayList(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| {
|
||||||
|
const uuid = UUID.parse(x) catch continue;
|
||||||
|
array.append(uuid) catch continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: This will not work if their is a space in one string. E.g ['Hello world'] will be split between Hello and world but it shouldn't
|
// FIXME: This will not work if their is a space in one string. E.g ['Hello world'] will be split between Hello and world but it shouldn't
|
||||||
pub fn parseArrayStr(allocator: std.mem.Allocator, array_str: []const u8) std.ArrayList([]const u8) {
|
pub fn parseArrayStr(allocator: std.mem.Allocator, array_str: []const u8) std.ArrayList([]const u8) {
|
||||||
var array = std.ArrayList([]const u8).init(allocator);
|
var array = std.ArrayList([]const u8).init(allocator);
|
||||||
|
@ -4,8 +4,10 @@ pub const DataType = enum {
|
|||||||
float,
|
float,
|
||||||
str,
|
str,
|
||||||
bool,
|
bool,
|
||||||
|
id,
|
||||||
int_array,
|
int_array,
|
||||||
float_array,
|
float_array,
|
||||||
str_array,
|
str_array,
|
||||||
bool_array,
|
bool_array,
|
||||||
|
id_array,
|
||||||
};
|
};
|
||||||
|
@ -56,6 +56,8 @@ pub const Parser = struct {
|
|||||||
// Endpoint
|
// Endpoint
|
||||||
parse_new_data_and_add_data,
|
parse_new_data_and_add_data,
|
||||||
filter_and_send,
|
filter_and_send,
|
||||||
|
filter_and_update,
|
||||||
|
filter_and_delete,
|
||||||
|
|
||||||
// For the main parse function
|
// For the main parse function
|
||||||
expect_struct_name,
|
expect_struct_name,
|
||||||
@ -87,6 +89,15 @@ pub const Parser = struct {
|
|||||||
add_array_to_map,
|
add_array_to_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ZiQlParserError = error{
|
||||||
|
SynthaxError,
|
||||||
|
MemberNotFound,
|
||||||
|
MemberMissing,
|
||||||
|
StructNotFound,
|
||||||
|
FeatureMissing,
|
||||||
|
ParsingValueError,
|
||||||
|
};
|
||||||
|
|
||||||
/// This is the [] part
|
/// This is the [] part
|
||||||
/// IDK if saving it into the Parser struct is a good idea
|
/// IDK if saving it into the Parser struct is a good idea
|
||||||
pub const AdditionalData = struct {
|
pub const AdditionalData = struct {
|
||||||
@ -144,16 +155,13 @@ pub const Parser = struct {
|
|||||||
self.action = .DELETE;
|
self.action = .DELETE;
|
||||||
self.state = .expect_struct_name;
|
self.state = .expect_struct_name;
|
||||||
},
|
},
|
||||||
else => {
|
else => return self.printError("Error: Expected action keyword. Available: GRAB ADD DELETE UPDATE", &token, ZiQlParserError.SynthaxError),
|
||||||
self.printError("Error: Expected action keyword. Available: GRAB ADD DELETE UPDATE", &token);
|
|
||||||
self.state = .end;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_struct_name => {
|
.expect_struct_name => {
|
||||||
// Check if the struct name is in the schema
|
// Check if the struct name is in the schema
|
||||||
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 (!self.file_engine.isStructNameExists(self.struct_name)) self.printError("Error: struct name not found in schema.", &token);
|
if (!self.file_engine.isStructNameExists(self.struct_name)) return self.printError("Error: struct name not found in schema.", &token, ZiQlParserError.StructNotFound);
|
||||||
switch (self.action) {
|
switch (self.action) {
|
||||||
.ADD => self.state = .expect_new_data,
|
.ADD => self.state = .expect_new_data,
|
||||||
else => self.state = .expect_filter_or_additional_data,
|
else => self.state = .expect_filter_or_additional_data,
|
||||||
@ -164,49 +172,81 @@ pub const Parser = struct {
|
|||||||
keep_next = true;
|
keep_next = true;
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.l_bracket => self.state = .parse_additional_data,
|
.l_bracket => self.state = .parse_additional_data,
|
||||||
.l_brace => self.state = .filter_and_send,
|
.l_brace => self.state = switch (self.action) {
|
||||||
else => self.printError("Error: Expect [ for additional data or { for a filter", &token),
|
.GRAB => .filter_and_send,
|
||||||
|
.UPDATE => .filter_and_update,
|
||||||
|
.DELETE => .filter_and_delete,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => return self.printError("Error: Expect [ for additional data or { for a filter", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.parse_additional_data => {
|
.parse_additional_data => {
|
||||||
try self.parseAdditionalData(&self.additional_data);
|
try self.parseAdditionalData(&self.additional_data);
|
||||||
self.state = .filter_and_send;
|
self.state = switch (self.action) {
|
||||||
|
.GRAB => .filter_and_send,
|
||||||
|
.UPDATE => .filter_and_update,
|
||||||
|
.DELETE => .filter_and_delete,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
.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);
|
||||||
|
|
||||||
|
// TODO: Use the additional data to reduce the array
|
||||||
|
|
||||||
self.sendEntity(array.items);
|
self.sendEntity(array.items);
|
||||||
self.state = .end;
|
self.state = .end;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// TODO: Optimize so it doesnt use parseFilter but just parse the file and directly check the condition. Here I end up parsing 2 times.
|
||||||
|
.filter_and_update => {
|
||||||
|
var array = std.ArrayList(UUID).init(self.allocator);
|
||||||
|
defer array.deinit();
|
||||||
|
token = try self.parseFilter(&array, self.struct_name, true);
|
||||||
|
|
||||||
|
// TODO: Use the additional data to reduce the array
|
||||||
|
|
||||||
|
if (token.tag != .equal_angle_bracket_right) return self.printError("Error: Expected =>", &token, ZiQlParserError.SynthaxError);
|
||||||
|
|
||||||
|
token = self.toker.next();
|
||||||
|
if (token.tag != .l_paren) return self.printError("Error: Expected (", &token, ZiQlParserError.SynthaxError);
|
||||||
|
|
||||||
|
var data_map = std.StringHashMap([]const u8).init(self.allocator);
|
||||||
|
defer data_map.deinit();
|
||||||
|
try self.parseNewData(&data_map);
|
||||||
|
|
||||||
|
try self.file_engine.updateEntities(self.struct_name, array, data_map);
|
||||||
|
self.state = .end;
|
||||||
|
},
|
||||||
|
|
||||||
|
.filter_and_delete => return self.printError("Error: Delete not yet implemented", &token, ZiQlParserError.FeatureMissing),
|
||||||
|
|
||||||
.expect_new_data => switch (token.tag) {
|
.expect_new_data => switch (token.tag) {
|
||||||
.l_paren => {
|
.l_paren => {
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
self.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 => return self.printError("Error: Expecting new data starting with (", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.parse_new_data_and_add_data => switch (self.action) {
|
.parse_new_data_and_add_data => {
|
||||||
.ADD => {
|
var data_map = std.StringHashMap([]const u8).init(self.allocator);
|
||||||
var data_map = std.StringHashMap([]const u8).init(self.allocator);
|
defer data_map.deinit();
|
||||||
defer data_map.deinit();
|
try self.parseNewData(&data_map);
|
||||||
self.parseNewData(&data_map);
|
|
||||||
|
|
||||||
// TODO: Print the list of missing
|
// TODO: Print the list of missing
|
||||||
if (!self.file_engine.checkIfAllMemberInMap(self.struct_name, &data_map)) self.printError("Error: Missing member", &token);
|
if (!self.file_engine.checkIfAllMemberInMap(self.struct_name, &data_map)) return self.printError("Error: Missing member", &token, ZiQlParserError.MemberMissing);
|
||||||
const uuid = self.file_engine.writeEntity(self.struct_name, data_map) catch {
|
const uuid = self.file_engine.writeEntity(self.struct_name, data_map) catch {
|
||||||
send("ZipponDB error: Couln't write new data to file", .{});
|
send("ZipponDB error: Couln't write new data to file", .{});
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
send("Successfully added new {s} with UUID: {s}", .{ self.struct_name, uuid.format_uuid() });
|
send("Successfully added new {s} with UUID: {s}", .{ self.struct_name, uuid.format_uuid() });
|
||||||
self.state = .end;
|
self.state = .end;
|
||||||
},
|
|
||||||
.UPDATE => {}, // TODO:
|
|
||||||
else => unreachable,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -232,7 +272,8 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
/// Take an array of UUID and populate it with what match what is between {}
|
/// Take an array of UUID and populate it with what match what is between {}
|
||||||
/// Main is to know if between {} or (), main is true if between {}, otherwise between () inside {}
|
/// Main is to know if between {} or (), main is true if between {}, otherwise between () inside {}
|
||||||
fn parseFilter(self: *Parser, left_array: *std.ArrayList(UUID), struct_name: []const u8, main: bool) !void {
|
/// TODO: Optimize this so it can use multiple condition at the same time instead of parsing the all file for each condition
|
||||||
|
fn parseFilter(self: *Parser, left_array: *std.ArrayList(UUID), struct_name: []const u8, main: bool) !Token {
|
||||||
var token = self.toker.next();
|
var token = self.toker.next();
|
||||||
var keep_next = false;
|
var keep_next = false;
|
||||||
self.state = State.expect_left_condition;
|
self.state = State.expect_left_condition;
|
||||||
@ -246,26 +287,22 @@ pub const Parser = struct {
|
|||||||
}) {
|
}) {
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
.expect_left_condition => {
|
.expect_left_condition => {
|
||||||
token = self.parseCondition(&left_condition, &token);
|
token = try self.parseCondition(&left_condition, &token);
|
||||||
try self.file_engine.getUUIDListUsingCondition(left_condition, left_array);
|
try self.file_engine.getUUIDListUsingCondition(left_condition, left_array);
|
||||||
self.state = State.expect_ANDOR_OR_end;
|
self.state = State.expect_ANDOR_OR_end;
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_ANDOR_OR_end => switch (token.tag) {
|
.expect_ANDOR_OR_end => switch (token.tag) {
|
||||||
.r_brace => {
|
.r_brace => if (main) {
|
||||||
if (main) {
|
self.state = State.end;
|
||||||
self.state = State.end;
|
} else {
|
||||||
} else {
|
return self.printError("Error: Expected } to end main condition or AND/OR to continue it", &token, ZiQlParserError.SynthaxError);
|
||||||
self.printError("Error: Expected } to end main condition or AND/OR to continue it", &token);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.r_paren => {
|
.r_paren => if (!main) {
|
||||||
if (!main) {
|
self.state = State.end;
|
||||||
self.state = State.end;
|
} else {
|
||||||
} else {
|
return self.printError("Error: Expected ) to end inside condition or AND/OR to continue it", &token, ZiQlParserError.SynthaxError);
|
||||||
self.printError("Error: Expected ) to end inside condition or AND/OR to continue it", &token);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.keyword_and => {
|
.keyword_and => {
|
||||||
curent_operation = .and_;
|
curent_operation = .and_;
|
||||||
@ -275,7 +312,7 @@ pub const Parser = struct {
|
|||||||
curent_operation = .or_;
|
curent_operation = .or_;
|
||||||
self.state = State.expect_right_uuid_array;
|
self.state = State.expect_right_uuid_array;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected a condition including AND or OR or } or )", &token),
|
else => return self.printError("Error: Expected a condition including AND OR or the end of the filter with } or )", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_right_uuid_array => {
|
.expect_right_uuid_array => {
|
||||||
@ -283,15 +320,15 @@ pub const Parser = struct {
|
|||||||
defer right_array.deinit();
|
defer right_array.deinit();
|
||||||
|
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.l_paren => try self.parseFilter(&right_array, struct_name, false), // run parserFilter to get the right array
|
.l_paren => _ = try self.parseFilter(&right_array, struct_name, false), // run parserFilter to get the right array
|
||||||
.identifier => {
|
.identifier => {
|
||||||
var right_condition = Condition.init(struct_name);
|
var right_condition = Condition.init(struct_name);
|
||||||
|
|
||||||
token = self.parseCondition(&right_condition, &token);
|
token = try self.parseCondition(&right_condition, &token);
|
||||||
keep_next = true;
|
keep_next = true;
|
||||||
try self.file_engine.getUUIDListUsingCondition(right_condition, &right_array);
|
try self.file_engine.getUUIDListUsingCondition(right_condition, &right_array);
|
||||||
}, // Create a new condition and compare it
|
}, // Create a new condition and compare it
|
||||||
else => self.printError("Error: Expecting ( or member name.", &token),
|
else => return self.printError("Error: Expecting ( or member name.", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (curent_operation) {
|
switch (curent_operation) {
|
||||||
@ -302,18 +339,19 @@ pub const Parser = struct {
|
|||||||
try OR(left_array, &right_array);
|
try OR(left_array, &right_array);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
std.debug.print("Token here {any}\n", .{token});
|
|
||||||
self.state = .expect_ANDOR_OR_end;
|
self.state = .expect_ANDOR_OR_end;
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse to get a Condition< Which is a struct that is use by the FileEngine to retreive data.
|
/// Parse to get a Condition< Which is a struct that is use by the FileEngine to retreive data.
|
||||||
/// In the query, it is this part name = 'Bob' or age <= 10
|
/// In the query, it is this part name = 'Bob' or age <= 10
|
||||||
fn parseCondition(self: *Parser, condition: *Condition, token_ptr: *Token) Token {
|
fn parseCondition(self: *Parser, condition: *Condition, token_ptr: *Token) !Token {
|
||||||
var keep_next = false;
|
var keep_next = false;
|
||||||
self.state = .expect_member;
|
self.state = .expect_member;
|
||||||
var token = token_ptr.*;
|
var token = token_ptr.*;
|
||||||
@ -326,13 +364,13 @@ pub const Parser = struct {
|
|||||||
.expect_member => switch (token.tag) {
|
.expect_member => switch (token.tag) {
|
||||||
.identifier => {
|
.identifier => {
|
||||||
if (!self.file_engine.isMemberNameInStruct(condition.struct_name, self.toker.getTokenSlice(token))) {
|
if (!self.file_engine.isMemberNameInStruct(condition.struct_name, self.toker.getTokenSlice(token))) {
|
||||||
self.printError("Error: Member not part of struct.", &token);
|
return self.printError("Error: Member not part of struct.", &token, ZiQlParserError.MemberNotFound);
|
||||||
}
|
}
|
||||||
condition.data_type = self.file_engine.memberName2DataType(condition.struct_name, self.toker.getTokenSlice(token)) orelse @panic("Couldn't find the struct and member");
|
condition.data_type = self.file_engine.memberName2DataType(condition.struct_name, self.toker.getTokenSlice(token)) orelse @panic("Couldn't find the struct and member");
|
||||||
condition.member_name = self.toker.getTokenSlice(token);
|
condition.member_name = self.toker.getTokenSlice(token);
|
||||||
self.state = State.expect_operation;
|
self.state = State.expect_operation;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected member name.", &token),
|
else => return self.printError("Error: Expected member name.", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_operation => {
|
.expect_operation => {
|
||||||
@ -343,7 +381,7 @@ pub const Parser = struct {
|
|||||||
.angle_bracket_left_equal => condition.operation = .inferior_or_equal, // <=
|
.angle_bracket_left_equal => condition.operation = .inferior_or_equal, // <=
|
||||||
.angle_bracket_right_equal => condition.operation = .superior_or_equal, // >=
|
.angle_bracket_right_equal => condition.operation = .superior_or_equal, // >=
|
||||||
.bang_equal => condition.operation = .different, // !=
|
.bang_equal => condition.operation = .different, // !=
|
||||||
else => self.printError("Error: Expected condition. Including < > <= >= = !=", &token),
|
else => return self.printError("Error: Expected condition. Including < > <= >= = !=", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
self.state = State.expect_value;
|
self.state = State.expect_value;
|
||||||
},
|
},
|
||||||
@ -353,25 +391,25 @@ pub const Parser = struct {
|
|||||||
.int => {
|
.int => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.int_literal => condition.value = self.toker.getTokenSlice(token),
|
.int_literal => condition.value = self.toker.getTokenSlice(token),
|
||||||
else => self.printError("Error: Expected int", &token),
|
else => return self.printError("Error: Expected int", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.float => {
|
.float => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.float_literal => condition.value = self.toker.getTokenSlice(token),
|
.float_literal => condition.value = self.toker.getTokenSlice(token),
|
||||||
else => self.printError("Error: Expected float", &token),
|
else => return self.printError("Error: Expected float", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.str => {
|
.str, .id => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.string_literal => condition.value = self.toker.getTokenSlice(token),
|
.string_literal => condition.value = self.toker.getTokenSlice(token),
|
||||||
else => self.printError("Error: Expected string", &token),
|
else => return self.printError("Error: Expected string", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.bool => {
|
.bool => {
|
||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.bool_literal_true, .bool_literal_false => condition.value = self.toker.getTokenSlice(token),
|
.bool_literal_true, .bool_literal_false => condition.value = self.toker.getTokenSlice(token),
|
||||||
else => self.printError("Error: Expected bool", &token),
|
else => return self.printError("Error: Expected bool", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.int_array => {
|
.int_array => {
|
||||||
@ -380,7 +418,7 @@ pub const Parser = struct {
|
|||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != 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 => return self.printError("Error: Expected int or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition.value = self.toker.buffer[start_index..token.loc.end];
|
condition.value = self.toker.buffer[start_index..token.loc.end];
|
||||||
@ -391,18 +429,18 @@ pub const Parser = struct {
|
|||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != 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 => return self.printError("Error: Expected float or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition.value = self.toker.buffer[start_index..token.loc.end];
|
condition.value = self.toker.buffer[start_index..token.loc.end];
|
||||||
},
|
},
|
||||||
.str_array => {
|
.str_array, .id_array => {
|
||||||
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 != 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 string or ].", &token),
|
else => return self.printError("Error: Expected string or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition.value = self.toker.buffer[start_index..token.loc.end];
|
condition.value = self.toker.buffer[start_index..token.loc.end];
|
||||||
@ -413,7 +451,7 @@ pub const Parser = struct {
|
|||||||
while (token.tag != Token.Tag.r_bracket) : (token = self.toker.next()) {
|
while (token.tag != 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 => return self.printError("Error: Expected bool or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition.value = self.toker.buffer[start_index..token.loc.end];
|
condition.value = self.toker.buffer[start_index..token.loc.end];
|
||||||
@ -444,9 +482,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.int_literal => {
|
.int_literal => {
|
||||||
const count = std.fmt.parseInt(usize, self.toker.getTokenSlice(token), 10) catch {
|
const count = std.fmt.parseInt(usize, self.toker.getTokenSlice(token), 10) catch {
|
||||||
self.printError("Error while transforming this into a integer.", &token);
|
return self.printError("Error while transforming this into a integer.", &token, ZiQlParserError.ParsingValueError);
|
||||||
self.state = .invalid;
|
|
||||||
continue;
|
|
||||||
};
|
};
|
||||||
additional_data.entity_count_to_find = count;
|
additional_data.entity_count_to_find = count;
|
||||||
self.state = .expect_semicolon_OR_right_bracket;
|
self.state = .expect_semicolon_OR_right_bracket;
|
||||||
@ -461,12 +497,12 @@ pub const Parser = struct {
|
|||||||
.expect_semicolon_OR_right_bracket => switch (token.tag) {
|
.expect_semicolon_OR_right_bracket => switch (token.tag) {
|
||||||
.semicolon => self.state = .expect_member,
|
.semicolon => self.state = .expect_member,
|
||||||
.r_bracket => self.state = .end,
|
.r_bracket => self.state = .end,
|
||||||
else => self.printError("Error: Expect ';' or ']'.", &token),
|
else => return self.printError("Error: Expect ';' or ']'.", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_member => switch (token.tag) {
|
.expect_member => switch (token.tag) {
|
||||||
.identifier => {
|
.identifier => {
|
||||||
if (!self.file_engine.isMemberNameInStruct(self.struct_name, self.toker.getTokenSlice(token))) self.printError("Member not found in struct.", &token);
|
if (!self.file_engine.isMemberNameInStruct(self.struct_name, self.toker.getTokenSlice(token))) return self.printError("Member not found in struct.", &token, ZiQlParserError.SynthaxError);
|
||||||
try additional_data.member_to_find.append(
|
try additional_data.member_to_find.append(
|
||||||
AdditionalDataMember.init(
|
AdditionalDataMember.init(
|
||||||
self.allocator,
|
self.allocator,
|
||||||
@ -476,7 +512,7 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
self.state = .expect_comma_OR_r_bracket_OR_l_bracket;
|
self.state = .expect_comma_OR_r_bracket_OR_l_bracket;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected a member name.", &token),
|
else => return self.printError("Error: Expected a member name.", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_comma_OR_r_bracket_OR_l_bracket => switch (token.tag) {
|
.expect_comma_OR_r_bracket_OR_l_bracket => switch (token.tag) {
|
||||||
@ -488,13 +524,13 @@ pub const Parser = struct {
|
|||||||
);
|
);
|
||||||
self.state = .expect_comma_OR_r_bracket;
|
self.state = .expect_comma_OR_r_bracket;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected , or ] or [", &token),
|
else => return self.printError("Error: Expected , or ] or [", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_comma_OR_r_bracket => switch (token.tag) {
|
.expect_comma_OR_r_bracket => switch (token.tag) {
|
||||||
.comma => self.state = .expect_member,
|
.comma => self.state = .expect_member,
|
||||||
.r_bracket => self.state = .end,
|
.r_bracket => self.state = .end,
|
||||||
else => self.printError("Error: Expected , or ]", &token),
|
else => return self.printError("Error: Expected , or ]", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -505,7 +541,7 @@ pub const Parser = struct {
|
|||||||
/// Take the tokenizer and return a map of the query for the ADD command.
|
/// Take the tokenizer and return a map of the query for the ADD command.
|
||||||
/// Keys are the member name and value are the string of the value in the query. E.g. 'Adrien' or '10'
|
/// Keys are the member name and value are the string of the value in the query. E.g. 'Adrien' or '10'
|
||||||
/// Entry token need to be (
|
/// Entry token need to be (
|
||||||
fn parseNewData(self: *Parser, member_map: *std.StringHashMap([]const u8)) void {
|
fn parseNewData(self: *Parser, member_map: *std.StringHashMap([]const u8)) !void {
|
||||||
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
|
||||||
@ -519,16 +555,16 @@ pub const Parser = struct {
|
|||||||
.expect_member => switch (token.tag) {
|
.expect_member => switch (token.tag) {
|
||||||
.identifier => {
|
.identifier => {
|
||||||
member_name = self.toker.getTokenSlice(token);
|
member_name = self.toker.getTokenSlice(token);
|
||||||
if (!self.file_engine.isMemberNameInStruct(self.struct_name, member_name)) self.printError("Member not found in struct.", &token);
|
if (!self.file_engine.isMemberNameInStruct(self.struct_name, member_name)) return self.printError("Member not found in struct.", &token, ZiQlParserError.MemberNotFound);
|
||||||
self.state = .expect_equal;
|
self.state = .expect_equal;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected member name.", &token),
|
else => return self.printError("Error: Expected member name.", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_equal => switch (token.tag) {
|
.expect_equal => switch (token.tag) {
|
||||||
// TODO: Add more comparison like IN or other stuff
|
// TODO: Add more comparison like IN or other stuff
|
||||||
.equal => self.state = .expect_new_value,
|
.equal => self.state = .expect_new_value,
|
||||||
else => self.printError("Error: Expected =", &token),
|
else => return self.printError("Error: Expected =", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
|
|
||||||
.expect_new_value => {
|
.expect_new_value => {
|
||||||
@ -539,14 +575,14 @@ pub const Parser = struct {
|
|||||||
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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected int", &token),
|
else => return self.printError("Error: Expected int", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.float => switch (token.tag) {
|
.float => switch (token.tag) {
|
||||||
.float_literal, .keyword_null => {
|
.float_literal, .keyword_null => {
|
||||||
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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected float", &token),
|
else => return self.printError("Error: Expected float", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.bool => switch (token.tag) {
|
.bool => switch (token.tag) {
|
||||||
.bool_literal_true => {
|
.bool_literal_true => {
|
||||||
@ -561,14 +597,14 @@ pub const Parser = struct {
|
|||||||
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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected bool: true false", &token),
|
else => return self.printError("Error: Expected bool: true false", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.str => switch (token.tag) {
|
.str, .id => switch (token.tag) {
|
||||||
.string_literal, .keyword_null => {
|
.string_literal, .keyword_null => {
|
||||||
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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected string between ''", &token),
|
else => return self.printError("Error: Expected string between ''", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
// TODO: Maybe upgrade that to use multiple state
|
// TODO: Maybe upgrade that to use multiple state
|
||||||
.int_array => switch (token.tag) {
|
.int_array => switch (token.tag) {
|
||||||
@ -578,14 +614,14 @@ pub const Parser = struct {
|
|||||||
while (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 => return self.printError("Error: Expected int or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => return self.printError("Error: Expected [ to start an array", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.float_array => switch (token.tag) {
|
.float_array => switch (token.tag) {
|
||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
@ -594,14 +630,14 @@ pub const Parser = struct {
|
|||||||
while (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 => return self.printError("Error: Expected float or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => return self.printError("Error: Expected [ to start an array", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.bool_array => switch (token.tag) {
|
.bool_array => switch (token.tag) {
|
||||||
.l_bracket => {
|
.l_bracket => {
|
||||||
@ -610,30 +646,30 @@ pub const Parser = struct {
|
|||||||
while (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 => return self.printError("Error: Expected bool or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => return self.printError("Error: Expected [ to start an array", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
.str_array => switch (token.tag) {
|
.str_array, .id_array => switch (token.tag) {
|
||||||
.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 != .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 => return self.printError("Error: Expected str or ].", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 = .expect_comma_OR_end;
|
self.state = .expect_comma_OR_end;
|
||||||
},
|
},
|
||||||
else => self.printError("Error: Expected [ to start an array", &token),
|
else => return self.printError("Error: Expected [ to start an array", &token, ZiQlParserError.SynthaxError),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -642,7 +678,7 @@ pub const Parser = struct {
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.r_paren => self.state = .end,
|
.r_paren => self.state = .end,
|
||||||
.comma => self.state = .expect_member,
|
.comma => self.state = .expect_member,
|
||||||
else => self.printError("Error: Expect , or )", &token),
|
else => return self.printError("Error: Expect , or )", &token, ZiQlParserError.SynthaxError),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -651,8 +687,9 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printError(self: *Parser, message: []const u8, token: *Token) void {
|
fn printError(self: *Parser, message: []const u8, token: *Token, err: ZiQlParserError) ZiQlParserError {
|
||||||
stdout.print("\n", .{}) catch {};
|
stdout.print("\n", .{}) catch {};
|
||||||
|
stdout.print("{s}\n", .{message}) catch {};
|
||||||
stdout.print("{s}\n", .{self.toker.buffer}) catch {};
|
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.
|
||||||
@ -668,9 +705,8 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
stdout.print(" \n", .{}) catch {}; // Align with the message
|
stdout.print(" \n", .{}) catch {}; // Align with the message
|
||||||
|
|
||||||
stdout.print("{s}\n", .{message}) catch {};
|
|
||||||
|
|
||||||
send("", .{});
|
send("", .{});
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user