Documentation
¶
Overview ¶
Package core provides shared types for the parse/filter and parse/patch sub-packages: field types, error types, parser configuration, and the schema generator with configurable naming conventions.
Most users import parse or its sub-packages (filter, patch) directly. Import core when you need shared types for custom schema construction or when configuring the schema generator.
Naming Conventions ¶
The schema generator converts Go struct field names to SQL column names and type names to table names. Override the defaults with convention functions:
gen := core.NewSchemaGenerator(
core.WithColumnConvention(core.CamelCase), // productType instead of product_type
core.WithTableConvention(core.Singular), // product instead of products
core.WithFieldNameTag("bson"), // read field names from bson tag
core.WithColumnTag("sql"), // read column names from sql tag
)
Tag Resolution Priority ¶
Column name: SQLColumnMapper → column tag value (default "db") → NamingConvention → snake_case.
Table name: WithSQLTableName → TableConvention → plural snake_case.
Field name: configured tag (default "json") → skip if empty.
Error Types ¶
ParseError is the single error type returned by all parse operations. It carries an E-code, a message, and the offending path or operation index; errors.Is matches it against any error with the same code.
Values ¶
NormalizeScalar, NormalizeInt, NormalizeFloat and NormalizeJSON give request values their canonical form — exact integers range-checked against the destination kind, canonical UUIDs and UTC timestamps, generic JSON documents — and TypeOf classifies Go field types into the storage model schemas are built from.
Index ¶
- Constants
- func AnySlice(v any) ([]any, bool)
- func CanonicalJSONMapKey(t reflect.Type, name string) (reflect.Value, string, error)
- func CompareDecimals(a, b any) (cmp int, ok bool)
- func CompareNumbers(a, b any) (cmp int, ok bool)
- func DecimalText(v any) (string, error)
- func EscapePointerToken(tok string) string
- func FormatPointer(tokens ...string) string
- func FormatTimestamp(t time.Time) string
- func IsDecimalType(t reflect.Type) bool
- func IsDocument(ft FieldType) bool
- func IsIdentifier(s string) bool
- func IsNumber(v any) bool
- func IsUUIDType(t reflect.Type) bool
- func MatchWildcard(pattern, path string) bool
- func NormalizeFloat(v any, kind reflect.Kind) (float64, error)
- func NormalizeInt(v any, kind reflect.Kind) (int64, error)
- func NormalizeJSON(v any) (any, error)
- func NormalizeScalar(dt FieldType, kind reflect.Kind, v any) (any, error)
- func NormalizeUint(v any, kind reflect.Kind) (uint64, error)
- func NumericKind(t reflect.Type) reflect.Kind
- func ParsePointer(p string) ([]string, error)
- func Pluralize(s string) string
- func PortableDecimal(s string) bool
- func ToSnakeCase(s string) string
- func UUIDText(v any) (text string, ok bool)
- func ValidateJSONKeyRepresentation(raw []byte, decoded any) error
- type Bounds
- type Capabilities
- type Code
- type Codec
- type ConstraintError
- type Date
- func (d Date) MarshalJSON() ([]byte, error)
- func (d Date) MarshalText() ([]byte, error)
- func (d *Date) Scan(value any) error
- func (d Date) String() string
- func (d Date) Time() (time.Time, error)
- func (d *Date) UnmarshalJSON(value []byte) error
- func (d *Date) UnmarshalText(value []byte) error
- func (d Date) Value() (driver.Value, error)
- type Decimal
- type Field
- type FieldType
- type GeneratorOption
- func WithColumnConvention(conv NamingConvention) GeneratorOption
- func WithColumnMapper(mapper SQLColumnMapper) GeneratorOption
- func WithColumnTag(tag string) GeneratorOption
- func WithColumnTypes(types map[string]SQLType) GeneratorOption
- func WithFieldNameTag(tag string) GeneratorOption
- func WithSQLTableName(name string) GeneratorOption
- func WithSearchParam(p string) GeneratorOption
- func WithSortMaxFields(n int) GeneratorOption
- func WithTableConvention(conv TableConvention) GeneratorOption
- type GeneratorOptions
- type NamingConvention
- type Option
- func WithClock(now func() time.Time) Option
- func WithCodec(codec Codec) Option
- func WithGeneratorOptions(opts ...GeneratorOption) Option
- func WithMaxArraySize(n int) Option
- func WithMaxConditions(n int) Option
- func WithMaxCost(cost int) Option
- func WithMaxDepth(depth int) Option
- func WithMaxInputSize(size int) Option
- func WithMaxPatchCopyBytes(n int64) Option
- type ParseError
- type ParseErrorKind
- type ParserConfig
- type PolicySubject
- type RelationKind
- type RelationSchema
- type SQLColumnMapper
- type SQLType
- type SchemaGenerator
- func (g *SchemaGenerator) ColumnExpr(table, field string, fieldType FieldType, dbTag string) (string, error)
- func (g *SchemaGenerator) ColumnName(field, dbTag string) (string, error)
- func (g *SchemaGenerator) ColumnTagKey() string
- func (g *SchemaGenerator) FieldColumn(f *Field) (column string, ok bool, err error)
- func (g *SchemaGenerator) FieldNameTag() string
- func (g *SchemaGenerator) FieldType(field *Field) (TypeInfo, error)
- func (g *SchemaGenerator) StructFields(t reflect.Type) (*StructFields, error)
- func (g *SchemaGenerator) TableName(t interface{ ... }) (string, error)
- type StdlibJSON
- type StructFields
- type TableConvention
- type Tags
- type TypeInfo
- type Validator
Constants ¶
const ( ConstraintEnum = "enum" ConstraintMinLen = "minlen" ConstraintMaxLen = "maxlen" ConstraintMin = "min" ConstraintMax = "max" ConstraintMinItems = "minitems" ConstraintMaxItems = "maxitems" )
Declared constraints shared by schema discovery and patch diagnostics.
const MaxDecimalDigits = 1000
MaxDecimalDigits bounds the digits of a decimal's plain notation, the "0" before the point of a fraction included: PostgreSQL's limit on a declared numeric precision. A short exponent literal ("1e999999") would otherwise render, bind and compare a million digits.
const TimestampLayout = "2006-01-02T15:04:05.000000000Z07:00"
TimestampLayout is the canonical timestamp text: RFC 3339 in UTC with exactly nine fractional digits. The width is fixed, so where timestamps are stored and compared as text (SQLite) text order is time order ; time.RFC3339Nano trims trailing zeros, which sorts `…05.5Z` before `…05Z`.
Variables ¶
This section is empty.
Functions ¶
func AnySlice ¶
AnySlice returns v as []any when it is the decoder's []any or any typed slice or array ([]string, []int64, []uuid.UUID). Byte slices are not treated as lists.
func CanonicalJSONMapKey ¶
CanonicalJSONMapKey decodes a member name into a map key and returns its JSON spelling. Dummy values keep the map element's custom codec out of this path.
func CompareDecimals ¶ added in v0.4.0
CompareDecimals compares two decimals exactly, returning -1, 0 or +1. Each operand is anything DecimalText accepts, pointers dereferenced; ok is false when either is not a decimal.
func CompareNumbers ¶
CompareNumbers compares two numeric values exactly — no float64 widening of integers — returning -1, 0 or +1. ok is false when either operand is not a number (see IsNumber) or is NaN.
func DecimalText ¶ added in v0.4.0
DecimalText is v's canonical decimal text: plain notation, no exponent, no leading zeros, no trailing fractional zeros, and "0" for a zero of either sign. One value has one text, so equal decimals have equal text ("1.50", "1.5e0" and 1.5 are all "1.5").
It accepts a JSON number or a string in the JSON number grammar (the wire form of shopspring's decimal is a string), any Go integer, a finite float (its shortest decimal form, as strconv formats it), a Decimal, and a type whose text (encoding.TextMarshaler) is a decimal. Hexadecimal, fractions, NaN, infinities, a leading "+" or "." and anything with more than MaxDecimalDigits digits in plain notation are errors.
func EscapePointerToken ¶
EscapePointerToken escapes one reference token for inclusion in a JSON Pointer ("~" → "~0", then "/" → "~1").
func FormatPointer ¶
FormatPointer joins reference tokens into an RFC 6901 JSON Pointer, escaping "~" and "/" inside each token.
func FormatTimestamp ¶
FormatTimestamp renders t in the canonical timestamp form (TimestampLayout).
func IsDecimalType ¶ added in v0.4.0
IsDecimalType reports a decimal type: a named type whose value or pointer has the Decimal method set.
func IsDocument ¶
IsDocument reports whether values of ft are JSON documents (json, object).
func IsIdentifier ¶
IsIdentifier reports whether s is a plain SQL identifier ([A-Za-z_][A-Za-z0-9_]*), safe to emit into SQL unquoted.
func IsNumber ¶
IsNumber reports whether v is a numeric value NormalizeInt / NormalizeFloat / CompareNumbers accept: json.Number or any Go integer or float kind.
func IsUUIDType ¶
IsUUIDType reports a UUID type: a named 16-byte array that marshals to text, as the standard library's uuid.UUID, github.com/google/uuid and github.com/gofrs/uuid all are. A plain [16]byte is binary.
func MatchWildcard ¶
MatchWildcard checks if a wildcard pattern matches a JSON Pointer path, token by token: * matches exactly one token and ** any number. Tokens are the pointer's own (RFC 6901), compared in their escaped form, so an empty key is a token like any other — "/a//b" is three tokens and "/a/*" does not match it. "/*" means exactly one token under root — the old match-everything special case over-granted patch policies intending top-level fields only.
func NormalizeFloat ¶
NormalizeFloat converts a decoded request value into a finite float64 with the precision of kind (reflect.Float32, otherwise float64). Integers are accepted; literals are parsed directly at the destination precision so SQL parameters and typed Go values round identically.
func NormalizeInt ¶
NormalizeInt converts a decoded request value into an exact int64 in the domain of the signed kind (reflect.Invalid is the int64 domain). It accepts json.Number, every Go integer kind, and floats that are integral and within ±2^53 — a float beyond that has already lost precision upstream, so it is rejected rather than guessed. Fractional values, NaN/Inf, strings and out-of-range values are errors, as is an unsigned kind (NormalizeUint).
func NormalizeJSON ¶
NormalizeJSON returns v as a generic JSON document: map[string]any, []any, string, bool, nil, and numbers as int64 (integers in range), uint64 (integers above math.MaxInt64) or finite float64. It is the form JSON filter values are compared and bound in. Decoder output converts in place; other Go values (typed maps, slices, structs) are read back through their JSON encoding first. An integer literal beyond 64 bits is an error: binding it would silently round it. Decimal/exponent integers are also kept exact; fractional literals must round-trip through float64 without changing their decimal value.
func NormalizeScalar ¶
NormalizeScalar validates a decoded request value against a field's data type and returns the canonical Go value filter ASTs and patch operations carry:
- FieldTypeInt → int64 (signed kinds) or uint64 (unsigned), range-checked against kind
- FieldTypeFloat → finite float64, range-checked against kind
- FieldTypeDecimal → canonical decimal text (DecimalText)
- FieldTypeString → string (encoding.TextMarshaler accepted)
- FieldTypeUUID → canonical lowercase UUID string
- FieldTypeBool → bool
- FieldTypeTimestamp → RFC 3339 UTC string with nanosecond precision (time.Time accepted)
Other data types pass through unchanged. Non-nil pointers are dereferenced first, so typed Go input (*int64, *time.Time) normalizes like its value. A nil value is an error; callers decide separately whether a field admits null.
func NormalizeUint ¶
NormalizeUint is NormalizeInt for an unsigned kind (reflect.Invalid is the uint64 domain): a negative value is an error.
func NumericKind ¶
NumericKind reports the numeric reflect.Kind a Go type decodes into (after pointer indirection), or reflect.Invalid for non-numeric types. Schemas record it so request values are range-checked against the real destination instead of a float64 approximation.
func ParsePointer ¶
ParsePointer splits an RFC 6901 JSON Pointer into its reference tokens, unescaping "~1" to "/" and "~0" to "~". The empty pointer (the whole document) yields no tokens. A non-empty pointer must start with "/"; a "~" not followed by "0" or "1" is malformed.
func Pluralize ¶
Pluralize returns the English plural form of a word using common rules. Handles -y → -ies, sibilant suffixes → -es, and default -s.
func PortableDecimal ¶
PortableDecimal reports whether a JSON number literal denotes exactly the decimal of its nearest float64's shortest form, so every backend compares the same value: PostgreSQL's numeric sees the literal, SQLite and Go see the float64. "0.1", "1.50" and "2e3" are portable; "0.10000000000000001" (which a float64 rounds to 0.1) and "1e400" (which overflows) are not.
func ToSnakeCase ¶
ToSnakeCase converts PascalCase or camelCase to snake_case.
func UUIDText ¶
UUIDText is v's canonical text when v is a UUID (IsUUIDType); ok is false for any other value.
func ValidateJSONKeyRepresentation ¶
ValidateJSONKeyRepresentation checks physical member names against a freshly decoded value, passed by non-nil pointer, without decoding or encoding its element values again. Ordinary map keys and recognized struct fields must retain their JSON spelling. Unknown struct members and interface, RawMessage and custom JSON subtrees are opaque.
Types ¶
type Bounds ¶ added in v0.5.0
type Bounds struct {
// MinLen and MaxLen are the fewest and most characters; nil is
// unbounded.
MinLen, MaxLen *int
// Min and Max are the least and greatest number as canonical decimal
// text (DecimalText); empty is unbounded.
Min, Max string
// MinItems and MaxItems are the fewest and most elements of an array;
// nil is unbounded.
MinItems, MaxItems *int
}
Bounds are a field's inclusive value bounds, from its minlen, maxlen, min, max, minitems and maxitems tags. A length bound counts a string's characters: Unicode code points, as a CHAR(n) or VARCHAR(n) column and PostgreSQL's char_length count them. A numeric bound is an exact decimal. On an array field each length and numeric bound applies to every element, as enum does; minitems and maxitems count the elements, as PostgreSQL's cardinality does.
func (Bounds) BoundsValues ¶ added in v0.7.0
BoundsValues reports bounds on a value, or on each element of an array: a length or a number.
func (Bounds) Check ¶ added in v0.5.0
Check refuses bounds the field's type cannot hold: length bounds belong to a string or an array of strings, numeric bounds to an int, float or decimal or an array of them, element counts to an array.
func (Bounds) CountsItems ¶ added in v0.7.0
CountsItems reports bounds on an array's number of elements.
type Capabilities ¶
Capabilities are the values of a field's `parse` tag. Excluded is `parse:"-"`, which also keeps a document's declared paths out of sorts.
type Code ¶
type Code string
Code identifies a parse error independently of an application error catalog. A Code is also an errors.Is target for ParseError.
func (Code) ErrorHTTPStatus ¶
ErrorHTTPStatus returns the code's HTTP status; unknown codes are invalid input.
func (Code) ErrorMessage ¶
ErrorMessage returns the code's default message, or empty for an unknown code.
func (Code) IsErrorUserFacing ¶
IsErrorUserFacing reports whether the category's message is safe to disclose.
type Codec ¶
Codec serializes request documents and typed patch round trips. StdlibJSON is the default; WithCodec selects another Encode/Decode implementation. Cursors use an independent, fixed wire format.
type ConstraintError ¶ added in v0.10.0
type ConstraintError struct {
Constraint string
Limit string
// contains filtered or unexported fields
}
ConstraintError identifies a declared constraint and its schema limit. Enum limits are the comma-separated allowlist; bounds retain schema text.
func NewConstraintError ¶ added in v0.10.0
func NewConstraintError(constraint, limit, detail string) *ConstraintError
NewConstraintError retains the value-specific diagnostic as Error's text.
func (*ConstraintError) Error ¶ added in v0.10.0
func (e *ConstraintError) Error() string
type Date ¶ added in v0.2.0
type Date string
Date is a Gregorian calendar date, independent of timezone or time of day. Its JSON, text and SQL representations are exactly YYYY-MM-DD. The zero value is invalid; use *Date for nullable values.
func ParseDate ¶ added in v0.2.0
ParseDate validates a civil date without interpreting it as an instant.
func (Date) MarshalJSON ¶ added in v0.2.0
func (Date) MarshalText ¶ added in v0.2.0
func (*Date) Scan ¶ added in v0.2.0
Scan accepts native SQL DATE values and canonical text. It never converts a timestamp's timezone or discards a time component supplied as text.
func (Date) Time ¶ added in v0.2.0
Time returns the calendar components at UTC midnight for APIs that require time.Time. The conversion does not apply a viewing or session timezone.
func (*Date) UnmarshalJSON ¶ added in v0.2.0
func (*Date) UnmarshalText ¶ added in v0.2.0
type Decimal ¶ added in v0.4.0
Decimal is an exact decimal number, Coefficient × 10^Exponent: the method set of github.com/shopspring/decimal.Decimal. A Go type with it is a decimal field (FieldTypeDecimal), recognized by shape so this package depends on no decimal library; a decimal type with another method set declares its column with `storage:"scalar:decimal"`.
type Field ¶
type Field struct {
// GoName is the Go field name.
GoName string
// Type is the field's declared type.
Type reflect.Type
// Route is the index path from the walked type to the field, through
// the embedded structs it is promoted from.
Route []int
// External is the field's name under the field-name tag, by
// encoding/json's rule (the tag's name, else the Go name). It is empty
// when the tag hides the field, or the embedded struct it is promoted
// from (`json:"-"`).
External string
// Tags are the field's annotations, parsed once.
Tags Tags
}
Field is one field of a StructFields walk.
func (*Field) HasFieldNameOption ¶
HasFieldNameOption reports whether the field-name tag carries option (omitempty, omitzero, ...).
func (*Field) Hidden ¶
Hidden reports a field the field-name tag hides: it has columns, but no name a request can use (relations and server fields name themselves).
type FieldType ¶
type FieldType string
FieldType represents the data type of a field in filter and patch schemas.
const ( FieldTypeString FieldType = "string" FieldTypeInt FieldType = "int" FieldTypeFloat FieldType = "float" FieldTypeDecimal FieldType = "decimal" FieldTypeBool FieldType = "bool" FieldTypeTimestamp FieldType = "timestamp" FieldTypeDate FieldType = "date" FieldTypeUUID FieldType = "uuid" FieldTypeJSON FieldType = "json" FieldTypeArray FieldType = "array" FieldTypeObject FieldType = "object" FieldTypeAny FieldType = "any" FieldTypeGeo FieldType = "geo" )
type GeneratorOption ¶
type GeneratorOption func(*GeneratorOptions)
GeneratorOption configures a SchemaGenerator.
func WithColumnConvention ¶
func WithColumnConvention(conv NamingConvention) GeneratorOption
WithColumnConvention sets the naming convention for SQL columns. Default: SnakeCase. Common alternatives: CamelCase, LowerCase.
core.WithColumnConvention(core.CamelCase)
func WithColumnMapper ¶
func WithColumnMapper(mapper SQLColumnMapper) GeneratorOption
WithColumnMapper sets a custom column mapper (full control).
func WithColumnTag ¶
func WithColumnTag(tag string) GeneratorOption
WithColumnTag sets which struct tag provides the SQL column name. Default: "db". The column tag value takes precedence over the naming convention.
core.WithColumnTag("sql") // read from `sql:"column_name"`
core.WithColumnTag("column") // read from `column:"col_name"`
func WithColumnTypes ¶
func WithColumnTypes(types map[string]SQLType) GeneratorOption
WithColumnTypes supplies physical storage declarations keyed by column name. The generator owns a copy of the map.
func WithFieldNameTag ¶
func WithFieldNameTag(tag string) GeneratorOption
WithFieldNameTag sets which struct tag provides the external field name. Default: "json". Use for APIs that serialize with a different format.
core.WithFieldNameTag("bson") // read from `bson:"field_name"`
core.WithFieldNameTag("yaml") // read from `yaml:"field_name"`
func WithSQLTableName ¶
func WithSQLTableName(name string) GeneratorOption
WithSQLTableName overrides the table name for a specific type.
func WithSearchParam ¶
func WithSearchParam(p string) GeneratorOption
WithSearchParam sets the query-string parameter name a generated SearchSchema advertises for its free-text search box. Default "search" (filter.ParamSearch).
func WithSortMaxFields ¶
func WithSortMaxFields(n int) GeneratorOption
WithSortMaxFields caps how many sort fields a generated SortSchema accepts. Default 3.
func WithTableConvention ¶
func WithTableConvention(conv TableConvention) GeneratorOption
WithTableConvention sets the naming convention for SQL table names. Default: PluralSnake ("Product" → "products").
core.WithTableConvention(core.Singular) // "product" core.WithTableConvention(core.PluralCamel) // "products"
type GeneratorOptions ¶
type GeneratorOptions struct {
// SQLTableName overrides the derived table name for this specific type.
// Takes precedence over TableConvention.
SQLTableName string
// ColumnTypes declares physical storage independently of Go field shape.
ColumnTypes map[string]SQLType
// ColumnMapper provides full control over column expression generation.
// Takes precedence over ColumnConvention and ColumnTag.
ColumnMapper SQLColumnMapper
// ColumnConvention transforms field names to SQL column names.
// Default: SnakeCase. Ignored when ColumnMapper is set.
ColumnConvention NamingConvention
// TableNameConvention transforms type names to SQL table names.
// Default: PluralSnake ("Product" → "products").
// Ignored when SQLTableName is set.
TableNameConvention TableConvention
// FieldNameTag is the struct tag to read for external field names.
// Default: "json". Set to "bson", "yaml", etc. for non-JSON APIs.
FieldNameTag string
// ColumnTag is the struct tag to read for SQL column names.
// Default: "db". Set to "sql", "column", etc. for your ORM.
ColumnTag string
// DefaultFilterOps maps FieldType to default filter operators when the
// filter_ops tag is omitted.
DefaultFilterOps map[FieldType][]string
// DefaultPatchOps maps FieldType to default patch operations when the
// patch_ops tag is omitted.
DefaultPatchOps map[FieldType][]string
// SortMaxFields caps how many sort fields a generated SortSchema accepts.
// Zero means the default of 3.
SortMaxFields int
// SearchParam is the query-string parameter name a generated SearchSchema
// advertises for its free-text search box. Empty means "search", the
// parameter list handlers read (filter.ParamSearch).
SearchParam string
}
GeneratorOptions holds options for schema generation. All fields have sensible defaults — override only what you need.
type NamingConvention ¶
NamingConvention transforms an identifier string according to a convention.
var ( // SnakeCase converts PascalCase/camelCase to snake_case (default). SnakeCase NamingConvention = ToSnakeCase // CamelCase converts PascalCase to camelCase (first letter lowercase). CamelCase NamingConvention = toCamelCase // PascalCase returns the string unchanged (Go's default naming). PascalCase NamingConvention = func(s string) string { return s } // LowerCase converts to all lowercase with no separators. LowerCase NamingConvention = strings.ToLower )
Built-in naming conventions.
type Option ¶
type Option func(*ParserConfig)
Option configures a Parser.
func WithClock ¶
WithClock pins the anchor for relative-time tokens (`now`, `now-7d`). Default: time.Now().UTC. Tests pass a frozen clock for deterministic resolution.
func WithCodec ¶
WithCodec sets the codec that decodes filter and patch bodies and round-trips documents during typed patch application. Default: StdlibJSON (numbers decode exactly). Cursors do not use it: their encoding is owned by the keyset cursor codec.
core.WithCodec(myMsgpackCodec{})
func WithGeneratorOptions ¶
func WithGeneratorOptions(opts ...GeneratorOption) Option
WithGeneratorOptions sets GeneratorOptions used by typed parsers.
func WithMaxArraySize ¶
WithMaxArraySize bounds $in / $nin members, array $contains elements and the values in a JSON filter document.
func WithMaxConditions ¶
WithMaxConditions sets the maximum number of filter conditions.
func WithMaxCost ¶
WithMaxCost sets the maximum estimated query cost.
func WithMaxDepth ¶
WithMaxDepth sets the maximum request depth: filter boolean nesting, JSON filter document nesting and patch JSON Pointer segments.
func WithMaxInputSize ¶
WithMaxInputSize sets the maximum input size in bytes.
func WithMaxPatchCopyBytes ¶
WithMaxPatchCopyBytes bounds the bytes a patch's copy operations may add to a document during typed apply. Default 1 MiB.
type ParseError ¶
type ParseError struct {
Code string `json:"code"`
Message string `json:"message"`
Kind ParseErrorKind `json:"kind"`
Path string `json:"path,omitempty"`
Index *int `json:"index,omitempty"` // pointer so op index 0 survives the wire
Details map[string]any `json:"details,omitempty"`
Cause error `json:"-"`
}
ParseError is the single error type for all parse operations.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
Error implements the error interface.
func (*ParseError) ErrorCode ¶
func (e *ParseError) ErrorCode() string
ErrorCode returns the E-code string for middleware introspection.
func (*ParseError) ErrorHTTPStatus ¶
func (e *ParseError) ErrorHTTPStatus() int
ErrorHTTPStatus returns the code's status, or 422 for unknown codes.
func (*ParseError) ErrorMessage ¶
func (e *ParseError) ErrorMessage() string
ErrorMessage returns the human-readable message.
func (*ParseError) Is ¶
func (e *ParseError) Is(target error) bool
Is reports whether target carries the same E-code — any error with an ErrorCode() string method, including Code — so a ParseError matches its code's sentinel across wrap chains. An empty code matches nothing; Cause stays reachable through Unwrap.
func (*ParseError) IsErrorUserFacing ¶
func (e *ParseError) IsErrorUserFacing() bool
IsErrorUserFacing reports the message safe to show the caller: it describes the request, never the database.
func (*ParseError) Unwrap ¶
func (e *ParseError) Unwrap() error
Unwrap returns the underlying cause for errors.Is/As compatibility.
type ParseErrorKind ¶
type ParseErrorKind string
ParseErrorKind identifies the subsystem that produced the error.
const ( ParseErrorKindFilter ParseErrorKind = "filter" ParseErrorKindPatch ParseErrorKind = "patch" ParseErrorKindSort ParseErrorKind = "sort" ParseErrorKindSchema ParseErrorKind = "schema" )
type ParserConfig ¶
type ParserConfig struct {
// MaxDepth bounds request structure depth: filter boolean nesting,
// JSON filter document nesting and patch JSON Pointer segments.
MaxDepth int
// MaxCost bounds a filter's estimated cost: about 1 per indexed
// condition, 10 per unindexed one, more for documents, relations,
// unanchored patterns and $or.
MaxCost int
// MaxInputSize bounds a filter or patch body in bytes.
MaxInputSize int
// MaxConditions bounds a filter's leaf conditions.
MaxConditions int
// MaxArraySize bounds $in / $nin members, array $contains elements and
// the values in a JSON filter document.
MaxArraySize int
// MaxPatchCopyBytes bounds the total bytes a patch's copy operations may
// add to a document during typed apply (copy amplification guard).
MaxPatchCopyBytes int64
GeneratorOpts []GeneratorOption
Codec Codec // Wire format codec. Nil = encoding/json fallback.
Clock func() time.Time // Relative-time anchor (`now-7d`). Nil = time.Now().UTC.
}
ParserConfig holds shared configuration for filter and patch parsers.
func DefaultConfig ¶
func DefaultConfig() *ParserConfig
DefaultConfig returns a ParserConfig with sensible defaults.
func (*ParserConfig) GetCodec ¶
func (c *ParserConfig) GetCodec() Codec
GetCodec returns the configured codec, falling back to the package default (StdlibJSON) when none is configured.
type PolicySubject ¶
type PolicySubject struct {
ID string
TenantID string
TenantPath string
Roles []string
Groups []string
Permissions []string
Attributes map[string]any
}
PolicySubject describes the actor making the request. Used by both filter and patch policy enforcement.
type RelationKind ¶
type RelationKind string
RelationKind is a relation's cardinality.
const ( // ManyToMany relates rows through a pair table; the zero kind. ManyToMany RelationKind = "" // HasMany relates an owner to the target rows whose foreign key holds // the owner's key. HasMany RelationKind = "has_many" // BelongsTo relates an owner to the one target row its foreign key // names. BelongsTo RelationKind = "belongs_to" )
type RelationSchema ¶
type RelationSchema struct {
// Kind is the relation's cardinality.
Kind RelationKind
// JoinTable is the name of the junction table (e.g. "widget_tags").
JoinTable string
// SourceColumn is the column on JoinTable that holds the owner's PK
// (e.g. "widget_id").
SourceColumn string
// TargetColumn is the column on JoinTable that holds the related
// entity's PK (e.g. "tag_id").
TargetColumn string
// PrimaryKey is the owner entity's PK column (defaults to "id" when
// empty).
PrimaryKey string
// TenantColumn names a tenant-scope column on the junction (typically
// "tenant_id"). When non-empty, every junction statement parse emits —
// filter, facet, include and relation patch — binds it to the caller's
// tenant, and a builder without a bound tenant fails closed unless the
// caller opts into unscoped relations explicitly. Empty
// means the junction is not tenant-scoped (a globally shared table).
TenantColumn string
// DeletedColumn is JoinTable's soft-delete column: a row with it set
// is not related.
DeletedColumn string
// TargetTable, when set, is the target table a many-to-many joins
// through its pair table (on TargetTable.TargetKey = JoinTable.TargetColumn)
// so predicates reach the target's columns; TargetTenant and
// TargetDeleted scope its rows as TenantColumn and DeletedColumn scope
// JoinTable's. Empty for a pair table compared by key alone.
TargetTable string
TargetKey string
TargetTenant string
TargetDeleted string
// Policy scopes the related target rows by the server's policy for the
// target table instead of the tenant column.
Policy bool
}
RelationSchema describes how a field's owner rows relate to other rows . Every predicate correlates JoinTable's rows to the owner by `JoinTable.SourceColumn = <owner>.PrimaryKey` and compiles to an EXISTS / NOT EXISTS. For a many-to-many JoinTable is the pair table and TargetColumn its target key; for a has-many or belongs-to JoinTable is the target table itself: a has-many correlates the target's foreign key to the owner's key, a belongs-to the target's key to the owner's foreign key (PrimaryKey).
The struct lives in parse/core (rather than parse/filter) because both parse/filter and parse/patch need to consult the same descriptor when emitting SQL.
func ParseRelationTag ¶
func ParseRelationTag(tag string) (*RelationSchema, error)
ParseRelationTag parses a `relation:"…"` struct-tag value into a RelationSchema. The tag format is positional with optional trailing fields:
relation:"<junction>,<src>,<tgt>[,<pk>[,<tenant_col>]]"
Examples:
relation:"widget_tags,widget_id,tag_id" // 3-arg relation:"widget_tags,widget_id,tag_id,id" // 4-arg, explicit pk relation:"widget_tags,widget_id,tag_id,id,tenant_id" // 5-arg, tenant-scoped relation:"system_tags,id,tag_id,id,-" // 5-arg, explicit no-tenant
Every part must be a plain SQL identifier: the values are emitted into SQL verbatim, so a malformed tag fails at schema generation, not in a query.
func (*RelationSchema) RelatedTable ¶
func (r *RelationSchema) RelatedTable() string
RelatedTable is the table whose rows a relation's nested predicates test: TargetTable through a pair table, else JoinTable itself.
type SQLColumnMapper ¶
SQLColumnMapper maps struct fields to SQL column expressions. Implement this for full control over column naming — it takes precedence over ColumnConvention and the db/column tag.
type SQLType ¶
type SQLType string
SQLType declares a resource column's storage role and any dialect read cast. JSON and native arrays remain distinct even when their Go shapes coincide.
const ( SQLDate SQLType = "date" SQLInet SQLType = "inet" SQLCIDR SQLType = "cidr" SQLInterval SQLType = "interval" SQLInetArray SQLType = "inet[]" SQLCIDRArray SQLType = "cidr[]" SQLIntervalArray SQLType = "interval[]" SQLJSON SQLType = "json" SQLJSONB SQLType = "jsonb" SQLTextArray SQLType = "text[]" SQLInt32Array SQLType = "integer[]" SQLUUIDArray SQLType = "uuid[]" )
type SchemaGenerator ¶
type SchemaGenerator struct {
Opts *GeneratorOptions
}
SchemaGenerator generates schemas from Go struct types using configurable naming conventions and struct tag keys.
func NewSchemaGenerator ¶
func NewSchemaGenerator(opts ...GeneratorOption) *SchemaGenerator
NewSchemaGenerator creates a SchemaGenerator with the given options.
func (*SchemaGenerator) ColumnExpr ¶
func (g *SchemaGenerator) ColumnExpr(table, field string, fieldType FieldType, dbTag string) (string, error)
ColumnExpr builds the SQL column expression for a field. Priority: ColumnMapper → columnTag value → ColumnConvention → SnakeCase default. Without a ColumnMapper the result is "table.column" and the column must be a plain identifier; a mapper's expressions are the developer's own SQL and are emitted as returned.
func (*SchemaGenerator) ColumnName ¶
func (g *SchemaGenerator) ColumnName(field, dbTag string) (string, error)
ColumnName returns just the column name (without table prefix), for patch SQL SET clauses and cursor row reads. Priority: columnTag value → ColumnConvention → SnakeCase default.
func (*SchemaGenerator) ColumnTagKey ¶
func (g *SchemaGenerator) ColumnTagKey() string
ColumnTagKey returns the struct tag key to read for SQL column names. Default: "db".
func (*SchemaGenerator) FieldColumn ¶
func (g *SchemaGenerator) FieldColumn(f *Field) (column string, ok bool, err error)
FieldColumn is the field's column: the column tag's name, else the generator's convention applied to its external name (its Go name when the field-name tag hides it). ok is false for a field that is not a column (column tag "-").
func (*SchemaGenerator) FieldNameTag ¶
func (g *SchemaGenerator) FieldNameTag() string
FieldNameTag returns the struct tag key to read for external field names. Default: "json".
func (*SchemaGenerator) FieldType ¶
func (g *SchemaGenerator) FieldType(field *Field) (TypeInfo, error)
FieldType combines a field's Go representation with its declared storage. JSON scalar and scalar-slice fields use document operators, while typed objects retain their member schema and native arrays retain array semantics.
func (*SchemaGenerator) StructFields ¶
func (g *SchemaGenerator) StructFields(t reflect.Type) (*StructFields, error)
StructFields walks t (a struct, or a pointer to one) under the generator's field-name and column tags. The walk is cached per type and tag pair. A name two fields claim — a shallower field shadowing a promoted one, or two promoted fields at one depth — is an error naming both fields: encoding/json keeps the shallower field or drops both, and parse must see exactly the fields encoding/json writes.
func (*SchemaGenerator) TableName ¶
func (g *SchemaGenerator) TableName(t interface{ Name() string }) (string, error)
TableName derives the SQL table name for a type. Priority: SQLTableName (explicit) → TableNameConvention → PluralSnake default. The name is emitted into SQL verbatim, so anything but a plain identifier is an error at schema generation.
type StdlibJSON ¶
type StdlibJSON struct{}
StdlibJSON is the default Codec: the standard library's JSON, with encoding/json's data model (field names, omitempty, durations as nanoseconds), so a document reads back the way responses are written. Decode is stricter than encoding/json's Unmarshal: a duplicate object member name, invalid UTF-8 or data after the value is an error, so a request cannot say a field twice and have one value win. It preserves numbers exactly: a number landing in an `any` becomes a json.Number rather than a float64, so integers beyond ±2^53 reach validation intact.
type StructFields ¶
type StructFields struct {
// Type is the walked struct type.
Type reflect.Type
// Fields holds the fields in declaration order, an embedded struct's
// promoted fields in place of it.
Fields []*Field
// contains filtered or unexported fields
}
StructFields is a struct type's fields, walked once and shared by every view parse builds: columns, the filter, sort, search and patch schemas, keyset cursor values, server-only patch paths and document members. The fields are the ones encoding/json writes under the generator's field-name tag — embedded structs promoted as encoding/json promotes them — plus the fields that tag hides, which columns, server-only paths and relations still read.
func StructFieldsOf ¶
func StructFieldsOf(t reflect.Type, nameTag, columnTag string) (*StructFields, error)
StructFieldsOf is SchemaGenerator.StructFields for explicit tag keys.
func (*StructFields) ColumnTagged ¶
func (s *StructFields) ColumnTagged(column string) (*Field, bool)
ColumnTagged returns the field whose column tag names column exactly.
type TableConvention ¶
TableConvention transforms a type name into a SQL table name.
var ( // PluralSnake converts PascalCase to plural snake_case: "Product" → "products" (default). PluralSnake TableConvention = func(s string) string { return Pluralize(ToSnakeCase(s)) } // Singular converts PascalCase to singular snake_case: "Product" → "product". Singular TableConvention = func(s string) string { return ToSnakeCase(s) } // PluralCamel converts PascalCase to plural camelCase: "Product" → "products". PluralCamel TableConvention = func(s string) string { return Pluralize(toCamelCase(s)) } )
Built-in table conventions.
type Tags ¶
type Tags struct {
// Parse is the field's parse capabilities.
Parse Capabilities
// Column is the column tag's text: empty when absent, "-" for a field
// that is not a column.
Column string
// FieldNameOptions are the field-name tag's options (omitempty, ...).
FieldNameOptions string
Relation, RelationName string
FilterOps, PatchOps string
Enum []string
Bounds Bounds
Facet string
Paths, Elements string
Storage string
Geo, GeoSRID string
GeoLat, GeoLon string
Indexed, Immutable bool
Label, Description string
Group, Order string
SortDefault string
SearchWeight string
}
Tags are the struct tags parse reads on a field. Option-bearing tags hold their raw text for the view that interprets them.
type TypeInfo ¶
type TypeInfo struct {
Type FieldType
// SQLType is the explicit storage declaration, empty for Go-only inference.
SQLType SQLType
// Elem is the element type of a FieldTypeArray; empty otherwise.
Elem FieldType
// NumberKind is the Go numeric kind of Type, or of Elem for an array;
// reflect.Invalid when not numeric.
NumberKind reflect.Kind
}
TypeInfo is how a Go field type is advertised and stored.
func TypeOf ¶
TypeOf classifies a Go field type (pointers stripped). The classification is the storage model every backend shares:
string / int / float / bool kinds string, int, float, bool time.Time, a UUID type (IsUUIDType) timestamp, uuid Date date a decimal type (IsDecimalType) decimal — PostgreSQL numeric; NUMERIC or REAL on SQLite slice or array of a scalar above, other than decimal array — a PostgreSQL native array (TEXT[], BIGINT[], …); JSON text on SQLite map, interface, json.RawMessage, slice of anything else json — a document: PostgreSQL jsonb; JSON text on SQLite struct object — a JSON document with a fixed shape []byte, chan, func, … any — no filter or patch semantics