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 2 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
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,
hazeycode marked this conversation as resolved.
Show resolved Hide resolved
};
};
};
Expand Down Expand Up @@ -2822,23 +2825,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 {
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 +3137,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{ .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 },
));
}