Compare commits

..

No commits in common. "02d6e1f130f34fc31ba69c15365bdaec2188f353" and "25913bbf9f6f1df2fe80a93e1b499074556fd7eb" have entirely different histories.

3 changed files with 6 additions and 287 deletions

View file

@ -4,7 +4,7 @@ SPDX-FileCopyrightText: 2024 Winni Neessen <wn@neessen.dev>
SPDX-License-Identifier: CC0-1.0
-->
# niljson - A simple Go package for (un-)marshalling null-able JSON types
# niljson - A simple Go package for unmarshalling null-able JSON types
[![GoDoc](https://godoc.org/github.com/wneessen/niljson?status.svg)](https://pkg.go.dev/github.com/wneessen/niljson)
[![codecov](https://codecov.io/gh/wneessen/niljson/branch/main/graph/badge.svg?token=W4QI1RMR4L)](https://codecov.io/gh/wneessen/niljson)
@ -12,7 +12,7 @@ SPDX-License-Identifier: CC0-1.0
[![REUSE status](https://api.reuse.software/badge/github.com/wneessen/niljson)](https://api.reuse.software/info/github.com/wneessen/niljson)
<a href="https://ko-fi.com/D1D24V9IX"><img src="https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/5cbed8a4ae2b88347c06c923_BuyMeACoffee_blue.png" height="20" alt="buy ma a coffee"></a>
niljson provides a simple and efficient way to handle nullable JSON fields during the (un-)marshalling process.
niljson provides a simple and efficient way to handle nullable JSON fields during the unmarshalling process.
In JSON, it's common to encounter fields that can be `null`, but handling these fields in Go can be cumbersome,
especially when dealing with primitive types like `int`, `float64`, `bool`. These types can all be either `0` (as value)
or `null`. In Go you can always work with pointers but these, of course, can lead to unhandled nil pointer dereferences.
@ -25,7 +25,9 @@ checks for `nil` values.
- **Nullable Types**: Provides a range of nullable types (`NilString`, `NilInt`, `NilFloat`, `NilBool`, etc.) that
are easy to use and integrate into your existing Go structs.
- **JSON Unmarshalling Support**: Automatically handles the (un-)marshalling of JSON fields, converting `null` JSON
- **Seamless Integration**: These types work just like Go's standard types but add support for `null` values,
enabling cleaner and more maintainable code.
- **JSON Unmarshalling Support**: Automatically handles the unmarshalling of JSON fields, converting `null` JSON
values to Go's `nil` or zero values, depending on the context.
- **Minimalistic and Lightweight**: Designed to be lightweight and unobtrusive, so it won't bloat your application
or introduce unnecessary dependencies (only relies on the Go standard library)
@ -85,12 +87,5 @@ func main() {
output += fmt.Sprintf("String is: %s", example.String.Value())
}
fmt.Println(output)
data, err := json.Marshal(&example)
if err != nil {
fmt.Printf("failed to marshal JSON: %s", err)
os.Exit(1)
}
fmt.Println(data)
}
```

View file

@ -36,14 +36,6 @@ func (v *Variable[T]) Reset() {
v.notNil = false
}
// NewVariable returns a new Variable of generic type
func NewVariable[T any](value T) Variable[T] {
return Variable[T]{
notNil: true,
value: value,
}
}
// NilBoolean is an boolean type that can be nil
type NilBoolean = Variable[bool]
@ -80,7 +72,7 @@ type NilFloat64 = Variable[float64]
// NilString is a string type that can be nil
type NilString = Variable[string]
// UnmarshalJSON satisfies the json.Unmarshaler interface for generic Variable types
// UnmarshalJSON interprets the generic Nil types and sets the value and notnil of the type
func (v *Variable[T]) UnmarshalJSON(data []byte) error {
if string(data) != "null" {
v.value = *new(T)
@ -89,11 +81,3 @@ func (v *Variable[T]) UnmarshalJSON(data []byte) error {
}
return nil
}
// MarshalJSON satisfies the json.Marshaler interface for generic Variable types
func (v *Variable[T]) MarshalJSON() ([]byte, error) {
if !v.notNil {
return json.Marshal(nil)
}
return json.Marshal(v.value)
}

View file

@ -56,25 +56,6 @@ func TestVariable_UnmarshalJSON_Boolean(t *testing.T) {
}
}
func TestVariable_MarshalJSON_Boolean(t *testing.T) {
type JSONType struct {
Value NilBoolean `json:"bool"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"bool":false,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(false),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_ByteSlice(t *testing.T) {
type JSONType struct {
Value NilByteSlice `json:"bytes"`
@ -102,25 +83,6 @@ func TestVariable_UnmarshalJSON_ByteSlice(t *testing.T) {
}
}
func TestVariable_MarshalJSON_ByteSlice(t *testing.T) {
type JSONType struct {
Value NilByteSlice `json:"bytes"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"bytes":"Ynl0ZXM=","nilvalue":null}`
jt := &JSONType{
Value: NewVariable([]byte("bytes")),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_Float32(t *testing.T) {
type JSONType struct {
Value NilFloat32 `json:"float32"`
@ -149,25 +111,6 @@ func TestVariable_UnmarshalJSON_Float32(t *testing.T) {
}
}
func TestVariable_MarshalJSON_Float32(t *testing.T) {
type JSONType struct {
Value NilFloat32 `json:"float32"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"float32":1.234,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(float32(1.234)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_Float64(t *testing.T) {
type JSONType struct {
Value NilFloat64 `json:"float64"`
@ -196,25 +139,6 @@ func TestVariable_UnmarshalJSON_Float64(t *testing.T) {
}
}
func TestVariable_MarshalJSON_Float64(t *testing.T) {
type JSONType struct {
Value NilFloat64 `json:"float64"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"float64":123.456,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(123.456),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_Int(t *testing.T) {
type JSONType struct {
Value NilInt `json:"int"`
@ -243,25 +167,6 @@ func TestVariable_UnmarshalJSON_Int(t *testing.T) {
}
}
func TestVariable_MarshalJSON_Int(t *testing.T) {
type JSONType struct {
Value NilInt `json:"int"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"int":123,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(123),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_Int64(t *testing.T) {
type JSONType struct {
Value NilInt64 `json:"int64"`
@ -290,25 +195,6 @@ func TestVariable_UnmarshalJSON_Int64(t *testing.T) {
}
}
func TestVariable_MarshalJSON_Int64(t *testing.T) {
type JSONType struct {
Value NilInt64 `json:"int64"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"int64":12345678901234,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(int64(12345678901234)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_String(t *testing.T) {
type JSONType struct {
Value NilString `json:"string"`
@ -337,25 +223,6 @@ func TestVariable_UnmarshalJSON_String(t *testing.T) {
}
}
func TestVariable_MarshalJSON_String(t *testing.T) {
type JSONType struct {
Value NilString `json:"string"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"string":"test123","nilvalue":null}`
jt := &JSONType{
Value: NewVariable("test123"),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_UInt(t *testing.T) {
type JSONType struct {
Value NilUInt `json:"uint"`
@ -384,25 +251,6 @@ func TestVariable_UnmarshalJSON_UInt(t *testing.T) {
}
}
func TestVariable_MarshalJSON_UInt(t *testing.T) {
type JSONType struct {
Value NilUInt `json:"uint"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"uint":123,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(uint(123)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_UInt8(t *testing.T) {
type JSONType struct {
Value NilUInt8 `json:"uint8"`
@ -431,25 +279,6 @@ func TestVariable_UnmarshalJSON_UInt8(t *testing.T) {
}
}
func TestVariable_MarshalJSON_UInt8(t *testing.T) {
type JSONType struct {
Value NilUInt8 `json:"uint8"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"uint8":1,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(uint8(1)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_UInt16(t *testing.T) {
type JSONType struct {
Value NilUInt16 `json:"uint16"`
@ -478,25 +307,6 @@ func TestVariable_UnmarshalJSON_UInt16(t *testing.T) {
}
}
func TestVariable_MarshalJSON_UInt16(t *testing.T) {
type JSONType struct {
Value NilUInt16 `json:"uint16"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"uint16":2,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(uint16(2)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_UInt32(t *testing.T) {
type JSONType struct {
Value NilUInt32 `json:"uint32"`
@ -525,25 +335,6 @@ func TestVariable_UnmarshalJSON_UInt32(t *testing.T) {
}
}
func TestVariable_MarshalJSON_UInt32(t *testing.T) {
type JSONType struct {
Value NilUInt32 `json:"uint32"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"uint32":3,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(uint32(3)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func TestVariable_UnmarshalJSON_UInt64(t *testing.T) {
type JSONType struct {
Value NilUInt64 `json:"uint64"`
@ -572,25 +363,6 @@ func TestVariable_UnmarshalJSON_UInt64(t *testing.T) {
}
}
func TestVariable_MarshalJSON_UInt64(t *testing.T) {
type JSONType struct {
Value NilUInt64 `json:"uint64"`
NilValue NilBoolean `json:"nilvalue,omitempty"`
}
expected := `{"uint64":4,"nilvalue":null}`
jt := &JSONType{
Value: NewVariable(uint64(4)),
}
data, err := json.Marshal(&jt)
if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err)
}
if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data))
}
}
func ExampleVariable_UnmarshalJSON() {
type JSONType struct {
Bool NilBoolean `json:"bool"`
@ -635,35 +407,3 @@ func ExampleVariable_UnmarshalJSON() {
fmt.Println(output)
// Output: Bool is: true, Float 32 is nil, Float 64 is: 0.000000, String is: test
}
func ExampleVariable_MarshalJSON() {
type JSONType struct {
Bool NilBoolean `json:"bool"`
ByteSlice NilByteSlice `json:"bytes"`
Float32 NilFloat32 `json:"float32,omitempty"`
Float64 NilFloat64 `json:"float64"`
Int NilInt `json:"int"`
Int64 NilInt64 `json:"int64"`
NullString NilString `json:"nilvalue,omitempty"`
String NilString `json:"string"`
UInt NilUInt `json:"uint"`
UInt8 NilUInt8 `json:"uint8"`
}
example := &JSONType{
Bool: NewVariable(false),
ByteSlice: NewVariable([]byte("bytes")),
Float64: NewVariable(123.456),
Int: NewVariable(123),
Int64: NewVariable(int64(12345678901234)),
String: NewVariable("test"),
UInt: NewVariable(uint(123)),
}
data, err := json.Marshal(example)
if err != nil {
fmt.Printf("failed to marshal JSON: %s", err)
os.Exit(1)
}
fmt.Println(string(data))
// Output: {"bool":false,"bytes":"Ynl0ZXM=","float32":null,"float64":123.456,"int":123,"int64":12345678901234,"nilvalue":null,"string":"test","uint":123,"uint8":null}
}