ecto

package module
v0.0.0-...-31c98c8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 28, 2026 License: MIT Imports: 10 Imported by: 0

README

Ecto

Library for deserialization and validation of input data**

Basic definitions

Schema — set of rules for transforming and validating input data. It consists of tests. A schema of type Atomic also contains a converter function and can provide a default value.

Converter function — function that transforms input data from one type to another for a subsequent test application.

Test - part of the schema consisting of a predicate function and an error template returned when the predicate fails. Tests may apply to all data types or only a restricted subset.

Predicate function — function describing a property or relation of a subject, which may be either true or false. Returns true / false.

Schema types

Atomic

Intended for describing scalar Go types or types that do not require recursive/internal processing (integers, booleans, strings, etc.).
Error format:

["error1", "error2"]
Struct

A composite schema that is represented as an associative list (dictionary), where each key is a struct field and the value is the schema for that field.
Example:

1 Struct-schema 1 {
2     Email: (Atom-schema 1)
3     Password: (Atom-schema 2)
4     Meta: (Struct-schema 2)
5 }

Error format:

{"Email": ["error1", "error2"], "Meta": {"meta1": ["error"]}}
List

A composite schema that applies a selected subschema to each element of an array/list.
Error format:

["error1", "error2"] // general errors

or

{"0": ["error"], "2": ["error"]} // per slice element
Map

A composite schema that supports general tests. At the moment there's no subschema support for keys/values.
Error format:

["error1", "error2"]
Optional Schema

A composite wrapper over any schema. The inner schema is applied only when data is present (not null). Requires a pointer type.
An error format is identical to Atomic.

The principle of composite schemas boils down to calling nested sub-schemas with additional options, while Atomic is a standalone schema and its mechanism is as follows:

flowchart LR
    A([Start]) --> B[Run converter]

    B --> C{Converter failed?}
    C -->|Yes| D([Error]):::error
    C -->|No| F{Go-zero value?}

    F -->|Yes| G{Required?}
    G -->|No| H{Has default?}
    G -->|Yes| D

    H -->|Yes| J[Set default value] --> K[Initialize empty error list]
    H -->|No| K

    F -->|No| K

    K --> L[i = 0]

    L --> M{i < number of tests?}
    M -->|Yes| N["Call test[i]"]
    
    N --> O{Test failed?}
    O -->|Yes| P[Append error to list] --> Q[i += 1] --> M
    O -->|No| Q --> M

    M -->|No| R{Length of error list > 0?}
    R -->|Yes| D
    R -->|No| T([Stop])

    classDef error fill:#ff0000;

Tests

  • Common for all types:

    • Required: value must not be zero-value. If this test fails, all subsequent tests are skipped.
      Error: required
    • OneOf: value must be one of the provided list.
      Error: must be one of %v
  • For integers

    • Eq: value must equal the specified integer
      Error: must be equal to %d
    • Min: minimum value (inclusive)
      Error: must be %d minimum
    • Max: maximum value (inclusive)
      Error: must be %d maximum
  • For floating-point numbers

    • Min: minimum value (inclusive)
      Error: must be %f minimum
    • Max: maximum value (inclusive)
      Error: must be %f maximum
    • MaxPrecision: limit on the number of digits after the decimal point
      Error: has more than %d precision digits
  • For strings

    • Min: minimum number of characters
      Error: must be at least %d characters long
    • Max: maximum number of characters
      Error: must be at most %d characters long
    • Regex: regular expression validation
      Error: must match regex %s
    • URL: Checks if the value is a valid URL
      Error: invalid URL
    • Currency: ISO-4217 currency standard
      Error: invalid ISO-4217 currency
    • IP: Checks IPv4/IPv6
      Error: invalid IP address
    • Lang: ISO-639-1 language code
      Error: invalid ISO-639-1 language code
    • Country: ISO-3166 country code
      Error: invalid ISO-3166 country code

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ScrubAny

func ScrubAny(ptr any)

ScrubAny replaces "" with nil in *string recursively of any Go type

func ScrubString

func ScrubString[S ~string](ptr **S)

ScrubString replaces "" with nil of *string. Simplified non-reflect version of ScrubAny

Types

type AtomicSchema

type AtomicSchema[T comparable, R any] struct {
	// contains filtered or unexported fields
}

AtomicSchema is a schema designed to describe scalar Go types or those that do not need to be recursively processed internally (ex. decimal.Decimal). Features: - Convert input data into another (from T to R) for further validations - Mark as required (check if value is Go zero-value) - Set default if value is zero - Set of Test predicates for validation

func Atomic

func Atomic[T comparable]() AtomicSchema[T, T]

func AtomicFrom

func AtomicFrom[T comparable, R any](convert func(*T) (*R, error)) AtomicSchema[T, R]

func Float

func Float() AtomicSchema[float64, float64]

Float shorthand

func FloatFrom

func FloatFrom[T comparable]() AtomicSchema[T, float64]

FloatFrom shorthand with conversion. Supported types in order: - float32/64 and its type definitions - json.Number

func Int

func Int() AtomicSchema[int, int]

Int shorthand

func IntFrom

func IntFrom[T constraints.Integer]() AtomicSchema[T, int]

IntFrom shorthand with conversion

func String

func String() AtomicSchema[string, string]

String shorthand

func StringFrom

func StringFrom[T comparable]() AtomicSchema[T, string]

StringFrom shorthand with conversion. Supported types in order: - fmt.Stringer - string and its type definitions

func (AtomicSchema[T, R]) Default

func (s AtomicSchema[T, R]) Default(value T) AtomicSchema[T, R]

func (AtomicSchema[T, R]) ForType

func (AtomicSchema[T, R]) ForType() reflect.Type

func (AtomicSchema[T, R]) IsRequired

func (s AtomicSchema[T, R]) IsRequired() bool

func (AtomicSchema[T, R]) OmitZero

func (s AtomicSchema[T, R]) OmitZero() AtomicSchema[T, R]

OmitZero Deprecated: for optional parameters use PtrSchema, this method is for backward compatibility

func (AtomicSchema[T, R]) Process

func (s AtomicSchema[T, R]) Process(data *T) error

Process may return ListError

func (AtomicSchema[T, R]) Required

func (s AtomicSchema[T, R]) Required() AtomicSchema[T, R]

func (AtomicSchema[T, R]) Test

func (s AtomicSchema[T, R]) Test(tests ...Test[R]) AtomicSchema[T, R]

func (AtomicSchema[T, R]) WithRequired

func (s AtomicSchema[T, R]) WithRequired(value bool) IAtomicOrPtrSchema

type CastOpt

type CastOpt func(*castConfig)

func Scrub

func Scrub() CastOpt

Scrub replaces empty strings with nil for every `*string` type

type Decoder

type Decoder interface {
	Decode(any) error
}

type Error

type Error string

func Errorf

func Errorf(format string, args ...any) Error

func (Error) Error

func (e Error) Error() string

type FieldMeta

type FieldMeta struct {
	Index int
	Tag   string
}

type IAtomicOrPtrSchema

type IAtomicOrPtrSchema interface {
	Schema
	IsRequired() bool
	WithRequired(value bool) IAtomicOrPtrSchema
}

type IMapSchema

type IMapSchema interface {
	Schema
	// contains filtered or unexported methods
}

type ISliceSchema

type ISliceSchema interface {
	Schema
	Inner() Schema
	WithInner(inner Schema) ISliceSchema
}

type IStructSchema

type IStructSchema interface {
	Schema
	Fields() M
	WithFields(M) IStructSchema
	CastToAny(src []byte, unmarshal func([]byte, any) error, opts ...CastOpt) (any, error)
	Meta() map[string]FieldMeta
}

type ListError

type ListError []Error

func (ListError) Error

func (e ListError) Error() string

func (ListError) JSON

func (e ListError) JSON() json.RawMessage

type M

type M = map[string]Schema

type MapError

type MapError map[string]error

func (*MapError) Add

func (e *MapError) Add(key string, err error)

func (MapError) Error

func (e MapError) Error() string

func (MapError) JSON

func (e MapError) JSON() json.RawMessage

type MapSchema

type MapSchema[M ~map[K]V, K comparable, V any] struct {
	// contains filtered or unexported fields
}

MapSchema represents a generic map type. There's no subschema support for key/value yet.

func Map

func Map[M ~map[K]V, K comparable, V any]() MapSchema[M, K, V]

func (MapSchema[M, K, V]) ForType

func (m MapSchema[M, K, V]) ForType() reflect.Type

func (MapSchema[M, K, V]) Process

func (s MapSchema[M, K, V]) Process(data M) error

Process may return ListError

func (MapSchema[M, K, V]) Test

func (m MapSchema[M, K, V]) Test(tests ...Test[M]) MapSchema[M, K, V]

type PtrSchema

type PtrSchema[To any] struct {
	// contains filtered or unexported fields
}

PtrSchema wraps inner Schema assuming input data as pointer. Features: - Mark a pointer as required (non-nil) - Process internal schema

func Ptr

func Ptr[To any](inner Schema) PtrSchema[To]

func (PtrSchema[T]) ForType

func (s PtrSchema[T]) ForType() reflect.Type

func (PtrSchema[T]) IsRequired

func (s PtrSchema[T]) IsRequired() bool

func (PtrSchema[T]) Process

func (s PtrSchema[T]) Process(data *T) error

Process may return ListError

func (PtrSchema[T]) Required

func (s PtrSchema[T]) Required() PtrSchema[T]

func (PtrSchema[To]) WithRequired

func (s PtrSchema[To]) WithRequired(value bool) IAtomicOrPtrSchema

type Schema

type Schema interface {
	ForType() reflect.Type
	// contains filtered or unexported methods
}

Schema common interface to process input data (conversions, validations etc.)

type SliceSchema

type SliceSchema[S ~[]T, T any] struct {
	// contains filtered or unexported fields
}

SliceSchema wraps inner Schema assuming input data as slice. Features: - Run slice-specific tests (see ecto/slices subpackage) - Process internal schema

func Slice

func Slice[S ~[]T, T any](inner Schema) SliceSchema[S, T]

func (SliceSchema[S, T]) ForType

func (SliceSchema[S, T]) ForType() reflect.Type

func (SliceSchema[S, T]) Inner

func (s SliceSchema[S, T]) Inner() Schema

func (SliceSchema[S, T]) Process

func (s SliceSchema[S, T]) Process(data []T) error

Process may return ListError (for list tests) or MapError for individual element errors. Map key is a stringified slice index

func (SliceSchema[S, T]) Test

func (s SliceSchema[S, T]) Test(tests ...Test[S]) SliceSchema[S, T]

func (SliceSchema[S, T]) WithInner

func (s SliceSchema[S, T]) WithInner(inner Schema) ISliceSchema

type StructSchema

type StructSchema[T any] struct {
	// contains filtered or unexported fields
}

StructSchema represents schema for struct types via hashmap as a struct field to its schema

func Struct

func Struct[T any](fields M) StructSchema[T]

func (StructSchema[T]) Cast

func (s StructSchema[T]) Cast(src []byte, deserialize func([]byte, any) error, opts ...CastOpt) (T, error)

Cast deserializes bytes into type and runs Process.

func (StructSchema[T]) CastJSON

func (s StructSchema[T]) CastJSON(src []byte, opts ...CastOpt) (T, error)

CastJSON is shorthand for Cast with json.Unmarshal deserializer

func (StructSchema[T]) CastToAny

func (s StructSchema[T]) CastToAny(src []byte, deserialize func([]byte, any) error, opts ...CastOpt) (any, error)

func (StructSchema[T]) Decode

func (s StructSchema[T]) Decode(dec Decoder, opts ...CastOpt) (T, error)

Decode decoding into T from external Decoder and runs Process

func (StructSchema[T]) Extend

func (s StructSchema[T]) Extend(fields M) StructSchema[T]

Extend existing schema

func (StructSchema[T]) Fields

func (s StructSchema[T]) Fields() M

func (StructSchema[T]) ForType

func (s StructSchema[T]) ForType() reflect.Type

func (StructSchema[T]) Meta

func (s StructSchema[T]) Meta() map[string]FieldMeta

func (StructSchema[T]) Process

func (s StructSchema[T]) Process(ptr *T) error

Process may return MapError

func (StructSchema[T]) WithFields

func (s StructSchema[T]) WithFields(fields M) IStructSchema

WithFields overwrites existing schema fields

type Test

type Test[T any] struct {
	Error Error
	Func  func(v *T) bool
}

Test holds predicate function to apply on validated data and returns Error in case of failure

func OneOf

func OneOf[T comparable](variants ...T) Test[T]

OneOf restricts value to limited variants

func (*Test[T]) Run

func (t *Test[T]) Run(ptr *T) *Error

Run applies predicate

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL