Item creation & insertion from JSON
This commit is contained in:
parent
c5a124b100
commit
b8908c7b22
80
src/Item.zig
80
src/Item.zig
|
@ -6,7 +6,7 @@ const sqlite = @import("sqlite");
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub const Tag = struct{
|
pub const Tag = struct {
|
||||||
// :0 for C compatility
|
// :0 for C compatility
|
||||||
name: [:0]const u8,
|
name: [:0]const u8,
|
||||||
value: ?[:0]const u8,
|
value: ?[:0]const u8,
|
||||||
|
@ -14,12 +14,27 @@ pub const Tag = struct{
|
||||||
|
|
||||||
id: ?i64, // If null, the object hasn't been persisted
|
id: ?i64, // If null, the object hasn't been persisted
|
||||||
tags: ?[]Tag,
|
tags: ?[]Tag,
|
||||||
|
allocator: ?std.mem.Allocator = null,
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
// If there's no allocator there has been no allocations
|
||||||
|
const allocator = self.allocator orelse return;
|
||||||
|
const tags = self.tags orelse return;
|
||||||
|
|
||||||
|
// Free each tag
|
||||||
|
for (tags) |*tag| {
|
||||||
|
allocator.free(tag.name);
|
||||||
|
|
||||||
|
if (tag.value) |value| {
|
||||||
|
allocator.free(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the tags buffer
|
||||||
|
allocator.free(tags);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn persist(self: *Self, db: *sqlite.Db) !void {
|
pub fn persist(self: *Self, db: *sqlite.Db) !void {
|
||||||
///////////////////////////////////
|
|
||||||
// ** Insert item **
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// Insert only if there's no ID.
|
// Insert only if there's no ID.
|
||||||
if (self.id == null) {
|
if (self.id == null) {
|
||||||
const query = "INSERT INTO item VALUES(NULL);";
|
const query = "INSERT INTO item VALUES(NULL);";
|
||||||
|
@ -29,44 +44,31 @@ pub fn persist(self: *Self, db: *sqlite.Db) !void {
|
||||||
self.id = try Db.getLastId(db);
|
self.id = try Db.getLastId(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////
|
|
||||||
// ** Insert tags **
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// If the tags haven't been initialized, don't touch anything
|
// If the tags haven't been initialized, don't touch anything
|
||||||
if (self.tags) |tags| {
|
if (self.tags) |tags| {
|
||||||
// TODO: Remove unused tag relations
|
|
||||||
// If the count drops to zero, delete.
|
|
||||||
|
|
||||||
// Create new tags if they don't exist
|
// Create new tags if they don't exist
|
||||||
|
// TODO: Do the "if they don't exist" part.
|
||||||
for (tags) |*tags_i| {
|
for (tags) |*tags_i| {
|
||||||
try db.exec(
|
const name_query = "INSERT INTO tag (name) VALUES (?)";
|
||||||
"INSERT INTO tag (name) VALUES (?);",
|
try db.exec(name_query, .{}, .{ .name = tags_i.name });
|
||||||
.{},
|
const rel_query = "INSERT INTO item_tag (item, tag, value) VALUES (?, ?, ?);";
|
||||||
.{ .name = tags_i.name }
|
try db.exec(rel_query, .{}, .{ .item = self.id, .tag = tags_i.name, .value = tags_i.value });
|
||||||
);
|
|
||||||
|
|
||||||
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
|
/// Convert into a JSON object. A call to deinit() is necessary from the caller's side
|
||||||
pub fn toJson(self: Self) json.Obj {
|
pub fn toJson(self: Self) json.Obj {
|
||||||
|
// Main object
|
||||||
var jobj = json.Obj.newObject();
|
var jobj = json.Obj.newObject();
|
||||||
|
|
||||||
jobj.objectAdd("id", &json.Obj.newInt64(self.id.?));
|
// Add id (i64|null)
|
||||||
|
jobj.objectAdd("id", if (self.id) |id| &json.Obj.newInt64(id) else null);
|
||||||
|
|
||||||
var jtags = json.Obj.newObject();
|
var jtags = json.Obj.newObject();
|
||||||
jobj.objectAdd("tags", &jtags);
|
jobj.objectAdd("tags", &jtags);
|
||||||
|
|
||||||
// If there are tags there's no point on continuing
|
// Add tags only if they're initialized
|
||||||
|
|
||||||
if (self.tags) |tags| {
|
if (self.tags) |tags| {
|
||||||
for (tags) |tag_i| {
|
for (tags) |tag_i| {
|
||||||
const jtag = if (tag_i.value) |value|
|
const jtag = if (tag_i.value) |value|
|
||||||
|
@ -80,3 +82,27 @@ pub fn toJson(self: Self) json.Obj {
|
||||||
|
|
||||||
return jobj;
|
return jobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fromJson(jobj: json.Obj, allocator: std.mem.Allocator) !Self {
|
||||||
|
var jtags = jobj.objectGet("tags");
|
||||||
|
defer jtags.deinit();
|
||||||
|
|
||||||
|
const len = @intCast(usize, jtags.objectLen());
|
||||||
|
var tags = try allocator.alloc(Tag, len);
|
||||||
|
|
||||||
|
var iter = jtags.objectGetIterator();
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (iter.next()) |*tag| {
|
||||||
|
tags[i].name = try allocator.dupeZ(u8, tag.key);
|
||||||
|
tags[i].value = if (tag.value) |*value| try allocator.dupeZ(u8, value.getString()) else null;
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Self{
|
||||||
|
.id = null,
|
||||||
|
.tags = tags,
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,10 @@ pub const Obj = struct {
|
||||||
return Obj{ .obj = c.json_object_get(obj).? };
|
return Obj{ .obj = c.json_object_get(obj).? };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn objectLen(self: *const Obj) c_int {
|
||||||
|
return c.json_object_object_length(self.obj);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn objectGetIterator(self: *Obj) ObjectIterator {
|
pub fn objectGetIterator(self: *Obj) ObjectIterator {
|
||||||
// TODO: Check errors
|
// TODO: Check errors
|
||||||
return ObjectIterator{
|
return ObjectIterator{
|
||||||
|
|
33
src/main.zig
33
src/main.zig
|
@ -9,15 +9,16 @@ const json = @import("json.zig");
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var db = try Db.init();
|
var db = try Db.init();
|
||||||
|
|
||||||
//var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
//defer arena.deinit();
|
defer arena.deinit();
|
||||||
//const alloc = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
const jsonText: [:0]const u8 =
|
const jsonText: [:0]const u8 =
|
||||||
\\{
|
\\{
|
||||||
\\ "tags": {
|
\\ "tags": {
|
||||||
\\ "title": "clean room",
|
\\ "title": "Programar sistema de TODO",
|
||||||
\\ "task": null
|
\\ "programming" : "zig",
|
||||||
|
\\ "due" : "2023-01-01"
|
||||||
\\ }
|
\\ }
|
||||||
\\}
|
\\}
|
||||||
;
|
;
|
||||||
|
@ -25,25 +26,13 @@ pub fn main() !void {
|
||||||
var jsonItem = json.Obj.newFromString(jsonText);
|
var jsonItem = json.Obj.newFromString(jsonText);
|
||||||
defer jsonItem.deinit();
|
defer jsonItem.deinit();
|
||||||
|
|
||||||
_ = db;
|
var item = try Item.fromJson(jsonItem, allocator);
|
||||||
|
defer item.deinit();
|
||||||
|
|
||||||
//var item = Item.fromJson(jsonItem);
|
try item.persist(&db);
|
||||||
|
|
||||||
//try item.persist(&db);
|
var jobj = item.toJson();
|
||||||
|
|
||||||
//var jobj = item.toJson();
|
|
||||||
|
|
||||||
var jobj = jsonItem.objectGet("tags");
|
|
||||||
defer jobj.deinit();
|
defer jobj.deinit();
|
||||||
|
|
||||||
var iter = jobj.objectGetIterator();
|
std.debug.print("{s}\n", .{jobj.toString()});
|
||||||
while(iter.next()) |*tag| {
|
|
||||||
std.debug.print("{s}", .{tag.key});
|
|
||||||
defer std.debug.print("\n", .{});
|
|
||||||
|
|
||||||
if (tag.value) |*value| {
|
|
||||||
std.debug.print(" => {s}", .{value.getString()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue