Skip to content

Commit

Permalink
Json Stringify option to not write out null optional fields
Browse files Browse the repository at this point in the history
  • Loading branch information
hazeycode committed Jun 3, 2021
1 parent 87dae0c commit 330f6b8
Showing 1 changed file with 54 additions and 14 deletions.
68 changes: 54 additions & 14 deletions lib/std/json.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2731,6 +2731,9 @@ pub const StringifyOptions = struct {

/// Should unicode characters be escaped in strings?
escape_unicode: bool = false,

/// Should optional fields with null value be written?
write_null_optional_fields: bool = true,
};
};
};
Expand Down Expand Up @@ -2814,6 +2817,7 @@ pub fn stringify(

try out_stream.writeByte('{');
comptime var field_output = false;
comptime var prev_skipped = false;
var child_options = options;
if (child_options.whitespace) |*child_whitespace| {
child_whitespace.indent_level += 1;
Expand All @@ -2822,23 +2826,30 @@ pub fn stringify(
// don't include void fields
if (Field.field_type == void) continue;

if (!field_output) {
field_output = true;
// don't include optional fields that are null when write_null_optional_fields is set to false
const write_null_optional_fields = (options.string == .String) and (options.string.String.write_null_optional_fields == false);
const is_null = (@typeInfo(Field.field_type) == .Optional) and (@field(value, Field.name) == null);
if (write_null_optional_fields and is_null) {
// skip
} else {
try out_stream.writeByte(',');
}
if (child_options.whitespace) |child_whitespace| {
try out_stream.writeByte('\n');
try child_whitespace.outputIndent(out_stream);
}
try stringify(Field.name, options, out_stream);
try out_stream.writeByte(':');
if (child_options.whitespace) |child_whitespace| {
if (child_whitespace.separator) {
try out_stream.writeByte(' ');
if (!field_output) {
field_output = true;
} else if (prev_skipped == false) {
try out_stream.writeByte(',');
}
if (child_options.whitespace) |child_whitespace| {
try out_stream.writeByte('\n');
try child_whitespace.outputIndent(out_stream);
}
try stringify(Field.name, options, out_stream);
try out_stream.writeByte(':');
if (child_options.whitespace) |child_whitespace| {
if (child_whitespace.separator) {
try out_stream.writeByte(' ');
}
}
try stringify(@field(value, Field.name), child_options, out_stream);
}
try stringify(@field(value, Field.name), child_options, out_stream);
}
if (field_output) {
if (options.whitespace) |whitespace| {
Expand Down Expand Up @@ -3127,3 +3138,32 @@ test "stringify struct with custom stringifier" {
test "stringify vector" {
try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
}

test "stringify null optional fields" {
const MyStruct = struct {
required: []const u8 = "something",
optional: ?[]const u8 = null,
another_required: []const u8 = "something else",
};
try teststringify(
\\{"required":"something","optional":null,"another_required":"something else"}
,
MyStruct{},
StringifyOptions{},
);
try teststringify(
\\{"required":"something","another_required":"something else"}
,
MyStruct{},
StringifyOptions{ .string = .{ .String = .{ .write_null_optional_fields = false } } },
);

try std.testing.expect(try parsesTo(
MyStruct,
MyStruct{},
&TokenStream.init(
\\{"required":"something","another_required":"something else"}
),
.{ .allocator = std.testing.allocator },
));
}

0 comments on commit 330f6b8

Please sign in to comment.