model

package
v0.0.0-...-1b2c9a0 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 2026 License: LGPL-2.1 Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	FieldDataTypeNameBoolean       = "boolean"
	FieldDataTypeNameDecimal       = "decimal"
	FieldDataTypeNameEmail         = "email"
	FieldDataTypeNameEnumInt32     = "enumInt32"
	FieldDataTypeNameEnumString    = "enumString"
	FieldDataTypeNameInt32         = "int32"
	FieldDataTypeNameInt64         = "int64"
	FieldDataTypeNameJsonMap       = "jsonmap"
	FieldDataTypeNameModel         = "model"
	FieldDataTypeNameModelDate     = "nikkiDate"
	FieldDataTypeNameModelDateTime = "nikkiDateTime"
	FieldDataTypeNameEtag          = "nikkiEtag"
	FieldDataTypeNameLangCode      = "nikkiLangCode"
	FieldDataTypeNameLangJson      = "nikkiLangJson"
	FieldDataTypeNameSlug          = "nikkiSlug"
	FieldDataTypeNameModelTime     = "nikkiTime"
	FieldDataTypeNamePhone         = "phone"
	FieldDataTypeNameSecret        = "secret"
	FieldDataTypeNameString        = "string"
	FieldDataTypeNameUlid          = "ulid"
	FieldDataTypeNameUrl           = "url"
	FieldDataTypeNameUuid          = "uuid"
)

FieldDataTypeName is the canonical string returned by FieldDataType.String() and used as a column / generic type id.

View Source
const (
	RelationCascadeNoAction   = RelationCascade("NO ACTION")
	RelationCascadeSetNull    = RelationCascade("SET NULL")
	RelationCascadeSetDefault = RelationCascade("SET DEFAULT")
	RelationCascadeCascade    = RelationCascade("CASCADE")
	// RelationCascadeRestrict refuses the parent delete outright. It differs from NO ACTION in
	// when the check runs: RESTRICT fires immediately, NO ACTION defers to the end of the
	// statement and so can be satisfied by a trigger that clears the reference first. For a
	// cross-module reference the immediate refusal is the intended one.
	RelationCascadeRestrict = RelationCascade("RESTRICT")
)
View Source
const (
	RelationTypeOneToOne   = RelationType("one:one")
	RelationTypeOneToMany  = RelationType("one:many")
	RelationTypeManyToOne  = RelationType("many:one")
	RelationTypeManyToMany = RelationType("many:many")
)
View Source
const (
	FieldDataTypeOptEnumValues        = FieldDataTypeOptName("enumValues")
	FieldDataTypeOptLangJsonWhitelist = FieldDataTypeOptName("langJsonWhitelist")
	FieldDataTypeOptLength            = FieldDataTypeOptName("length")
	FieldDataTypeOptPattern           = FieldDataTypeOptName("pattern")
	FieldDataTypeOptRange             = FieldDataTypeOptName("range")
	FieldDataTypeOptSanitizeType      = FieldDataTypeOptName("sanitizeType")
	FieldDataTypeOptScale             = FieldDataTypeOptName("scale")
)
View Source
const (
	SanitizeTypeNone      = SanitizeType("none")
	SanitizeTypeHtml      = SanitizeType("html")
	SanitizeTypePlainText = SanitizeType("plaintext")
)
View Source
const (
	FieldRuleArrayLengthType = FieldRuleName("arrlength")
)
View Source
const JsonFieldTag = "json"

Variables

This section is empty.

Functions

func CoerceFilterBool

func CoerceFilterBool(value any) (bool, error)

CoerceFilterBool parses search-graph filter values into bool (bool, *bool, string literals, etc.).

func GetEdgeNames

func GetEdgeNames(name string) (edgeNames []string)

func GetFieldNames

func GetFieldNames(name string) (fieldNames []string)

GetFieldNames lists what a client may ask for, so it reports readable fields rather than physical columns: a virtual scalar is selectable even though it has no column.

func GetSchemaBuilderFn

func GetSchemaBuilderFn(name string) func() *ModelSchemaBuilder

GetSchemaBuilderFn returns the builder factory registered under name, or nil when absent.

func IsFieldDataTypeModel

func IsFieldDataTypeModel(dt FieldDataType) bool

func NewFormatMismatchErr

func NewFormatMismatchErr(field string) *ft.ClientErrorItem

func NewInvalidDataTypeErr

func NewInvalidDataTypeErr(field string, typeName ...string) *ft.ClientErrorItem

func NewMissingFieldErr

func NewMissingFieldErr(field string) *ft.ClientErrorItem

func PrefixedThroughColumn

func PrefixedThroughColumn(prefix, fieldName string) string

PrefixedThroughColumn returns junction column name prefix_fieldName (e.g. user + id -> user_id).

func RegisterComputedDescriber

func RegisterComputedDescriber(describer ComputedDescriberFn)

RegisterComputedDescriber installs the describer. Called once, from the computed package's init.

func RegisterComputedFinalizer

func RegisterComputedFinalizer(finalizer ComputedFinalizer)

RegisterComputedFinalizer installs the finalizer. Called once, from the computed package's init.

func RegisterComputedJsonParser

func RegisterComputedJsonParser(parser ComputedJsonParser)

RegisterComputedJsonParser installs the parser. Called once, from the computed package's init.

func RegisterSchema

func RegisterSchema(schema *ModelSchema) error

RegisterSchema registers a schema using its name as the registry key. Returns an error if a schema with the same name is already registered.

func RegisterSchemaB

func RegisterSchemaB(schemaBuilder *ModelSchemaBuilder) error

RegisterSchemaB executes the schemaBuilder then registers a schema using its name (set via ModelSchemaBuilder.Name) as the registry key. Returns an error if a schema with the same name is already registered.

func RegisterSchemaBuilderFn

func RegisterSchemaBuilderFn(name string, factory func() *ModelSchemaBuilder) error

RegisterSchemaBuilderFn registers a builder factory under name, so that JSON models can reference it from "extend_before" / "extend_after". Returns an error on duplicate registration.

func RelationsShareForeignKeyColumns

func RelationsShareForeignKeyColumns(a, b ModelRelation) bool

RelationsShareForeignKeyColumns reports whether two relations use the same FK column pairs.

func SetBaseModelSchemaBuilder

func SetBaseModelSchemaBuilder(builder *ModelSchemaBuilder)

func ValidateArrayLength

func ValidateArrayLength(value any, opts any) *ft.ClientErrorItem

ValidateArrayLength validates that slice/array length is between min and max (inclusive). opts must be []int{min, max}.

func ValidateEmail

func ValidateEmail(value string) *ft.ClientErrorItem

func ValidateMax

func ValidateMax(value any, opts any) *ft.ClientErrorItem

ValidateMax validates that value is not greater than max. Supports numbers, strings (length), slices (length).

func ValidateMin

func ValidateMin(value any, opts any) *ft.ClientErrorItem

ValidateMin validates that value is not less than min. Supports numbers, strings (length), slices (length).

func ValidateNotEmpty

func ValidateNotEmpty(value any) *ft.ClientErrorItem

func ValidateNotNil

func ValidateNotNil(value any) *ft.ClientErrorItem

func ValidateOneOf

func ValidateOneOf(value any, opts any) *ft.ClientErrorItem

ValidateOneOf validates that value is one of the allowed values. opts must be []any of allowed values.

func ValidatePattern

func ValidatePattern(value string, re *regexp.Regexp) bool

func ValidateUrl

func ValidateUrl(value string) *ft.ClientErrorItem

func ValidateUuid

func ValidateUuid(value string) bool

func Value

func Value(val any) value

Types

type CompositeUniqueParam

type CompositeUniqueParam struct {
	// IndexName is optional. When empty, the constraint name is derived as
	// "{tableName}_{tenantKey}_{Fields...}". When set, it replaces that whole stem, so it must
	// carry the table prefix itself. The "_ukey" suffix is always appended by the query builder;
	// never write it here. See docs/wiki "04. Dynamic schema" for the 63-byte naming rules.
	IndexName string
	// Fields must all be requiredForCreate. Use PartialUniqueLoose or PartialUniqueStrict when
	// one of them is nullable.
	Fields []string
}

type ComputedDescriberFn

type ComputedDescriberFn func(expression any) *ComputedDescriptor

ComputedDescriberFn summarizes a field's raw computed expression for ToSimplized. Registered through the same seam as the parser and finalizer, and for the same reason: only the computed package can read its own expression types.

type ComputedDescriptor

type ComputedDescriptor struct {
	// Kind is the computed kind, e.g. "expression", "related", "function".
	Kind string `json:"kind,omitempty"`
	// DependsOn names the same-schema field a function-kind computation reads, when it declares
	// one. A form recomputes the field through meta/compute the moment that field changes.
	DependsOn string `json:"depends_on,omitempty"`
}

ComputedDescriptor is the client-facing summary of a computed field: enough for a form to know how the value arrives and what to watch, never the expression tree itself.

type ComputedFinalizer

type ComputedFinalizer func(reg *SchemaRegistry) error

ComputedFinalizer validates every computed field once all schemas are registered and relations are resolved. FinalizeRelations invokes it AFTER releasing the registry lock, so the finalizer may use the registry's ordinary (read-locking) accessors.

type ComputedJsonParser

type ComputedJsonParser func(raw []byte, fieldName string) (expression any, isStored bool, err error)

ComputedJsonParser turns a field's raw "computed" JSON block into the expression value that FieldBuilder.Computed accepts, plus the declared is_stored flag.

The parser lives in common/dynamicmodel/computed, which imports this package — so this package cannot import it back. Instead the computed package registers its parser here at init time, and buildFieldFromDto calls through this seam. A schema that declares "computed" without the computed package linked in fails loudly rather than silently dropping the definition.

type Condition

type Condition []any

func NewCondition

func NewCondition(field string, operator Operator, values ...any) Condition

func (Condition) Field

func (c Condition) Field() string

func (Condition) Operator

func (c Condition) Operator() Operator

func (Condition) Value

func (c Condition) Value() any

func (Condition) Values

func (c Condition) Values() []any

type DynamicFields

type DynamicFields map[string]any

func ExtractFieldsArr

func ExtractFieldsArr[TSrc DynamicModelGetter](arr []TSrc) []DynamicFields

func (DynamicFields) GetAny

func (this DynamicFields) GetAny(key string) any

func (DynamicFields) GetBool

func (this DynamicFields) GetBool(key string) *bool

func (DynamicFields) GetDecimal

func (this DynamicFields) GetDecimal(key string) *decimal.Decimal

GetDecimal reads a decimal field in whatever shape it arrived in.

It used to bare type-assert to decimal.Decimal, which PANICKED on every other shape - and a decimal crosses JSON as a STRING precisely so it does not lose precision, so any value read back through a jsonb column crashed the caller rather than answering. Four modules had independently written their own switch to route around this (accounting/domain/services/values.go, inventory/domain/services/stock_scrap_domservice.go, paymentinvoice/dynamicengines/order_actions.go, purchase/domain/services/purchase_service.go); accepting the shapes here means they did not have to.

A value that cannot be read as a decimal returns nil, the same answer an absent field gives. That is deliberate: the alternative is a panic, and a caller that already handles "not set" handles this correctly, while none of them is prepared to recover from a crash mid-transaction.

func (DynamicFields) GetEtag

func (this DynamicFields) GetEtag(key string) *model.Etag

func (DynamicFields) GetInt32

func (this DynamicFields) GetInt32(key string) *int32

func (DynamicFields) GetInt64

func (this DynamicFields) GetInt64(key string) *int64

GetInt64 returns the int64 value at key. Returns nil if key is missing or value is nil. Caller must ensure the map is initialized (non-nil).

func (DynamicFields) GetLangJson

func (this DynamicFields) GetLangJson(key string) *model.LangJson

GetLangJson safely extracts a LangJson from DynamicFields. Returns nil if key is missing, value is nil, or type assertion fails. This method validates each entry to ensure type safety.

func (DynamicFields) GetModelDate

func (this DynamicFields) GetModelDate(key string) *model.ModelDate

func (DynamicFields) GetModelDateTime

func (this DynamicFields) GetModelDateTime(key string) *model.ModelDateTime

func (DynamicFields) GetModelId

func (this DynamicFields) GetModelId(key string) *model.Id

GetModelId returns the model.Id value at key. Returns nil if key is missing or value is nil. Caller must ensure the map is initialized (non-nil).

func (DynamicFields) GetModelTime

func (this DynamicFields) GetModelTime(key string) *model.ModelTime

func (DynamicFields) GetSlug

func (this DynamicFields) GetSlug(key string) *model.Slug

func (DynamicFields) GetString

func (this DynamicFields) GetString(key string) *string

GetString returns the string value at key. Returns nil if key is missing or value is nil. Caller must ensure the map is initialized (non-nil).

func (DynamicFields) GetStrings

func (this DynamicFields) GetStrings(key string) []string

func (*DynamicFields) Merge

func (this *DynamicFields) Merge(data DynamicFields) error

func (DynamicFields) MustGetInt64

func (this DynamicFields) MustGetInt64(key string) (result int64)

func (DynamicFields) SetAny

func (this DynamicFields) SetAny(key string, v any)

func (DynamicFields) SetBool

func (this DynamicFields) SetBool(key string, v *bool)

func (DynamicFields) SetDecimal

func (this DynamicFields) SetDecimal(key string, v *decimal.Decimal)

func (DynamicFields) SetDecimalStr

func (this DynamicFields) SetDecimalStr(key string, v *string)

func (DynamicFields) SetEtag

func (this DynamicFields) SetEtag(key string, v *model.Etag)

func (DynamicFields) SetInt32

func (this DynamicFields) SetInt32(key string, v *int32)

func (DynamicFields) SetInt64

func (this DynamicFields) SetInt64(key string, v *int64)

func (DynamicFields) SetLangJson

func (this DynamicFields) SetLangJson(key string, v *model.LangJson)

SetLangJson stores a LangJson value in DynamicFields. Sets nil if the input value is nil.

func (DynamicFields) SetModelDate

func (this DynamicFields) SetModelDate(key string, v *model.ModelDate)

func (DynamicFields) SetModelDateTime

func (this DynamicFields) SetModelDateTime(key string, v *model.ModelDateTime)

func (DynamicFields) SetModelId

func (this DynamicFields) SetModelId(key string, v *model.Id)

SetModelId sets the model.Id value at key. Caller must ensure the map is initialized (non-nil).

func (DynamicFields) SetModelTime

func (this DynamicFields) SetModelTime(key string, v *model.ModelTime)

func (DynamicFields) SetSlug

func (this DynamicFields) SetSlug(key string, v *model.Slug)

func (DynamicFields) SetString

func (this DynamicFields) SetString(key string, v *string)

SetString sets the string value at key. Caller must ensure the map is initialized (non-nil).

func (DynamicFields) SetStrings

func (this DynamicFields) SetStrings(key string, v []string)

func (*DynamicFields) UnmarshalJSON

func (this *DynamicFields) UnmarshalJSON(data []byte) error

Implements json.Unmarshaler interface

func (*DynamicFields) UnmarshalText

func (this *DynamicFields) UnmarshalText(text []byte) error

Implements encoding.TextUnmarshaler interface

type DynamicModel

type DynamicModel interface {
	DynamicModelGetter
	DynamicModelSetter
}

type DynamicModelGetter

type DynamicModelGetter interface {
	GetFieldData() DynamicFields
}

type DynamicModelSetter

type DynamicModelSetter interface {
	SetFieldData(data DynamicFields)
}

type FieldBuilder

type FieldBuilder struct {
	// contains filtered or unexported fields
}

func DefineField

func DefineField() *FieldBuilder

func (*FieldBuilder) AutoGenerated

func (this *FieldBuilder) AutoGenerated() *FieldBuilder

Indicates that the field value cannot be set by user but by the system. Any input value will be silently ignored when creating or updating the model. If a default value is registered, it will be used in create operations.

func (*FieldBuilder) Build

func (this *FieldBuilder) Build() *ModelField

func (*FieldBuilder) Computed

func (this *FieldBuilder) Computed(isStored bool, expression any) *FieldBuilder

Computed marks the field's value as the result of a declared calculation, never user input. The expression comes from the computed package's chained constructors:

Computed(false, computed.Sub(computed.F("on_hand_quantity"), computed.F("reserved_quantity")))
Computed(false, computed.Related("template.name"))

isStored=false computes the value when the resource is read; the field is virtual (no column). isStored=true — compute at write time with source-change propagation — is reserved for a future phase and rejected at Build(). The expression is typed `any` to avoid an import cycle with the computed package; it is validated and resolved at schema finalize time.

func (*FieldBuilder) DataType

func (this *FieldBuilder) DataType(dataType FieldDataType) *FieldBuilder

func (*FieldBuilder) DbNullable

func (this *FieldBuilder) DbNullable() *FieldBuilder

DbNullable drops the column's NOT NULL constraint while leaving the field required for create.

Use it only where the database itself must be able to write NULL: a foreign key declared ON DELETE SET NULL clears the column when the parent is deleted, which a NOT NULL column would refuse. It does not make the field optional to a client - RequiredForCreate still applies - so it never widens what the API accepts.

func (*FieldBuilder) Default

func (this *FieldBuilder) Default(val any) *FieldBuilder

Sets the default value for the field. Default value is only used for create operations and when the input field is nil. Read-only fields are always set to the default value regardless of the input. The precedence is: Default > DefaultFn > UseTypeDefault.

func (*FieldBuilder) DefaultFn

func (this *FieldBuilder) DefaultFn(fn func() any) *FieldBuilder

Registers a function to generate the default value for the field. Default value is only used for create operations and when the input field is nil. Read-only fields are always set to the default value regardless of the input. The precedence is: Default > DefaultFn > UseTypeDefault.

func (*FieldBuilder) Description

func (this *FieldBuilder) Description(description model.LangJson) *FieldBuilder

func (*FieldBuilder) IsAutoGenerated

func (this *FieldBuilder) IsAutoGenerated(isAutoGenerated bool) *FieldBuilder

func (*FieldBuilder) IsRequired

func (this *FieldBuilder) IsRequired(isRequired bool) *FieldBuilder

func (*FieldBuilder) IsRequiredForCreate

func (this *FieldBuilder) IsRequiredForCreate(isRequired bool) *FieldBuilder

func (*FieldBuilder) IsRequiredForUpdate

func (this *FieldBuilder) IsRequiredForUpdate(isRequired bool) *FieldBuilder

func (*FieldBuilder) Label

func (this *FieldBuilder) Label(label model.LangJson) *FieldBuilder

func (*FieldBuilder) LabelRef

func (this *FieldBuilder) LabelRef(key string) *FieldBuilder

func (*FieldBuilder) Metadata

func (this *FieldBuilder) Metadata(metadata map[string]any) *FieldBuilder

Allows setting value on create but not on update. Metadata attaches arbitrary module-defined data to the field. The engine never interprets it; a consuming module reads its own keys back through ModelField.Metadata(), and the frontend receives it in the meta/schema payload.

Calling it more than once merges: later keys win, earlier ones survive. That is also what makes it composable with Extend — a schema extending a mixin can add a key without discarding the ones the mixin declared.

Values must be plain JSON-serializable data. The whole schema is round-tripped through JSON by contract, so a func, channel or struct here would be silently lost or would fail to encode.

func (*FieldBuilder) Name

func (this *FieldBuilder) Name(name string) *FieldBuilder

func (*FieldBuilder) NoUpdate

func (this *FieldBuilder) NoUpdate() *FieldBuilder

func (*FieldBuilder) Placeholder

func (this *FieldBuilder) Placeholder(placeholder model.LangJson) *FieldBuilder

func (*FieldBuilder) PrimaryKey

func (this *FieldBuilder) PrimaryKey(isAutoGenerated ...bool) *FieldBuilder

func (*FieldBuilder) RequiredAlways

func (this *FieldBuilder) RequiredAlways() *FieldBuilder

A shortcut to set both RequiredForCreate() and RequiredForUpdate() at once. Use this for schemas used for validation and not for SQL generation.

func (*FieldBuilder) RequiredForCreate

func (this *FieldBuilder) RequiredForCreate() *FieldBuilder

Causes the field to be required for create operations, and determines the "NOT NULL" constraint for the database column. Missing field error will occur when the input value is nil and the field doesn't have a registered default value.

func (*FieldBuilder) RequiredForUpdate

func (this *FieldBuilder) RequiredForUpdate() *FieldBuilder

Causes the field to be required for update operations, but doesn't affect the generated CREATE SQL query. Missing field error will occur when the input value is nil REGARDLESS the field has a registered default value or not.

func (*FieldBuilder) RequiredWith

func (this *FieldBuilder) RequiredWith(otherFieldName string) *FieldBuilder

func (*FieldBuilder) Rule

func (this *FieldBuilder) Rule(rule FieldRule) *FieldBuilder

func (*FieldBuilder) ServiceInjected

func (this *FieldBuilder) ServiceInjected(injectFn func(ctx context.Context, forEdit bool) any) *FieldBuilder

func (*FieldBuilder) SetUseTypeDefault

func (this *FieldBuilder) SetUseTypeDefault(useTypeDefault bool) *FieldBuilder

func (*FieldBuilder) TenantKey

func (this *FieldBuilder) TenantKey() *FieldBuilder

func (*FieldBuilder) Unique

func (this *FieldBuilder) Unique() *FieldBuilder

func (*FieldBuilder) UseTypeDefault

func (this *FieldBuilder) UseTypeDefault() *FieldBuilder

Indicates that the field should use the default value from the type definition. Default value is only used for create operations and when the input field is nil. Read-only fields are always set to the default value regardless of the input. The precedence is: Default > DefaultFn > UseTypeDefault.

func (*FieldBuilder) VersioningKey

func (this *FieldBuilder) VersioningKey() *FieldBuilder

Indicates that the field value is used for versioning the model, which means it is both read-only and required for update operations.

type FieldDataType

type FieldDataType interface {
	ArrayType() FieldDataType
	DefaultValue() value
	IsArray() bool
	Options() FieldDataTypeOptions
	String() string
	TryConvert(val any, options FieldDataTypeOptions) (value, error)
	ToSimplized() any
	Validate(val value) (value, *ft.ClientErrorItem)
}

FieldDataType defines the interface for dynamic field data types. Validate returns (validatedValue, nil) on success or (nil, ValidationError) on failure. Validate always runs TryConvert first to coerce the payload to the concrete storage type, then applies type-specific rules. Options are embedded in the data type; both use them internally.

func FieldDataTypeBoolean

func FieldDataTypeBoolean() FieldDataType

func FieldDataTypeDate

func FieldDataTypeDate() FieldDataType

func FieldDataTypeDateTime

func FieldDataTypeDateTime() FieldDataType

func FieldDataTypeDecimal

func FieldDataTypeDecimal(min string, max string, scale uint) FieldDataType

func FieldDataTypeEmail

func FieldDataTypeEmail() FieldDataType

func FieldDataTypeEnumInt32

func FieldDataTypeEnumInt32(enumValues []int32) FieldDataType

func FieldDataTypeEnumString

func FieldDataTypeEnumString(enumValues []string) FieldDataType

func FieldDataTypeEtag

func FieldDataTypeEtag() FieldDataType

func FieldDataTypeInt32

func FieldDataTypeInt32(min int32, max int32) FieldDataType

func FieldDataTypeInt64

func FieldDataTypeInt64(min int64, max int64) FieldDataType

func FieldDataTypeJsonMap

func FieldDataTypeJsonMap() FieldDataType

FieldDataTypeJsonMap stores JSON in jsonb: one object (map[string]any) or one JSON array ([]any), e.g. [{...}]. Root JSON primitives are rejected.

func FieldDataTypeLangCode

func FieldDataTypeLangCode() FieldDataType

func FieldDataTypeLangJson

func FieldDataTypeLangJson(minLength int, maxLength int, stringOpts ...FieldDataTypeStringOpts) FieldDataType

func FieldDataTypeModel

func FieldDataTypeModel() FieldDataType

FieldDataTypeModel represents a virtual/implicit field that holds a related model or slice of models. It is not persisted as a DB column; it is used for graph traversal and API response expansion.

func FieldDataTypePhone

func FieldDataTypePhone() FieldDataType

func FieldDataTypeSecret

func FieldDataTypeSecret(minLength int, maxLength int) FieldDataType

func FieldDataTypeSlug

func FieldDataTypeSlug() FieldDataType

func FieldDataTypeString

func FieldDataTypeString(minLength int, maxLength int, stringOpts ...FieldDataTypeStringOpts) FieldDataType

func FieldDataTypeTime

func FieldDataTypeTime() FieldDataType

func FieldDataTypeUlid

func FieldDataTypeUlid() FieldDataType

func FieldDataTypeUrl

func FieldDataTypeUrl() FieldDataType

func FieldDataTypeUuid

func FieldDataTypeUuid() FieldDataType

type FieldDataTypeOptName

type FieldDataTypeOptName string

type FieldDataTypeOptions

type FieldDataTypeOptions map[FieldDataTypeOptName]any

type FieldDataTypeStringOpts

type FieldDataTypeStringOpts struct {
	SanitizeType SanitizeType
	Regex        *regexp.Regexp
}

type FieldRule

type FieldRule []any

func FieldRuleArrayLength

func FieldRuleArrayLength(min, max int) FieldRule

func (FieldRule) RuleName

func (this FieldRule) RuleName() FieldRuleName

func (FieldRule) RuleOptions

func (this FieldRule) RuleOptions() any

type FieldRuleName

type FieldRuleName string

type ForeignKeyColumnPair

type ForeignKeyColumnPair struct {
	FkColumn         string `json:"fk_column"`
	ReferencedColumn string `json:"referenced_column"`
}

ForeignKeyColumnPair describes one column of a (possibly composite) foreign key. FkColumn is always on the table that owns the FK constraint; ReferencedColumn is on the referenced table.

type M2mPeerLink struct {
	DestSchema      *ModelSchema
	ThroughSchema   *ModelSchema
	SrcFieldPrefix  string
	DestFieldPrefix string
	Edge            string
}

M2mPeerLink holds junction and FK-prefix metadata for a finalized many-to-many edge from the owning schema toward DestSchema (peer). Used by repositories to insert junction rows without a schema registry.

type ModelField

type ModelField struct {
	// contains filtered or unexported fields
}

func (*ModelField) Clone

func (this *ModelField) Clone() *ModelField

func (*ModelField) ColumnNullable

func (this *ModelField) ColumnNullable() string

ColumnNullable returns "NOT NULL" if required, else "NULL".

func (*ModelField) ColumnType

func (this *ModelField) ColumnType() string

ColumnType returns the SQL column type string (from DataType).

func (*ModelField) Copy

func (this *ModelField) Copy() *ModelField

Copy creates a new instance of ModelField with the same name, data type, and rules; other properties are not copied.

func (*ModelField) DataType

func (this *ModelField) DataType() FieldDataType

func (*ModelField) Default

func (this *ModelField) Default() *value

func (*ModelField) DefaultFn

func (this *ModelField) DefaultFn() func() any

func (*ModelField) Description

func (this *ModelField) Description() model.LangJson

func (*ModelField) InjectFn

func (this *ModelField) InjectFn() func(ctx context.Context, forEdit bool) any

func (*ModelField) IsArray

func (this *ModelField) IsArray() bool

func (*ModelField) IsAutoGenerated

func (this *ModelField) IsAutoGenerated() bool

func (*ModelField) IsComputed

func (this *ModelField) IsComputed() bool

IsComputed is true when the field's value is derived rather than supplied by the client: either a declared computation, or an edge hydrated from the peer schema. It says nothing about whether the value occupies a column — that is IsPersisted.

func (*ModelField) IsEdgeModel

func (this *ModelField) IsEdgeModel() bool

IsEdgeModel is true for FieldDataTypeModel: a model-typed field standing for a relation, hydrated from the peer schema rather than read from a column of its own.

func (*ModelField) IsForeignKey

func (this *ModelField) IsForeignKey() bool

IsForeignKey is true when the field is the local side of an edge's key map, or a junction-table FK column.

func (*ModelField) IsNoUpdate

func (this *ModelField) IsNoUpdate() bool

func (*ModelField) IsNullable

func (this *ModelField) IsNullable() bool

IsNullable returns true if the column allows NULL.

func (*ModelField) IsPersisted

func (this *ModelField) IsPersisted() bool

IsPersisted is true when the field's value occupies a database column. True for every ordinary field; false for an edge and for a computed field evaluated at read time.

func (*ModelField) IsPrimaryKey

func (this *ModelField) IsPrimaryKey() bool

func (*ModelField) IsRequiredForCreate

func (this *ModelField) IsRequiredForCreate() bool

func (*ModelField) IsRequiredForUpdate

func (this *ModelField) IsRequiredForUpdate() bool

func (*ModelField) IsServiceInjected

func (this *ModelField) IsServiceInjected() bool

func (*ModelField) IsSystemField

func (this *ModelField) IsSystemField() bool

IsSystemField is true for a field the server owns rather than the client: the keys that identify, version or scope a record, plus the foreign keys that wire it to its peers. Deliberately says nothing about whether the field has a column — that is IsVirtual.

func (*ModelField) IsTenantKey

func (this *ModelField) IsTenantKey() bool

func (*ModelField) IsUnique

func (this *ModelField) IsUnique() bool

func (*ModelField) IsVersioningKey

func (this *ModelField) IsVersioningKey() bool

func (*ModelField) IsVirtual

func (this *ModelField) IsVirtual() bool

IsVirtual is true when the field has no database column, for either reason: a read-time computed scalar or an edge. Use it wherever the question is "can this be written, filtered or ordered"; use IsEdgeModel when the answer differs between an edge and a virtual scalar.

func (*ModelField) Label

func (this *ModelField) Label() model.LangJson

func (*ModelField) Metadata

func (this *ModelField) Metadata() map[string]any

Metadata returns the field's module-defined metadata, or nil when none was declared. The returned map is the field's own, so callers must not mutate it.

func (*ModelField) MetadataValue

func (this *ModelField) MetadataValue(key string) (any, bool)

MetadataValue returns a single metadata entry and whether it was present.

func (*ModelField) Name

func (this *ModelField) Name() string

Getter methods

func (*ModelField) RawComputedExpr

func (this *ModelField) RawComputedExpr() any

RawComputedExpr returns the untyped computed expression. Callers outside this package use computed.DefOf for the typed view; the indirection exists solely to avoid an import cycle.

func (*ModelField) Rules

func (this *ModelField) Rules() []*FieldRule

func (*ModelField) ToModelJson

func (this *ModelField) ToModelJson() (map[string]any, error)

ToModelJson renders one field in the model-JSON shape its parser counterpart reads.

func (ModelField) ToSimplized

func (this ModelField) ToSimplized() any

func (*ModelField) Validate

func (this *ModelField) Validate(val any, forEdit ...bool) (value, *ft.ClientErrorItem)

Validate invokes the field's data type Validate (which validates and may sanitize), then applies field rules. Returns the validated value and technical error if any. When value is empty: uses default if available; otherwise errors only when required with no fallback.

type ModelRelation

type ModelRelation struct {
	Edge         string       `json:"edge"`
	SrcField     string       `json:"src_field"`
	RelationType RelationType `json:"relation_type"`

	DestSchemaName string `json:"dest_schema_name"`
	DestField      string `json:"dest_field"`
	// ForeignKeys is the canonical multi-column FK. When empty, SrcField/DestField represent a single pair.
	ForeignKeys []ForeignKeyColumnPair `json:"foreign_keys,omitempty"`
	// UnvalidatedFkMap is consumed by SchemaRegistry.FinalizeRelations (src field name -> dest field name).
	UnvalidatedFkMap DynamicFields `json:"-"`
	// InversePeerSchemaName and InversePeerEdgeName are set by EdgeFrom / Existing() and cleared after finalize.
	InversePeerSchemaName string          `json:"inverse_peer_schema_name,omitempty"`
	InversePeerEdgeName   string          `json:"inverse_peer_edge_name,omitempty"`
	OnDelete              RelationCascade `json:"on_delete"`
	OnUpdate              RelationCascade `json:"on_update"`
	// IsInverse marks relations resolved from EdgeFrom. The FK columns in ForeignKeys reference the
	// destination table's columns, not this schema's own columns. This distinction is needed for
	// correct JOIN direction, hydrate filters, and FK dependency ordering.
	IsInverse bool `json:"is_inverse,omitempty"`

	M2mThroughModel      *ModelSchema `json:"through_model,omitempty"`
	M2mThroughSchemaName string       `json:"through_table_name,omitempty"`
	// M2mSrcFieldPrefix is this (src) schema's junction-table FK prefix, not a single physical column name.
	// JOINs use PrefixedThroughColumn(M2mSrcFieldPrefix, pk) for each entry in this schema's PrimaryKeys(),
	// and PrefixedThroughColumn(M2mSrcFieldPrefix, tenantKey) when a tenant key exists (e.g. user -> user_id,
	// user_tenant_id). The peer (dest) side uses DestFieldPrefix the same way.
	M2mSrcFieldPrefix string `json:"src_field_prefix,omitempty"`
	// M2mDestFieldPrefix is the peer (dest) schema's junction FK prefix; set by FinalizeRelations.
	M2mDestFieldPrefix string `json:"dest_field_prefix,omitempty"`
	// contains filtered or unexported fields
}

func (ModelRelation) EffectiveForeignKeys

func (this ModelRelation) EffectiveForeignKeys() []ForeignKeyColumnPair

EffectiveForeignKeys returns the resolved FK column pairs for this relation.

func (ModelRelation) Label

func (this ModelRelation) Label() model.LangJson

func (ModelRelation) ToSimplized

func (this ModelRelation) ToSimplized() any

type ModelSchema

type ModelSchema struct {
	// contains filtered or unexported fields
}

func GetOrRegisterSchema

func GetOrRegisterSchema(schemaName string, getBuilder func() *ModelSchemaBuilder) *ModelSchema

GetOrRegisterSchema first attempts to retrieve a registered schema by its name. If not found, it builds a new schema using the builder and registers it.

func GetSchema

func GetSchema(name string) *ModelSchema

GetSchema retrieves a registered schema by its name.

func MustGetSchema

func MustGetSchema(name string) *ModelSchema

MustGetSchema retrieves a registered schema by its name.

func (ModelSchema) AllUniqueGroups

func (this ModelSchema) AllUniqueGroups() []CompositeUniqueParam

AllUniqueGroups returns all unique constraints (field-level and schema-level) with their optional index names. Field-level Unique() columns always carry an empty IndexName.

func (ModelSchema) AllUniques

func (this ModelSchema) AllUniques() [][]string

AllUniques returns the column groups of all unique constraints (field-level and schema-level), for callers that only compare column sets. Use AllUniqueGroups when the index name matters.

func (ModelSchema) Column

func (this ModelSchema) Column(name string) (*ModelField, bool)

Column returns the field by name (alias for Field for ORM compatibility).

func (ModelSchema) Columns

func (this ModelSchema) Columns() []*ModelField

Columns returns fields in definition order for SQL operations. Fields with no DB column are excluded: model-typed edge fields and virtual scalars alike. This is the "physical column" list — use it for DDL and writes. For the set a client may select and receive, use ReadableFields.

func (ModelSchema) CompositeUniques

func (this ModelSchema) CompositeUniques() []CompositeUniqueParam

CompositeUniques returns schema-level composite UNIQUE constraints (all columns NOT NULL).

func (ModelSchema) DefaultSearchFields

func (this ModelSchema) DefaultSearchFields() []string

DefaultSearchFields is the field list a search on this schema returns when it specifies neither an explicit field list nor a resolvable view. Empty when the schema declares none.

func (ModelSchema) Description

func (this ModelSchema) Description() model.LangJson

func (ModelSchema) Etag

func (this ModelSchema) Etag() model.Etag

func (ModelSchema) Field

func (this ModelSchema) Field(name string) (*ModelField, bool)

func (ModelSchema) FieldNames

func (this ModelSchema) FieldNames() []string

func (ModelSchema) Fields

func (this ModelSchema) Fields() map[string]*ModelField

func (ModelSchema) FromRelations

func (this ModelSchema) FromRelations() []ModelRelation

func (*ModelSchema) InjectServiceFields

func (this *ModelSchema) InjectServiceFields(ctx context.Context, result DynamicFields, forEdit bool)

func (ModelSchema) IsPrimaryKey

func (this ModelSchema) IsPrimaryKey(name string) bool

IsPrimaryKey returns true if the given field is a primary key.

func (ModelSchema) IsTenantKey

func (this ModelSchema) IsTenantKey(name string) bool

IsTenantKey returns true if the given field is the tenant key.

func (ModelSchema) IsVersioningKey

func (this ModelSchema) IsVersioningKey(name string) bool

IsVersioningKey returns true if the given field is an audit key.

func (ModelSchema) KeyColumns

func (this ModelSchema) KeyColumns() []string

KeyColumns returns primary keys plus tenant key if present.

func (ModelSchema) Label

func (this ModelSchema) Label() model.LangJson

func (*ModelSchema) M2mPeerLinkForDest

func (this *ModelSchema) M2mPeerLinkForDest(destSchemaName string) (*M2mPeerLink, bool)

M2mPeerLinkForDest returns the link for associating this schema with the given peer schema name.

func (*ModelSchema) M2mPeerLinkForEdge

func (this *ModelSchema) M2mPeerLinkForEdge(edge string) (*M2mPeerLink, bool)

M2mPeerLinkForEdge returns finalized many-to-many metadata for an outgoing M2M edge name on this schema.

func (ModelSchema) MustField

func (this ModelSchema) MustField(name string) *ModelField

func (ModelSchema) Name

func (this ModelSchema) Name() string

func (ModelSchema) PartialUniques

func (this ModelSchema) PartialUniques() []PartialUniqueParam

PartialUniques returns every partial unique index definition, loose and strict alike.

A loose group emits UNIQUE (not-null columns, nullable column) WHERE nullable IS NOT NULL, plus UNIQUE (not-null columns) WHERE nullable IS NULL. A strict group emits only the first of those. Only populated after ShouldBuildDb / populateDbMetadata validation.

func (ModelSchema) PartialUniquesLoose

func (this ModelSchema) PartialUniquesLoose() []PartialUniqueParam

PartialUniquesLoose returns only the groups that also constrain their NULL rows.

func (ModelSchema) PartialUniquesStrict

func (this ModelSchema) PartialUniquesStrict() []PartialUniqueParam

PartialUniquesStrict returns only the groups that leave their NULL rows unconstrained.

func (ModelSchema) Pick

func (this ModelSchema) Pick(fieldNames []string) *ModelSchema

Picks creates a new instance of ModelSchema with only the specified fields. Other information such as table name, labels, descriptions, etc. are not copied.

func (ModelSchema) PrimaryKeys

func (this ModelSchema) PrimaryKeys() []string

PrimaryKeys returns the list of primary key column names.

func (ModelSchema) ReadableFields

func (this ModelSchema) ReadableFields() []*ModelField

ReadableFields returns every field a client may select and receive in a result row, in definition order: physical columns plus virtual scalars. Model-typed edge fields are excluded, because an edge is selected by its own name and hydrated separately rather than being read as a column.

func (ModelSchema) RecordLabelField

func (this ModelSchema) RecordLabelField() string

RecordLabelField is the field identifying a record of this model to a human. Empty when the schema has not declared one, in which case a client must fall back to the primary key.

func (ModelSchema) RecordSubLabelField

func (this ModelSchema) RecordSubLabelField() string

RecordSubLabelField is the optional secondary field shown beneath the main label. Empty when the schema declares none.

func (ModelSchema) Relations

func (this ModelSchema) Relations() []ModelRelation

Relations returns to-relations first, then from-relations (navigation, graph, legacy callers).

func (ModelSchema) SearchIndexGroups

func (this ModelSchema) SearchIndexGroups() []SearchIndexGroupParam

SearchIndexGroups returns grouped CREATE INDEX definitions.

func (ModelSchema) TableName

func (this ModelSchema) TableName() string

TableName returns the table name associated with this schema.

func (ModelSchema) TenantKey

func (this ModelSchema) TenantKey() string

TenantKey returns the tenant key column name, or empty if not tenant-scoped.

func (*ModelSchema) ToModelJson

func (this *ModelSchema) ToModelJson() (map[string]any, error)

ToModelJson renders a built schema back into the model-JSON shape ParseModelJson accepts.

This is deliberately NOT ToSimplized. The two serve opposite directions and are not interchangeable:

  • ToSimplized is an OUTPUT format for clients. It keys fields by name, flattens the builder's state into is_* booleans, and names data types by their canonical Go id ("enumString").
  • Model JSON is the INPUT format. It lists fields as an array, uses the builder's own verbs ("required_for_create", "auto_generated"), names data types with their JSON ids ("enum_string"), and refuses properties it does not declare.

Feeding ToSimplized's output back into the parser therefore fails. Anything that stores a schema and later rebuilds it — the settings module registers module declarations this way — needs this direction instead.

Only what the parser accepts is emitted, and only what a settings-style declaration carries: fields, their types, labels, defaults and metadata. Table-building concerns (table_name, should_build_db, edges, composite uniques) are intentionally left out.

func (ModelSchema) ToRelations

func (this ModelSchema) ToRelations() []ModelRelation

func (*ModelSchema) ToSimplized

func (this *ModelSchema) ToSimplized() any

func (*ModelSchema) Validate

func (this *ModelSchema) Validate(input DynamicFields, forEdit ...bool) (DynamicFields, ft.ClientErrors)

ValidateMap validates each map key against the corresponding schema field by invoking ModelField.Validate. Returns a new map with validated and sanitized values, or (nil, ClientErrors) when invalid.

func (*ModelSchema) ValidateStruct

func (this *ModelSchema) ValidateStruct(target any, forEdit ...bool) (any, ft.ClientErrors)

ValidateStruct validates a struct pointer by converting to map and validating. Uses "json" struct tag: missing tag uses field name, tag "-" skips the field.

type ModelSchemaBuilder

type ModelSchemaBuilder struct {
	// contains filtered or unexported fields
}

func DefineModel

func DefineModel(name string) *ModelSchemaBuilder

func GetSchemaBuilder

func GetSchemaBuilder(name string) *ModelSchemaBuilder

GetSchemaBuilder builds a fresh *ModelSchemaBuilder from the factory registered under name, or nil when no factory is registered.

func ParseModelJson

func ParseModelJson(modelJson string) *ModelSchemaBuilder

ParseModelJson builds a *ModelSchemaBuilder from a model JSON string, validating it against the model JSON Schema first.

It panics when the JSON is invalid, matching the rest of the builder API, which treats a malformed schema definition as a programming error rather than user input. Use ParseModelJsonSafe to handle the errors instead.

func ParseModelJsonSafe

func ParseModelJsonSafe(modelJson string) (*ModelSchemaBuilder, ft.ClientErrors)

ParseModelJsonSafe is ParseModelJson without the panic: it returns the validation errors, and a nil builder when validation failed.

func (*ModelSchemaBuilder) Build

func (this *ModelSchemaBuilder) Build() *ModelSchema

func (*ModelSchemaBuilder) CompositeUnique

func (this *ModelSchemaBuilder) CompositeUnique(param CompositeUniqueParam) *ModelSchemaBuilder

CompositeUnique registers a multi-column UNIQUE constraint. All columns must be requiredForCreate, enforced in Build() when ShouldBuildDb is set.

func (*ModelSchemaBuilder) CopyField

func (this *ModelSchemaBuilder) CopyField(schema *ModelSchema, fieldName string) *ModelSchemaBuilder

func (*ModelSchemaBuilder) CopyFieldN

func (this *ModelSchemaBuilder) CopyFieldN(schemaName string, fieldName string) *ModelSchemaBuilder

func (*ModelSchemaBuilder) DefaultSearchFields

func (this *ModelSchemaBuilder) DefaultSearchFields(fieldNames ...string) *ModelSchemaBuilder

DefaultSearchFields declares the field list a search on this schema returns when it specifies neither an explicit field list nor a resolvable view. Primary keys are always included by the query builder regardless of this list. Each name must exist on the schema when Build runs.

func (*ModelSchemaBuilder) Description

func (this *ModelSchemaBuilder) Description(description model.LangJson) *ModelSchemaBuilder

func (*ModelSchemaBuilder) EdgeFrom

func (*ModelSchemaBuilder) EdgeTo

func (*ModelSchemaBuilder) ExclusiveRequiredFields

func (this *ModelSchemaBuilder) ExclusiveRequiredFields(fieldNames ...string) *ModelSchemaBuilder

ExclusiveRequiredFields registers one exclusive group: exactly one of the listed fields must be non-empty and required on validate. The slice may contain any number of field names (minimum two). Call multiple times to register multiple independent groups. Each name must exist on the schema when Build runs.

func (*ModelSchemaBuilder) Extend

func (*ModelSchemaBuilder) ExtendBase

func (this *ModelSchemaBuilder) ExtendBase() *ModelSchemaBuilder

func (*ModelSchemaBuilder) ExtendByName

func (this *ModelSchemaBuilder) ExtendByName(schemaName string) *ModelSchemaBuilder

ExtendByName extends this schema with the builder registered under schemaName via RegisterSchemaBuilderFn. Panics when no builder is registered, because a JSON model referencing an unknown base schema is a programming error, not user input.

func (*ModelSchemaBuilder) Field

func (this *ModelSchemaBuilder) Field(fieldBuilder *FieldBuilder) *ModelSchemaBuilder

func (*ModelSchemaBuilder) GetField

func (this *ModelSchemaBuilder) GetField(name string) *FieldBuilder

GetField returns a FieldBuilder wrapping an already-added field, so callers can apply options that cannot be expressed in JSON (ServiceInjected, DefaultFn). The returned builder mutates the field in place, so there is no need to re-add it. Panics when the field does not exist.

func (*ModelSchemaBuilder) HasField

func (this *ModelSchemaBuilder) HasField(name string) bool

HasField reports whether a field of the given name has been added to this schema.

func (*ModelSchemaBuilder) Label

func (*ModelSchemaBuilder) LabelRef

func (this *ModelSchemaBuilder) LabelRef(key string) *ModelSchemaBuilder

func (*ModelSchemaBuilder) Name

func (this *ModelSchemaBuilder) Name(name string) *ModelSchemaBuilder

func (*ModelSchemaBuilder) PartialUniqueLoose

func (this *ModelSchemaBuilder) PartialUniqueLoose(param PartialUniqueParam) *ModelSchemaBuilder

PartialUniqueLoose registers a PAIR of partial unique indexes: one over NotNullFields plus NullableField where the latter IS NOT NULL, and one over NotNullFields alone where it IS NULL.

The second index is the point of it: it expresses tenant/org-scoped uniqueness, where "unique per organization" must also mean "unique among the rows belonging to no organization". A role name scoped by a nullable org_id is the canonical case.

It is the wrong tool when the nullable column is the VALUE being constrained rather than the scope. There the second index constrains only NotNullFields, so it permits exactly one row per scope with a NULL value — use PartialUniqueStrict instead.

Enforced in Build() when ShouldBuildDb is set.

func (*ModelSchemaBuilder) PartialUniqueStrict

func (this *ModelSchemaBuilder) PartialUniqueStrict(param PartialUniqueParam) *ModelSchemaBuilder

PartialUniqueStrict registers a SINGLE partial unique index over NotNullFields plus NullableField, where the latter IS NOT NULL. Rows with a NULL value are unconstrained, and any number of them may share the same NotNullFields.

This is the tool for "unique when present": an optional external reference, an optional display code. Its loose counterpart would additionally forbid a second NULL-valued row per scope, which for such a column is a bug rather than a constraint.

Enforced in Build() when ShouldBuildDb is set.

func (*ModelSchemaBuilder) RecordLabelField

func (this *ModelSchemaBuilder) RecordLabelField(fieldName string) *ModelSchemaBuilder

RecordLabelField declares the field that identifies a record of this model to a human — the text a client shows wherever a record stands in for itself, such as a relation picker or a breadcrumb. The named field must exist on the schema when Build runs.

func (*ModelSchemaBuilder) RecordSubLabelField

func (this *ModelSchemaBuilder) RecordSubLabelField(fieldName string) *ModelSchemaBuilder

RecordSubLabelField declares an optional secondary field, shown beneath the main label to tell apart records that share one. The named field must exist on the schema when Build runs.

func (*ModelSchemaBuilder) SearchIndex

func (this *ModelSchemaBuilder) SearchIndex(fields ...string) *ModelSchemaBuilder

SearchIndex causes the migration script to generate CREATE INDEX statement for the given fields. Field order matters: Place the most frequently queried column or the one with the highest selectivity (most unique values) first.

func (*ModelSchemaBuilder) SearchIndexGroup

func (this *ModelSchemaBuilder) SearchIndexGroup(group SearchIndexGroupParam) *ModelSchemaBuilder

SearchIndexGroup causes the migration script to generate CREATE INDEX statement for the given fields.

func (*ModelSchemaBuilder) ShouldBuildDb

func (this *ModelSchemaBuilder) ShouldBuildDb() *ModelSchemaBuilder

func (*ModelSchemaBuilder) TableName

func (this *ModelSchemaBuilder) TableName(tableName string) *ModelSchemaBuilder

type ModelSchemaValidateOpts

type ModelSchemaValidateOpts struct {
	// Whether to validate for edit or create (default).
	ForEdit bool
}

type Operator

type Operator string
const (
	Equals        Operator = "="
	NotEquals     Operator = "!="
	GreaterThan   Operator = ">"
	GreaterEqual  Operator = ">="
	LessThan      Operator = "<"
	LessEqual     Operator = "<="
	Contains      Operator = "*"
	NotContains   Operator = "!*"
	StartsWith    Operator = "^"
	NotStartsWith Operator = "!^"
	EndsWith      Operator = "$"
	NotEndsWith   Operator = "!$"
	In            Operator = "in"
	NotIn         Operator = "not_in"
	IsSet         Operator = "is_set"
	IsNotSet      Operator = "not_set"
	// Linked / NotLinked: only for graph conditions on a many edge (one:many, many:many).
	// Field is the edge name (no dot). Value is the peer / child row primary key to test linkage.
	Linked    Operator = "linked"
	NotLinked Operator = "not_linked"
)

type OrderDirection

type OrderDirection string
const (
	Asc  OrderDirection = "asc"
	Desc OrderDirection = "desc"
)

type PartialUniqueParam

type PartialUniqueParam struct {
	// IndexName is optional. When empty, the index name is derived as
	// "{tableName}_{tenantKey}_{NotNullFields...}_{NullableField}". When set, it replaces that whole
	// stem, so it must carry the table prefix itself. The suffixes are always appended by the query
	// builder; never write them here. A loose group appends "_ukey_notnull" and "_ukey_null"; a
	// strict group appends "_ukey".
	IndexName string
	// NotNullFields must all be requiredForCreate.
	NotNullFields []string
	// NullableField must NOT be requiredForCreate.
	NullableField string
	// Strict selects which pair of indexes this group emits. See PartialUniqueLoose and
	// PartialUniqueStrict; it is set by those builders rather than by a caller.
	Strict bool
}

type RelationBuilder

type RelationBuilder struct {
	// contains filtered or unexported fields
}

func Edge

func Edge(edgeName string) *RelationBuilder

func (*RelationBuilder) Build

func (this *RelationBuilder) Build() *ModelRelation

func (*RelationBuilder) Existing

func (this *RelationBuilder) Existing(srcSchemaName, srcEdgeName string) *RelationBuilder

func (*RelationBuilder) Label

func (this *RelationBuilder) Label(label model.LangJson) *RelationBuilder

func (*RelationBuilder) ManyToMany

func (this *RelationBuilder) ManyToMany(peerSchemaName, throughSchemaName, srcFieldPrefix string) *RelationBuilder

func (*RelationBuilder) ManyToOne

func (this *RelationBuilder) ManyToOne(destSchemaName string, srcDestKeyMap DynamicFields) *RelationBuilder

func (*RelationBuilder) OnDelete

func (this *RelationBuilder) OnDelete(onDelete RelationCascade) *RelationBuilder

func (*RelationBuilder) OnUpdate

func (this *RelationBuilder) OnUpdate(onUpdate RelationCascade) *RelationBuilder

func (*RelationBuilder) OneToMany

func (this *RelationBuilder) OneToMany(destSchemaName string, srcDestKeyMap DynamicFields) *RelationBuilder

func (*RelationBuilder) OneToOne

func (this *RelationBuilder) OneToOne(destSchemaName string, srcDestKeyMap DynamicFields) *RelationBuilder

type RelationCascade

type RelationCascade string

func (RelationCascade) IsValid

func (this RelationCascade) IsValid() bool

IsValid reports whether this is a referential action PostgreSQL accepts. The JSON model files carry the value as a free string, so an unrecognized one must be caught while the schema is built rather than reaching the database as invalid DDL.

func (RelationCascade) Sql

func (this RelationCascade) Sql() string

Sql returns the SQL keyword for this cascade action, defaulting to NO ACTION for the zero value.

type RelationType

type RelationType string

type RelationValidator

type RelationValidator func(registry *SchemaRegistry, schemaName string, relation ModelRelation) error

type SanitizeType

type SanitizeType string

type SchemaGetter

type SchemaGetter interface {
	GetSchema() *ModelSchema
}

type SchemaRegistry

type SchemaRegistry struct {
	// contains filtered or unexported fields
}

func GetSchemaRegistry

func GetSchemaRegistry() *SchemaRegistry

func NewSchemaRegistry

func NewSchemaRegistry() *SchemaRegistry

NewSchemaRegistry creates an empty, standalone registry. The application works with the package singleton (GetSchemaRegistry); standalone instances serve tests that must register and finalize a schema set in isolation.

func (*SchemaRegistry) Field

func (this *SchemaRegistry) Field(schemaName string, fieldName string) *ModelField

func (*SchemaRegistry) FieldSafe

func (this *SchemaRegistry) FieldSafe(schemaName string, fieldName string) (*ModelField, error)

func (*SchemaRegistry) FinalizeRelations

func (this *SchemaRegistry) FinalizeRelations() error

FinalizeRelations runs all schema relation finalization after every model is registered: foreign-key map normalization, EdgeFrom peer resolution, then many-to-many junction wiring. Internal helpers must index reg.schemas directly instead of Get, because this method holds reg.mu.Lock and Get uses RLock (same goroutine would deadlock: RWMutex is not reentrant).

func (*SchemaRegistry) ForEach

func (this *SchemaRegistry) ForEach(fn func(schemaName string, schema *ModelSchema) error) error

ForEach iterates schemas in alphabetical order by name. The order is fixed rather than following Go's randomized map range because callers emit DDL from it: the generated CREATE TABLE constraints would otherwise be ordered differently on each run, making Atlas diff two identical schemas as a change.

func (*SchemaRegistry) ForEachOrder

func (this *SchemaRegistry) ForEachOrder(fn func(schemaName string, schema *ModelSchema) error) error

ForEachOrder iterates schemas in FK-dependency order (parents before children), suitable for generating CREATE TABLE statements in the correct sequence.

func (*SchemaRegistry) Get

func (this *SchemaRegistry) Get(name string) *ModelSchema

func (*SchemaRegistry) Register

func (this *SchemaRegistry) Register(schema *ModelSchema) error

Register registers a schema on this registry instance, keyed by its name. Returns an error if a schema with the same name is already registered.

type SearchGraph

type SearchGraph struct {
	// contains filtered or unexported fields
}

func MergeAndCondition

func MergeAndCondition(
	requested *SearchGraph, field string, operator Operator, values ...any,
) *SearchGraph

MergeAndCondition is MergeAndNode for the common case of narrowing by a single field condition.

func MergeAndNode

func MergeAndNode(requested *SearchGraph, leading ...SearchNode) *SearchGraph

MergeAndNode ANDs the leading nodes above a caller's graph, so the caller's own shape - a top-level OR included - can only narrow the result, never widen it past them.

func NewSearchGraph

func NewSearchGraph() *SearchGraph

func (*SearchGraph) And

func (this *SearchGraph) And(nodes ...SearchNode) *SearchGraph

func (*SearchGraph) Condition

func (this *SearchGraph) Condition(c Condition) *SearchGraph

func (*SearchGraph) GetAnd

func (this *SearchGraph) GetAnd() []SearchNode

func (*SearchGraph) GetCondition

func (this *SearchGraph) GetCondition() Condition

func (*SearchGraph) GetOr

func (this *SearchGraph) GetOr() []SearchNode

func (*SearchGraph) GetOrder

func (this *SearchGraph) GetOrder() SearchOrder

func (*SearchGraph) IsEmpty

func (this *SearchGraph) IsEmpty() bool

func (*SearchGraph) MarshalJSON

func (this *SearchGraph) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (*SearchGraph) NewCondition

func (this *SearchGraph) NewCondition(field string, operator Operator, values ...any) *SearchGraph

func (*SearchGraph) Or

func (this *SearchGraph) Or(nodes ...SearchNode) *SearchGraph

func (*SearchGraph) Order

func (this *SearchGraph) Order(o SearchOrder) *SearchGraph

func (*SearchGraph) OrderBy

func (this *SearchGraph) OrderBy(field string, direction ...OrderDirection) *SearchGraph

func (*SearchGraph) ToSearchNode

func (this *SearchGraph) ToSearchNode() *SearchNode

func (*SearchGraph) UnmarshalJSON

func (this *SearchGraph) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

func (*SearchGraph) UnmarshalText

func (this *SearchGraph) UnmarshalText(text []byte) error

type SearchIndexGroupParam

type SearchIndexGroupParam struct {
	// If not specified, a default name will be generated from all field names.
	// Recommend to provide an index name when the number of fields is more than 2.
	IndexName string
	// Field order matters: Place the most frequently queried column or
	// the one with the highest selectivity (most unique values) first.
	Fields []string
}

type SearchNode

type SearchNode struct {
	// contains filtered or unexported fields
}

func NewSearchNode

func NewSearchNode() *SearchNode

func (*SearchNode) And

func (this *SearchNode) And(nodes ...SearchNode) *SearchNode

func (*SearchNode) Condition

func (this *SearchNode) Condition(c Condition) *SearchNode

func (*SearchNode) GetAnd

func (this *SearchNode) GetAnd() []SearchNode

func (*SearchNode) GetCondition

func (this *SearchNode) GetCondition() Condition

func (*SearchNode) GetOr

func (this *SearchNode) GetOr() []SearchNode

func (*SearchNode) MarshalJSON

func (this *SearchNode) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (*SearchNode) NewCondition

func (this *SearchNode) NewCondition(field string, operator Operator, values ...any) *SearchNode

func (*SearchNode) Or

func (this *SearchNode) Or(nodes ...SearchNode) *SearchNode

func (*SearchNode) UnmarshalJSON

func (this *SearchNode) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

type SearchOrder

type SearchOrder []SearchOrderItem

func NewSearchOrder

func NewSearchOrder(field string, direction ...OrderDirection) SearchOrder

func NewSearchOrderMulti

func NewSearchOrderMulti(items map[string]OrderDirection) SearchOrder

type SearchOrderItem

type SearchOrderItem []string

func NewSearchOrderItem

func NewSearchOrderItem(field string, direction ...OrderDirection) SearchOrderItem

func (SearchOrderItem) Direction

func (item SearchOrderItem) Direction() OrderDirection

func (SearchOrderItem) Field

func (item SearchOrderItem) Field() string

Jump to

Keyboard shortcuts

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