diff --git a/src/cli.zig b/src/cli.zig index 4778b6a..53a71ce 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -34,6 +34,7 @@ const State = enum { end, }; +// TODO: Check id the argument --query or --q is in the command and just run the query instead pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); @@ -42,17 +43,29 @@ pub fn main() !void { .leak => std.log.debug("We fucked it up bro...\n", .{}), }; + var db_path = std.ArrayList(u8).init(allocator); + defer db_path.deinit(); + const path_env_variable = utils.getEnvVariables(allocator, "ZIPPONDB_PATH"); - defer if (path_env_variable) |path| allocator.free(path); var file_engine: FileEngine = undefined; defer file_engine.deinit(); if (path_env_variable) |path| { - std.debug.print("Environment variable found: {s}\n", .{path}); - file_engine = FileEngine.init(allocator, path_env_variable.?); + std.debug.print("ZIPONDB_PATH environment variable found: {s}\n", .{path}); + + var already_init = false; + _ = std.fs.cwd().openDir(path, .{}) catch { + std.debug.print("Error opening ZipponDB path using environment variable, please select the database using 'db use' or create a new one with 'db new'\n", .{}); + file_engine = FileEngine.init(allocator, try allocator.dupe(u8, "")); + already_init = true; + }; + if (!already_init) { + try checkAndCreateDirectories(path, allocator); + file_engine = FileEngine.init(allocator, path_env_variable.?); + } } else { - file_engine = FileEngine.init(allocator, ""); - std.debug.print("No ZIPONDB_PATH envirionment variable found, please use the command:\n db use path/to/db \nor\n db new /path/to/dir\n", .{}); + file_engine = FileEngine.init(allocator, try allocator.dupe(u8, "")); + std.debug.print("No ZIPONDB_PATH environment variable found, please use the command:\n db use path/to/db \nor\n db new /path/to/dir\n", .{}); } const line_buf = try allocator.alloc(u8, 1024 * 50); @@ -153,7 +166,7 @@ pub fn main() !void { .expect_path_to_db => switch (token.tag) { .identifier => { file_engine.deinit(); - file_engine = FileEngine.init(allocator, cliToker.getTokenSlice(token)); + file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token))); send("Successfully started using the database!", .{}); state = .end; }, @@ -171,7 +184,7 @@ pub fn main() !void { continue; }; file_engine.deinit(); - file_engine = FileEngine.init(allocator, cliToker.getTokenSlice(token)); + file_engine = FileEngine.init(allocator, try allocator.dupe(u8, cliToker.getTokenSlice(token))); send("Successfully initialized the database!", .{}); state = .end; }, @@ -279,7 +292,7 @@ pub fn runQuery(null_term_query_str: [:0]const u8, file_engine: *FileEngine) voi // TODO: Put that in the FileEngine fn checkAndCreateDirectories(sub_path: []const u8, allocator: Allocator) !void { - var path_buff = try std.fmt.allocPrint(allocator, "{s}/ZipponDB", .{sub_path}); + var path_buff = try std.fmt.allocPrint(allocator, "{s}", .{sub_path}); defer allocator.free(path_buff); const cwd = std.fs.cwd(); @@ -290,7 +303,7 @@ fn checkAndCreateDirectories(sub_path: []const u8, allocator: Allocator) !void { }; allocator.free(path_buff); - path_buff = try std.fmt.allocPrint(allocator, "{s}/ZipponDB/DATA", .{sub_path}); + path_buff = try std.fmt.allocPrint(allocator, "{s}/DATA", .{sub_path}); cwd.makeDir(path_buff) catch |err| switch (err) { error.PathAlreadyExists => {}, @@ -298,7 +311,7 @@ fn checkAndCreateDirectories(sub_path: []const u8, allocator: Allocator) !void { }; allocator.free(path_buff); - path_buff = try std.fmt.allocPrint(allocator, "{s}/ZipponDB/BACKUP", .{sub_path}); + path_buff = try std.fmt.allocPrint(allocator, "{s}/BACKUP", .{sub_path}); cwd.makeDir(path_buff) catch |err| switch (err) { error.PathAlreadyExists => {}, @@ -306,7 +319,7 @@ fn checkAndCreateDirectories(sub_path: []const u8, allocator: Allocator) !void { }; allocator.free(path_buff); - path_buff = try std.fmt.allocPrint(allocator, "{s}/ZipponDB/LOG", .{sub_path}); + path_buff = try std.fmt.allocPrint(allocator, "{s}/LOG", .{sub_path}); cwd.makeDir(path_buff) catch |err| switch (err) { error.PathAlreadyExists => {}, diff --git a/src/fileEngine.zig b/src/fileEngine.zig index 0b16256..54ede00 100644 --- a/src/fileEngine.zig +++ b/src/fileEngine.zig @@ -50,6 +50,7 @@ pub const FileEngine = struct { for (self.struct_array.items) |*elem| elem.deinit(); self.struct_array.deinit(); self.allocator.free(self.null_terminated_schema_buff); + self.allocator.free(self.path_to_ZipponDB_dir); } const ComparisonValue = union { @@ -86,6 +87,7 @@ pub const FileEngine = struct { /// Take a list of UUID and, a buffer array and the additional data to write into the buffer the JSON to send /// TODO: Optimize + /// FIXME: Array of string are not working pub fn parseAndWriteToSend(self: *FileEngine, struct_name: []const u8, uuids: []UUID, buffer: *std.ArrayList(u8), additional_data: AdditionalData) !void { const max_file_index = try self.maxFileIndex(struct_name); var current_index: usize = 0; @@ -161,6 +163,9 @@ pub const FileEngine = struct { if (founded) { 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 @@ -174,6 +179,8 @@ pub const FileEngine = struct { try out_writer.print("\"{s}\"", .{str_slice[1 .. str_slice.len - 1]}); }, .str_array => { + try out_writer.writeAll(data_toker.getTokenSlice(token)); + token = data_toker.next(); while (token.tag != .r_bracket) : (token = data_toker.next()) { try out_writer.writeAll("\""); try out_writer.writeAll(data_toker.getTokenSlice(token)[1..(token.loc.end - token.loc.start)]); @@ -777,26 +784,26 @@ pub const FileEngine = struct { const writer = buffer.writer(); try writer.print("Database path: {s}\n", .{path}); const main_size = try self.getDirTotalSize(main_dir); - try writer.print("Total size: {d:.2}Mb\n", .{@as(f64, @floatFromInt(main_size)) / 1e-6}); + try writer.print("Total size: {d:.2}Mb\n", .{@as(f64, @floatFromInt(main_size)) / 1e6}); const log_dir = try main_dir.openDir("LOG", .{ .iterate = true }); const log_size = try self.getDirTotalSize(log_dir); - try writer.print("LOG: {d:.2}Mb\n", .{@as(f64, @floatFromInt(log_size)) / 1e-6}); + try writer.print("LOG: {d:.2}Mb\n", .{@as(f64, @floatFromInt(log_size)) / 1e6}); const backup_dir = try main_dir.openDir("BACKUP", .{ .iterate = true }); const backup_size = try self.getDirTotalSize(backup_dir); - try writer.print("BACKUP: {d:.2}Mb\n", .{@as(f64, @floatFromInt(backup_size)) / 1e-6}); + try writer.print("BACKUP: {d:.2}Mb\n", .{@as(f64, @floatFromInt(backup_size)) / 1e6}); const data_dir = try main_dir.openDir("DATA", .{ .iterate = true }); const data_size = try self.getDirTotalSize(data_dir); - try writer.print("DATA: {d:.2}Mb\n", .{@as(f64, @floatFromInt(data_size)) / 1e-6}); + try writer.print("DATA: {d:.2}Mb\n", .{@as(f64, @floatFromInt(data_size)) / 1e6}); var iter = data_dir.iterate(); while (try iter.next()) |entry| { if (entry.kind != .directory) continue; const sub_dir = try data_dir.openDir(entry.name, .{ .iterate = true }); const size = try self.getDirTotalSize(sub_dir); - try writer.print(" {s}: {d:.}Mb\n", .{ entry.name, @as(f64, @floatFromInt(size)) / 1e-6 }); + try writer.print(" {s}: {d:.}Mb\n", .{ entry.name, @as(f64, @floatFromInt(size)) / 1e6 }); } } @@ -828,7 +835,7 @@ pub const FileEngine = struct { }; /// Request a path to a schema file and then create the struct folder - /// TODO: Delete current folder before new one are created + /// 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 { var schema_buf = self.allocator.alloc(u8, 1024 * 50) catch @panic("Cant allocate the schema buffer"); defer self.allocator.free(schema_buf); @@ -990,7 +997,8 @@ pub const FileEngine = struct { test "Get list of UUID using condition" { const allocator = std.testing.allocator; - var file_engine = FileEngine.init(allocator, "ZipponDB"); + const path = try allocator.dupe(u8, "ZipponDB"); + var file_engine = FileEngine.init(allocator, path); defer file_engine.deinit(); var uuid_array = std.ArrayList(UUID).init(allocator); @@ -1060,13 +1068,15 @@ pub fn parseArrayUUID(allocator: std.mem.Allocator, array_str: []const u8) std.A 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: I think it will not work if there is a ' inside the string pub fn parseArrayStr(allocator: std.mem.Allocator, array_str: []const u8) std.ArrayList([]const u8) { var array = std.ArrayList([]const u8).init(allocator); - var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " "); + var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], "'"); while (it.next()) |x| { + if (std.mem.eql(u8, " ", x)) continue; const x_copy = allocator.dupe(u8, x) catch @panic("=("); + // FIXME: I think I need to add the '' on each side again array.append(x_copy) catch {}; } diff --git a/src/schemaParser.zig b/src/schemaParser.zig index 4fe5682..d5214b7 100644 --- a/src/schemaParser.zig +++ b/src/schemaParser.zig @@ -59,7 +59,6 @@ pub const Parser = struct { expect_comma, }; - // TODO: Pass that to the FileEngine and do the metadata.zig file instead pub fn parse(self: *Parser, struct_array: *std.ArrayList(SchemaStruct)) !void { var state: State = .expect_struct_name_OR_end; var index: usize = 0; diff --git a/src/ziqlParser.zig b/src/ziqlParser.zig index abcac59..ccc156c 100644 --- a/src/ziqlParser.zig +++ b/src/ziqlParser.zig @@ -282,7 +282,7 @@ pub const Parser = struct { keep_next = true; self.state = .parse_new_data_and_add_data; }, - else => return self.printError("Error: Expecting new data starting with (", &token, ZiQlParserError.SynthaxError), + else => return self.printError("Error: Expected new data starting with (", &token, ZiQlParserError.SynthaxError), }, .parse_new_data_and_add_data => { @@ -392,7 +392,7 @@ pub const Parser = struct { keep_next = true; try self.file_engine.getUUIDListUsingCondition(right_condition, &right_array); }, // Create a new condition and compare it - else => return self.printError("Error: Expecting ( or member name.", &token, ZiQlParserError.SynthaxError), + else => return self.printError("Error: Expected ( or member name.", &token, ZiQlParserError.SynthaxError), } switch (curent_operation) { @@ -953,7 +953,8 @@ test "Synthax error" { fn testParsing(source: [:0]const u8) !void { const allocator = std.testing.allocator; - var file_engine = FileEngine.init(allocator, "ZipponDB"); + const path = try allocator.dupe(u8, "ZipponDB"); + var file_engine = FileEngine.init(allocator, path); defer file_engine.deinit(); var tokenizer = Tokenizer.init(source); @@ -966,7 +967,8 @@ fn testParsing(source: [:0]const u8) !void { fn expectParsingError(source: [:0]const u8, err: Parser.ZiQlParserError) !void { const allocator = std.testing.allocator; - var file_engine = FileEngine.init(allocator, "ZipponDB"); + const path = try allocator.dupe(u8, "ZipponDB"); + var file_engine = FileEngine.init(allocator, path); defer file_engine.deinit(); var tokenizer = Tokenizer.init(source);