commit a5068885b61dc3bbf5c753d34a3e2647772d3a00
parent 024cbd81efc4632394c4c7422263c5f7e09ec8cc
Author: Francois Parquet <francois.parquet@gmail.com>
Date: Tue, 21 Aug 2018 18:07:18 +0800
Merge pull request #63 from francoispqt/add-marshal-null-empty-methods
add handling of null empty and add null methods
Diffstat:
19 files changed, 1951 insertions(+), 6 deletions(-)
diff --git a/encode.go b/encode.go
@@ -1,12 +1,14 @@
package gojay
import (
- "io"
+ "encoding/json"
"fmt"
+ "io"
"reflect"
- "encoding/json"
)
+var nullBytes = []byte("null")
+
// MarshalJSONObject returns the JSON encoding of v.
//
// It takes a struct implementing Marshaler to a JSON slice of byte
@@ -178,7 +180,7 @@ func marshal(v interface{}, any bool) ([]byte, error) {
return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String()))
}
- } ()
+ }()
enc.Release()
return buf, err
diff --git a/encode_array.go b/encode_array.go
@@ -28,11 +28,17 @@ func (enc *Encoder) AddArray(v MarshalerJSONArray) {
}
// AddArrayOmitEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
-// value must implement Marshaler
+// value must implement MarshalerAddArrayOmitEmpty
func (enc *Encoder) AddArrayOmitEmpty(v MarshalerJSONArray) {
enc.ArrayOmitEmpty(v)
}
+// AddArrayNullEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
+// value must implement Marshaler, if v is empty, `null` will be encoded`
+func (enc *Encoder) AddArrayNullEmpty(v MarshalerJSONArray) {
+ enc.ArrayNullEmpty(v)
+}
+
// AddArrayKey adds an array or slice to be encoded, must be used inside an object as it will encode a key
// value must implement Marshaler
func (enc *Encoder) AddArrayKey(key string, v MarshalerJSONArray) {
@@ -45,6 +51,12 @@ func (enc *Encoder) AddArrayKeyOmitEmpty(key string, v MarshalerJSONArray) {
enc.ArrayKeyOmitEmpty(key, v)
}
+// AddArrayKeyNullEmpty adds an array or slice to be encoded and skips it if it is nil.
+// Must be called inside an object as it will encode a key. `null` will be encoded`
+func (enc *Encoder) AddArrayKeyNullEmpty(key string, v MarshalerJSONArray) {
+ enc.ArrayKeyNullEmpty(key, v)
+}
+
// Array adds an implementation of MarshalerJSONArray to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
func (enc *Encoder) Array(v MarshalerJSONArray) {
@@ -84,6 +96,23 @@ func (enc *Encoder) ArrayOmitEmpty(v MarshalerJSONArray) {
enc.writeByte(']')
}
+// ArrayNullEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
+// value must implement Marshaler
+func (enc *Encoder) ArrayNullEmpty(v MarshalerJSONArray) {
+ enc.grow(4)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v.IsNil() {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeByte('[')
+ v.MarshalJSONArray(enc)
+ enc.writeByte(']')
+}
+
// ArrayKey adds an array or slice to be encoded, must be used inside an object as it will encode a key
// value must implement Marshaler
func (enc *Encoder) ArrayKey(key string, v MarshalerJSONArray) {
@@ -111,7 +140,7 @@ func (enc *Encoder) ArrayKey(key string, v MarshalerJSONArray) {
enc.writeByte(']')
}
-// ArrayKeyOmitEmpty adds an array or slice to be encoded and skips it if it is nil.
+// ArrayKeyOmitEmpty adds an array or slice to be encoded and skips if it is nil.
// Must be called inside an object as it will encode a key.
func (enc *Encoder) ArrayKeyOmitEmpty(key string, v MarshalerJSONArray) {
if v.IsNil() {
@@ -129,6 +158,25 @@ func (enc *Encoder) ArrayKeyOmitEmpty(key string, v MarshalerJSONArray) {
enc.writeByte(']')
}
+// ArrayKeyNullEmpty adds an array or slice to be encoded and encodes `null`` if it is nil.
+// Must be called inside an object as it will encode a key.
+func (enc *Encoder) ArrayKeyNullEmpty(key string, v MarshalerJSONArray) {
+ enc.grow(5 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ if v.IsNil() {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKeyArr)
+ v.MarshalJSONArray(enc)
+ enc.writeByte(']')
+}
+
// EncodeArrayFunc is a custom func type implementing MarshaleArray.
// Use it to cast a func(*Encoder) to Marshal an object.
//
diff --git a/encode_array_test.go b/encode_array_test.go
@@ -336,3 +336,57 @@ func TestEncoderArrayFunc(t *testing.T) {
var f EncodeArrayFunc
assert.True(t, f.IsNil())
}
+
+func TestEncodeArrayNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name, baseJSON, expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,["foo"]`,
+ },
+ {
+ name: "basic 1st elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,["foo"]`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddArrayNullEmpty(&TestEncodingArrStrings{})
+ enc.ArrayNullEmpty(&TestEncodingArrStrings{"foo"})
+ })
+ }
+}
+
+func TestEncodeArrayKeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name, baseJSON, expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":["foo"]`,
+ },
+ {
+ name: "basic 1st elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":["foo"]`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddArrayKeyNullEmpty("foo", &TestEncodingArrStrings{})
+ enc.ArrayKeyNullEmpty("bar", &TestEncodingArrStrings{"foo"})
+ })
+ }
+}
diff --git a/encode_bool.go b/encode_bool.go
@@ -37,17 +37,28 @@ func (enc *Encoder) AddBoolOmitEmpty(v bool) {
enc.BoolOmitEmpty(v)
}
+// AddBoolNullEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddBoolNullEmpty(v bool) {
+ enc.BoolNullEmpty(v)
+}
+
// AddBoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKey(key string, v bool) {
enc.BoolKey(key, v)
}
-// AddBoolKeyOmitEmpty adds a bool to be encoded and skips it if it is zero value.
+// AddBoolKeyOmitEmpty adds a bool to be encoded and skips if it is zero value.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKeyOmitEmpty(key string, v bool) {
enc.BoolKeyOmitEmpty(key, v)
}
+// AddBoolKeyNullEmpty adds a bool to be encoded and encodes `null` if it is zero value.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddBoolKeyNullEmpty(key string, v bool) {
+ enc.BoolKeyNullEmpty(key, v)
+}
+
// Bool adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Bool(v bool) {
enc.grow(5)
@@ -75,6 +86,20 @@ func (enc *Encoder) BoolOmitEmpty(v bool) {
enc.writeString("true")
}
+// BoolNullEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) BoolNullEmpty(v bool) {
+ enc.grow(5)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == false {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeString("true")
+}
+
// BoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
func (enc *Encoder) BoolKey(key string, value bool) {
enc.grow(5 + len(key))
@@ -104,3 +129,21 @@ func (enc *Encoder) BoolKeyOmitEmpty(key string, v bool) {
enc.writeBytes(objKey)
enc.buf = strconv.AppendBool(enc.buf, v)
}
+
+// BoolKeyNullEmpty adds a bool to be encoded and skips it if it is zero value.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) BoolKeyNullEmpty(key string, v bool) {
+ enc.grow(5 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == false {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendBool(enc.buf, v)
+}
diff --git a/encode_bool_test.go b/encode_bool_test.go
@@ -62,3 +62,63 @@ func TestEncoderBoolErrors(t *testing.T) {
assert.NotNil(t, err, "err should not be nil")
})
}
+
+func TestEncoderBoolNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: "[null,true",
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,true`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.BoolNullEmpty(false)
+ enc.AddBoolNullEmpty(true)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderBoolNullKeyEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":true`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":true`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.BoolKeyNullEmpty("foo", false)
+ enc.AddBoolKeyNullEmpty("bar", true)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_null.go b/encode_null.go
@@ -0,0 +1,34 @@
+package gojay
+
+// AddNull adds a `null` to be encoded. Must be used while encoding an array.`
+func (enc *Encoder) AddNull() {
+ enc.Null()
+}
+
+// Null adds a `null` to be encoded. Must be used while encoding an array.`
+func (enc *Encoder) Null() {
+ enc.grow(5)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ enc.writeBytes(nullBytes)
+}
+
+// AddNullKey adds a `null` to be encoded. Must be used while encoding an array.`
+func (enc *Encoder) AddNullKey(key string) {
+ enc.NullKey(key)
+}
+
+// NullKey adds a `null` to be encoded. Must be used while encoding an array.`
+func (enc *Encoder) NullKey(key string) {
+ enc.grow(5 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ enc.writeBytes(nullBytes)
+}
diff --git a/encode_null_test.go b/encode_null_test.go
@@ -0,0 +1,70 @@
+package gojay
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEncodeNull(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st element",
+ baseJSON: `[`,
+ expectedJSON: `[null,null`,
+ },
+ {
+ name: "basic last element",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,null`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Null()
+ enc.AddNull()
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncodeNullKey(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st element",
+ baseJSON: `{`,
+ expectedJSON: `{"foo":null,"bar":null`,
+ },
+ {
+ name: "basic last element",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":null`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.NullKey("foo")
+ enc.AddNullKey("bar")
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_number_float.go b/encode_number_float.go
@@ -50,6 +50,12 @@ func (enc *Encoder) AddFloatOmitEmpty(v float64) {
enc.Float64OmitEmpty(v)
}
+// AddFloatNullEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddFloatNullEmpty(v float64) {
+ enc.Float64NullEmpty(v)
+}
+
// Float adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float(v float64) {
enc.Float64(v)
@@ -61,6 +67,12 @@ func (enc *Encoder) FloatOmitEmpty(v float64) {
enc.Float64OmitEmpty(v)
}
+// FloatNullEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) FloatNullEmpty(v float64) {
+ enc.Float64NullEmpty(v)
+}
+
// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloatKey(key string, v float64) {
enc.Float64Key(key, v)
@@ -72,6 +84,12 @@ func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
enc.Float64KeyOmitEmpty(key, v)
}
+// AddFloatKeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddFloatKeyNullEmpty(key string, v float64) {
+ enc.Float64KeyNullEmpty(key, v)
+}
+
// FloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) FloatKey(key string, v float64) {
enc.Float64Key(key, v)
@@ -83,6 +101,12 @@ func (enc *Encoder) FloatKeyOmitEmpty(key string, v float64) {
enc.Float64KeyOmitEmpty(key, v)
}
+// FloatKeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) FloatKeyNullEmpty(key string, v float64) {
+ enc.Float64KeyNullEmpty(key, v)
+}
+
// AddFloat64 adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat64(v float64) {
enc.Float(v)
@@ -118,6 +142,21 @@ func (enc *Encoder) Float64OmitEmpty(v float64) {
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
+// Float64NullEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Float64NullEmpty(v float64) {
+ enc.grow(10)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
+}
+
// AddFloat64Key adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat64Key(key string, v float64) {
enc.FloatKey(key, v)
@@ -159,6 +198,24 @@ func (enc *Encoder) Float64KeyOmitEmpty(key string, v float64) {
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
+// Float64KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Float64KeyNullEmpty(key string, v float64) {
+ enc.grow(10 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
+}
+
// AddFloat32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat32(v float32) {
enc.Float32(v)
@@ -170,6 +227,12 @@ func (enc *Encoder) AddFloat32OmitEmpty(v float32) {
enc.Float32OmitEmpty(v)
}
+// AddFloat32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddFloat32NullEmpty(v float32) {
+ enc.Float32NullEmpty(v)
+}
+
// Float32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float32(v float32) {
r := enc.getPreviousRune()
@@ -193,6 +256,21 @@ func (enc *Encoder) Float32OmitEmpty(v float32) {
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
+// Float32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Float32NullEmpty(v float32) {
+ enc.grow(10)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
+}
+
// AddFloat32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat32Key(key string, v float32) {
enc.Float32Key(key, v)
@@ -204,6 +282,12 @@ func (enc *Encoder) AddFloat32KeyOmitEmpty(key string, v float32) {
enc.Float32KeyOmitEmpty(key, v)
}
+// AddFloat32KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddFloat32KeyNullEmpty(key string, v float32) {
+ enc.Float32KeyNullEmpty(key, v)
+}
+
// Float32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Float32Key(key string, v float32) {
enc.grow(10 + len(key))
@@ -234,3 +318,21 @@ func (enc *Encoder) Float32KeyOmitEmpty(key string, v float32) {
enc.writeBytes(objKey)
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
+
+// Float32KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) Float32KeyNullEmpty(key string, v float32) {
+ enc.grow(10 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
+}
diff --git a/encode_number_float_test.go b/encode_number_float_test.go
@@ -117,3 +117,123 @@ func TestEncoderFloat64(t *testing.T) {
})
}
}
+
+func TestEncoderFloat64NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.FloatNullEmpty(0)
+ enc.AddFloatNullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderFloat64KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.FloatKeyNullEmpty("foo", 0)
+ enc.AddFloatKeyNullEmpty("bar", 1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderFloat32NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Float32NullEmpty(0)
+ enc.AddFloat32NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderFloat32KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Float32KeyNullEmpty("foo", 0)
+ enc.AddFloat32KeyNullEmpty("bar", 1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_number_int.go b/encode_number_int.go
@@ -51,6 +51,12 @@ func (enc *Encoder) AddIntOmitEmpty(v int) {
enc.IntOmitEmpty(v)
}
+// AddIntNullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddIntNullEmpty(v int) {
+ enc.IntNullEmpty(v)
+}
+
// Int adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int(v int) {
enc.grow(10)
@@ -75,6 +81,21 @@ func (enc *Encoder) IntOmitEmpty(v int) {
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
+// IntNullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) IntNullEmpty(v int) {
+ enc.grow(10)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
+}
+
// AddIntKey adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddIntKey(key string, v int) {
enc.IntKey(key, v)
@@ -86,6 +107,12 @@ func (enc *Encoder) AddIntKeyOmitEmpty(key string, v int) {
enc.IntKeyOmitEmpty(key, v)
}
+// AddIntKeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddIntKeyNullEmpty(key string, v int) {
+ enc.IntKeyNullEmpty(key, v)
+}
+
// IntKey adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) IntKey(key string, v int) {
enc.grow(10 + len(key))
@@ -116,6 +143,24 @@ func (enc *Encoder) IntKeyOmitEmpty(key string, v int) {
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
+// IntKeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) IntKeyNullEmpty(key string, v int) {
+ enc.grow(10 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
+}
+
// AddInt64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt64(v int64) {
enc.Int64(v)
@@ -127,6 +172,12 @@ func (enc *Encoder) AddInt64OmitEmpty(v int64) {
enc.Int64OmitEmpty(v)
}
+// AddInt64NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddInt64NullEmpty(v int64) {
+ enc.Int64NullEmpty(v)
+}
+
// Int64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int64(v int64) {
enc.grow(10)
@@ -151,6 +202,21 @@ func (enc *Encoder) Int64OmitEmpty(v int64) {
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
+// Int64NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Int64NullEmpty(v int64) {
+ enc.grow(10)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendInt(enc.buf, v, 10)
+}
+
// AddInt64Key adds an int64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt64Key(key string, v int64) {
enc.Int64Key(key, v)
@@ -162,6 +228,12 @@ func (enc *Encoder) AddInt64KeyOmitEmpty(key string, v int64) {
enc.Int64KeyOmitEmpty(key, v)
}
+// AddInt64KeyNullEmpty adds an int64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddInt64KeyNullEmpty(key string, v int64) {
+ enc.Int64KeyNullEmpty(key, v)
+}
+
// Int64Key adds an int64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int64Key(key string, v int64) {
enc.grow(10 + len(key))
@@ -192,6 +264,24 @@ func (enc *Encoder) Int64KeyOmitEmpty(key string, v int64) {
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
+// Int64KeyNullEmpty adds an int64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Int64KeyNullEmpty(key string, v int64) {
+ enc.grow(10 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendInt(enc.buf, v, 10)
+}
+
// AddInt32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt32(v int32) {
enc.Int64(int64(v))
@@ -203,6 +293,12 @@ func (enc *Encoder) AddInt32OmitEmpty(v int32) {
enc.Int64OmitEmpty(int64(v))
}
+// AddInt32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddInt32NullEmpty(v int32) {
+ enc.Int64NullEmpty(int64(v))
+}
+
// Int32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int32(v int32) {
enc.Int64(int64(v))
@@ -214,6 +310,12 @@ func (enc *Encoder) Int32OmitEmpty(v int32) {
enc.Int64OmitEmpty(int64(v))
}
+// Int32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Int32NullEmpty(v int32) {
+ enc.Int64NullEmpty(int64(v))
+}
+
// AddInt32Key adds an int32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt32Key(key string, v int32) {
enc.Int64Key(key, int64(v))
@@ -236,6 +338,12 @@ func (enc *Encoder) Int32KeyOmitEmpty(key string, v int32) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
+// Int32KeyNullEmpty adds an int32 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Int32KeyNullEmpty(key string, v int32) {
+ enc.Int64KeyNullEmpty(key, int64(v))
+}
+
// AddInt16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt16(v int16) {
enc.Int64(int64(v))
@@ -258,6 +366,12 @@ func (enc *Encoder) Int16OmitEmpty(v int16) {
enc.Int64OmitEmpty(int64(v))
}
+// Int16NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Int16NullEmpty(v int16) {
+ enc.Int64NullEmpty(int64(v))
+}
+
// AddInt16Key adds an int16 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt16Key(key string, v int16) {
enc.Int64Key(key, int64(v))
@@ -269,6 +383,12 @@ func (enc *Encoder) AddInt16KeyOmitEmpty(key string, v int16) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
+// AddInt16KeyNullEmpty adds an int16 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddInt16KeyNullEmpty(key string, v int16) {
+ enc.Int64KeyNullEmpty(key, int64(v))
+}
+
// Int16Key adds an int16 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int16Key(key string, v int16) {
enc.Int64Key(key, int64(v))
@@ -280,6 +400,12 @@ func (enc *Encoder) Int16KeyOmitEmpty(key string, v int16) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
+// Int16KeyNullEmpty adds an int16 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Int16KeyNullEmpty(key string, v int16) {
+ enc.Int64KeyNullEmpty(key, int64(v))
+}
+
// AddInt8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt8(v int8) {
enc.Int64(int64(v))
@@ -291,6 +417,12 @@ func (enc *Encoder) AddInt8OmitEmpty(v int8) {
enc.Int64OmitEmpty(int64(v))
}
+// AddInt8NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddInt8NullEmpty(v int8) {
+ enc.Int64NullEmpty(int64(v))
+}
+
// Int8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int8(v int8) {
enc.Int64(int64(v))
@@ -302,6 +434,12 @@ func (enc *Encoder) Int8OmitEmpty(v int8) {
enc.Int64OmitEmpty(int64(v))
}
+// Int8NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Int8NullEmpty(v int8) {
+ enc.Int64NullEmpty(int64(v))
+}
+
// AddInt8Key adds an int8 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt8Key(key string, v int8) {
enc.Int64Key(key, int64(v))
@@ -313,6 +451,12 @@ func (enc *Encoder) AddInt8KeyOmitEmpty(key string, v int8) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
+// AddInt8KeyNullEmpty adds an int8 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddInt8KeyNullEmpty(key string, v int8) {
+ enc.Int64KeyNullEmpty(key, int64(v))
+}
+
// Int8Key adds an int8 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int8Key(key string, v int8) {
enc.Int64Key(key, int64(v))
@@ -323,3 +467,9 @@ func (enc *Encoder) Int8Key(key string, v int8) {
func (enc *Encoder) Int8KeyOmitEmpty(key string, v int8) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
+
+// Int8KeyNullEmpty adds an int8 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Int8KeyNullEmpty(key string, v int8) {
+ enc.Int64KeyNullEmpty(key, int64(v))
+}
diff --git a/encode_number_int_test.go b/encode_number_int_test.go
@@ -536,3 +536,303 @@ func TestEncoderInt8(t *testing.T) {
})
}
}
+
+func TestEncoderIntNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.IntNullEmpty(0)
+ enc.AddIntNullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderIntKeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.IntKeyNullEmpty("foo", 0)
+ enc.AddIntKeyNullEmpty("bar", 1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt64NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Int64NullEmpty(0)
+ enc.AddInt64NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt64KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Int64KeyNullEmpty("foo", 0)
+ enc.AddInt64KeyNullEmpty("bar", 1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt32NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Int32NullEmpty(0)
+ enc.AddInt32NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt32KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Int32KeyNullEmpty("foo", 0)
+ enc.Int32KeyNullEmpty("bar", int32(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt16NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Int16NullEmpty(0)
+ enc.Int16NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt16KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddInt16KeyNullEmpty("foo", 0)
+ enc.Int16KeyNullEmpty("bar", int16(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt8NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddInt8NullEmpty(0)
+ enc.Int8NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderInt8KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddInt8KeyNullEmpty("foo", 0)
+ enc.Int8KeyNullEmpty("bar", int8(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_number_uint.go b/encode_number_uint.go
@@ -32,6 +32,12 @@ func (enc *Encoder) AddUint64OmitEmpty(v uint64) {
enc.Uint64OmitEmpty(v)
}
+// AddUint64NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddUint64NullEmpty(v uint64) {
+ enc.Uint64NullEmpty(v)
+}
+
// Uint64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint64(v uint64) {
enc.grow(10)
@@ -56,6 +62,21 @@ func (enc *Encoder) Uint64OmitEmpty(v uint64) {
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
+// Uint64NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Uint64NullEmpty(v uint64) {
+ enc.grow(10)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendUint(enc.buf, v, 10)
+}
+
// AddUint64Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint64Key(key string, v uint64) {
enc.Uint64Key(key, v)
@@ -67,6 +88,12 @@ func (enc *Encoder) AddUint64KeyOmitEmpty(key string, v uint64) {
enc.Uint64KeyOmitEmpty(key, v)
}
+// AddUint64KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddUint64KeyNullEmpty(key string, v uint64) {
+ enc.Uint64KeyNullEmpty(key, v)
+}
+
// Uint64Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint64Key(key string, v uint64) {
enc.grow(10 + len(key))
@@ -97,6 +124,24 @@ func (enc *Encoder) Uint64KeyOmitEmpty(key string, v uint64) {
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
+// Uint64KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Uint64KeyNullEmpty(key string, v uint64) {
+ enc.grow(10 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == 0 {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.buf = strconv.AppendUint(enc.buf, v, 10)
+}
+
// AddUint32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint32(v uint32) {
enc.Uint64(uint64(v))
@@ -108,6 +153,12 @@ func (enc *Encoder) AddUint32OmitEmpty(v uint32) {
enc.Uint64OmitEmpty(uint64(v))
}
+// AddUint32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddUint32NullEmpty(v uint32) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// Uint32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint32(v uint32) {
enc.Uint64(uint64(v))
@@ -119,6 +170,12 @@ func (enc *Encoder) Uint32OmitEmpty(v uint32) {
enc.Uint64OmitEmpty(uint64(v))
}
+// Uint32NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Uint32NullEmpty(v uint32) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// AddUint32Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint32Key(key string, v uint32) {
enc.Uint64Key(key, uint64(v))
@@ -130,6 +187,12 @@ func (enc *Encoder) AddUint32KeyOmitEmpty(key string, v uint32) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+// AddUint32KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddUint32KeyNullEmpty(key string, v uint32) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
+
// Uint32Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint32Key(key string, v uint32) {
enc.Uint64Key(key, uint64(v))
@@ -141,6 +204,12 @@ func (enc *Encoder) Uint32KeyOmitEmpty(key string, v uint32) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+// Uint32KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Uint32KeyNullEmpty(key string, v uint32) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
+
// AddUint16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint16(v uint16) {
enc.Uint64(uint64(v))
@@ -152,6 +221,12 @@ func (enc *Encoder) AddUint16OmitEmpty(v uint16) {
enc.Uint64OmitEmpty(uint64(v))
}
+// AddUint16NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddUint16NullEmpty(v uint16) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// Uint16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint16(v uint16) {
enc.Uint64(uint64(v))
@@ -163,6 +238,12 @@ func (enc *Encoder) Uint16OmitEmpty(v uint16) {
enc.Uint64OmitEmpty(uint64(v))
}
+// Uint16NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Uint16NullEmpty(v uint16) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// AddUint16Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint16Key(key string, v uint16) {
enc.Uint64Key(key, uint64(v))
@@ -174,6 +255,12 @@ func (enc *Encoder) AddUint16KeyOmitEmpty(key string, v uint16) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+// AddUint16KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddUint16KeyNullEmpty(key string, v uint16) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
+
// Uint16Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint16Key(key string, v uint16) {
enc.Uint64Key(key, uint64(v))
@@ -185,6 +272,12 @@ func (enc *Encoder) Uint16KeyOmitEmpty(key string, v uint16) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+// Uint16KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Uint16KeyNullEmpty(key string, v uint16) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
+
// AddUint8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint8(v uint8) {
enc.Uint64(uint64(v))
@@ -196,6 +289,12 @@ func (enc *Encoder) AddUint8OmitEmpty(v uint8) {
enc.Uint64OmitEmpty(uint64(v))
}
+// AddUint8NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddUint8NullEmpty(v uint8) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// Uint8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint8(v uint8) {
enc.Uint64(uint64(v))
@@ -207,6 +306,12 @@ func (enc *Encoder) Uint8OmitEmpty(v uint8) {
enc.Uint64OmitEmpty(uint64(v))
}
+// Uint8NullEmpty adds an int to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) Uint8NullEmpty(v uint8) {
+ enc.Uint64NullEmpty(uint64(v))
+}
+
// AddUint8Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint8Key(key string, v uint8) {
enc.Uint64Key(key, uint64(v))
@@ -218,6 +323,12 @@ func (enc *Encoder) AddUint8KeyOmitEmpty(key string, v uint8) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+// AddUint8KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) AddUint8KeyNullEmpty(key string, v uint8) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
+
// Uint8Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint8Key(key string, v uint8) {
enc.Uint64Key(key, uint64(v))
@@ -228,3 +339,9 @@ func (enc *Encoder) Uint8Key(key string, v uint8) {
func (enc *Encoder) Uint8KeyOmitEmpty(key string, v uint8) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
+
+// Uint8KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key.
+func (enc *Encoder) Uint8KeyNullEmpty(key string, v uint8) {
+ enc.Uint64KeyNullEmpty(key, uint64(v))
+}
diff --git a/encode_number_uint_test.go b/encode_number_uint_test.go
@@ -531,3 +531,243 @@ func TestEncoderUint8(t *testing.T) {
})
}
}
+
+func TestEncoderUint64NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Uint64NullEmpty(0)
+ enc.AddUint64NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint64KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Uint64KeyNullEmpty("foo", 0)
+ enc.AddUint64KeyNullEmpty("bar", 1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint32NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.Uint32NullEmpty(0)
+ enc.AddUint32NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint32KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddUint32KeyNullEmpty("foo", 0)
+ enc.Uint32KeyNullEmpty("bar", uint32(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint16NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddUint16NullEmpty(0)
+ enc.Uint16NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint16KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddUint16KeyNullEmpty("foo", 0)
+ enc.Uint16KeyNullEmpty("bar", uint16(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint8NullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddUint8NullEmpty(0)
+ enc.Uint8NullEmpty(1)
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderUint8KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddUint8KeyNullEmpty("foo", 0)
+ enc.Uint8KeyNullEmpty("bar", uint8(1))
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_object.go b/encode_object.go
@@ -46,6 +46,13 @@ func (enc *Encoder) AddObjectOmitEmpty(v MarshalerJSONObject) {
enc.ObjectOmitEmpty(v)
}
+// AddObjectNullEmpty 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
+func (enc *Encoder) AddObjectNullEmpty(v MarshalerJSONObject) {
+ enc.ObjectNullEmpty(v)
+}
+
// AddObjectKey adds a struct to be encoded, must be used inside an object as it will encode a key
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectKey(key string, v MarshalerJSONObject) {
@@ -59,6 +66,13 @@ func (enc *Encoder) AddObjectKeyOmitEmpty(key string, v MarshalerJSONObject) {
enc.ObjectKeyOmitEmpty(key, v)
}
+// AddObjectKeyNullEmpty 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
+func (enc *Encoder) AddObjectKeyNullEmpty(key string, v MarshalerJSONObject) {
+ enc.ObjectKeyNullEmpty(key, v)
+}
+
// Object adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) Object(v MarshalerJSONObject) {
@@ -99,6 +113,24 @@ func (enc *Encoder) ObjectOmitEmpty(v MarshalerJSONObject) {
enc.writeByte('}')
}
+// ObjectNullEmpty 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
+func (enc *Encoder) ObjectNullEmpty(v MarshalerJSONObject) {
+ enc.grow(2)
+ r := enc.getPreviousRune()
+ if r != '[' {
+ enc.writeByte(',')
+ }
+ if v.IsNil() {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeByte('{')
+ v.MarshalJSONObject(enc)
+ enc.writeByte('}')
+}
+
// ObjectKey adds a struct to be encoded, must be used inside an object as it will encode a key
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectKey(key string, value MarshalerJSONObject) {
@@ -145,6 +177,27 @@ func (enc *Encoder) ObjectKeyOmitEmpty(key string, value MarshalerJSONObject) {
enc.writeByte('}')
}
+// ObjectKeyNullEmpty 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
+func (enc *Encoder) ObjectKeyNullEmpty(key string, value MarshalerJSONObject) {
+ enc.grow(5 + len(key))
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeByte(',')
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if value.IsNil() {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeByte('{')
+ value.MarshalJSONObject(enc)
+ enc.writeByte('}')
+}
+
// EncodeObjectFunc is a custom func type implementing MarshaleObject.
// Use it to cast a func(*Encoder) to Marshal an object.
//
diff --git a/encode_object_test.go b/encode_object_test.go
@@ -419,3 +419,63 @@ func TestEncoderObjectEncodeAPIError(t *testing.T) {
assert.True(t, false, "should not be called as it should have panicked")
})
}
+
+func TestEncoderObjectKeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddObjectKeyNullEmpty("foo", (*TestEncoding)(nil))
+ enc.ObjectKeyNullEmpty("bar", &TestEncoding{})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderObjectNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddObjectNullEmpty((*TestEncoding)(nil))
+ enc.ObjectNullEmpty(&TestEncoding{})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_sqlnull.go b/encode_sqlnull.go
@@ -29,6 +29,14 @@ func (enc *Encoder) AddSQLNullStringOmitEmpty(v *sql.NullString) {
}
}
+// AddSQLNullStringNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddSQLNullStringNullEmpty(v *sql.NullString) {
+ if v != nil && v.Valid {
+ enc.StringNullEmpty(v.String)
+ }
+}
+
// AddSQLNullStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullStringKey(key string, v *sql.NullString) {
enc.StringKey(key, v.String)
@@ -54,6 +62,13 @@ func (enc *Encoder) SQLNullStringOmitEmpty(v *sql.NullString) {
}
}
+// SQLNullStringNullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullStringNullEmpty(v *sql.NullString) {
+ if v != nil && v.Valid {
+ enc.StringNullEmpty(v.String)
+ }
+}
+
// SQLNullStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringKey(key string, v *sql.NullString) {
enc.StringKey(key, v.String)
@@ -67,6 +82,14 @@ func (enc *Encoder) SQLNullStringKeyOmitEmpty(key string, v *sql.NullString) {
}
}
+// SQLNullStringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullStringKeyNullEmpty(key string, v *sql.NullString) {
+ if v != nil && v.Valid {
+ enc.StringKeyNullEmpty(key, v.String)
+ }
+}
+
// NullInt64
// EncodeSQLNullInt64 encodes a string to
@@ -96,6 +119,14 @@ func (enc *Encoder) AddSQLNullInt64OmitEmpty(v *sql.NullInt64) {
}
}
+// AddSQLNullInt64NullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddSQLNullInt64NullEmpty(v *sql.NullInt64) {
+ if v != nil && v.Valid {
+ enc.Int64NullEmpty(v.Int64)
+ }
+}
+
// AddSQLNullInt64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullInt64Key(key string, v *sql.NullInt64) {
enc.Int64Key(key, v.Int64)
@@ -109,6 +140,14 @@ func (enc *Encoder) AddSQLNullInt64KeyOmitEmpty(key string, v *sql.NullInt64) {
}
}
+// AddSQLNullInt64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddSQLNullInt64KeyNullEmpty(key string, v *sql.NullInt64) {
+ if v != nil && v.Valid {
+ enc.Int64KeyNullEmpty(key, v.Int64)
+ }
+}
+
// SQLNullInt64 adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64(v *sql.NullInt64) {
enc.Int64(v.Int64)
@@ -121,6 +160,13 @@ func (enc *Encoder) SQLNullInt64OmitEmpty(v *sql.NullInt64) {
}
}
+// SQLNullInt64NullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullInt64NullEmpty(v *sql.NullInt64) {
+ if v != nil && v.Valid {
+ enc.Int64NullEmpty(v.Int64)
+ }
+}
+
// SQLNullInt64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64Key(key string, v *sql.NullInt64) {
enc.Int64Key(key, v.Int64)
@@ -134,6 +180,14 @@ func (enc *Encoder) SQLNullInt64KeyOmitEmpty(key string, v *sql.NullInt64) {
}
}
+// SQLNullInt64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullInt64KeyNullEmpty(key string, v *sql.NullInt64) {
+ if v != nil && v.Valid {
+ enc.Int64KeyNullEmpty(key, v.Int64)
+ }
+}
+
// NullFloat64
// EncodeSQLNullFloat64 encodes a string to
@@ -163,6 +217,14 @@ func (enc *Encoder) AddSQLNullFloat64OmitEmpty(v *sql.NullFloat64) {
}
}
+// AddSQLNullFloat64NullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddSQLNullFloat64NullEmpty(v *sql.NullFloat64) {
+ if v != nil && v.Valid {
+ enc.Float64NullEmpty(v.Float64)
+ }
+}
+
// AddSQLNullFloat64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullFloat64Key(key string, v *sql.NullFloat64) {
enc.Float64Key(key, v.Float64)
@@ -176,6 +238,14 @@ func (enc *Encoder) AddSQLNullFloat64KeyOmitEmpty(key string, v *sql.NullFloat64
}
}
+// AddSQLNullFloat64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddSQLNullFloat64KeyNullEmpty(key string, v *sql.NullFloat64) {
+ if v != nil && v.Valid {
+ enc.Float64KeyNullEmpty(key, v.Float64)
+ }
+}
+
// SQLNullFloat64 adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64(v *sql.NullFloat64) {
enc.Float64(v.Float64)
@@ -188,6 +258,13 @@ func (enc *Encoder) SQLNullFloat64OmitEmpty(v *sql.NullFloat64) {
}
}
+// SQLNullFloat64NullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullFloat64NullEmpty(v *sql.NullFloat64) {
+ if v != nil && v.Valid {
+ enc.Float64NullEmpty(v.Float64)
+ }
+}
+
// SQLNullFloat64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64Key(key string, v *sql.NullFloat64) {
enc.Float64Key(key, v.Float64)
@@ -201,6 +278,14 @@ func (enc *Encoder) SQLNullFloat64KeyOmitEmpty(key string, v *sql.NullFloat64) {
}
}
+// SQLNullFloat64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullFloat64KeyNullEmpty(key string, v *sql.NullFloat64) {
+ if v != nil && v.Valid {
+ enc.Float64KeyNullEmpty(key, v.Float64)
+ }
+}
+
// NullBool
// EncodeSQLNullBool encodes a string to
@@ -243,6 +328,14 @@ func (enc *Encoder) AddSQLNullBoolKeyOmitEmpty(key string, v *sql.NullBool) {
}
}
+// AddSQLNullBoolKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddSQLNullBoolKeyNullEmpty(key string, v *sql.NullBool) {
+ if v != nil && v.Valid {
+ enc.BoolKeyNullEmpty(key, v.Bool)
+ }
+}
+
// SQLNullBool adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBool(v *sql.NullBool) {
enc.Bool(v.Bool)
@@ -255,6 +348,13 @@ func (enc *Encoder) SQLNullBoolOmitEmpty(v *sql.NullBool) {
}
}
+// SQLNullBoolNullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullBoolNullEmpty(v *sql.NullBool) {
+ if v != nil && v.Valid {
+ enc.BoolNullEmpty(v.Bool)
+ }
+}
+
// SQLNullBoolKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolKey(key string, v *sql.NullBool) {
enc.BoolKey(key, v.Bool)
@@ -267,3 +367,11 @@ func (enc *Encoder) SQLNullBoolKeyOmitEmpty(key string, v *sql.NullBool) {
enc.BoolKeyOmitEmpty(key, v.Bool)
}
}
+
+// SQLNullBoolKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) SQLNullBoolKeyNullEmpty(key string, v *sql.NullBool) {
+ if v != nil && v.Valid {
+ enc.BoolKeyNullEmpty(key, v.Bool)
+ }
+}
diff --git a/encode_sqlnull_test.go b/encode_sqlnull_test.go
@@ -1119,3 +1119,243 @@ func TestAddSQLNullBool(t *testing.T) {
},
)
}
+
+func TestEncoderSQLNullStringEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,"bar"`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,"bar"`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullStringNullEmpty(&sql.NullString{"", true})
+ enc.SQLNullStringNullEmpty(&sql.NullString{"bar", true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullStringKeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":"bar"`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":"bar"`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.SQLNullStringKeyNullEmpty("foo", &sql.NullString{"", true})
+ enc.SQLNullStringKeyNullEmpty("bar", &sql.NullString{"bar", true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullBoolEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,true`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,true`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.SQLNullBoolNullEmpty(&sql.NullBool{false, true})
+ enc.SQLNullBoolNullEmpty(&sql.NullBool{true, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullBoolKeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":true`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":true`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullBoolKeyNullEmpty("foo", &sql.NullBool{false, true})
+ enc.SQLNullBoolKeyNullEmpty("bar", &sql.NullBool{true, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullInt64Empty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullInt64NullEmpty(&sql.NullInt64{0, true})
+ enc.SQLNullInt64NullEmpty(&sql.NullInt64{1, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullInt64KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullInt64KeyNullEmpty("foo", &sql.NullInt64{0, true})
+ enc.SQLNullInt64KeyNullEmpty("bar", &sql.NullInt64{1, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullFloat64Empty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullFloat64NullEmpty(&sql.NullFloat64{0, true})
+ enc.SQLNullFloat64NullEmpty(&sql.NullFloat64{1, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderSQLNullFloat64KeyNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":1`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":1`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.AddSQLNullFloat64KeyNullEmpty("foo", &sql.NullFloat64{0, true})
+ enc.SQLNullFloat64KeyNullEmpty("bar", &sql.NullFloat64{1, true})
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_string.go b/encode_string.go
@@ -41,6 +41,12 @@ func (enc *Encoder) AddStringOmitEmpty(v string) {
enc.StringOmitEmpty(v)
}
+// AddStringNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddStringNullEmpty(v string) {
+ enc.StringNullEmpty(v)
+}
+
// AddStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddStringKey(key, v string) {
enc.StringKey(key, v)
@@ -52,6 +58,12 @@ func (enc *Encoder) AddStringKeyOmitEmpty(key, v string) {
enc.StringKeyOmitEmpty(key, v)
}
+// AddStringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddStringKeyNullEmpty(key, v string) {
+ enc.StringKeyNullEmpty(key, v)
+}
+
// String adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) String(v string) {
enc.grow(len(v) + 4)
@@ -81,6 +93,28 @@ func (enc *Encoder) StringOmitEmpty(v string) {
enc.writeByte('"')
}
+// StringNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) StringNullEmpty(v string) {
+ r := enc.getPreviousRune()
+ if v == "" {
+ if r != '[' {
+ enc.writeByte(',')
+ enc.writeBytes(nullBytes)
+ } else {
+ enc.writeBytes(nullBytes)
+ }
+ return
+ }
+ if r != '[' {
+ enc.writeTwoBytes(',', '"')
+ } else {
+ enc.writeByte('"')
+ }
+ enc.writeStringEscape(v)
+ enc.writeByte('"')
+}
+
// StringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) StringKey(key, v string) {
enc.grow(len(key) + len(v) + 5)
@@ -114,3 +148,24 @@ func (enc *Encoder) StringKeyOmitEmpty(key, v string) {
enc.writeStringEscape(v)
enc.writeByte('"')
}
+
+// StringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) StringKeyNullEmpty(key, v string) {
+ enc.grow(len(key) + len(v) + 5)
+ r := enc.getPreviousRune()
+ if r != '{' {
+ enc.writeTwoBytes(',', '"')
+ } else {
+ enc.writeByte('"')
+ }
+ enc.writeStringEscape(key)
+ enc.writeBytes(objKey)
+ if v == "" {
+ enc.writeBytes(nullBytes)
+ return
+ }
+ enc.writeByte('"')
+ enc.writeStringEscape(v)
+ enc.writeByte('"')
+}
diff --git a/encode_string_test.go b/encode_string_test.go
@@ -162,3 +162,92 @@ func TestEncoderStringMarshalAPI(t *testing.T) {
"Result of marshalling is different as the one expected")
})
}
+
+func TestEncoderStringNullEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `[null,"true"`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,"true"`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `["test"`,
+ expectedJSON: `["test",null,"true"`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.StringNullEmpty("")
+ enc.AddStringNullEmpty("true")
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderStringNullEmpty2(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "[",
+ expectedJSON: `["test"`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.StringNullEmpty("test")
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
+
+func TestEncoderStringNullKeyEmpty(t *testing.T) {
+ var testCases = []struct {
+ name string
+ baseJSON string
+ expectedJSON string
+ }{
+ {
+ name: "basic 1st elem",
+ baseJSON: "{",
+ expectedJSON: `{"foo":null,"bar":"true"`,
+ },
+ {
+ name: "basic 2nd elem",
+ baseJSON: `{"test":"test"`,
+ expectedJSON: `{"test":"test","foo":null,"bar":"true"`,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run("true", func(t *testing.T) {
+ var b strings.Builder
+ var enc = NewEncoder(&b)
+ enc.writeString(testCase.baseJSON)
+ enc.StringKeyNullEmpty("foo", "")
+ enc.AddStringKeyNullEmpty("bar", "true")
+ enc.Write()
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}