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 gonullis theNullabletype, 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 - Nullablewith an initial value using the NewNullable function. This also sets the- Validflag to true.
- Database Integration: - gonullmakes it seamless to integrate nullable values with- database/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 ( - UnmarshalJSONand- MarshalJSON) 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