commit 7b5e7ace256a95ad5c478070fb89fd175638e371
parent aa40cf1b0005c69a3fe5a1c172d73590c0da6d17
Author: francoispqt <francois@parquet.ninja>
Date: Wed, 29 Aug 2018 13:16:43 +0800
add ObjectKeyWithKeys and ObjectWithKeys methods to encode items with specific keys
Diffstat:
3 files changed, 176 insertions(+), 4 deletions(-)
diff --git a/decode_object.go b/decode_object.go
@@ -5,10 +5,6 @@ import (
"unsafe"
)
-type IsNiler interface {
- IsNil() bool
-}
-
// DecodeObject reads the next JSON-encoded value from its input and stores it in the value pointed to by v.
//
// v must implement UnmarshalerJSONObject.
diff --git a/encode_object.go b/encode_object.go
@@ -120,6 +120,35 @@ func (enc *Encoder) Object(v MarshalerJSONObject) {
enc.writeByte('}')
}
+// ObjectWithKeys adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
+// value must implement MarshalerJSONObject. It will only encode the keys in keys.
+func (enc *Encoder) ObjectWithKeys(v MarshalerJSONObject, keys []string) {
+ if v.IsNil() {
+ enc.grow(2)
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('{')
+ enc.writeByte('}')
+ return
+ }
+ enc.grow(4)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('{')
+ var origKeys = enc.keys
+ var origHasKeys = enc.hasKeys
+ enc.hasKeys = true
+ enc.keys = keys
+ v.MarshalJSONObject(enc)
+ enc.hasKeys = origHasKeys
+ enc.keys = origKeys
+ enc.writeByte('}')
+}
+
// ObjectOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
@@ -187,6 +216,44 @@ func (enc *Encoder) ObjectKey(key string, value MarshalerJSONObject) {
enc.writeByte('}')
}
+// ObjectKeyWithKeys adds a struct to be encoded, must be used inside an object as it will encode a key.
+// Value must implement MarshalerJSONObject. It will only encode the keys in keys.
+func (enc *Encoder) ObjectKeyWithKeys(key string, value MarshalerJSONObject, keys []string) {
+ if enc.hasKeys {
+ if !enc.keyExists(key) {
+ return
+ }
+ }
+ if value.IsNil() {
+ enc.grow(2 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKeyObj)
+ enc.writeByte('}')
+ return
+ }
+ enc.grow(5 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKeyObj)
+ var origKeys = enc.keys
+ var origHasKeys = enc.hasKeys
+ enc.hasKeys = true
+ enc.keys = keys
+ value.MarshalJSONObject(enc)
+ enc.hasKeys = origHasKeys
+ enc.keys = origKeys
+ enc.writeByte('}')
+}
+
// ObjectKeyOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
diff --git a/encode_object_test.go b/encode_object_test.go
@@ -565,6 +565,11 @@ func (o *ObjectWithKeys) IsNil() bool {
return o == nil
}
+type NilObject struct{}
+
+func (n *NilObject) MarshalJSONObject(enc *Encoder) {}
+func (n *NilObject) IsNil() bool { return true }
+
func TestEncodeObjectWithKeys(t *testing.T) {
t.Run(
"should not encode any key",
@@ -620,4 +625,108 @@ func TestEncodeObjectWithKeys(t *testing.T) {
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
})
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeObjectKeys(EncodeObjectFunc(func(enc *Encoder) {
+ enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }), []string{})
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `{}`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
+ enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
+ enc.keys = nil
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `{"test":{}}`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
+ enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `{"test":{"test":"hello"}}`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
+ enc.writeByte(' ')
+ enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `{ ,"test":{"test":"hello"}}`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
+ enc.writeByte(' ')
+ enc.ObjectKeyWithKeys("test", &NilObject{}, []string{})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `{ ,"test":{}}`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
+ enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `[{"test":"hello"}]`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
+ enc.writeByte(' ')
+ enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
+ enc.StringKey("test", "hello")
+ enc.StringKey("test2", "hello")
+ }), []string{"test"})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `[ ,{"test":"hello"}]`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
+ enc.ObjectWithKeys(&NilObject{}, []string{})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `[{}]`, b.String())
+ })
+ t.Run("encode-object-with-keys", func(t *testing.T) {
+ b := &strings.Builder{}
+ enc := NewEncoder(b)
+ err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
+ enc.writeByte(' ')
+ enc.ObjectWithKeys(&NilObject{}, []string{})
+ }))
+ assert.Nil(t, err, "Error should not be nil")
+ assert.Equal(t, `[ ,{}]`, b.String())
+ })
}