Skip to content

Commit

Permalink
sq
Browse files Browse the repository at this point in the history
  • Loading branch information
jamietanna committed Jan 4, 2024
1 parent b1098f3 commit c56794f
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 2 deletions.
3 changes: 2 additions & 1 deletion types/nullable.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func (t *Nullable[T]) IsSet() bool {

// UnmarshalJSON implements the Unmarshaler interface.
func (t *Nullable[T]) UnmarshalJSON(data []byte) error {
fmt.Println(data)
t.Set = true
if bytes.Equal(data, nullBytes) {
// t.Null = true
Expand Down Expand Up @@ -71,7 +72,7 @@ func (t Nullable[T]) MarshalJSON() ([]byte, error) {
// IsNull returns true if the value is explicitly provided `null` in json
func (t *Nullable[T]) IsNull() bool {
if t == nil {
return true
return false
}

return t.Value == nil
Expand Down
206 changes: 205 additions & 1 deletion types/nullable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,58 @@ import (
"github.com/stretchr/testify/require"
)

/* ...... */
// Adapted from https://www.calhoun.io/how-to-determine-if-a-json-key-has-been-set-to-null-or-not-provided/
type Nullable_[T any] struct {
// Value contains the underlying value of the field. If `Set` is true, and `Null` is false, **??**
Value *T
// Set will be true if the field was sent
Set bool
// Valid will be true if the value is a valid type - either a value of T or as an explicit `null`
Valid bool
}

func (t *Nullable_[T]) UnmarshalJSON(data []byte) error {
// If this method is called, there was a value explicitly sent, which was either <nil> or a value of `T`
t.Set = true

// we received an explicit value of null
if string(data) == "null" {
// which is deemed valid, because we allow either <nil> or a value of `T`
t.Valid = true
t.Value = nil
return nil
}

// we received a value of `T`
var temp T
if err := json.Unmarshal(data, &temp); err != nil {
return err
}
t.Value = &temp
t.Valid = true
return nil
}

/* </adapted from https://www.calhoun.io/how-to-determine-if-a-json-key-has-been-set-to-null-or-not-provided/> */
/* ...... */

func (t *Nullable_[T]) IsSet() bool {
if t == nil {
return false
}

return t.Set
}

func (t *Nullable_[T]) IsValid() bool {
if t == nil {
return false
}

return t.Valid
}

func ExampleNullable_foo() {
obj := struct {
ID *Nullable[int] `json:"id,omitempty"`
Expand All @@ -18,6 +70,158 @@ func ExampleNullable_foo() {
// Output:
}

// func (t *Nullable_[T]) IsSet() bool {
// if t == nil {
// return false
// }
// return t.Set
// }
// func (t *Nullable_[T]) IsValid() bool {
// if t == nil {
// return false
// }
// return t.Valid
// }

// return t.Value == nil
// }

func TestNullable___foo(t *testing.T) {
obj := struct {
ID Nullable_[int] `json:"id"`
}{}

// when unset
obj.ID = Nullable_[int]{}
// assert.False(t, obj.ID.IsSet())
// assert.False(t, obj.ID.IsNull())
// assert.False(t, obj.ID.Valid)

// when empty body
obj.ID = Nullable_[int]{}
err := json.Unmarshal([]byte("{}"), &obj)
require.NoError(t, err)
fmt.Printf("empty\t%v: %v %v\n", obj.ID, obj.ID.IsSet(), obj.ID.IsValid())

// assert.False(t, obj.ID.IsSet())
// assert.False(t, obj.ID.IsNull())
// fmt.Printf("obj: %v\n", obj)
assert.False(t, obj.ID.IsValid())

// when explicit null body
obj.ID = Nullable_[int]{}
err = json.Unmarshal([]byte(`{"id": null}`), &obj)
require.NoError(t, err)
fmt.Printf("null\t%v: %v %v\n", obj.ID, obj.ID.IsSet(), obj.ID.IsValid())

// fmt.Printf("obj.ID: %#v\n", obj.ID)
// assert.True(t, obj.ID.IsSet())
// assert.True(t, obj.ID.IsNull())
assert.False(t, obj.ID.IsValid())

// when explicit zero value
obj.ID = Nullable_[int]{}
err = json.Unmarshal([]byte(`{"id": 0}`), &obj)
require.NoError(t, err)
fmt.Printf("zero\t%v: %v %v\n", obj.ID, obj.ID.IsSet(), obj.ID.IsValid())
if assert.NotNil(t, obj.ID.Value) {
fmt.Printf("obj.ID.Value: %v\n", *obj.ID.Value)
}

// assert.True(t, obj.ID.IsSet())
// assert.False(t, obj.ID.IsNull())
if assert.NotNil(t, obj.ID.Value) {
assert.Equal(t, 0, *obj.ID.Value)
}
assert.True(t, obj.ID.IsValid())

// when explicit value
obj.ID = Nullable_[int]{}
err = json.Unmarshal([]byte(`{"id": 1230}`), &obj)
require.NoError(t, err)
fmt.Printf("val\t%v: %v %v\n", obj.ID, obj.ID.IsSet(), obj.ID.IsValid())
if assert.NotNil(t, obj.ID.Value) {
fmt.Printf("obj.ID.Value: %v\n", *obj.ID.Value)
}

// assert.True(t, obj.ID.IsSet())
// assert.False(t, obj.ID.IsNull())
if assert.NotNil(t, obj.ID.Value) {
assert.Equal(t, 1230, *obj.ID.Value)
}
assert.True(t, obj.ID.Valid)
}

func TestNullable___food(t *testing.T) {
obj := struct {
ID *Nullable[int] `json:"id,omitempty"`
}{}

// when unset
obj.ID = nil
assert.False(t, obj.ID.IsSet())
assert.False(t, obj.ID.IsNull())

// when empty body
obj.ID = nil
err := json.Unmarshal([]byte("{}"), &obj)
require.NoError(t, err)

assert.False(t, obj.ID.IsSet())
assert.False(t, obj.ID.IsNull())

// when explicit null body
obj.ID = nil
err = json.Unmarshal([]byte(`{"id": null}`), &obj)
require.NoError(t, err)

fmt.Printf("obj.ID: %#v\n", obj.ID)
assert.True(t, obj.ID.IsSet())
assert.True(t, obj.ID.IsNull())

// when explicit zero value
obj.ID = nil
err = json.Unmarshal([]byte(`{"id": 0}`), &obj)
require.NoError(t, err)

assert.True(t, obj.ID.IsSet())
assert.False(t, obj.ID.IsNull())
if assert.NotNil(t, obj.ID.Value) {
assert.Equal(t, 0, *obj.ID.Value)
}

// when explicit value
obj.ID = nil
err = json.Unmarshal([]byte(`{"id": 1230}`), &obj)
require.NoError(t, err)

assert.True(t, obj.ID.IsSet())
assert.False(t, obj.ID.IsNull())
if assert.NotNil(t, obj.ID.Value) {
assert.Equal(t, 1230, *obj.ID.Value)
}
}

func TestNullable_UnmarshalJSON1(t *testing.T) {
jsonPayload := []byte(`{"replicaCount":null}`)
var obj SimpleInt
err := json.Unmarshal(jsonPayload, &obj)
require.NoError(t, err)
// This panics but expectation is -- it should print true
fmt.Println(obj.ReplicaCount.IsNull())
assert.True(t, obj.ReplicaCount.IsSet())
assert.True(t, obj.ReplicaCount.IsNull())

jsonPayload1 := []byte(`{}`)
var obj1 SimpleInt
err = json.Unmarshal(jsonPayload1, &obj1)
require.NoError(t, err)
// This panics but expectation is -- it should print false
fmt.Println(obj1.ReplicaCount.IsNull())
assert.False(t, obj1.ReplicaCount.IsNull())
assert.False(t, obj1.ReplicaCount.IsSet())
}

func ExampleNullable_marshal() {
obj := struct {
ID *Nullable[int] `json:"id,omitempty"`
Expand Down Expand Up @@ -218,7 +422,7 @@ func TestSimpleString(t *testing.T) {
}

type SimpleInt struct {
ReplicaCount Nullable[int] `json:"replicaCount"`
ReplicaCount *Nullable[int] `json:"replicaCount,omitempty"`
}

func TestSimpleInt(t *testing.T) {
Expand Down

0 comments on commit c56794f

Please sign in to comment.