packages/param/param.go (75 lines of code) (raw):
package param
import (
"encoding/json"
"reflect"
)
// NullObj is used to mark a struct as null.
// To send null to an [Opt] field use [NullOpt].
func NullObj[T NullableObject, PT Settable[T]]() T {
var t T
pt := PT(&t)
pt.setMetadata(nil)
return *pt
}
// To override a specific field in a struct, use its [WithExtraFields] method.
func OverrideObj[T OverridableObject, PT Settable[T]](v any) T {
var t T
pt := PT(&t)
pt.setMetadata(v)
return *pt
}
// IsOmitted returns true if v is the zero value of its type.
//
// It indicates if a field with the `json:"...,omitzero"` tag will be omitted
// from serialization.
//
// If v is set explicitly to the JSON value "null", this function will return false.
// Therefore, when available, prefer using the [IsPresent] method to check whether
// a field is present.
//
// Generally, this function should only be used on structs, arrays, maps.
func IsOmitted(v any) bool {
if v == nil {
return false
}
if o, ok := v.(interface{ IsOmitted() bool }); ok {
return o.IsOmitted()
}
return reflect.ValueOf(v).IsZero()
}
type NullableObject = overridableStruct
type OverridableObject = overridableStruct
type Settable[T overridableStruct] interface {
setMetadata(any)
*T
}
type overridableStruct interface {
IsNull() bool
IsOverridden() (any, bool)
GetExtraFields() map[string]any
}
// APIObject should be embedded in api object fields, preferably using an alias to make private
type APIObject struct{ metadata }
// APIUnion should be embedded in all api unions fields, preferably using an alias to make private
type APIUnion struct{ metadata }
type forceOmit int
// Omit can be used with [metadata.WithExtraFields] to ensure that a
// required field is omitted. This is useful as an escape hatch for
// when a required is unwanted for some unexpected reason.
const Omit forceOmit = -1
type metadata struct{ any }
type metadataNull struct{}
type metadataExtraFields map[string]any
// IsNull returns true if the field is the explicit value `null`,
// prefer using [IsPresent] to check for presence, since it checks against null and omitted.
func (m metadata) IsNull() bool {
if _, ok := m.any.(metadataNull); ok {
return true
}
if msg, ok := m.any.(json.RawMessage); ok {
return string(msg) == "null"
}
return false
}
func (m metadata) IsOverridden() (any, bool) {
if _, ok := m.any.(metadataExtraFields); ok {
return nil, false
}
return m.any, m.any != nil
}
func (m metadata) GetExtraFields() map[string]any {
if extras, ok := m.any.(metadataExtraFields); ok {
return extras
}
return nil
}
// WithExtraFields adds extra fields to the JSON object.
//
// WithExtraFields will override any existing fields with the same key.
// For security reasons, ensure this is only used with trusted input data.
//
// To intentionally omit a required field, use [Omit].
//
// foo.WithExtraFields(map[string]any{"bar": Omit})
func (m *metadata) WithExtraFields(extraFields map[string]any) {
m.any = metadataExtraFields(extraFields)
}
func (m *metadata) setMetadata(override any) {
if override == nil {
m.any = metadataNull{}
return
}
m.any = override
}