Created
June 25, 2026 05:39
-
-
Save Lightnet/d893b2263478398e6b514d42f119c402 to your computer and use it in GitHub Desktop.
sample database struct AI base model test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // zig 0.16.0 | |
| const std = @import("std"); | |
| pub const User = struct { | |
| id: u32, | |
| name: []const u8, | |
| date: []const u8, | |
| }; | |
| pub fn Table(comptime T: type) type { | |
| const type_info = @typeInfo(T); | |
| if (type_info != .@"struct") { | |
| @compileError("Table type must be a struct"); | |
| } | |
| if (!@hasField(T, "id") or @TypeOf(@field(@as(T, undefined), "id")) != u32) { | |
| @compileError("Table struct must contain an 'id: u32' field for indexing"); | |
| } | |
| return struct { | |
| rows: std.ArrayList(T), | |
| index_map: std.array_hash_map.Auto(u32, usize), | |
| allocator: std.mem.Allocator, | |
| pub fn init(allocator: std.mem.Allocator) @This() { | |
| return .{ | |
| .rows = .empty, | |
| .index_map = .empty, | |
| .allocator = allocator, | |
| }; | |
| } | |
| pub fn deinit(self: *@This()) void { | |
| // Safely frees every string because the table now guarantees 100% ownership | |
| for (self.rows.items) |row| { | |
| inline for (@typeInfo(T).@"struct".fields) |field| { | |
| if (field.type == []const u8 or field.type == []u8) { | |
| self.allocator.free(@field(row, field.name)); | |
| } | |
| } | |
| } | |
| self.rows.deinit(self.allocator); | |
| self.index_map.deinit(self.allocator); | |
| } | |
| pub fn insert(self: *@This(), record: T) !void { | |
| const new_idx = self.rows.items.len; | |
| if (self.index_map.contains(record.id)) return error.DuplicatePrimaryKey; | |
| // FIXED: Automatically duplicate string fields so the database owns its memory | |
| var owned_record = record; | |
| inline for (@typeInfo(T).@"struct".fields) |field| { | |
| if (field.type == []const u8 or field.type == []u8) { | |
| const original_str = @field(record, field.name); | |
| @field(owned_record, field.name) = try self.allocator.dupe(u8, original_str); | |
| } | |
| } | |
| try self.rows.append(self.allocator, owned_record); | |
| try self.index_map.put(self.allocator, record.id, new_idx); | |
| } | |
| pub fn findById(self: *@This(), id: u32) ?*T { | |
| const idx = self.index_map.get(id) orelse return null; | |
| return &self.rows.items[idx]; | |
| } | |
| fn readExact(reader: anytype, dest: []u8) !void { | |
| for (dest) |*b| { | |
| b.* = try reader.takeByte(); | |
| } | |
| } | |
| pub fn saveToFile(self: *@This(), io: std.Io, path: []const u8) !void { | |
| var file = try std.Io.Dir.createFileAbsolute(io, path, .{}); | |
| defer file.close(io); | |
| var buf: [4096]u8 = undefined; | |
| var file_writer = file.writer(io, &buf); | |
| const writer = &file_writer.interface; | |
| var len_buf: [8]u8 = undefined; | |
| std.mem.writeInt(u64, &len_buf, self.rows.items.len, .little); | |
| try writer.writeAll(&len_buf); | |
| for (self.rows.items) |row| { | |
| var id_buf: [4]u8 = undefined; | |
| std.mem.writeInt(u32, &id_buf, row.id, .little); | |
| try writer.writeAll(&id_buf); | |
| var name_len_buf: [4]u8 = undefined; | |
| std.mem.writeInt(u32, &name_len_buf, @as(u32, @intCast(row.name.len)), .little); | |
| try writer.writeAll(&name_len_buf); | |
| try writer.writeAll(row.name); | |
| var date_len_buf: [4]u8 = undefined; | |
| std.mem.writeInt(u32, &date_len_buf, @as(u32, @intCast(row.date.len)), .little); | |
| try writer.writeAll(&date_len_buf); | |
| try writer.writeAll(row.date); | |
| } | |
| try file_writer.flush(); | |
| } | |
| pub fn loadFromFile(self: *@This(), io: std.Io, path: []const u8) !void { | |
| var file = try std.Io.Dir.openFileAbsolute(io, path, .{ .mode = .read_only }); | |
| defer file.close(io); | |
| var buf: [4096]u8 = undefined; | |
| var file_reader = file.reader(io, &buf); | |
| const reader = &file_reader.interface; | |
| var len_buf: [8]u8 = undefined; | |
| try readExact(reader, &len_buf); | |
| const total_rows = std.mem.readInt(u64, &len_buf, .little); | |
| var i: usize = 0; | |
| while (i < total_rows) : (i += 1) { | |
| var id_buf: [4]u8 = undefined; | |
| try readExact(reader, &id_buf); | |
| const id = std.mem.readInt(u32, &id_buf, .little); | |
| // Read into a temporary buffer, let insert copy it, then free it | |
| var name_len_buf: [4]u8 = undefined; | |
| try readExact(reader, &name_len_buf); | |
| const name_len = std.mem.readInt(u32, &name_len_buf, .little); | |
| const temp_name = try self.allocator.alloc(u8, name_len); | |
| defer self.allocator.free(temp_name); | |
| try readExact(reader, temp_name); | |
| var date_len_buf: [4]u8 = undefined; | |
| try readExact(reader, &date_len_buf); | |
| const date_len = std.mem.readInt(u32, &date_len_buf, .little); | |
| const temp_date = try self.allocator.alloc(u8, date_len); | |
| defer self.allocator.free(temp_date); | |
| try readExact(reader, temp_date); | |
| // insert will cleanly duplicate them into persistent database memory | |
| try self.insert(.{ | |
| .id = id, | |
| .name = temp_name, | |
| .date = temp_date, | |
| }); | |
| } | |
| } | |
| }; | |
| } | |
| pub fn main() !void { | |
| var gpa = std.heap.DebugAllocator(.{}){}; | |
| defer _ = gpa.deinit(); | |
| const allocator = gpa.allocator(); | |
| var threaded: std.Io.Threaded = .init_single_threaded; | |
| const io = threaded.io(); | |
| var stdout_file = std.Io.File.stdout(); | |
| var file_writer = stdout_file.writer(io, &.{}); | |
| const stdout = &file_writer.interface; | |
| // 1. DYNAMIC PATHING: Fetch the running application workspace directory [1.1] | |
| const cwd_path = try std.process.currentPathAlloc(io, allocator); | |
| defer allocator.free(cwd_path); | |
| // 2. Build absolute destination path | |
| const filename = "users.dat"; | |
| const absolute_db_path = try std.fs.path.join(allocator, &.{ cwd_path, filename }); | |
| defer allocator.free(absolute_db_path); | |
| // 3. EXISTENCE CHECK: Verify if file exists [1.1] | |
| var file_exists = true; | |
| std.Io.Dir.accessAbsolute(io, absolute_db_path, .{}) catch |err| { | |
| if (err == error.FileNotFound) file_exists = false else return err; | |
| }; | |
| var db = Table(User).init(allocator); | |
| defer db.deinit(); | |
| if (file_exists) { | |
| try db.loadFromFile(io, absolute_db_path); | |
| try stdout.print("Database loaded complete!\n\n", .{}); | |
| // if (db.findById(101)) |user| { | |
| // try stdout.print("-> Restored Primary Key ID 20: Name={s}, Date={s}\n", .{ user.name, user.date }); | |
| // } | |
| for (db.rows.items) |*row| { | |
| try stdout.print("ID: {}, Name: {s}\n", .{ row.id, row.name }); | |
| } | |
| } else { | |
| try db.insert(.{ .id = 101, .name = "Alice", .date = "2026-01-15" }); | |
| try db.insert(.{ .id = 20, .name = "Bob", .date = "2026-06-24" }); | |
| try db.saveToFile(io, absolute_db_path); | |
| try stdout.print("Database save complete!\n\n", .{}); | |
| } | |
| } | |
| // pub fn main() !void { | |
| // var gpa = std.heap.DebugAllocator(.{}){}; | |
| // defer _ = gpa.deinit(); | |
| // const allocator = gpa.allocator(); | |
| // var threaded: std.Io.Threaded = .init_single_threaded; | |
| // const io = threaded.io(); | |
| // var stdout_file = std.Io.File.stdout(); | |
| // var file_writer = stdout_file.writer(io, &.{}); | |
| // const stdout = &file_writer.interface; | |
| // const db_path = "x:\\xxx\\users.dat"; | |
| // // const db_path = "users.dat"; | |
| // // { | |
| // // try stdout.print("=== Phase 1: populating and saving database ===\n", .{}); | |
| // // var write_db = Table(User).init(allocator); | |
| // // defer write_db.deinit(); | |
| // // try write_db.insert(.{ .id = 10, .name = "Alice", .date = "2026-01-15" }); | |
| // // try write_db.insert(.{ .id = 20, .name = "Bob", .date = "2026-06-24" }); | |
| // // try stdout.print("Saving database file to disk...\n", .{}); | |
| // // try write_db.saveToFile(io, db_path); | |
| // // try stdout.print("Database file serialized successfully!\n\n", .{}); | |
| // // } | |
| // { | |
| // try stdout.print("=== Phase 2: instantiating empty engine & reading from file ===\n", .{}); | |
| // var read_db = Table(User).init(allocator); | |
| // defer read_db.deinit(); | |
| // try stdout.print("Loading data records into memory...\n", .{}); | |
| // try read_db.loadFromFile(io, db_path); | |
| // try stdout.print("Database restoration complete!\n\n", .{}); | |
| // try stdout.print("Verifying fast index lookups from loaded records:\n", .{}); | |
| // if (read_db.findById(20)) |user| { | |
| // try stdout.print("-> Restored Primary Key ID 20: Name={s}, Date={s}\n", .{ user.name, user.date }); | |
| // } | |
| // if (read_db.findById(10)) |user| { | |
| // try stdout.print("-> Restored Primary Key ID 10: Name={s}, Date={s}\n", .{ user.name, user.date }); | |
| // } | |
| // } | |
| // } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment