commit c74d5aa06ea19e49f686cd8ed8505c7062a7971c
parent 5c45cc8f3d0ad91d4278919db98b40a4d57d8c4b
Author: Yongbin Kim <iam@yongbin.kim>
Date: Mon, 10 Oct 2022 21:28:30 +0900
Added JSONObjectArray
MarshalerJSONObjectArray(arr []T) encodes object slice, UnmarshalerJSONObjectArray(arr *[]T, constructor func() T) decodes object slice.
Both uses generics, so, you can use `[]*someObject` directly.
Signed-off-by: Yongbin Kim <iam@yongbin.kim>
Diffstat:
4 files changed, 157 insertions(+), 0 deletions(-)
diff --git a/decode_slice.go b/decode_slice.go
@@ -1,5 +1,27 @@
package gojay
+type unmarshalerJSONObjectArray[T UnmarshalerJSONObject] struct {
+ arr *[]T
+ constructor func() T
+}
+
+// UnmarshalerJSONObjectArray returns UnmarshalerJSONArray interface for given slice
+func UnmarshalerJSONObjectArray[T UnmarshalerJSONObject](arr *[]T, constructor func() T) UnmarshalerJSONArray {
+ return &unmarshalerJSONObjectArray[T]{
+ arr: arr,
+ constructor: constructor,
+ }
+}
+
+func (a *unmarshalerJSONObjectArray[T]) UnmarshalJSONArray(dec *Decoder) error {
+ t := a.constructor()
+ if err := dec.Object(t); err != nil {
+ return err
+ }
+ *a.arr = append(*a.arr, t)
+ return nil
+}
+
// AddSliceString unmarshals the next JSON array of strings to the given *[]string s
func (dec *Decoder) AddSliceString(s *[]string) error {
return dec.SliceString(s)
diff --git a/decode_slice_test.go b/decode_slice_test.go
@@ -32,6 +32,64 @@ func (s *slicesTestObject) NKeys() int {
return 4
}
+func TestUnmarshalerJSONObjectArray(t *testing.T) {
+ testCases := []struct {
+ name string
+ json string
+ expectedResult []*slicesTestObject
+ err bool
+ }{
+ {
+ name: "basic string array",
+ json: `[{
+ "sliceString": ["foo","bar"]
+ }]`,
+ expectedResult: []*slicesTestObject{{
+ sliceString: []string{"foo", "bar"},
+ }},
+ },
+ {
+ name: "many string array",
+ json: `[{
+ "sliceString": ["foo1","bar"]
+ },{
+ "sliceString": ["foo2","bar"]
+ },{
+ "sliceString": ["foo3","bar"]
+ }]`,
+ expectedResult: []*slicesTestObject{{
+ sliceString: []string{"foo1", "bar"},
+ }, {
+ sliceString: []string{"foo2", "bar"},
+ }, {
+ sliceString: []string{"foo3", "bar"},
+ }},
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(
+ testCase.name,
+ func(t *testing.T) {
+ dec := BorrowDecoder(strings.NewReader(testCase.json))
+ var slice []*slicesTestObject
+ err := dec.Decode(UnmarshalerJSONObjectArray(
+ &slice,
+ func() *slicesTestObject {
+ return &slicesTestObject{}
+ },
+ ))
+
+ if testCase.err {
+ require.NotNil(t, err, "err should not be nil")
+ return
+ }
+ require.Nil(t, err, "err should be nil")
+ require.Equal(t, testCase.expectedResult, slice)
+ },
+ )
+ }
+}
+
func TestDecodeSlices(t *testing.T) {
testCases := []struct {
name string
diff --git a/encode_slice.go b/encode_slice.go
@@ -1,5 +1,22 @@
package gojay
+type marshalerObjectArray[T MarshalerJSONObject] []T
+
+// MarshalerJSONObjectArray returns MarshalerJSONArray interface for given slice
+func MarshalerJSONObjectArray[T MarshalerJSONObject](arr []T) MarshalerJSONArray {
+ return marshalerObjectArray[T](arr)
+}
+
+func (arr marshalerObjectArray[T]) MarshalJSONArray(enc *Encoder) {
+ for _, obj := range arr {
+ enc.Object(obj)
+ }
+}
+
+func (arr marshalerObjectArray[T]) IsNil() bool {
+ return len(arr) == 0
+}
+
// AddSliceString marshals the given []string s
func (enc *Encoder) AddSliceString(s []string) {
enc.SliceString(s)
diff --git a/encode_slice_test.go b/encode_slice_test.go
@@ -18,6 +18,66 @@ func (s *slicesTestObject) IsNil() bool {
return s == nil
}
+func TestMarshalerJSONObjectArray(t *testing.T) {
+ testCases := []struct {
+ name string
+ json string
+ obj []*slicesTestObject
+ }{
+ {
+ name: "basic slice",
+ json: `[{
+ "sliceString": ["foo","bar"],
+ "sliceInt": [],
+ "sliceFloat64": [],
+ "sliceBool": []
+ }]`,
+ obj: []*slicesTestObject{{
+ sliceString: []string{"foo", "bar"},
+ }},
+ },
+ {
+ name: "many slices",
+ json: `[{
+ "sliceString": ["foo1","bar"],
+ "sliceInt": [],
+ "sliceFloat64": [],
+ "sliceBool": []
+ }, {
+ "sliceString": ["foo2","bar"],
+ "sliceInt": [],
+ "sliceFloat64": [],
+ "sliceBool": []
+ }, {
+ "sliceString": ["foo3","bar"],
+ "sliceInt": [],
+ "sliceFloat64": [],
+ "sliceBool": []
+ }]`,
+ obj: []*slicesTestObject{{
+ sliceString: []string{"foo1", "bar"},
+ }, {
+ sliceString: []string{"foo2", "bar"},
+ }, {
+ sliceString: []string{"foo3", "bar"},
+ }},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(
+ testCase.name,
+ func(t *testing.T) {
+ b := strings.Builder{}
+ enc := BorrowEncoder(&b)
+ err := enc.EncodeArray(MarshalerJSONObjectArray(testCase.obj))
+ require.Nil(t, err, "err should be nil")
+ require.JSONEq(t, testCase.json, b.String())
+ },
+ )
+ }
+}
+
func TestEncodeSlices(t *testing.T) {
testCases := []struct {
name string