Skip to content

Commit

Permalink
Bugfixes (#4)
Browse files Browse the repository at this point in the history
* rename isvalid to valid

* wrap driver value

* return nil instead
  • Loading branch information
LukaGiorgadze authored May 4, 2023
1 parent 6f1aac9 commit 0b0630d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 39 deletions.
28 changes: 14 additions & 14 deletions gonull.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,51 +15,51 @@ var (
)

// Nullable is a generic struct that holds a nullable value of any type T.
// It keeps track of the value (Val) and a flag (IsValid) indicating whether the value has been set.
// It keeps track of the value (Val) and a flag (Valid) indicating whether the value has been set.
// This allows for better handling of nullable values, ensuring proper value management and serialization.
type Nullable[T any] struct {
Val T
IsValid bool
Val T
Valid bool
}

// NewNullable creates a new Nullable with the given value and sets IsValid to true.
// NewNullable creates a new Nullable with the given value and sets Valid to true.
// This is useful when you want to create a Nullable with an initial value, explicitly marking it as set.
func NewNullable[T any](value T) Nullable[T] {
return Nullable[T]{Val: value, IsValid: true}
return Nullable[T]{Val: value, Valid: true}
}

// Scan implements the sql.Scanner interface for Nullable, allowing it to be used as a nullable field in database operations.
// It is responsible for properly setting the IsValid flag and converting the scanned value to the target type T.
// It is responsible for properly setting the Valid flag and converting the scanned value to the target type T.
// This enables seamless integration with database/sql when working with nullable values.
func (n *Nullable[T]) Scan(value interface{}) error {
if value == nil {
n.Val = zeroValue[T]()
n.IsValid = false
n.Valid = false
return nil
}

var err error
n.Val, err = convertToType[T](value)
if err == nil {
n.IsValid = true
n.Valid = true
}
return err
}

// Value implements the driver.Valuer interface for Nullable, enabling it to be used as a nullable field in database operations.
// This method ensures that the correct value is returned for serialization, handling unset Nullable values by returning nil.
func (n Nullable[T]) Value() (driver.Value, error) {
if !n.IsValid {
if !n.Valid {
return nil, nil
}
return n.Val, nil
return driver.Value(n.Val), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for Nullable, allowing it to be used as a nullable field in JSON operations.
// This method ensures proper unmarshalling of JSON data into the Nullable value, correctly setting the IsValid flag based on the JSON data.
// This method ensures proper unmarshalling of JSON data into the Nullable value, correctly setting the Valid flag based on the JSON data.
func (n *Nullable[T]) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
n.IsValid = false
n.Valid = false
return nil
}

Expand All @@ -69,14 +69,14 @@ func (n *Nullable[T]) UnmarshalJSON(data []byte) error {
}

n.Val = value
n.IsValid = true
n.Valid = true
return nil
}

// MarshalJSON implements the json.Marshaler interface for Nullable, enabling it to be used as a nullable field in JSON operations.
// This method ensures proper marshalling of Nullable values into JSON data, representing unset values as null in the serialized output.
func (n Nullable[T]) MarshalJSON() ([]byte, error) {
if !n.IsValid {
if !n.Valid {
return []byte("null"), nil
}

Expand Down
50 changes: 25 additions & 25 deletions gonull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ func TestNewNullable(t *testing.T) {
value := "test"
n := NewNullable(value)

assert.True(t, n.IsValid)
assert.True(t, n.Valid)
assert.Equal(t, value, n.Val)
}

func TestNullableScan(t *testing.T) {
tests := []struct {
name string
value interface{}
IsValid bool
Valid bool
wantErr bool
}{
{
name: "nil value",
value: nil,
IsValid: false,
name: "nil value",
value: nil,
Valid: false,
},
{
name: "string value",
value: "test",
IsValid: true,
name: "string value",
value: "test",
Valid: true,
},
{
name: "unsupported type",
Expand All @@ -48,8 +48,8 @@ func TestNullableScan(t *testing.T) {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.IsValid, n.IsValid)
if tt.IsValid {
assert.Equal(t, tt.Valid, n.Valid)
if tt.Valid {
assert.Equal(t, tt.value, n.Val)
}
}
Expand All @@ -72,7 +72,7 @@ func TestNullableValue(t *testing.T) {
},
{
name: "unset value",
nullable: Nullable[string]{IsValid: false},
nullable: Nullable[string]{Valid: false},
wantValue: nil,
wantErr: nil,
},
Expand All @@ -90,24 +90,24 @@ func TestNullableValue(t *testing.T) {

func TestNullableUnmarshalJSON(t *testing.T) {
type testCase struct {
name string
jsonData []byte
expectedVal int
expectedIsValid bool
name string
jsonData []byte
expectedVal int
expectedValid bool
}

testCases := []testCase{
{
name: "ValuePresent",
jsonData: []byte(`123`),
expectedVal: 123,
expectedIsValid: true,
name: "ValuePresent",
jsonData: []byte(`123`),
expectedVal: 123,
expectedValid: true,
},
{
name: "ValueNull",
jsonData: []byte(`null`),
expectedVal: 0,
expectedIsValid: false,
name: "ValueNull",
jsonData: []byte(`null`),
expectedVal: 0,
expectedValid: false,
},
}

Expand All @@ -118,7 +118,7 @@ func TestNullableUnmarshalJSON(t *testing.T) {
err := nullable.UnmarshalJSON(tc.jsonData)
assert.NoError(t, err)
assert.Equal(t, tc.expectedVal, nullable.Val)
assert.Equal(t, tc.expectedIsValid, nullable.IsValid)
assert.Equal(t, tc.expectedValid, nullable.Valid)
})
}
}
Expand All @@ -138,7 +138,7 @@ func TestNullableMarshalJSON(t *testing.T) {
},
{
name: "ValueNull",
nullable: Nullable[int]{Val: 0, IsValid: false},
nullable: Nullable[int]{Val: 0, Valid: false},
expectedJSON: []byte(`null`),
},
}
Expand Down

0 comments on commit 0b0630d

Please sign in to comment.