Skip to content

Commit

Permalink
Improve JSON output for Zed maps (#4589)
Browse files Browse the repository at this point in the history
In JSON output, a Zed map becomes an array of {"key":KEY,"value":VALUE}
objects.  Change that to a single object object whose keys are ZSON
representations of the map keys, as in {"KEY":VALUE}.

* String keys are used directly.
* Non-string primitive keys are converted to undecorated ZSON.
* Union keys are untagged and then converted to ZSON (with decoration
  for uniqueness).
* Enum keys are converted to their corresponding symbol.
* All other keys are converted to ZSON.

Closes #4567.
  • Loading branch information
nwt authored May 16, 2023
1 parent 6a74ad7 commit a2626a7
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 12 deletions.
2 changes: 1 addition & 1 deletion service/ztests/python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ outputs:
{'u8': 0, 'u16': 0, 'u32': 0, 'u64': 0, 'i8': 0, 'i16': 0, 'i32': 0, 'i64': 0, 'dur': datetime.timedelta(0), 'tim': datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzutc()), 'f64': 0.0, 'boo': False, 'byt': b'\x00', 'str': '', 'ip': IPv4Address('0.0.0.0'), 'net': IPv4Network('0.0.0.0/0'), 'err': '', 'nul': None}
{'u8': 0, 'u16': 0, 'u32': 0, 'u64': 0, 'i8': 0, 'i16': 0, 'i32': 0, 'i64': 0, 'dur': datetime.timedelta(0), 'tim': datetime.datetime(1970, 1, 1, 0, 0, tzinfo=tzutc()), 'f64': 0.0, 'boo': False, 'byt': b'\x00', 'str': '', 'ip': IPv4Address('0.0.0.0'), 'net': IPv4Network('0.0.0.0/0'), 'err': '', 'nul': None}
=== JSON
[{"map":[{"key":"a","value":{"a":1,"b":2}},{"key":"b","value":{"a":2,"b":3}},{"key":"c","value":{"a":3,"b":4}}]},{"set":[1,2,3,4]},{"union":["a","b"]},{"union":[1,2]},{"union":"hello"},{"array":[{"a":1},{"a":2}]},{"union":123},{"enum":"bar"},{"u8":0,"u16":0,"u32":0,"u64":0,"i8":0,"i16":0,"i32":0,"i64":0,"dur":"0s","tim":"1970-01-01T00:00:00Z","f64":0,"boo":false,"byt":"0x00","str":"","ip":"0.0.0.0","net":"0.0.0.0/0","err":{"error":""},"nul":null},{"u8":0,"u16":0,"u32":0,"u64":0,"i8":0,"i16":0,"i32":0,"i64":0,"dur":"0s","tim":"1970-01-01T00:00:00Z","f64":0,"boo":false,"byt":"0x00","str":"","ip":"0.0.0.0","net":"0.0.0.0/0","err":{"error":""},"nul":null}]
[{"map":{"a":{"a":1,"b":2},"b":{"a":2,"b":3},"c":{"a":3,"b":4}}},{"set":[1,2,3,4]},{"union":["a","b"]},{"union":[1,2]},{"union":"hello"},{"array":[{"a":1},{"a":2}]},{"union":123},{"enum":"bar"},{"u8":0,"u16":0,"u32":0,"u64":0,"i8":0,"i16":0,"i32":0,"i64":0,"dur":"0s","tim":"1970-01-01T00:00:00Z","f64":0,"boo":false,"byt":"0x00","str":"","ip":"0.0.0.0","net":"0.0.0.0/0","err":{"error":""},"nul":null},{"u8":0,"u16":0,"u32":0,"u64":0,"i8":0,"i16":0,"i32":0,"i64":0,"dur":"0s","tim":"1970-01-01T00:00:00Z","f64":0,"boo":false,"byt":"0x00","str":"","ip":"0.0.0.0","net":"0.0.0.0/0","err":{"error":""},"nul":null}]
===
RequestError('test: pool already exists')
Expand Down
34 changes: 23 additions & 11 deletions zio/jsonio/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,32 @@ func marshalSet(typ *zed.TypeSet, bytes zcode.Bytes) interface{} {
return s
}

type Entry struct {
Key interface{} `json:"key"`
Value interface{} `json:"value"`
}

func marshalMap(typ *zed.TypeMap, bytes zcode.Bytes) interface{} {
var entries []Entry
it := bytes.Iter()
for !it.Done() {
key := marshalAny(typ.KeyType, it.Next())
keyType := zed.TypeUnder(typ.KeyType)
rec := record{}
for it := bytes.Iter(); !it.Done(); {
var key string
switch kind := keyType.Kind(); {
case keyType == zed.TypeString:
// Don't quote strings.
key = zed.DecodeString(it.Next())
case kind == zed.PrimitiveKind:
// Undecorated ZSON.
key = zson.FormatPrimitive(keyType, it.Next())
case kind == zed.UnionKind:
// Untagged, decorated ZSON so
// |{0:1,0(uint64):2,0(=t):3,"0":4}| gets unique keys.
typ, bytes := keyType.(*zed.TypeUnion).Untag(it.Next())
key = zson.MustFormatValue(zed.NewValue(typ, bytes))
case kind == zed.EnumKind:
key = marshalEnum(keyType.(*zed.TypeEnum), it.Next()).(string)
default:
key = zson.MustFormatValue(zed.NewValue(keyType, it.Next()))
}
val := marshalAny(typ.ValType, it.Next())
entries = append(entries, Entry{key, val})
rec = append(rec, field{key, val})
}
return entries
return rec
}

func marshalEnum(typ *zed.TypeEnum, bytes zcode.Bytes) interface{} {
Expand Down
67 changes: 67 additions & 0 deletions zio/jsonio/ztests/map-output.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
zed: '*'

input: |
|{}|
// Primitive keys
|{8(uint8):1}|
|{16(uint16):1}|
|{32(uint32):1}|
|{64:1}|
|{-8(int8):1}|
|{-16(int16):1}|
|{-32(int32):1}|
|{-64:1}|
|{1s:1}|
|{1970-01-01T00:00:00Z:1}|
|{16.(float16):1}|
|{32.(float32):1}|
|{64.:1}|
|{false:1}|
|{0x01020304:1}|
|{"string":1}|
|{1.2.3.4:1}|
|{5.6.7.0/24:1}|
|{<uint8>:1}|
|{null:1}|
// Complex keys
|{{record:0}:1}|
|{["array"]:1}|
|{|["set"]|:1}|
|{|{"map":0}|:1}|
|{0:1,0(uint64):2,0(=t):3,"0":4}|
|{%e0(enum(e0)):1}|
|{error(0):1}|
|{"named"(=t):1}|
output-flags: -f json

output: |
{}
{"8":1}
{"16":1}
{"32":1}
{"64":1}
{"-8":1}
{"-16":1}
{"-32":1}
{"-64":1}
{"1s":1}
{"1970-01-01T00:00:00Z":1}
{"16.":1}
{"32.":1}
{"64.":1}
{"false":1}
{"0x01020304":1}
{"string":1}
{"1.2.3.4":1}
{"5.6.7.0/24":1}
{"<uint8>":1}
{"null":1}
{"{record:0}":1}
{"[\"array\"]":1}
{"|[\"set\"]|":1}
{"|{\"map\":0}|":1}
{"0(uint64)":2,"0":1,"0(=t)":3,"\"0\"":4}
{"e0":1}
{"error(0)":1}
{"named":1}

0 comments on commit a2626a7

Please sign in to comment.