Start cleaning before working one 0.2
This commit is contained in:
parent
c93538f4b0
commit
29af5a7ac0
348
src/cli.zig
348
src/cli.zig
@ -85,187 +85,185 @@ pub fn main() !void {
|
|||||||
var token = cliToker.next();
|
var token = cliToker.next();
|
||||||
state = .expect_main_command;
|
state = .expect_main_command;
|
||||||
|
|
||||||
while ((state != .end) and (state != .quit)) : (token = cliToker.next()) {
|
while ((state != .end) and (state != .quit)) : (token = cliToker.next()) switch (state) {
|
||||||
switch (state) {
|
.expect_main_command => switch (token.tag) {
|
||||||
.expect_main_command => switch (token.tag) {
|
.keyword_run => {
|
||||||
.keyword_run => {
|
if (!file_engine.usable) {
|
||||||
if (!file_engine.usable) {
|
send("Error: No database selected. Please use db new or db use.", .{});
|
||||||
send("Error: No database selected. Please use db new or db use.", .{});
|
state = .end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
state = .expect_query;
|
||||||
|
},
|
||||||
|
.keyword_db => state = .expect_db_command,
|
||||||
|
.keyword_schema => {
|
||||||
|
if (!file_engine.usable) {
|
||||||
|
send("Error: No database selected. Please use db new or db use.", .{});
|
||||||
|
state = .end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
state = .expect_schema_command;
|
||||||
|
},
|
||||||
|
.keyword_help => {
|
||||||
|
send("{s}", .{
|
||||||
|
\\Welcome to ZipponDB v0.1!
|
||||||
|
\\
|
||||||
|
\\Available commands:
|
||||||
|
\\run To run a query.
|
||||||
|
\\db Create or chose a database.
|
||||||
|
\\schema Initialize the database schema.
|
||||||
|
\\quit Stop the CLI with memory safety.
|
||||||
|
\\
|
||||||
|
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
||||||
|
\\
|
||||||
|
});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
.keyword_quit => state = .quit,
|
||||||
|
.eof => state = .end,
|
||||||
|
else => {
|
||||||
|
send("Command need to start with a keyword, including: run, db, schema, help and quit", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_db_command => switch (token.tag) {
|
||||||
|
.keyword_new => state = .expect_path_to_new_db,
|
||||||
|
.keyword_use => state = .expect_path_to_db,
|
||||||
|
.keyword_metrics => {
|
||||||
|
if (!file_engine.usable) {
|
||||||
|
send("Error: No database selected. Please use db new or db use.", .{});
|
||||||
|
state = .end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer = std.ArrayList(u8).init(allocator);
|
||||||
|
defer buffer.deinit();
|
||||||
|
|
||||||
|
try file_engine.writeDbMetrics(&buffer);
|
||||||
|
send("{s}", .{buffer.items});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
.keyword_help => {
|
||||||
|
send("{s}", .{
|
||||||
|
\\Available commands:
|
||||||
|
\\new Create a new database using a path to a sub folder.
|
||||||
|
\\use Select another ZipponDB folder to use as database.
|
||||||
|
\\metrics Print some metrics of the current database.
|
||||||
|
\\
|
||||||
|
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
||||||
|
\\
|
||||||
|
});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
send("Error: db commands available: new, metrics, swap & help", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_path_to_db => switch (token.tag) {
|
||||||
|
.identifier => {
|
||||||
|
file_engine.deinit();
|
||||||
|
file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token)));
|
||||||
|
send("Successfully started using the database!", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
send("Error Expect a path to a ZipponDB folder.", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_path_to_new_db => switch (token.tag) {
|
||||||
|
.identifier => {
|
||||||
|
checkAndCreateDirectories(cliToker.getTokenSlice(token), allocator) catch |err| {
|
||||||
|
send("Error: Coulnt create database directories: {any}", .{err});
|
||||||
|
state = .end;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
file_engine.deinit();
|
||||||
|
file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token)));
|
||||||
|
send("Successfully initialized the database!", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
send("Error Expect a path to a folder.", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_query => switch (token.tag) {
|
||||||
|
.string_literal => {
|
||||||
|
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);
|
||||||
|
runQuery(null_term_query_str, &file_engine);
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
.keyword_help => {
|
||||||
|
send("The run command take a ZiQL query between \" and run it. eg: run \"GRAB User\"", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
send("Error: After command run, need a query, eg: \"GRAB User\"", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_schema_command => switch (token.tag) {
|
||||||
|
.keyword_describe => {
|
||||||
|
if (std.mem.eql(u8, file_engine.path_to_ZipponDB_dir, "")) send("Error: No database selected. Please use db bew or db use.", .{});
|
||||||
|
|
||||||
|
if (file_engine.null_terminated_schema_buff.len == 0) {
|
||||||
|
send("Need to init the schema first. Please use the schema init path/to/schema command to start.", .{});
|
||||||
|
} else {
|
||||||
|
send("Schema:\n {s}", .{file_engine.null_terminated_schema_buff});
|
||||||
|
}
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
.keyword_init => state = .expect_path_to_schema,
|
||||||
|
.keyword_help => {
|
||||||
|
send("{s}", .{
|
||||||
|
\\Available commands:
|
||||||
|
\\describe Print the schema use by the currently selected database.
|
||||||
|
\\init Take the path to a schema file and initialize the database.
|
||||||
|
\\
|
||||||
|
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
||||||
|
\\
|
||||||
|
});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
send("Error: schema commands available: describe, init & help", .{});
|
||||||
|
state = .end;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_path_to_schema => switch (token.tag) {
|
||||||
|
.identifier => {
|
||||||
|
file_engine.initDataFolder(cliToker.getTokenSlice(token)) catch |err| switch (err) {
|
||||||
|
error.SchemaFileNotFound => {
|
||||||
|
send("Coulnt find the schema file at {s}", .{cliToker.getTokenSlice(token)});
|
||||||
state = .end;
|
state = .end;
|
||||||
continue;
|
},
|
||||||
}
|
else => {
|
||||||
state = .expect_query;
|
send("Error initializing the schema", .{});
|
||||||
},
|
|
||||||
.keyword_db => state = .expect_db_command,
|
|
||||||
.keyword_schema => {
|
|
||||||
if (!file_engine.usable) {
|
|
||||||
send("Error: No database selected. Please use db new or db use.", .{});
|
|
||||||
state = .end;
|
state = .end;
|
||||||
continue;
|
},
|
||||||
}
|
};
|
||||||
state = .expect_schema_command;
|
send("Successfully initialized the database schema!", .{});
|
||||||
},
|
state = .end;
|
||||||
.keyword_help => {
|
|
||||||
send("{s}", .{
|
|
||||||
\\Welcome to ZipponDB v0.1!
|
|
||||||
\\
|
|
||||||
\\Available commands:
|
|
||||||
\\run To run a query.
|
|
||||||
\\db Create or chose a database.
|
|
||||||
\\schema Initialize the database schema.
|
|
||||||
\\quit Stop the CLI with memory safety.
|
|
||||||
\\
|
|
||||||
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
|
||||||
\\
|
|
||||||
});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
.keyword_quit => state = .quit,
|
|
||||||
.eof => state = .end,
|
|
||||||
else => {
|
|
||||||
send("Command need to start with a keyword, including: run, db, schema, help and quit", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
else => {
|
||||||
.expect_db_command => switch (token.tag) {
|
send("Error: Expect path to schema file.", .{});
|
||||||
.keyword_new => state = .expect_path_to_new_db,
|
state = .end;
|
||||||
.keyword_use => state = .expect_path_to_db,
|
|
||||||
.keyword_metrics => {
|
|
||||||
if (!file_engine.usable) {
|
|
||||||
send("Error: No database selected. Please use db new or db use.", .{});
|
|
||||||
state = .end;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffer = std.ArrayList(u8).init(allocator);
|
|
||||||
defer buffer.deinit();
|
|
||||||
|
|
||||||
try file_engine.writeDbMetrics(&buffer);
|
|
||||||
send("{s}", .{buffer.items});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
.keyword_help => {
|
|
||||||
send("{s}", .{
|
|
||||||
\\Available commands:
|
|
||||||
\\new Create a new database using a path to a sub folder.
|
|
||||||
\\use Select another ZipponDB folder to use as database.
|
|
||||||
\\metrics Print some metrics of the current database.
|
|
||||||
\\
|
|
||||||
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
|
||||||
\\
|
|
||||||
});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error: db commands available: new, metrics, swap & help", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.expect_path_to_db => switch (token.tag) {
|
.quit, .end => break,
|
||||||
.identifier => {
|
};
|
||||||
file_engine.deinit();
|
|
||||||
file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token)));
|
|
||||||
send("Successfully started using the database!", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error Expect a path to a ZipponDB folder.", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.expect_path_to_new_db => switch (token.tag) {
|
|
||||||
.identifier => {
|
|
||||||
checkAndCreateDirectories(cliToker.getTokenSlice(token), allocator) catch |err| {
|
|
||||||
send("Error: Coulnt create database directories: {any}", .{err});
|
|
||||||
state = .end;
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
file_engine.deinit();
|
|
||||||
file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token)));
|
|
||||||
send("Successfully initialized the database!", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error Expect a path to a folder.", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.expect_query => switch (token.tag) {
|
|
||||||
.string_literal => {
|
|
||||||
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);
|
|
||||||
runQuery(null_term_query_str, &file_engine);
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
.keyword_help => {
|
|
||||||
send("The run command take a ZiQL query between \" and run it. eg: run \"GRAB User\"", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error: After command run, need a query, eg: \"GRAB User\"", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.expect_schema_command => switch (token.tag) {
|
|
||||||
.keyword_describe => {
|
|
||||||
if (std.mem.eql(u8, file_engine.path_to_ZipponDB_dir, "")) send("Error: No database selected. Please use db bew or db use.", .{});
|
|
||||||
|
|
||||||
if (file_engine.null_terminated_schema_buff.len == 0) {
|
|
||||||
send("Need to init the schema first. Please use the schema init path/to/schema command to start.", .{});
|
|
||||||
} else {
|
|
||||||
send("Schema:\n {s}", .{file_engine.null_terminated_schema_buff});
|
|
||||||
}
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
.keyword_init => state = .expect_path_to_schema,
|
|
||||||
.keyword_help => {
|
|
||||||
send("{s}", .{
|
|
||||||
\\Available commands:
|
|
||||||
\\describe Print the schema use by the currently selected database.
|
|
||||||
\\init Take the path to a schema file and initialize the database.
|
|
||||||
\\
|
|
||||||
\\ For more informations: https://github.com/MrBounty/ZipponDB
|
|
||||||
\\
|
|
||||||
});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error: schema commands available: describe, init & help", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.expect_path_to_schema => switch (token.tag) {
|
|
||||||
.identifier => {
|
|
||||||
file_engine.initDataFolder(cliToker.getTokenSlice(token)) catch |err| switch (err) {
|
|
||||||
error.SchemaFileNotFound => {
|
|
||||||
send("Coulnt find the schema file at {s}", .{cliToker.getTokenSlice(token)});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error initializing the schema", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
send("Successfully initialized the database schema!", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
send("Error: Expect path to schema file.", .{});
|
|
||||||
state = .end;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.quit, .end => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state == .quit) break;
|
|
||||||
}
|
}
|
||||||
|
if (state == .quit) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,17 +8,25 @@ const SchemaStruct = @import("schemaParser.zig").Parser.SchemaStruct;
|
|||||||
const SchemaParser = @import("schemaParser.zig").Parser;
|
const SchemaParser = @import("schemaParser.zig").Parser;
|
||||||
const SchemaTokenizer = @import("tokenizers/schema.zig").Tokenizer;
|
const SchemaTokenizer = @import("tokenizers/schema.zig").Tokenizer;
|
||||||
const SchemaToken = @import("tokenizers/schema.zig").Token;
|
const SchemaToken = @import("tokenizers/schema.zig").Token;
|
||||||
const AdditionalData = @import("ziqlParser.zig").Parser.AdditionalData;
|
const AdditionalData = @import("parsing-tools/additionalData.zig").AdditionalData;
|
||||||
|
|
||||||
//TODO: Create a union class and chose between file and memory
|
// TODO: Use those errors everywhere in this file
|
||||||
|
const FileEngineError = error{
|
||||||
|
SchemaFileNotFound,
|
||||||
|
SchemaNotConform,
|
||||||
|
DATAFolderNotFound,
|
||||||
|
StructFolderNotFound,
|
||||||
|
CantMakeDir,
|
||||||
|
CantMakeFile,
|
||||||
|
};
|
||||||
|
|
||||||
/// Manage everything that is relate to read or write in files
|
/// Manage everything that is relate to read or write in files
|
||||||
/// Or even get stats, whatever. If it touch files, it's here
|
/// Or even get stats, whatever. If it touch files, it's here
|
||||||
pub const FileEngine = struct {
|
pub const FileEngine = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
usable: bool,
|
usable: bool,
|
||||||
path_to_ZipponDB_dir: []const u8, // Make that into a list
|
path_to_ZipponDB_dir: []const u8, // TODO: Put in config file
|
||||||
max_file_size: usize = 5e+4, // 50kb TODO: Change
|
max_file_size: usize = 5e+4, // 50kb TODO: Put in config file
|
||||||
null_terminated_schema_buff: [:0]u8,
|
null_terminated_schema_buff: [:0]u8,
|
||||||
struct_array: std.ArrayList(SchemaStruct),
|
struct_array: std.ArrayList(SchemaStruct),
|
||||||
|
|
||||||
@ -81,10 +89,6 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn setPath(self: *FileEngine, path: []const u8) void {
|
|
||||||
self.path_to_ZipponDB_dir = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take a list of UUID and, a buffer array and the additional data to write into the buffer the JSON to send
|
/// Take a list of UUID and, a buffer array and the additional data to write into the buffer the JSON to send
|
||||||
/// TODO: Optimize
|
/// TODO: Optimize
|
||||||
/// FIXME: Array of string are not working
|
/// FIXME: Array of string are not working
|
||||||
@ -161,62 +165,55 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (founded) {
|
if (!founded) continue;
|
||||||
try out_writer.writeAll("{");
|
|
||||||
try out_writer.writeAll("id:\"");
|
|
||||||
try out_writer.print("{s}", .{output_fbs.getWritten()[0..36]});
|
|
||||||
try out_writer.writeAll("\", ");
|
|
||||||
for (self.structName2structMembers(struct_name), self.structName2DataType(struct_name)) |member_name, member_type| {
|
|
||||||
token = data_toker.next();
|
|
||||||
// FIXME: When relationship will be implemented, need to check if the len of NON link is 0
|
|
||||||
if ((additional_data.member_to_find.items.len == 0) or (self.isMemberNameInAdditionalData(self.locToSlice(member_name), additional_data))) {
|
|
||||||
// write the member name and = sign
|
|
||||||
try out_writer.print("{s}: ", .{self.locToSlice(member_name)});
|
|
||||||
|
|
||||||
switch (member_type) {
|
try out_writer.writeAll("{");
|
||||||
.str => {
|
try out_writer.writeAll("id:\"");
|
||||||
const str_slice = data_toker.getTokenSlice(token);
|
try out_writer.print("{s}", .{output_fbs.getWritten()[0..36]});
|
||||||
try out_writer.print("\"{s}\"", .{str_slice[1 .. str_slice.len - 1]});
|
try out_writer.writeAll("\", ");
|
||||||
},
|
for (self.structName2structMembers(struct_name), self.structName2DataType(struct_name)) |member_name, member_type| {
|
||||||
.str_array => {
|
token = data_toker.next();
|
||||||
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
// FIXME: When relationship will be implemented, need to check if the len of NON link is 0
|
||||||
token = data_toker.next();
|
if (!(additional_data.member_to_find.items.len == 0) or !(additional_data.contains(self.locToSlice(member_name)))) continue;
|
||||||
while (token.tag != .r_bracket) : (token = data_toker.next()) {
|
|
||||||
try out_writer.writeAll("\"");
|
// write the member name and = sign
|
||||||
try out_writer.writeAll(data_toker.getTokenSlice(token)[1..(token.loc.end - token.loc.start)]);
|
try out_writer.print("{s}: ", .{self.locToSlice(member_name)});
|
||||||
try out_writer.writeAll("\"");
|
|
||||||
try out_writer.writeAll(" ");
|
switch (member_type) {
|
||||||
}
|
.str => {
|
||||||
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
const str_slice = data_toker.getTokenSlice(token);
|
||||||
},
|
try out_writer.print("\"{s}\"", .{str_slice[1 .. str_slice.len - 1]});
|
||||||
.int_array, .float_array, .bool_array, .id_array => {
|
},
|
||||||
while (token.tag != .r_bracket) : (token = data_toker.next()) {
|
.str_array => {
|
||||||
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
||||||
try out_writer.writeAll(" ");
|
token = data_toker.next();
|
||||||
}
|
while (token.tag != .r_bracket) : (token = data_toker.next()) {
|
||||||
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
try out_writer.writeAll("\"");
|
||||||
},
|
try out_writer.writeAll(data_toker.getTokenSlice(token)[1..(token.loc.end - token.loc.start)]);
|
||||||
else => try out_writer.writeAll(data_toker.getTokenSlice(token)), //write the value as if
|
try out_writer.writeAll("\"");
|
||||||
|
try out_writer.writeAll(" ");
|
||||||
}
|
}
|
||||||
try out_writer.writeAll(", ");
|
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
||||||
}
|
},
|
||||||
|
.int_array, .float_array, .bool_array, .id_array => {
|
||||||
|
while (token.tag != .r_bracket) : (token = data_toker.next()) {
|
||||||
|
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
||||||
|
try out_writer.writeAll(" ");
|
||||||
|
}
|
||||||
|
try out_writer.writeAll(data_toker.getTokenSlice(token));
|
||||||
|
},
|
||||||
|
else => try out_writer.writeAll(data_toker.getTokenSlice(token)), //write the value as if
|
||||||
}
|
}
|
||||||
try out_writer.writeAll("}");
|
|
||||||
try out_writer.writeAll(", ");
|
try out_writer.writeAll(", ");
|
||||||
}
|
}
|
||||||
|
try out_writer.writeAll("}");
|
||||||
|
try out_writer.writeAll(", ");
|
||||||
}
|
}
|
||||||
// Write the end }
|
|
||||||
try out_writer.writeAll("]");
|
try out_writer.writeAll("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isMemberNameInAdditionalData(_: *FileEngine, member_name: []const u8, additional_data: AdditionalData) bool {
|
|
||||||
for (additional_data.member_to_find.items) |elem| {
|
|
||||||
if (std.mem.eql(u8, member_name, elem.name)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use a struct name to populate a list with all UUID of this struct
|
/// Use a struct name to populate a list with all UUID of this struct
|
||||||
|
/// TODO: Optimize this, I'm sure I can do better than that
|
||||||
pub fn getAllUUIDList(self: *FileEngine, struct_name: []const u8, uuid_array: *std.ArrayList(UUID)) !void {
|
pub fn getAllUUIDList(self: *FileEngine, struct_name: []const u8, uuid_array: *std.ArrayList(UUID)) !void {
|
||||||
const max_file_index = try self.maxFileIndex(struct_name);
|
const max_file_index = try self.maxFileIndex(struct_name);
|
||||||
var current_index: usize = 0;
|
var current_index: usize = 0;
|
||||||
@ -431,9 +428,7 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Clean a bit the code
|
// Do I need a map here ? Cant I use something else ?
|
||||||
// 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 - 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)) !UUID {
|
pub fn writeEntity(self: *FileEngine, struct_name: []const u8, data_map: std.StringHashMap([]const u8)) !UUID {
|
||||||
const uuid = UUID.init();
|
const uuid = UUID.init();
|
||||||
|
|
||||||
@ -566,7 +561,14 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (founded) {
|
if (!founded) {
|
||||||
|
// 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");
|
||||||
|
} else {
|
||||||
for (self.structName2structMembers(struct_name), self.structName2DataType(struct_name)) |member_name, member_type| {
|
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
|
// 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();
|
output_fbs.reset();
|
||||||
@ -610,13 +612,6 @@ pub const FileEngine = struct {
|
|||||||
|
|
||||||
try reader.streamUntilDelimiter(writer, '\n', null);
|
try reader.streamUntilDelimiter(writer, '\n', null);
|
||||||
try new_file.writeAll("\n");
|
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -807,40 +802,13 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe make it so it use itself to search if it find a directory
|
|
||||||
fn getDirTotalSize(self: FileEngine, dir: std.fs.Dir) !u64 {
|
|
||||||
var total: u64 = 0;
|
|
||||||
var stat: std.fs.File.Stat = undefined;
|
|
||||||
var iter = dir.iterate();
|
|
||||||
while (try iter.next()) |entry| {
|
|
||||||
if (entry.kind == .directory) {
|
|
||||||
const sub_dir = try dir.openDir(entry.name, .{ .iterate = true });
|
|
||||||
total += try self.getDirTotalSize(sub_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.kind != .file) continue;
|
|
||||||
stat = try dir.statFile(entry.name);
|
|
||||||
total += stat.size;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FileError = error{
|
|
||||||
SchemaFileNotFound,
|
|
||||||
SchemaNotConform,
|
|
||||||
DATAFolderNotFound,
|
|
||||||
StructFolderNotFound,
|
|
||||||
CantMakeDir,
|
|
||||||
CantMakeFile,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Request a path to a schema file and then create the struct folder
|
/// Request a path to a schema file and then create the struct folder
|
||||||
/// TODO: Check if some data already exist and if so ask if the user want to delete it and make a backup
|
/// TODO: Check if some data already exist and if so ask if the user want to delete it and make a backup
|
||||||
pub fn initDataFolder(self: *FileEngine, path_to_schema_file: []const u8) FileError!void {
|
pub fn initDataFolder(self: *FileEngine, path_to_schema_file: []const u8) FileEngineError!void {
|
||||||
var schema_buf = self.allocator.alloc(u8, 1024 * 50) catch @panic("Cant allocate the schema buffer");
|
var schema_buf = self.allocator.alloc(u8, 1024 * 50) catch @panic("Cant allocate the schema buffer");
|
||||||
defer self.allocator.free(schema_buf);
|
defer self.allocator.free(schema_buf);
|
||||||
|
|
||||||
const file = std.fs.cwd().openFile(path_to_schema_file, .{}) catch return FileError.SchemaFileNotFound;
|
const file = std.fs.cwd().openFile(path_to_schema_file, .{}) catch return FileEngineError.SchemaFileNotFound;
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const len = file.readAll(schema_buf) catch @panic("Can't read schema file");
|
const len = file.readAll(schema_buf) catch @panic("Can't read schema file");
|
||||||
@ -860,19 +828,19 @@ pub const FileEngine = struct {
|
|||||||
const path = std.fmt.allocPrint(self.allocator, "{s}/DATA", .{self.path_to_ZipponDB_dir}) catch @panic("Cant allocate path");
|
const path = std.fmt.allocPrint(self.allocator, "{s}/DATA", .{self.path_to_ZipponDB_dir}) catch @panic("Cant allocate path");
|
||||||
defer self.allocator.free(path);
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
var data_dir = std.fs.cwd().openDir(path, .{}) catch return FileError.DATAFolderNotFound;
|
var data_dir = std.fs.cwd().openDir(path, .{}) catch return FileEngineError.DATAFolderNotFound;
|
||||||
defer data_dir.close();
|
defer data_dir.close();
|
||||||
|
|
||||||
for (self.struct_array.items) |struct_item| {
|
for (self.struct_array.items) |struct_item| {
|
||||||
data_dir.makeDir(self.locToSlice(struct_item.name)) catch |err| switch (err) {
|
data_dir.makeDir(self.locToSlice(struct_item.name)) catch |err| switch (err) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return FileError.CantMakeDir,
|
else => return FileEngineError.CantMakeDir,
|
||||||
};
|
};
|
||||||
const struct_dir = data_dir.openDir(self.locToSlice(struct_item.name), .{}) catch return FileError.StructFolderNotFound;
|
const struct_dir = data_dir.openDir(self.locToSlice(struct_item.name), .{}) catch return FileEngineError.StructFolderNotFound;
|
||||||
|
|
||||||
_ = struct_dir.createFile("0.zippondata", .{}) catch |err| switch (err) {
|
_ = struct_dir.createFile("0.zippondata", .{}) catch |err| switch (err) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return FileError.CantMakeFile,
|
else => return FileEngineError.CantMakeFile,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,6 +848,7 @@ pub const FileEngine = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stuff for schema
|
// Stuff for schema
|
||||||
|
// TODO: Check all those functions and remove if not use
|
||||||
|
|
||||||
pub fn readSchemaFile(allocator: Allocator, sub_path: []const u8, buffer: []u8) !usize {
|
pub fn readSchemaFile(allocator: Allocator, sub_path: []const u8, buffer: []u8) !usize {
|
||||||
const path = try std.fmt.allocPrint(allocator, "{s}/schema.zipponschema", .{sub_path});
|
const path = try std.fmt.allocPrint(allocator, "{s}/schema.zipponschema", .{sub_path});
|
||||||
@ -1011,6 +980,7 @@ test "Get list of UUID using condition" {
|
|||||||
// Series of functions to use just before creating an entity.
|
// Series of functions to use just before creating an entity.
|
||||||
// Will transform the string of data into data of the right type./
|
// Will transform the string of data into data of the right type./
|
||||||
|
|
||||||
|
// TODO: Put those functions somewhere else
|
||||||
pub fn parseInt(value_str: []const u8) i64 {
|
pub fn parseInt(value_str: []const u8) i64 {
|
||||||
return std.fmt.parseInt(i64, value_str, 10) catch return 0;
|
return std.fmt.parseInt(i64, value_str, 10) catch return 0;
|
||||||
}
|
}
|
||||||
|
40
src/parsing-tools/additionalData.zig
Normal file
40
src/parsing-tools/additionalData.zig
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
/// This is the [] part
|
||||||
|
/// IDK if saving it into the Parser struct is a good idea
|
||||||
|
pub const AdditionalData = struct {
|
||||||
|
entity_count_to_find: usize = 0,
|
||||||
|
member_to_find: std.ArrayList(AdditionalDataMember),
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator) AdditionalData {
|
||||||
|
return AdditionalData{ .member_to_find = std.ArrayList(AdditionalDataMember).init(allocator) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *AdditionalData) void {
|
||||||
|
for (0..self.member_to_find.items.len) |i| {
|
||||||
|
self.member_to_find.items[i].additional_data.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.member_to_find.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(additional_data: AdditionalData, member_name: []const u8) bool {
|
||||||
|
for (additional_data.member_to_find.items) |elem| {
|
||||||
|
if (std.mem.eql(u8, member_name, elem.name)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is name in: [name]
|
||||||
|
// There is an additional data because it can be [friend [1; name]]
|
||||||
|
pub const AdditionalDataMember = struct {
|
||||||
|
name: []const u8,
|
||||||
|
additional_data: AdditionalData,
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator, name: []const u8) AdditionalDataMember {
|
||||||
|
const additional_data = AdditionalData.init(allocator);
|
||||||
|
return AdditionalDataMember{ .name = name, .additional_data = additional_data };
|
||||||
|
}
|
||||||
|
};
|
31
src/parsing-tools/utils.zig
Normal file
31
src/parsing-tools/utils.zig
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn getEnvVariables(allocator: std.mem.Allocator, variable: []const u8) ?[]const u8 {
|
||||||
|
var env_map = std.process.getEnvMap(allocator) catch return null;
|
||||||
|
defer env_map.deinit();
|
||||||
|
|
||||||
|
var iter = env_map.iterator();
|
||||||
|
|
||||||
|
while (iter.next()) |entry| {
|
||||||
|
if (std.mem.eql(u8, entry.key_ptr.*, variable)) return allocator.dupe(u8, entry.value_ptr.*) catch return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDirTotalSize(dir: std.fs.Dir) !u64 {
|
||||||
|
var total: u64 = 0;
|
||||||
|
var stat: std.fs.File.Stat = undefined;
|
||||||
|
var iter = dir.iterate();
|
||||||
|
while (try iter.next()) |entry| {
|
||||||
|
if (entry.kind == .directory) {
|
||||||
|
const sub_dir = try dir.openDir(entry.name, .{ .iterate = true });
|
||||||
|
total += try getDirTotalSize(sub_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.kind != .file) continue;
|
||||||
|
stat = try dir.statFile(entry.name);
|
||||||
|
total += stat.size;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
@ -6,6 +6,7 @@ const Token = @import("tokenizers/schema.zig").Token;
|
|||||||
|
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
|
// Fuse this with the same function in the ZiQL parser
|
||||||
fn send(comptime format: []const u8, args: anytype) void {
|
fn send(comptime format: []const u8, args: anytype) void {
|
||||||
stdout.print(format, args) catch |err| {
|
stdout.print(format, args) catch |err| {
|
||||||
std.log.err("Can't send: {any}", .{err});
|
std.log.err("Can't send: {any}", .{err});
|
||||||
@ -68,124 +69,122 @@ pub const Parser = struct {
|
|||||||
while ((state != .end) and (state != .invalid)) : ({
|
while ((state != .end) and (state != .invalid)) : ({
|
||||||
token = if (!keep_next) self.toker.next() else token;
|
token = if (!keep_next) self.toker.next() else token;
|
||||||
keep_next = false;
|
keep_next = false;
|
||||||
}) {
|
}) switch (state) {
|
||||||
switch (state) {
|
.expect_struct_name_OR_end => switch (token.tag) {
|
||||||
.expect_struct_name_OR_end => switch (token.tag) {
|
.identifier => {
|
||||||
.identifier => {
|
state = .expect_l_paren;
|
||||||
state = .expect_l_paren;
|
struct_array.append(SchemaStruct.init(self.allocator, token.loc)) catch @panic("Error appending a struct name.");
|
||||||
struct_array.append(SchemaStruct.init(self.allocator, token.loc)) catch @panic("Error appending a struct name.");
|
|
||||||
},
|
|
||||||
.eof => state = .end,
|
|
||||||
else => {
|
|
||||||
self.printError("Error parsing schema: Expected a struct name", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
.eof => state = .end,
|
||||||
.expect_l_paren => switch (token.tag) {
|
else => {
|
||||||
.l_paren => state = .expect_member_name,
|
self.printError("Error parsing schema: Expected a struct name", &token);
|
||||||
else => {
|
state = .invalid;
|
||||||
self.printError("Error parsing schema: Expected (", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.expect_member_name_OR_r_paren => switch (token.tag) {
|
.expect_l_paren => switch (token.tag) {
|
||||||
.identifier => {
|
.l_paren => state = .expect_member_name,
|
||||||
state = .expect_member_name;
|
else => {
|
||||||
keep_next = true;
|
self.printError("Error parsing schema: Expected (", &token);
|
||||||
},
|
state = .invalid;
|
||||||
.r_paren => {
|
|
||||||
state = .expect_struct_name_OR_end;
|
|
||||||
index += 1;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
self.printError("Error parsing schema: Expected member name or )", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.expect_member_name => {
|
.expect_member_name_OR_r_paren => switch (token.tag) {
|
||||||
state = .expect_two_dot;
|
.identifier => {
|
||||||
struct_array.items[index].members.append(token.loc) catch @panic("Error appending a member name.");
|
state = .expect_member_name;
|
||||||
|
keep_next = true;
|
||||||
},
|
},
|
||||||
|
.r_paren => {
|
||||||
.expect_two_dot => switch (token.tag) {
|
state = .expect_struct_name_OR_end;
|
||||||
.two_dot => state = .expect_value_type,
|
index += 1;
|
||||||
else => {
|
|
||||||
self.printError("Error parsing schema: Expected :", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
else => {
|
||||||
.expect_value_type => switch (token.tag) {
|
self.printError("Error parsing schema: Expected member name or )", &token);
|
||||||
.type_int => {
|
state = .invalid;
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.int) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_str => {
|
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.str) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_float => {
|
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.float) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_bool => {
|
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.bool) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_date => @panic("Date not yet implemented"),
|
|
||||||
.identifier => @panic("Link not yet implemented"),
|
|
||||||
.lr_bracket => state = .expext_array_type,
|
|
||||||
else => {
|
|
||||||
self.printError("Error parsing schema: Expected data type", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.expext_array_type => switch (token.tag) {
|
.expect_member_name => {
|
||||||
.type_int => {
|
state = .expect_two_dot;
|
||||||
state = .expect_comma;
|
struct_array.items[index].members.append(token.loc) catch @panic("Error appending a member name.");
|
||||||
struct_array.items[index].types.append(DataType.int_array) catch @panic("Error appending a type.");
|
},
|
||||||
},
|
|
||||||
.type_str => {
|
.expect_two_dot => switch (token.tag) {
|
||||||
state = .expect_comma;
|
.two_dot => state = .expect_value_type,
|
||||||
struct_array.items[index].types.append(DataType.str_array) catch @panic("Error appending a type.");
|
else => {
|
||||||
},
|
self.printError("Error parsing schema: Expected :", &token);
|
||||||
.type_float => {
|
state = .invalid;
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.float_array) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_bool => {
|
|
||||||
state = .expect_comma;
|
|
||||||
struct_array.items[index].types.append(DataType.bool_array) catch @panic("Error appending a type.");
|
|
||||||
},
|
|
||||||
.type_date => {
|
|
||||||
self.printError("Error parsing schema: Data not yet implemented", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
.identifier => {
|
|
||||||
self.printError("Error parsing schema: Relationship not yet implemented", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
self.printError("Error parsing schema: Expected data type", &token);
|
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.expect_comma => switch (token.tag) {
|
.expect_value_type => switch (token.tag) {
|
||||||
.comma => state = .expect_member_name_OR_r_paren,
|
.type_int => {
|
||||||
else => {
|
state = .expect_comma;
|
||||||
self.printError("Error parsing schema: Expected ,", &token);
|
struct_array.items[index].types.append(DataType.int) catch @panic("Error appending a type.");
|
||||||
state = .invalid;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
.type_str => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.str) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_float => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.float) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_bool => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.bool) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_date => @panic("Date not yet implemented"),
|
||||||
|
.identifier => @panic("Link not yet implemented"),
|
||||||
|
.lr_bracket => state = .expext_array_type,
|
||||||
|
else => {
|
||||||
|
self.printError("Error parsing schema: Expected data type", &token);
|
||||||
|
state = .invalid;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
else => unreachable,
|
.expext_array_type => switch (token.tag) {
|
||||||
}
|
.type_int => {
|
||||||
}
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.int_array) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_str => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.str_array) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_float => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.float_array) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_bool => {
|
||||||
|
state = .expect_comma;
|
||||||
|
struct_array.items[index].types.append(DataType.bool_array) catch @panic("Error appending a type.");
|
||||||
|
},
|
||||||
|
.type_date => {
|
||||||
|
self.printError("Error parsing schema: Data not yet implemented", &token);
|
||||||
|
state = .invalid;
|
||||||
|
},
|
||||||
|
.identifier => {
|
||||||
|
self.printError("Error parsing schema: Relationship not yet implemented", &token);
|
||||||
|
state = .invalid;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
self.printError("Error parsing schema: Expected data type", &token);
|
||||||
|
state = .invalid;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
.expect_comma => switch (token.tag) {
|
||||||
|
.comma => state = .expect_member_name_OR_r_paren,
|
||||||
|
else => {
|
||||||
|
self.printError("Error parsing schema: Expected ,", &token);
|
||||||
|
state = .invalid;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
// if invalid, empty the list
|
// if invalid, empty the list
|
||||||
if (state == .invalid) {
|
if (state == .invalid) {
|
||||||
|
@ -123,9 +123,94 @@ pub const UUID = struct {
|
|||||||
// Zero UUID
|
// Zero UUID
|
||||||
pub const zero: UUID = .{ .bytes = .{0} ** 16 };
|
pub const zero: UUID = .{ .bytes = .{0} ** 16 };
|
||||||
|
|
||||||
// Convenience function to return a new v4 UUID.
|
// TODO: Optimize both
|
||||||
pub fn newV4() UUID {
|
pub fn OR(arr1: *std.ArrayList(UUID), arr2: *std.ArrayList(UUID)) !void {
|
||||||
return UUID.init();
|
for (0..arr2.items.len) |i| {
|
||||||
|
if (!containUUID(arr1.*, arr2.items[i])) {
|
||||||
|
try arr1.append(arr2.items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn AND(arr1: *std.ArrayList(UUID), arr2: *std.ArrayList(UUID)) !void {
|
||||||
|
var i: usize = 0;
|
||||||
|
for (0..arr1.items.len) |_| {
|
||||||
|
if (!containUUID(arr2.*, arr1.items[i])) {
|
||||||
|
_ = arr1.orderedRemove(i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "OR & AND" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
var right_arr = std.ArrayList(UUID).init(allocator);
|
||||||
|
defer right_arr.deinit();
|
||||||
|
try right_arr.append(try UUID.parse("00000000-0000-0000-0000-000000000000"));
|
||||||
|
try right_arr.append(try UUID.parse("00000000-0000-0000-0000-000000000001"));
|
||||||
|
try right_arr.append(try UUID.parse("00000000-0000-0000-0000-000000000005"));
|
||||||
|
try right_arr.append(try UUID.parse("00000000-0000-0000-0000-000000000006"));
|
||||||
|
try right_arr.append(try UUID.parse("00000000-0000-0000-0000-000000000007"));
|
||||||
|
|
||||||
|
var left_arr1 = std.ArrayList(UUID).init(allocator);
|
||||||
|
defer left_arr1.deinit();
|
||||||
|
try left_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000000"));
|
||||||
|
try left_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000001"));
|
||||||
|
try left_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000002"));
|
||||||
|
try left_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000003"));
|
||||||
|
try left_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000004"));
|
||||||
|
|
||||||
|
var expected_arr1 = std.ArrayList(UUID).init(allocator);
|
||||||
|
defer expected_arr1.deinit();
|
||||||
|
try expected_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000000"));
|
||||||
|
try expected_arr1.append(try UUID.parse("00000000-0000-0000-0000-000000000001"));
|
||||||
|
|
||||||
|
try AND(&left_arr1, &right_arr);
|
||||||
|
try std.testing.expect(compareUUIDArray(left_arr1, expected_arr1));
|
||||||
|
|
||||||
|
var left_arr2 = std.ArrayList(UUID).init(allocator);
|
||||||
|
defer left_arr2.deinit();
|
||||||
|
try left_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000000"));
|
||||||
|
try left_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000001"));
|
||||||
|
try left_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000002"));
|
||||||
|
try left_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000003"));
|
||||||
|
try left_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000004"));
|
||||||
|
|
||||||
|
var expected_arr2 = std.ArrayList(UUID).init(allocator);
|
||||||
|
defer expected_arr2.deinit();
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000000"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000001"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000002"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000003"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000004"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000005"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000006"));
|
||||||
|
try expected_arr2.append(try UUID.parse("00000000-0000-0000-0000-000000000007"));
|
||||||
|
|
||||||
|
try OR(&left_arr2, &right_arr);
|
||||||
|
|
||||||
|
try std.testing.expect(compareUUIDArray(left_arr2, expected_arr2));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn containUUID(arr: std.ArrayList(UUID), value: UUID) bool {
|
||||||
|
return for (arr.items) |elem| {
|
||||||
|
if (value.compare(elem)) break true;
|
||||||
|
} else false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compareUUIDArray(arr1: std.ArrayList(UUID), arr2: std.ArrayList(UUID)) bool {
|
||||||
|
if (arr1.items.len != arr2.items.len) {
|
||||||
|
std.debug.print("Not same array len when comparing UUID. arr1: {d} arr2: {d}\n", .{ arr1.items.len, arr2.items.len });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (0..arr1.items.len) |i| {
|
||||||
|
if (!containUUID(arr2, arr1.items[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parse and format" {
|
test "parse and format" {
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub fn getEnvVariables(allocator: std.mem.Allocator, variable: []const u8) ?[]const u8 {
|
|
||||||
var env_map = std.process.getEnvMap(allocator) catch return null;
|
|
||||||
defer env_map.deinit();
|
|
||||||
|
|
||||||
var iter = env_map.iterator();
|
|
||||||
|
|
||||||
while (iter.next()) |entry| {
|
|
||||||
if (std.mem.eql(u8, entry.key_ptr.*, variable)) return allocator.dupe(u8, entry.value_ptr.*) catch return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
1256
src/ziqlParser.zig
1256
src/ziqlParser.zig
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user