When working with databases and JSON, developers often come across the challenge of managing nullable values. Nulls can be pesky. They can introduce unexpected errors if not handled correctly, and often require additional checks in the code. To address this, the open-source package gonull steps in as a solution.
What is gonull?
gonull provides a generic Nullable type for Go applications. Its core purpose is to simplify the process of handling nullable values, especially when dealing with databases and JSON.
Core Features:
-
Generic Nullable Type: At the heart of
gonull
is theNullable
type, which can hold a nullable value of any specified type. This type has two fields:-
Val
: Holds the actual value. -
Valid
: A flag indicating whether the value has been set or not.
-
Ease of Creation: You can quickly create a new
Nullable
with an initial value using the NewNullable function. This also sets theValid
flag to true.Database Integration:
gonull
makes it seamless to integrate nullable values withdatabase/sql
. The Scan and Value methods enable the Nullable type to act as a nullable field in database operations.JSON Operations: The package provides built-in methods (
UnmarshalJSON
andMarshalJSON
) to handle the serialization and deserialization of nullable values when working with JSON data.
How Does it Work?
Consider a scenario where you want to represent a Person
with optional fields, such as Age
, Address
, and Height
. These fields might or might not have values, and when serialized into JSON, they should be represented correctly (either with their value or with null).
Here's a simple example using the gonull
package:
package main
import (
"encoding/json"
"fmt"
"github.com/lomsa-dev/gonull"
)
type MyCustomInt int
type MyCustomFloat32 float32
type Person struct {
Name string
Age gonull.Nullable[MyCustomInt]
Address gonull.Nullable[string]
Height gonull.Nullable[MyCustomFloat32]
}
func main() {
jsonData := []byte(`{"Name":"Alice","Age":15,"Address":null,"Height":null}`)
var person Person
err := json.Unmarshal(jsonData, &person)
if err != nil {
panic(err)
}
fmt.Printf("Unmarshalled Person: %+v\n", person)
marshalledData, err := json.Marshal(person)
if err != nil {
panic(err)
}
fmt.Printf("Marshalled JSON: %s\n", string(marshalledData))
}
In the above example, the Age
, Address
, and Height
fields of the Person struct are of the Nullable
type. When we unmarshal the JSON data, these fields correctly interpret the JSON values, including recognizing null values. When marshaled back into JSON, the fields that are unset (or not valid) are represented as null.
Top comments (1)
cool, but I used to using "samber/mo".Option[T] type which essentially does the same thing + implements db scanner and json marshaler