Skip to content

LukaGiorgadze/gonull

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Nullable with Generics

PkgGoDev go-mod-verify go-vuln golangci-lint codecov

Go package simplifies nullable fields handling with Go Generics.

gonull is a Go package that provides type-safe handling of nullable values using generics. It's designed to work seamlessly with JSON and SQL operations, making it perfect for web services and database interactions.

Features

  • 🎯 One generic Nullable[T] works with any type
  • 💡 Omitzero support
  • 🔄 Built-in JSON marshaling/unmarshaling
  • 📊 SQL database compatibility
  • 🔢 Handles numeric values returned as strings by SQL drivers
  • 🧩 Works seamlessly with your own alias or enum types
  • ✨ Zero dependencies

Why gonull?

Nullable[T] keeps your code concise by using Go generics for any type. You don't need separate wrappers for strings, ints or custom enumerations. Built-in sql.Scanner and json support make it easy to integrate with databases and APIs.

type Status string

type Task struct {
    ID    int
    State gonull.Nullable[Status]
}

Usage

go get github.com/LukaGiorgadze/gonull/v2

Example #1

package main

import (
    "encoding/json"
    "fmt"

    "github.com/LukaGiorgadze/gonull"
)

type MyCustomInt int
type MyCustomFloat32 float32

type Person struct {
    Name     string                           `json:"name"`
    Age      gonull.Nullable[MyCustomInt]     `json:"age"`
    Address  gonull.Nullable[string]          `json:"address"`
    Height   gonull.Nullable[MyCustomFloat32] `json:"height"`
    IsZero   gonull.Nullable[bool]            `json:"is_zero,omitzero"` // This property will be omitted from the output since it's not present in jsonData.
}

func main() {
    jsonData := []byte(`
    {
        "name": "Alice",
        "age": 15,
        "address": null,
        "height": null
    }`)

    var person Person
    json.Unmarshal(jsonData, &person)
    fmt.Printf("Unmarshalled Person: %+v\n", person)

    marshalledData, _ := json.Marshal(person)
    fmt.Printf("Marshalled JSON: %s\n", string(marshalledData))

    // Output:
    // Unmarshalled Person: {Name:Alice Age:15 Address: Height:0 IsZero:false}
    // Marshalled JSON: {"name":"Alice","age":15,"address":null,"height":null}
    // As you see, IsZero is not present in the output, because we used the omitzero tag introduced in go v1.24.
}

Example #2

type User struct {
    Name     gonull.Nullable[string]
    Age      gonull.Nullable[int]
}

func main() {
    // ...
    rows, err := db.Query("SELECT id, name, age FROM users")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    for rows.Next() {
        var user User
        err := rows.Scan(&user.Name, &user.Age)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("ID: %d, Name: %v, Age: %v\n", user.Name.Val, user.Age.Val)
    }
    // ...
}

Explore More Examples

See ./examples directory.

Contribution

Made with contrib.rocks.

About

Go package simplifies nullable fields handling using Go Generics.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 8

Languages