const std = @import("std"); const json = @import("json.zig"); const Db = @import("Db.zig"); const sqlite = @import("sqlite"); const Self = @This(); pub const Tag = struct{ // :0 for C compatility name: [:0]const u8, value: ?[:0]const u8, }; id: ?i64, // If null, the object hasn't been persisted tags: ?[]Tag, pub fn persist(self: *Self, db: *sqlite.Db) !void { /////////////////////////////////// // ** Insert item ** ///////////////////////////////// // Insert only if there's no ID. if (self.id == null) { const query = "INSERT INTO item VALUES(NULL);"; try db.exec(query, .{}, .{}); // Update the ID field self.id = try Db.getLastId(db); } /////////////////////////////////// // ** Insert tags ** ///////////////////////////////// // If the tags haven't been initialized, don't touch anything if (self.tags) |tags| { // TODO: Remove unused tag relations // If the count drops to zero, delete. // Create new tags if they don't exist for (tags) |*tags_i| { try db.exec( "INSERT INTO tag (name) VALUES (?);", .{}, .{ .name = tags_i.name } ); try db.exec( "INSERT INTO item_tag (item, tag, value) VALUES (?, ?, ?);", .{}, .{ .item = self.id, .tag = tags_i.name, .value = tags_i.value } ); } } } /// Convert into a JSON object. A call to deinit() is necessary from the caller's side pub fn toJson(self: Self) json.Obj { var jobj = json.Obj.newObject(); jobj.objectAdd("id", &json.Obj.newInt64(self.id.?)); var jtags = json.Obj.newObject(); jobj.objectAdd("tags", &jtags); // If there are tags there's no point on continuing if (self.tags) |tags| { for (tags) |tag_i| { const jtag = if (tag_i.value) |value| &json.Obj.newString(value) else null; jtags.objectAdd(tag_i.name, jtag); } } return jobj; }