Skip to content

Commit 7d07dc7

Browse files
Merge pull request #24 from hellofresh/patch/metadata-easyjson
Use easyjson for metadata unmarshaling
2 parents 8ca50cd + 3ecb830 commit 7d07dc7

File tree

5 files changed

+83
-49
lines changed

5 files changed

+83
-49
lines changed

Gopkg.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

metadata/metadata.go

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package metadata
22

3-
import "encoding/json"
3+
import (
4+
"encoding/json"
5+
6+
"github.com/mailru/easyjson/jlexer"
7+
)
48

59
// Metadata is an immutable map[string]interface{} implementation
610
type Metadata interface {
@@ -94,35 +98,31 @@ func (v *valueData) MarshalJSON() ([]byte, error) {
9498
return json.Marshal(v.AsMap())
9599
}
96100

97-
// JSONMetadata is a special struct to UnmarshalJSON metadata
98-
type JSONMetadata struct {
99-
Metadata Metadata
100-
}
101-
102-
var (
103-
// Ensure JSONMetadata implements the json.Marshaler interface
104-
_ json.Marshaler = &JSONMetadata{}
105-
// Ensure JSONMetadata implements the json.Unmarshaler interface
106-
_ json.Unmarshaler = &JSONMetadata{}
107-
)
108-
109-
// MarshalJSON returns a json representation of the wrapped Metadata
110-
func (j JSONMetadata) MarshalJSON() ([]byte, error) {
111-
if j.Metadata == nil {
112-
j.Metadata = New()
101+
func UnmarshalJSON(json []byte) (Metadata, error) {
102+
in := jlexer.Lexer{Data: json}
103+
metadata := New()
104+
105+
isTopLevel := in.IsStart()
106+
if in.IsNull() {
107+
if isTopLevel {
108+
in.Consumed()
109+
}
110+
in.Skip()
111+
return metadata, in.Error()
113112
}
114113

115-
return json.Marshal(j.Metadata)
116-
}
114+
in.Delim('{')
115+
for !in.IsDelim('}') {
116+
key := in.UnsafeString()
117+
in.WantColon()
118+
metadata = WithValue(metadata, key, in.Interface())
119+
in.WantComma()
120+
}
121+
in.Delim('}')
117122

118-
// UnmarshalJSON unmarshal the json into Metdadata
119-
func (j *JSONMetadata) UnmarshalJSON(data []byte) error {
120-
var valueMap map[string]interface{}
121-
err := json.Unmarshal(data, &valueMap)
122-
if err != nil {
123-
return err
123+
if isTopLevel {
124+
in.Consumed()
124125
}
125126

126-
j.Metadata = FromMap(valueMap)
127-
return nil
127+
return metadata, in.Error()
128128
}

metadata/metadata_test.go

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,30 @@ var jsonTestCases = []struct {
172172
"another": "value"
173173
}`,
174174
},
175+
{
176+
"metadata with 'complex' json",
177+
func() metadata.Metadata {
178+
m := metadata.New()
179+
m = metadata.WithValue(m, "test", nil)
180+
m = metadata.WithValue(m, "another", "value")
181+
m = metadata.WithValue(m, "arr", []interface{}{"a", "b", "c"})
182+
m = metadata.WithValue(m, "arrInArr", []interface{}{"a", []interface{}{"b"}})
183+
m = metadata.WithValue(m, "obj", map[string]interface{}{"a": float64(1)})
184+
m = metadata.WithValue(m, "objInObj", map[string]interface{}{
185+
"a": float64(1),
186+
"b": map[string]interface{}{"a": float64(2)},
187+
})
188+
return m
189+
},
190+
`{
191+
"test": null,
192+
"another": "value",
193+
"arr": [ "a", "b", "c" ],
194+
"arrInArr": [ "a", [ "b" ] ],
195+
"obj": { "a": 1 },
196+
"objInObj": { "a": 1, "b": {"a": 2} }
197+
}`,
198+
},
175199
}
176200

177201
func TestMetadata_MarshalJSON(t *testing.T) {
@@ -187,30 +211,27 @@ func TestMetadata_MarshalJSON(t *testing.T) {
187211
}
188212
}
189213

190-
func TestJSONMetadata_MarshalJSON(t *testing.T) {
214+
func TestJSONMetadata_UnmarshalJSON(t *testing.T) {
191215
for _, testCase := range jsonTestCases {
192216
t.Run(testCase.title, func(t *testing.T) {
193-
m := metadata.JSONMetadata{
194-
Metadata: testCase.metadata(),
195-
}
217+
m, err := metadata.UnmarshalJSON([]byte(testCase.json))
196218

197-
mJSON, err := json.Marshal(m)
198-
199-
assert.JSONEq(t, testCase.json, string(mJSON))
200-
assert.NoError(t, err)
219+
// Need to use AsMap otherwise we can have inconsistent tests results.
220+
if assert.NoError(t, err) {
221+
assert.Equal(t, testCase.metadata().AsMap(), m.AsMap())
222+
}
201223
})
202224
}
203225
}
204226

205-
func TestJSONMetadata_UnmarshalJSON(t *testing.T) {
206-
for _, testCase := range jsonTestCases {
207-
t.Run(testCase.title, func(t *testing.T) {
208-
var m metadata.JSONMetadata
209-
err := json.Unmarshal([]byte(testCase.json), &m)
227+
func BenchmarkJSONMetadata_UnmarshalJSON(b *testing.B) {
228+
payload := []byte(`{"_aggregate_id": "b9ebca7a-c1eb-40dd-94a4-fac7c5e84fb5", "_aggregate_type": "bank_account", "_aggregate_version": 1}`)
210229

211-
// Need to use AsMap otherwise we can have inconsistent tests results.
212-
assert.Equal(t, testCase.metadata().AsMap(), m.Metadata.AsMap())
213-
assert.NoError(t, err)
214-
})
230+
b.ResetTimer()
231+
for i := 0; i < b.N; i++ {
232+
_, err := metadata.UnmarshalJSON(payload)
233+
if err != nil {
234+
b.Fail()
235+
}
215236
}
216237
}

strategy/json/sql/message_factory_aggregate.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package sql
22

33
import (
44
"database/sql"
5-
"encoding/json"
65
"fmt"
76
"time"
87

@@ -78,11 +77,10 @@ func (a *aggregateChangedEventStream) Message() (goengine.Message, int64, error)
7877
return nil, 0, err
7978
}
8079

81-
metadataWrapper := metadata.JSONMetadata{Metadata: metadata.New()}
82-
if err := json.Unmarshal(jsonMetadata, &metadataWrapper); err != nil {
80+
meta, err := metadata.UnmarshalJSON(jsonMetadata)
81+
if err != nil {
8382
return nil, 0, err
8483
}
85-
meta := metadataWrapper.Metadata
8684

8785
payload, err := a.payloadFactory.CreatePayload(eventName, jsonPayload)
8886
if err != nil {

strategy/json/sql/message_factory_aggregate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func TestAggregateChangedFactory_CreateFromRows(t *testing.T) {
164164

165165
return mockRows, mocks.NewMessagePayloadFactory(ctrl)
166166
},
167-
"unexpected end of JSON input",
167+
"parse error: expected { near offset 1 of ''",
168168
},
169169
{
170170
"bad payload",

0 commit comments

Comments
 (0)