Writer produce correct top-level or in-array optional elem when custom flavor omit optional fields

This commit is contained in:
jangko 2024-01-11 16:51:00 +07:00
parent 164a8bcbd5
commit 9c74b885ea
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
5 changed files with 125 additions and 4 deletions

View File

@ -27,7 +27,8 @@ proc writeValue*(writer: var JsonWriter, value: Option) {.raises: [IOError].} =
if value.isSome: if value.isSome:
writer.writeValue value.get writer.writeValue value.get
elif not flavorOmitsOptionalFields(Flavor): elif not flavorOmitsOptionalFields(Flavor) or
writer.nesting != JsonNesting.WriteObject:
writer.writeValue JsonString("null") writer.writeValue JsonString("null")
proc readValue*[T](reader: var JsonReader, value: var Option[T]) = proc readValue*[T](reader: var JsonReader, value: var Option[T]) =

View File

@ -31,7 +31,8 @@ proc writeValue*[T](
if value.isOk: if value.isOk:
writer.writeValue value.get writer.writeValue value.get
elif not flavorOmitsOptionalFields(Flavor): elif not flavorOmitsOptionalFields(Flavor) or
writer.nesting != JsonNesting.WriteObject:
writer.writeValue JsonString("null") writer.writeValue JsonString("null")
proc readValue*[T](reader: var JsonReader, value: var Result[T, void]) = proc readValue*[T](reader: var JsonReader, value: var Result[T, void]) =

View File

@ -22,12 +22,19 @@ type
RecordStarted RecordStarted
AfterField AfterField
JsonNesting* {.pure.} = enum
TopLevel
WriteObject
WriteArray
JsonWriter*[Flavor = DefaultFlavor] = object JsonWriter*[Flavor = DefaultFlavor] = object
stream*: OutputStream stream*: OutputStream
hasTypeAnnotations: bool hasTypeAnnotations: bool
hasPrettyOutput*: bool # read-only hasPrettyOutput*: bool # read-only
nestingLevel*: int # read-only nestingLevel*: int # read-only
state: JsonWriterState state: JsonWriterState
nesting: JsonNesting
prevNesting: seq[JsonNesting]
Json.setWriter JsonWriter, Json.setWriter JsonWriter,
PreferredOutput = string PreferredOutput = string
@ -38,7 +45,11 @@ func init*(W: type JsonWriter, stream: OutputStream,
hasPrettyOutput: pretty, hasPrettyOutput: pretty,
hasTypeAnnotations: typeAnnotations, hasTypeAnnotations: typeAnnotations,
nestingLevel: if pretty: 0 else: -1, nestingLevel: if pretty: 0 else: -1,
state: RecordExpected) state: RecordExpected,
nesting: JsonNesting.TopLevel)
func nesting*(w: JsonWriter): JsonNesting =
w.nesting
proc beginRecord*(w: var JsonWriter, T: type) proc beginRecord*(w: var JsonWriter, T: type)
proc beginRecord*(w: var JsonWriter) proc beginRecord*(w: var JsonWriter)
@ -90,6 +101,8 @@ template fieldWritten*(w: var JsonWriter) =
proc beginRecord*(w: var JsonWriter) = proc beginRecord*(w: var JsonWriter) =
doAssert w.state == RecordExpected doAssert w.state == RecordExpected
w.prevNesting.add w.nesting
w.nesting = JsonNesting.WriteObject
append '{' append '{'
if w.hasPrettyOutput: if w.hasPrettyOutput:
w.nestingLevel += 2 w.nestingLevel += 2
@ -109,12 +122,15 @@ proc endRecord*(w: var JsonWriter) =
indent() indent()
append '}' append '}'
w.nesting = w.prevNesting.pop()
template endRecordField*(w: var JsonWriter) = template endRecordField*(w: var JsonWriter) =
endRecord(w) endRecord(w)
w.state = AfterField w.state = AfterField
iterator stepwiseArrayCreation*[C](w: var JsonWriter, collection: C): auto = iterator stepwiseArrayCreation*[C](w: var JsonWriter, collection: C): auto =
w.prevNesting.add w.nesting
w.nesting = JsonNesting.WriteArray
append '[' append '['
if w.hasPrettyOutput: if w.hasPrettyOutput:
@ -140,6 +156,7 @@ iterator stepwiseArrayCreation*[C](w: var JsonWriter, collection: C): auto =
indent() indent()
append ']' append ']'
w.nesting = w.prevNesting.pop()
proc writeIterable*(w: var JsonWriter, collection: auto) = proc writeIterable*(w: var JsonWriter, collection: auto) =
mixin writeValue mixin writeValue

View File

@ -16,4 +16,5 @@ import
test_spec, test_spec,
test_parser, test_parser,
test_line_col, test_line_col,
test_reader test_reader,
test_writer

101
tests/test_writer.nim Normal file
View File

@ -0,0 +1,101 @@
# json-serialization
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
import
unittest2,
../json_serialization/stew/results,
../json_serialization/std/options,
../json_serialization
createJsonFlavor YourJson,
omitOptionalFields = false
createJsonFlavor MyJson,
omitOptionalFields = true
suite "Test writer":
test "stdlib option top level some YourJson":
var val = some(123)
let json = YourJson.encode(val)
check json == "123"
test "stdlib option top level none YourJson":
var val = none(int)
let json = YourJson.encode(val)
check json == "null"
test "stdlib option top level some MyJson":
var val = some(123)
let json = MyJson.encode(val)
check json == "123"
test "stdlib option top level none MyJson":
var val = none(int)
let json = MyJson.encode(val)
check json == "null"
test "results option top level some YourJson":
var val = Opt.some(123)
let json = YourJson.encode(val)
check json == "123"
test "results option top level none YourJson":
var val = Opt.none(int)
let json = YourJson.encode(val)
check json == "null"
test "results option top level some MyJson":
var val = Opt.some(123)
let json = MyJson.encode(val)
check json == "123"
test "results option top level none MyJson":
var val = Opt.none(int)
let json = MyJson.encode(val)
check json == "null"
test "stdlib option array some YourJson":
var val = [some(123), some(345)]
let json = YourJson.encode(val)
check json == "[123,345]"
test "stdlib option array none YourJson":
var val = [some(123), none(int), some(777)]
let json = YourJson.encode(val)
check json == "[123,null,777]"
test "stdlib option array some MyJson":
var val = [some(123), some(345)]
let json = MyJson.encode(val)
check json == "[123,345]"
test "stdlib option array none MyJson":
var val = [some(123), none(int), some(777)]
let json = MyJson.encode(val)
check json == "[123,null,777]"
test "results option array some YourJson":
var val = [Opt.some(123), Opt.some(345)]
let json = YourJson.encode(val)
check json == "[123,345]"
test "results option array none YourJson":
var val = [Opt.some(123), Opt.none(int), Opt.some(777)]
let json = YourJson.encode(val)
check json == "[123,null,777]"
test "results option array some MyJson":
var val = [Opt.some(123), Opt.some(345)]
let json = MyJson.encode(val)
check json == "[123,345]"
test "results option array none MyJson":
var val = [Opt.some(123), Opt.none(int), Opt.some(777)]
let json = MyJson.encode(val)
check json == "[123,null,777]"