From 0dd3fe83e66e7b23649f78c4465e5e641de90d39 Mon Sep 17 00:00:00 2001 From: fgalic Date: Tue, 2 Aug 2022 13:54:48 +0200 Subject: [PATCH] [#222]: Make TextualFromNative output deterministic --- map.go | 14 +++++++++++++- map_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/map.go b/map.go index cfda161..9e94e3e 100644 --- a/map.go +++ b/map.go @@ -15,6 +15,7 @@ import ( "io" "math" "reflect" + "sort" ) func makeMapCodec(st map[string]*Codec, namespace string, schemaMap map[string]interface{}, cb *codecBuilder) (*Codec, error) { @@ -243,8 +244,10 @@ func genericMapTextEncoder(buf []byte, datum interface{}, defaultCodec *Codec, c var atLeastOne bool buf = append(buf, '{') + sortedKeys := sortKeys(mapValues) - for key, value := range mapValues { + for _, key := range sortedKeys { + value := mapValues[key] atLeastOne = true // Find a codec for the key @@ -305,3 +308,12 @@ func convertMap(datum interface{}) (map[string]interface{}, error) { } return mapValues, nil } + +func sortKeys(m map[string]interface{}) (keys []string) { + for key, _ := range m { + keys = append(keys, key) + } + + sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) + return keys +} diff --git a/map_test.go b/map_test.go index d1b02d2..1cb5a2d 100644 --- a/map_test.go +++ b/map_test.go @@ -173,3 +173,58 @@ func ExampleMap() { fmt.Println(string(buf)) // Output: {"f1":{"k1":3.5}} } + +func ExampleMapDeterministic() { + codec, err := NewCodec(`{ + "name":"r1", + "type":"record", + "fields":[ + { + "name":"f1", + "type":{ + "type":"double" + } + }, + { + "name":"a1", + "type":{ + "type":"double" + } + }, + { + "name":"b2", + "type":{ + "type":"double" + } + }, + { + "name":"c3", + "type":{ + "type":"double" + } + }, + { + "name":"d4", + "type":{ + "type":"double" + } + } + ] +}`) + if err != nil { + log.Fatal(err) + } + + buf, err := codec.TextualFromNative(nil, map[string]interface{}{ + "f1": 3.5, + "a1": 3.5, + "b2": 3.5, + "c3": 3.5, + "d4": 3.5, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(buf)) + // Output: {"a1":3.5,"b2":3.5,"c3":3.5,"d4":3.5,"f1":3.5} +}