Initial comit / Pre db simplification
This commit is contained in:
		
						commit
						54d504c3de
					
				|  | @ -0,0 +1,3 @@ | ||||||
|  | * text=auto | ||||||
|  | *.zig text eol=lf | ||||||
|  | zigmod.* text eol=lf | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | zig-* | ||||||
|  | .zigmod | ||||||
|  | deps.zig | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | 
 | ||||||
|  | pub fn build(b: *std.build.Builder) void { | ||||||
|  |     // Standard target options allows the person running `zig build` to choose | ||||||
|  |     // what target to build for. Here we do not override the defaults, which | ||||||
|  |     // means any target is allowed, and the default is native. Other options | ||||||
|  |     // for restricting supported target set are available. | ||||||
|  |     const target = b.standardTargetOptions(.{}); | ||||||
|  | 
 | ||||||
|  |     // Standard release options allow the person running `zig build` to select | ||||||
|  |     // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. | ||||||
|  |     const mode = b.standardReleaseOptions(); | ||||||
|  | 
 | ||||||
|  |     // Import autogenerated zigmod dependencies | ||||||
|  |     const deps = @import("deps.zig"); | ||||||
|  | 
 | ||||||
|  |     const exe = b.addExecutable("uos", "src/main.zig"); | ||||||
|  |     exe.use_stage1 = true; // for sqlite | ||||||
|  |     deps.addAllTo(exe); // zigmod dependencies | ||||||
|  |     exe.setTarget(target); | ||||||
|  |     exe.setBuildMode(mode); | ||||||
|  |     exe.install(); | ||||||
|  | 
 | ||||||
|  |     const run_cmd = exe.run(); | ||||||
|  |     run_cmd.step.dependOn(b.getInstallStep()); | ||||||
|  |     if (b.args) |args| { | ||||||
|  |         run_cmd.addArgs(args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const run_step = b.step("run", "Run the app"); | ||||||
|  |     run_step.dependOn(&run_cmd.step); | ||||||
|  | 
 | ||||||
|  |     const exe_tests = b.addTest("src/main.zig"); | ||||||
|  |     exe_tests.setTarget(target); | ||||||
|  |     exe_tests.setBuildMode(mode); | ||||||
|  | 
 | ||||||
|  |     const test_step = b.step("test", "Run unit tests"); | ||||||
|  |     test_step.dependOn(&exe_tests.step); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,133 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | const sqlite = @import("sqlite"); | ||||||
|  | 
 | ||||||
|  | const ObjectError = error{ | ||||||
|  |     IncompatibleObjectType, // No ?u32 "id" field | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pub fn persist(db: *sqlite.Db, obj: anytype) !void { | ||||||
|  |     const T = @TypeOf(obj); | ||||||
|  | 
 | ||||||
|  |     // Check that object is a valid type for the DB system. | ||||||
|  |     // It should have an "id" field and be of type "?u32" | ||||||
|  |     if (!@hasField(T, "id") or @TypeOf(@field(obj, "id")) != ?u32) { | ||||||
|  |         return ObjectError.IncompatibleObjectType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Tried to persist something that is already persisted | ||||||
|  |     if (@field(obj, "id") != null) { | ||||||
|  |         std.debug.print("Can't persist an object with an id.\n", .{}); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const fields = std.meta.fields(T); | ||||||
|  | 
 | ||||||
|  |     const query_init = "INSTERT INTO " ++ @typeName(T) ++ " ("; | ||||||
|  | 
 | ||||||
|  |     const sep = ", "; | ||||||
|  |     var buf: [1024]u8 = .{0} ** 1024; | ||||||
|  |     var offset: usize = 0; | ||||||
|  | 
 | ||||||
|  |     std.mem.copy(u8, buf[offset..], query_init); | ||||||
|  |     offset += query_init.len; | ||||||
|  | 
 | ||||||
|  |     // Keep track of how many fields to instert | ||||||
|  |     comptime var count: u8 = 0; | ||||||
|  |     inline for (fields) |field_i| { | ||||||
|  |         // Do not input "id" field. | ||||||
|  |         comptime if (std.mem.eql(u8, field_i.name, "id")) { | ||||||
|  |             continue; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Do not input array fields (they got their own table) | ||||||
|  |         comptime switch (@typeInfo(field_i.field_type)) { | ||||||
|  |             .Array => continue, | ||||||
|  |             .Pointer => |info| switch (info.size) { | ||||||
|  |                 .One => {}, | ||||||
|  |                 .Many, .C, .Slice => continue, | ||||||
|  |             }, | ||||||
|  |             else => {}, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         count += 1; | ||||||
|  | 
 | ||||||
|  |         std.mem.copy(u8, buf[offset..], field_i.name); | ||||||
|  |         offset += field_i.name.len; | ||||||
|  |         std.mem.copy(u8, buf[offset..], sep); | ||||||
|  |         offset += sep.len; | ||||||
|  |     } | ||||||
|  |     offset -= sep.len; | ||||||
|  | 
 | ||||||
|  |     const query_end = ") VALUES (" ++ ("?, " ** (count - 1)) ++ "?);"; | ||||||
|  | 
 | ||||||
|  |     std.mem.copy(u8, buf[offset..], query_end); | ||||||
|  |     offset += query_end.len; | ||||||
|  | 
 | ||||||
|  |     std.debug.print("{s}\n", .{buf[0..offset]}); | ||||||
|  | 
 | ||||||
|  |     _ = db; | ||||||
|  | 
 | ||||||
|  |     //const query = "INSERT INTO item (name) VALUES (?);"; | ||||||
|  | 
 | ||||||
|  |     //try db.exec(query, .{}, .{ .name = name }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn queryTest(db: *sqlite.Db) ![]const u8 { | ||||||
|  |     const row = try db.one( | ||||||
|  |         struct { | ||||||
|  |             version: [128:0]u8, | ||||||
|  |         }, | ||||||
|  |         "SELECT sqlite_version();", | ||||||
|  |         .{}, | ||||||
|  |         .{}, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (row) |row_i| { | ||||||
|  |         return std.mem.sliceTo(&row_i.version, 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return "N/A"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn init() !sqlite.Db { | ||||||
|  |     var db = try sqlite.Db.init(.{ | ||||||
|  |         .mode = .{ .File = "/tmp/data.db" }, | ||||||
|  |         .open_flags = .{ | ||||||
|  |             .write = true, | ||||||
|  |             .create = true, | ||||||
|  |         }, | ||||||
|  |         .threading_mode = .MultiThread, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     try migrate(&db); | ||||||
|  | 
 | ||||||
|  |     return db; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TODO: Make a proper migration system. | ||||||
|  | fn migrate(db: *sqlite.Db) !void { | ||||||
|  |     try db.exec( | ||||||
|  |         \\ CREATE TABLE IF NOT EXISTS item ( | ||||||
|  |         \\   id    INTEGER  PRIMARY KEY, | ||||||
|  |         \\   name  TEXT     NOT NULL | ||||||
|  |         \\ ); | ||||||
|  |         \\ | ||||||
|  |         \\ CREATE TABLE IF NOT EXISTS tag ( | ||||||
|  |         \\   id    INTEGER  PRIMARY KEY, | ||||||
|  |         \\   name  TEXT     NOT NULL | ||||||
|  |         \\ ); | ||||||
|  |         \\ | ||||||
|  |         \\ CREATE TABLE IF NOT EXISTS item_tag ( | ||||||
|  |         \\   item  INTEGER, | ||||||
|  |         \\   tag   INTEGER, | ||||||
|  |         \\ | ||||||
|  |         \\   PRIMARY KEY (item, tag), | ||||||
|  |         \\ | ||||||
|  |         \\   FOREIGN KEY (item) REFERENCES item(id) ON DELETE CASCADE, | ||||||
|  |         \\   FOREIGN KEY (tag)  REFERENCES  tag(id) ON DELETE CASCADE | ||||||
|  |         \\ ); | ||||||
|  |     , | ||||||
|  |         .{}, | ||||||
|  |         .{}, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | const Db = @import("Db.zig"); | ||||||
|  | const Tag = @import("Tag.zig"); | ||||||
|  | 
 | ||||||
|  | id: ?u32, // If null, the object hasn't been persisted | ||||||
|  | name: []const u8, | ||||||
|  | tags: ?[]Tag, | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | const Db = @import("Db.zig"); | ||||||
|  | const Item = @import("Item.zig"); | ||||||
|  | 
 | ||||||
|  | id: ?u32, | ||||||
|  | name: []const u8, | ||||||
|  | items: ?[]Item, | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | const sqlite = @import("sqlite"); | ||||||
|  | 
 | ||||||
|  | const Db = @import("Db.zig"); | ||||||
|  | const Item = @import("Item.zig"); | ||||||
|  | 
 | ||||||
|  | pub fn main() !void { | ||||||
|  |     var db = try Db.init(); | ||||||
|  | 
 | ||||||
|  |     const item = Item{ .name = "hola", .id = null, .tags = null }; | ||||||
|  |     try Db.persist(&db, item); | ||||||
|  | 
 | ||||||
|  |     const version = try Db.queryTest(&db); | ||||||
|  |     std.debug.print("Version: {s}\n", .{version}); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | 2 | ||||||
|  | git https://github.com/getty-zig/json commit-0c2e645fc1304ab57f9819445b91ea064da0b27b | ||||||
|  | git https://github.com/getty-zig/getty commit-102f17a | ||||||
|  | git https://github.com/ibokuri/concepts commit-05c7368 | ||||||
|  | git https://github.com/vrischmann/zig-sqlite commit-5b8b472276829f75dced4dc405b66b7b986498b3 | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | id: xstmgop7lwvcrkd18q3u95noqfk3oromr3vixj1ud67rhbwl | ||||||
|  | name: uos | ||||||
|  | license: AGPLv3 | ||||||
|  | description: Tagging system with a JSON API | ||||||
|  | root_dependencies: | ||||||
|  |   - src: git https://github.com/vrischmann/zig-sqlite branch-master | ||||||
|  |   - src: git https://github.com/getty-zig/json | ||||||
		Loading…
	
		Reference in New Issue