Documentation
¶
Overview ¶
Package optional provides a three-state generic container for Go that distinguishes between a present value, an explicit null, and a missing (omitted) field.
This is especially useful for JSON APIs with PATCH semantics and for working with nullable SQL columns, where you need to know whether a field was explicitly set to null, set to a value, or not provided at all.
Three States ¶
Every Field is in exactly one of these states:
- Present — the field contains a value.
- Null — the field was explicitly set to null.
- Missing — the field was not provided (the zero value of Field).
JSON Integration ¶
Field implements encoding/json.Marshaler and encoding/json.Unmarshaler. When unmarshalling JSON:
- A JSON value → present state.
- A JSON null → null state.
- A missing JSON key → missing state (zero value, never touched by unmarshaler).
Use the "omitzero" tag (Go 1.24+) to omit missing fields during marshalling:
type UpdateRequest struct {
Name optional.String `json:"name,omitzero"`
Age optional.Int `json:"age,omitzero"`
}
SQL Integration ¶
The concrete scalar types (Bool, Int, String, UUID, etc.) implement database/sql.Scanner and database/sql/driver.Valuer for seamless database integration with any SQL driver. Scan handles the standard driver value types (int64, float64, bool, []byte, string, time.Time) with automatic type conversion and range checking.
Scalar Types ¶
The following concrete types are provided for direct use with SQL databases:
- Bool
- Int, Int8, Int16, Int32, Int64
- Uint, Uint8, Uint16, Uint32, Uint64, Uintptr
- Float32, Float64
- String, Bytes
- Time
- UUID (requires github.com/google/uuid)
- Decimal (requires github.com/shopspring/decimal)
Functional Helpers ¶
Standalone generic functions are provided for common transformations:
Index ¶
- func Equal[T comparable](a, b Field[T]) bool
- type Bool
- type Bytes
- type Decimal
- type Field
- func (f Field[T]) Get() (T, bool)
- func (f Field[T]) GetOr(defaultValue T) T
- func (f Field[T]) GoString() string
- func (f Field[T]) IsMissing() bool
- func (f Field[T]) IsNull() bool
- func (f Field[T]) IsPresent() bool
- func (f Field[T]) IsZero() bool
- func (f Field[T]) MarshalJSON() ([]byte, error)
- func (f Field[T]) MustGet() T
- func (f Field[T]) Or(other Field[T]) Field[T]
- func (f Field[T]) OrElse(fn func() T) T
- func (f Field[T]) Ptr() *T
- func (f Field[T]) String() string
- func (f *Field[T]) UnmarshalJSON(data []byte) error
- func (f Field[T]) Value() (driver.Value, error)
- type Float32
- type Float64
- type Int
- type Int8
- type Int16
- type Int32
- type Int64
- type String
- type Time
- type UUID
- type Uint
- type Uint8
- type Uint16
- type Uint32
- type Uint64
- type Uintptr
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Equal ¶
func Equal[T comparable](a, b Field[T]) bool
Equal reports whether two fields are equal. Two fields are equal if they have the same state and, when present, the same value.
Equal requires the [comparable] constraint because Go methods cannot introduce additional type constraints.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
fmt.Println(optional.Equal(optional.Of(42), optional.Of(42))) // true
fmt.Println(optional.Equal(optional.Of(1), optional.Of(2))) // false
fmt.Println(optional.Equal(optional.Null[int](), optional.Null[int]())) // true
}
Output: true false true
Types ¶
type Bool ¶
Bool is a three-state optional for bool values.
func FromBoolPtr ¶
FromBoolPtr creates a Bool from a pointer. If ptr is nil, the Bool is null; otherwise it contains the dereferenced value.
func OfNullableBool ¶
OfNullableBool creates a Bool from a pointer. It is an alias for FromBoolPtr.
func (*Bool) Scan ¶
Scan implements sql.Scanner.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
var b optional.Bool
// Simulate scanning NULL from database.
b.Scan(nil)
fmt.Println(b.IsNull()) // true
// Simulate scanning a value.
b.Scan(true)
fmt.Println(b.MustGet()) // true
// Some databases return 0/1 for booleans.
b.Scan(int64(1))
fmt.Println(b.MustGet()) // true
}
Output: true true true
type Bytes ¶
Bytes is a three-state optional for []byte values (e.g., BLOB, BYTEA columns).
func FromBytesPtr ¶
FromBytesPtr creates a Bytes from a pointer.
func OfNullableBytes ¶
OfNullableBytes creates a Bytes from a pointer. It is an alias for FromBytesPtr.
type Decimal ¶
Decimal is a three-state optional for decimal.Decimal values.
func FromDecimalPtr ¶
FromDecimalPtr creates a Decimal from a pointer.
func MissingDecimal ¶
func MissingDecimal() Decimal
MissingDecimal creates a Decimal in the missing state.
func OfNullableDecimal ¶
OfNullableDecimal creates a Decimal from a pointer. It is an alias for FromDecimalPtr.
func (*Decimal) Scan ¶
Scan implements sql.Scanner. Supports string, []byte, float64, and int64 source types.
type Field ¶
type Field[T any] struct { // contains filtered or unexported fields }
Field is a generic three-state container that distinguishes between a present value, an explicit null, and a missing (omitted) field. The zero value of Field is the missing state.
func FlatMap ¶
FlatMap transforms the value inside a Field using fn, which itself returns a Field. If the field is present, fn is applied and its result is returned directly. If the field is null or missing, the corresponding state is preserved.
FlatMap is a standalone function because Go does not support additional type parameters on methods.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
safeDivide := func(divisor int) optional.Field[float64] {
if divisor == 0 {
return optional.Null[float64]()
}
return optional.Of(100.0 / float64(divisor))
}
result := optional.FlatMap(optional.Of(4), safeDivide)
fmt.Println(result.MustGet()) // 25
zero := optional.FlatMap(optional.Of(0), safeDivide)
fmt.Println(zero.IsNull()) // true
}
Output: 25 true
func FromPtr ¶
FromPtr creates a Field from a pointer. If ptr is nil, the Field is null. If ptr is non-nil, the Field contains the dereferenced value.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
v := 42
present := optional.FromPtr(&v)
null := optional.FromPtr[int](nil)
fmt.Println(present.IsPresent()) // true
fmt.Println(null.IsNull()) // true
}
Output: true true
func Map ¶
Map transforms the value inside a Field using fn. If the field is present, fn is applied to the value and the result is wrapped in a new present Field. If the field is null or missing, the corresponding state is preserved in the returned Field.
Map is a standalone function because Go does not support additional type parameters on methods.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
f := optional.Of(5)
doubled := optional.Map(f, func(n int) int { return n * 2 })
fmt.Println(doubled.MustGet()) // 10
null := optional.Null[int]()
result := optional.Map(null, func(n int) int { return n * 2 })
fmt.Println(result.IsNull()) // true
}
Output: 10 true
func Missing ¶
Missing creates a Field in the missing state. This is equivalent to the zero value of Field[T].
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
f := optional.Missing[int]()
fmt.Println(f.IsMissing()) // true
fmt.Println(f.IsZero()) // true (same as missing)
}
Output: true true
func Null ¶
Null creates a Field in the null state.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
f := optional.Null[string]()
fmt.Println(f.IsNull()) // true
fmt.Println(f.IsPresent()) // false
}
Output: true false
func Of ¶
Of creates a Field containing the given value in the present state.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
f := optional.Of(42)
fmt.Println(f.IsPresent()) // true
fmt.Println(f.MustGet()) // 42
}
Output: true 42
func OfNullable ¶
OfNullable creates a Field from a pointer. It is an alias for FromPtr.
func (Field[T]) GetOr ¶
func (f Field[T]) GetOr(defaultValue T) T
GetOr returns the value if present, otherwise returns defaultValue.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
present := optional.Of(5)
null := optional.Null[int]()
fmt.Println(present.GetOr(99)) // 5
fmt.Println(null.GetOr(99)) // 99
}
Output: 5 99
func (Field[T]) GoString ¶
GoString returns a Go-syntax representation of the field for use with %#v.
func (Field[T]) IsZero ¶
IsZero reports whether the field is in the missing state (zero value of Field). This method supports the omitzero JSON tag introduced in Go 1.24+.
func (Field[T]) MarshalJSON ¶
MarshalJSON implements json.Marshaler. Returns an error for missing values — use the omitzero tag to omit them.
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
type Request struct {
Name optional.Field[string] `json:"name,omitzero"`
Age optional.Field[int] `json:"age,omitzero"`
}
// All fields present.
r1 := Request{Name: optional.Of("Alice"), Age: optional.Of(30)}
data1, _ := json.Marshal(r1)
fmt.Println(string(data1))
// Age is null.
r2 := Request{Name: optional.Of("Bob"), Age: optional.Null[int]()}
data2, _ := json.Marshal(r2)
fmt.Println(string(data2))
// Age is missing (omitted from JSON).
r3 := Request{Name: optional.Of("Carol")}
data3, _ := json.Marshal(r3)
fmt.Println(string(data3))
}
Output: {"name":"Alice","age":30} {"name":"Bob","age":null} {"name":"Carol"}
func (Field[T]) MustGet ¶
func (f Field[T]) MustGet() T
MustGet returns the value if present, otherwise panics.
func (Field[T]) Or ¶
Or returns f if it contains a present value, otherwise returns other.
Example ¶
package main
import (
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
a := optional.Null[int]()
b := optional.Of(42)
result := a.Or(b)
fmt.Println(result.MustGet()) // 42
}
Output: 42
func (Field[T]) OrElse ¶
func (f Field[T]) OrElse(fn func() T) T
OrElse returns the value if present, otherwise calls fn and returns its result.
func (Field[T]) Ptr ¶
func (f Field[T]) Ptr() *T
Ptr returns a pointer to the value if present, otherwise nil.
func (*Field[T]) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler. JSON null sets the field to the null state. Any other valid JSON sets it to present. Fields not present in JSON remain in the missing state (zero value).
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/eremin-daniil/optional"
)
func main() {
type Request struct {
Name optional.Field[string] `json:"name"`
Age optional.Field[int] `json:"age"`
}
// All fields present.
var r1 Request
json.Unmarshal([]byte(`{"name":"Alice","age":30}`), &r1)
fmt.Printf("name: present=%v, age: present=%v\n", r1.Name.IsPresent(), r1.Age.IsPresent())
// Age is null.
var r2 Request
json.Unmarshal([]byte(`{"name":"Bob","age":null}`), &r2)
fmt.Printf("name: present=%v, age: null=%v\n", r2.Name.IsPresent(), r2.Age.IsNull())
// Age is missing.
var r3 Request
json.Unmarshal([]byte(`{"name":"Carol"}`), &r3)
fmt.Printf("name: present=%v, age: missing=%v\n", r3.Name.IsPresent(), r3.Age.IsMissing())
}
Output: name: present=true, age: present=true name: present=true, age: null=true name: present=true, age: missing=true
func (Field[T]) Value ¶
Value implements driver.Valuer. Returns nil for null, an error for missing, and the raw value for present.
Note: for scalar wrapper types (Int, UUID, Decimal, etc.), the Value method is overridden to return a valid driver.Value type.
type Float32 ¶
Float32 is a three-state optional for float32 values.
func FromFloat32Ptr ¶
FromFloat32Ptr creates a Float32 from a pointer.
func MissingFloat32 ¶
func MissingFloat32() Float32
MissingFloat32 creates a Float32 in the missing state.
func OfNullableFloat32 ¶
OfNullableFloat32 creates a Float32 from a pointer. It is an alias for FromFloat32Ptr.
type Float64 ¶
Float64 is a three-state optional for float64 values.
func FromFloat64Ptr ¶
FromFloat64Ptr creates a Float64 from a pointer.
func MissingFloat64 ¶
func MissingFloat64() Float64
MissingFloat64 creates a Float64 in the missing state.
func OfNullableFloat64 ¶
OfNullableFloat64 creates a Float64 from a pointer. It is an alias for FromFloat64Ptr.
type Int ¶
Int is a three-state optional for int values.
func OfNullableInt ¶
OfNullableInt creates an Int from a pointer. It is an alias for FromIntPtr.
type Int8 ¶
Int8 is a three-state optional for int8 values.
func OfNullableInt8 ¶
OfNullableInt8 creates an Int8 from a pointer. It is an alias for FromInt8Ptr.
type Int16 ¶
Int16 is a three-state optional for int16 values.
func FromInt16Ptr ¶
FromInt16Ptr creates an Int16 from a pointer.
func OfNullableInt16 ¶
OfNullableInt16 creates an Int16 from a pointer. It is an alias for FromInt16Ptr.
type Int32 ¶
Int32 is a three-state optional for int32 values.
func FromInt32Ptr ¶
FromInt32Ptr creates an Int32 from a pointer.
func OfNullableInt32 ¶
OfNullableInt32 creates an Int32 from a pointer. It is an alias for FromInt32Ptr.
type Int64 ¶
Int64 is a three-state optional for int64 values.
func FromInt64Ptr ¶
FromInt64Ptr creates an Int64 from a pointer.
func OfNullableInt64 ¶
OfNullableInt64 creates an Int64 from a pointer. It is an alias for FromInt64Ptr.
type String ¶
String is a three-state optional for string values.
func FromStringPtr ¶
FromStringPtr creates a String from a pointer.
func MissingString ¶
func MissingString() String
MissingString creates a String in the missing state.
func OfNullableString ¶
OfNullableString creates a String from a pointer. It is an alias for FromStringPtr.
type Time ¶
Time is a three-state optional for time.Time values.
func OfNullableTime ¶
OfNullableTime creates a Time from a pointer. It is an alias for FromTimePtr.
type UUID ¶
UUID is a three-state optional for uuid.UUID values.
func OfNullableUUID ¶
OfNullableUUID creates a UUID from a pointer. It is an alias for FromUUIDPtr.
type Uint ¶
Uint is a three-state optional for uint values.
func OfNullableUint ¶
OfNullableUint creates a Uint from a pointer. It is an alias for FromUintPtr.
type Uint8 ¶
Uint8 is a three-state optional for uint8 values.
func FromUint8Ptr ¶
FromUint8Ptr creates a Uint8 from a pointer.
func OfNullableUint8 ¶
OfNullableUint8 creates a Uint8 from a pointer. It is an alias for FromUint8Ptr.
type Uint16 ¶
Uint16 is a three-state optional for uint16 values.
func FromUint16Ptr ¶
FromUint16Ptr creates a Uint16 from a pointer.
func MissingUint16 ¶
func MissingUint16() Uint16
MissingUint16 creates a Uint16 in the missing state.
func OfNullableUint16 ¶
OfNullableUint16 creates a Uint16 from a pointer. It is an alias for FromUint16Ptr.
type Uint32 ¶
Uint32 is a three-state optional for uint32 values.
func FromUint32Ptr ¶
FromUint32Ptr creates a Uint32 from a pointer.
func MissingUint32 ¶
func MissingUint32() Uint32
MissingUint32 creates a Uint32 in the missing state.
func OfNullableUint32 ¶
OfNullableUint32 creates a Uint32 from a pointer. It is an alias for FromUint32Ptr.
type Uint64 ¶
Uint64 is a three-state optional for uint64 values.
func FromUint64Ptr ¶
FromUint64Ptr creates a Uint64 from a pointer.
func MissingUint64 ¶
func MissingUint64() Uint64
MissingUint64 creates a Uint64 in the missing state.
func OfNullableUint64 ¶
OfNullableUint64 creates a Uint64 from a pointer. It is an alias for FromUint64Ptr.
func (Uint64) Value ¶
Value implements driver.Valuer, returning int64 for SQL compatibility. Returns an error if the value exceeds math.MaxInt64.
type Uintptr ¶
Uintptr is a three-state optional for uintptr values.
func FromUintptrPtr ¶
FromUintptrPtr creates a Uintptr from a pointer.
func MissingUintptr ¶
func MissingUintptr() Uintptr
MissingUintptr creates a Uintptr in the missing state.
func OfNullableUintptr ¶
OfNullableUintptr creates a Uintptr from a pointer. It is an alias for FromUintptrPtr.
func (Uintptr) Value ¶
Value implements driver.Valuer, returning int64 for SQL compatibility. Returns an error if the value exceeds math.MaxInt64.