Detect tag ausence when parsing JSON to Item
This commit is contained in:
parent
b8908c7b22
commit
3032957071
37
src/Item.zig
37
src/Item.zig
|
@ -65,11 +65,11 @@ pub fn toJson(self: Self) json.Obj {
|
|||
// Add id (i64|null)
|
||||
jobj.objectAdd("id", if (self.id) |id| &json.Obj.newInt64(id) else null);
|
||||
|
||||
var jtags = json.Obj.newObject();
|
||||
jobj.objectAdd("tags", &jtags);
|
||||
|
||||
// Add tags only if they're initialized
|
||||
if (self.tags) |tags| {
|
||||
var jtags = json.Obj.newObject();
|
||||
jobj.objectAdd("tags", &jtags);
|
||||
|
||||
for (tags) |tag_i| {
|
||||
const jtag = if (tag_i.value) |value|
|
||||
&json.Obj.newString(value)
|
||||
|
@ -78,26 +78,37 @@ pub fn toJson(self: Self) json.Obj {
|
|||
|
||||
jtags.objectAdd(tag_i.name, jtag);
|
||||
}
|
||||
} else {
|
||||
// If nothing is found, set it to null
|
||||
// just to make it more explicit
|
||||
jobj.objectAdd("tags", null);
|
||||
}
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
pub fn fromJson(jobj: json.Obj, allocator: std.mem.Allocator) !Self {
|
||||
var jtags = jobj.objectGet("tags");
|
||||
defer jtags.deinit();
|
||||
// Try to assemble a Item object from a JSON string
|
||||
// An item could be just an id, just tags or both.
|
||||
|
||||
const len = @intCast(usize, jtags.objectLen());
|
||||
var tags = try allocator.alloc(Tag, len);
|
||||
var opt_jtags = jobj.objectGet("tags") catch null;
|
||||
var tags: ?[]Tag = null;
|
||||
|
||||
var iter = jtags.objectGetIterator();
|
||||
if (opt_jtags) |*jtags| {
|
||||
defer jtags.deinit();
|
||||
const len = @intCast(usize, jtags.objectLen());
|
||||
tags = try allocator.alloc(Tag, len);
|
||||
|
||||
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;
|
||||
var iter = jtags.objectGetIterator();
|
||||
|
||||
i += 1;
|
||||
var i: usize = 0;
|
||||
while (iter.next()) |*tag| {
|
||||
// Whe know it's not null at this point
|
||||
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{
|
||||
|
|
46
src/json.zig
46
src/json.zig
|
@ -1,10 +1,21 @@
|
|||
const c = @cImport({
|
||||
pub const c = @cImport({
|
||||
@cInclude("json.h");
|
||||
});
|
||||
const std = @import("std");
|
||||
|
||||
const Type = enum(c.json_type) {
|
||||
@"null" = c.json_type_null,
|
||||
boolean = c.json_type_boolean,
|
||||
double = c.json_type_double,
|
||||
int = c.json_type_int,
|
||||
object = c.json_type_object,
|
||||
array = c.json_type_array,
|
||||
string = c.json_type_string,
|
||||
};
|
||||
|
||||
pub const Obj = struct {
|
||||
obj: *c.json_object,
|
||||
// Option because a null value is treated as the C value NULL in json-c
|
||||
obj: ?*c.json_object,
|
||||
|
||||
// TODO: Port type attribute to a zig enum and assign it upon creation
|
||||
|
||||
|
@ -31,6 +42,15 @@ pub const Obj = struct {
|
|||
return Obj{ .obj = c.json_tokener_parse(s).? };
|
||||
}
|
||||
|
||||
const TypeError = error {
|
||||
TypeMismatch, // Tried to use a function on the wrong JSON format
|
||||
};
|
||||
|
||||
pub fn getType(self: Obj) Type {
|
||||
//std.debug.print("{}\n", .{c.json_object_get_type(self.obj)});
|
||||
return @intToEnum(Type, c.json_object_get_type(self.obj));
|
||||
}
|
||||
|
||||
// Not *const Obj because the json_object retains ownership of the string
|
||||
pub fn getString(self: *Obj) []const u8 {
|
||||
// TODO: Check type to not allow other types
|
||||
|
@ -51,13 +71,27 @@ pub const Obj = struct {
|
|||
// ** Object functions **
|
||||
/////////////////////////////////
|
||||
|
||||
// TODO: Create an error for type checking.
|
||||
const GetError = error {
|
||||
TypeMismatch, // Not an object/array
|
||||
KeyNotFound, // Key or ID not present in the object/array
|
||||
};
|
||||
|
||||
pub fn objectGet(self: *const Obj, key: [*c]const u8) Obj {
|
||||
pub fn objectGet(self: *const Obj, key: [*c]const u8) GetError!Obj {
|
||||
// TODO: Check type and null return as errors
|
||||
var obj: ?*c.json_object = undefined;
|
||||
_ = c.json_object_object_get_ex(self.obj, key, &obj);
|
||||
return Obj{ .obj = c.json_object_get(obj).? };
|
||||
const succ = c.json_object_object_get_ex(self.obj, key, &obj);
|
||||
|
||||
// Everything went alright
|
||||
if (obj) |ret| {
|
||||
return Obj{ .obj = c.json_object_get(ret).? };
|
||||
} else if (obj == null and succ != 0){
|
||||
// The actual value is just null
|
||||
return Obj{ .obj = null };
|
||||
} else if (self.getType() != Type.object){
|
||||
return GetError.TypeMismatch;
|
||||
} else {
|
||||
return GetError.KeyNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn objectLen(self: *const Obj) c_int {
|
||||
|
|
14
src/main.zig
14
src/main.zig
|
@ -31,7 +31,19 @@ pub fn main() !void {
|
|||
|
||||
try item.persist(&db);
|
||||
|
||||
var jobj = item.toJson();
|
||||
// ----------
|
||||
|
||||
const jsonText2: [:0]const u8 =
|
||||
\\{ "id" : 1 }
|
||||
;
|
||||
|
||||
var jsonItem2 = json.Obj.newFromString(jsonText2);
|
||||
defer jsonItem2.deinit();
|
||||
|
||||
var item2 = try Item.fromJson(jsonItem2, allocator);
|
||||
defer item2.deinit();
|
||||
|
||||
var jobj = item2.toJson();
|
||||
defer jobj.deinit();
|
||||
|
||||
std.debug.print("{s}\n", .{jobj.toString()});
|
||||
|
|
Loading…
Reference in New Issue