Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json Stringify option to not write out null optional fields #8979

Merged
merged 4 commits into from
Nov 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 61 additions & 15 deletions lib/std/json.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,9 @@ pub const StringifyOptions = struct {
/// Controls the whitespace emitted
whitespace: ?Whitespace = null,

/// Should optional fields with null value be written?
emit_null_optional_fields: bool = true,

string: StringOptions = StringOptions{ .String = .{} },

/// Should []u8 be serialised as a string? or an array?
Expand Down Expand Up @@ -2813,7 +2816,7 @@ pub fn stringify(
}

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

if (!field_output) {
field_output = true;
} else {
try out_stream.writeByte(',');
}
if (child_options.whitespace) |child_whitespace| {
try out_stream.writeByte('\n');
try child_whitespace.outputIndent(out_stream);
var emit_field = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks redundant with field_output


// don't include optional fields that are null when emit_null_optional_fields is set to false
if (@typeInfo(Field.field_type) == .Optional) {
if (options.emit_null_optional_fields == false) {
if (@field(value, Field.name) == null) {
emit_field = false;
}
}
}
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 (emit_field) {
if (!field_output) {
field_output = true;
} 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(' ');
}
}
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 +3143,33 @@ 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 {
optional: ?[]const u8 = null,
required: []const u8 = "something",
another_optional: ?[]const u8 = null,
another_required: []const u8 = "something else",
};
try teststringify(
\\{"optional":null,"required":"something","another_optional":null,"another_required":"something else"}
,
MyStruct{},
StringifyOptions{},
);
try teststringify(
\\{"required":"something","another_required":"something else"}
,
MyStruct{},
StringifyOptions{ .emit_null_optional_fields = false },
);

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