Detect tag ausence when parsing JSON to Item
This commit is contained in:
parent
b8908c7b22
commit
3032957071
25
src/Item.zig
25
src/Item.zig
|
@ -65,11 +65,11 @@ pub fn toJson(self: Self) json.Obj {
|
||||||
// Add id (i64|null)
|
// Add id (i64|null)
|
||||||
jobj.objectAdd("id", if (self.id) |id| &json.Obj.newInt64(id) else null);
|
jobj.objectAdd("id", if (self.id) |id| &json.Obj.newInt64(id) else null);
|
||||||
|
|
||||||
|
// Add tags only if they're initialized
|
||||||
|
if (self.tags) |tags| {
|
||||||
var jtags = json.Obj.newObject();
|
var jtags = json.Obj.newObject();
|
||||||
jobj.objectAdd("tags", &jtags);
|
jobj.objectAdd("tags", &jtags);
|
||||||
|
|
||||||
// Add tags only if they're initialized
|
|
||||||
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|
|
||||||
&json.Obj.newString(value)
|
&json.Obj.newString(value)
|
||||||
|
@ -78,27 +78,38 @@ pub fn toJson(self: Self) json.Obj {
|
||||||
|
|
||||||
jtags.objectAdd(tag_i.name, jtag);
|
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;
|
return jobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromJson(jobj: json.Obj, allocator: std.mem.Allocator) !Self {
|
pub fn fromJson(jobj: json.Obj, allocator: std.mem.Allocator) !Self {
|
||||||
var jtags = jobj.objectGet("tags");
|
// Try to assemble a Item object from a JSON string
|
||||||
defer jtags.deinit();
|
// An item could be just an id, just tags or both.
|
||||||
|
|
||||||
|
var opt_jtags = jobj.objectGet("tags") catch null;
|
||||||
|
var tags: ?[]Tag = null;
|
||||||
|
|
||||||
|
if (opt_jtags) |*jtags| {
|
||||||
|
defer jtags.deinit();
|
||||||
const len = @intCast(usize, jtags.objectLen());
|
const len = @intCast(usize, jtags.objectLen());
|
||||||
var tags = try allocator.alloc(Tag, len);
|
tags = try allocator.alloc(Tag, len);
|
||||||
|
|
||||||
var iter = jtags.objectGetIterator();
|
var iter = jtags.objectGetIterator();
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (iter.next()) |*tag| {
|
while (iter.next()) |*tag| {
|
||||||
tags[i].name = try allocator.dupeZ(u8, tag.key);
|
// Whe know it's not null at this point
|
||||||
tags[i].value = if (tag.value) |*value| try allocator.dupeZ(u8, value.getString()) else null;
|
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;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Self{
|
return Self{
|
||||||
.id = null,
|
.id = null,
|
||||||
|
|
46
src/json.zig
46
src/json.zig
|
@ -1,10 +1,21 @@
|
||||||
const c = @cImport({
|
pub const c = @cImport({
|
||||||
@cInclude("json.h");
|
@cInclude("json.h");
|
||||||
});
|
});
|
||||||
const std = @import("std");
|
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 {
|
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
|
// 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).? };
|
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
|
// Not *const Obj because the json_object retains ownership of the string
|
||||||
pub fn getString(self: *Obj) []const u8 {
|
pub fn getString(self: *Obj) []const u8 {
|
||||||
// TODO: Check type to not allow other types
|
// TODO: Check type to not allow other types
|
||||||
|
@ -51,13 +71,27 @@ pub const Obj = struct {
|
||||||
// ** Object functions **
|
// ** 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
|
// TODO: Check type and null return as errors
|
||||||
var obj: ?*c.json_object = undefined;
|
var obj: ?*c.json_object = undefined;
|
||||||
_ = c.json_object_object_get_ex(self.obj, key, &obj);
|
const succ = c.json_object_object_get_ex(self.obj, key, &obj);
|
||||||
return Obj{ .obj = c.json_object_get(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 {
|
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);
|
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();
|
defer jobj.deinit();
|
||||||
|
|
||||||
std.debug.print("{s}\n", .{jobj.toString()});
|
std.debug.print("{s}\n", .{jobj.toString()});
|
||||||
|
|
Loading…
Reference in New Issue