-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from Cleverse/feat/nullable
- Loading branch information
Showing
7 changed files
with
653 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ use ( | |
./address | ||
./errors | ||
./fixedpoint | ||
./nullable | ||
./queue | ||
./utils | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[![Go Reference](https://pkg.go.dev/badge/github.com/Cleverse/go-utilities/nullable.svg)](https://pkg.go.dev/github.com/Cleverse/go-utilities/nullable) | ||
[![Report card](https://goreportcard.com/badge/github.com/Cleverse/go-utilities/nullable)](https://goreportcard.com/report/github.com/Cleverse/go-utilities/nullable) | ||
|
||
# nullable | ||
|
||
A safe way to represent nullable primitive values in Go. Supports JSON serialization. | ||
|
||
## Installation | ||
|
||
```shell | ||
go get github.com/Cleverse/go-utilities/nullable | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module github.com/Cleverse/go-utilities/nullable | ||
|
||
go 1.21 | ||
|
||
require ( | ||
github.com/Cleverse/go-utilities/errors v0.0.0-20231113142714-2364608744a9 | ||
github.com/stretchr/testify v1.8.4 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/Cleverse/go-utilities/errors v0.0.0-20231113142714-2364608744a9 h1:nHdki9biYL351wAyweRn7AOtEtOcIUN30DK7Xbx8dG0= | ||
github.com/Cleverse/go-utilities/errors v0.0.0-20231113142714-2364608744a9/go.mod h1:1QK+h746G1DwellQ6KK2rBCJusZqIDTZ9QFVGnUX9+Q= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// Package nullable provides a safe way to represent nullable primitive values in Go. | ||
package nullable | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
|
||
"github.com/Cleverse/go-utilities/errors" | ||
) | ||
|
||
// Primitive is a type constraint for all primitive types, except pointers, slices, maps, channels and structs. | ||
type Primitive interface { | ||
~int | ~int8 | ~int16 | ~int32 | ~int64 | | ||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | | ||
~float32 | ~float64 | ~bool | ~string | ||
} | ||
|
||
var nullBytes = []byte("null") | ||
|
||
// Nullable is a generic type that can be used to represent a nullable value. If valid is true, then data is considered non-null. | ||
// If valid is false, then data is considered null. Nullable supports all primitive types, except pointers, slices, maps, channels and structs. | ||
// Nullable supports | ||
type Nullable[T Primitive] struct { | ||
valid bool | ||
data T | ||
} | ||
|
||
// New returns a new null Nullable. | ||
func New[T Primitive]() Nullable[T] { | ||
return Nullable[T]{} | ||
} | ||
|
||
// From returns a non-null Nullable with the given data. | ||
func From[T Primitive](data T) Nullable[T] { | ||
return Nullable[T]{ | ||
valid: true, | ||
data: data, | ||
} | ||
} | ||
|
||
// Zero returns a non-null Nullable with the zero value of the given type. | ||
func Zero[T Primitive]() Nullable[T] { | ||
return Nullable[T]{ | ||
valid: true, | ||
} | ||
} | ||
|
||
// Get returns the data and a boolean indicating whether the Nullable is considered null or non-null. | ||
// If boolean is false, then Nullable is considered null. If boolean is true, then Nullable is considered non-null. | ||
func (n Nullable[T]) Get() (T, bool) { | ||
return n.data, n.valid | ||
} | ||
|
||
// Data returns the without checking if Nullable is considered null. Only use this if you are sure that Nullable is non-null. | ||
func (n Nullable[T]) Data() T { | ||
return n.data | ||
} | ||
|
||
// Set sets the data and marks it as non-null. | ||
func (n *Nullable[T]) Set(data T) { | ||
n.valid = true | ||
n.data = data | ||
} | ||
|
||
// SetNull marks the data as null. | ||
func (n *Nullable[T]) SetNull() { | ||
var zero T | ||
n.valid = false | ||
n.data = zero | ||
} | ||
|
||
// SetZero sets the data to the zero value of the given type and marks it as non-null. | ||
func (n *Nullable[T]) SetZero() { | ||
var zero T | ||
n.valid = true | ||
n.data = zero | ||
} | ||
|
||
// IsValid returns true if the Nullable is non-null. | ||
func (n Nullable[T]) IsValid() bool { | ||
return n.valid | ||
} | ||
|
||
// IsZero returns true if the Nullable is non-null and is the zero value of the given type. | ||
func (n Nullable[T]) IsZero() bool { | ||
if !n.valid { | ||
return false | ||
} | ||
var zero T | ||
return n.data == zero | ||
} | ||
|
||
// Ptr returns a pointer to the data. If the Nullable is null, then nil is returned. | ||
func (n Nullable[T]) Ptr() *T { | ||
if !n.valid { | ||
return nil | ||
} | ||
return &n.data | ||
} | ||
|
||
// Equal returns true if both Nullable are null or if both Nullable are non-null and have the same data. | ||
func (n Nullable[T]) Equal(other Nullable[T]) bool { | ||
if !n.valid && !other.valid { | ||
return true | ||
} | ||
if n.valid && other.valid && n.data == other.data { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// MarshalJSON implements json.Marshaler interface. If the Nullable is considered null, then "null" is returned. | ||
func (n Nullable[T]) MarshalJSON() ([]byte, error) { | ||
if !n.valid { | ||
return json.Marshal(nil) | ||
} | ||
data, err := json.Marshal(n.data) | ||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
return data, nil | ||
} | ||
|
||
// UnmarshalJSON implements json.Unmarshaler interface. If "null" is passed, then the Nullable is marked as null. | ||
// Otherwise, the data is marked as non-null and the data is unmarshalled. | ||
func (n *Nullable[T]) UnmarshalJSON(data []byte) error { | ||
if bytes.EqualFold(data, nullBytes) { | ||
n.valid = false | ||
return nil | ||
} | ||
if err := json.Unmarshal(data, &n.data); err != nil { | ||
n.valid = false | ||
return errors.WithStack(err) | ||
} | ||
|
||
n.valid = true | ||
return nil | ||
} |
Oops, something went wrong.