Documentation
¶
Index ¶
- func FormatValidationErrors(errors map[string]string) []string
- func SeedDataFromContext(ctx context.Context) ([]byte, error)
- func WithSeedDataContext(ctx context.Context, sfs fs.FS, path string) context.Context
- type AccessControl
- type AccessDeclaration
- type BoolColumn
- type Condition
- type Endpoint
- type Entity
- type EntityConfig
- type EntityDeclaration
- type ExposureConfig
- type ExposureDeclaration
- type FieldDeclaration
- type FloatColumn
- func (c FloatColumn) Asc() Order
- func (c FloatColumn) Desc() Order
- func (c FloatColumn) Eq(v float64) Condition
- func (c FloatColumn) Gt(v float64) Condition
- func (c FloatColumn) Gte(v float64) Condition
- func (c FloatColumn) IsNotNull() Condition
- func (c FloatColumn) IsNull() Condition
- func (c FloatColumn) Lt(v float64) Condition
- func (c FloatColumn) Lte(v float64) Condition
- func (c FloatColumn) Neq(v float64) Condition
- type Index
- type IntColumn
- func (c IntColumn) Asc() Order
- func (c IntColumn) Desc() Order
- func (c IntColumn) Eq(v int) Condition
- func (c IntColumn) Gt(v int) Condition
- func (c IntColumn) Gte(v int) Condition
- func (c IntColumn) In(values ...int) Condition
- func (c IntColumn) IsNotNull() Condition
- func (c IntColumn) IsNull() Condition
- func (c IntColumn) Lt(v int) Condition
- func (c IntColumn) Lte(v int) Condition
- func (c IntColumn) Neq(v int) Condition
- type Order
- type PaginationConfig
- type PaginationDeclaration
- type Registry
- type Relation
- type RelationType
- type ScopeConfig
- type ScopeDeclaration
- type StringColumn
- func (c StringColumn) Asc() Order
- func (c StringColumn) Desc() Order
- func (c StringColumn) Eq(v string) Condition
- func (c StringColumn) In(values ...string) Condition
- func (c StringColumn) IsNotNull() Condition
- func (c StringColumn) IsNull() Condition
- func (c StringColumn) Like(pattern string) Condition
- func (c StringColumn) Neq(v string) Condition
- func (c StringColumn) NotLike(pattern string) Condition
- type TimestampColumn
- func (c TimestampColumn) Asc() Order
- func (c TimestampColumn) Desc() Order
- func (c TimestampColumn) Eq(v any) Condition
- func (c TimestampColumn) Gt(v any) Condition
- func (c TimestampColumn) Gte(v any) Condition
- func (c TimestampColumn) IsNotNull() Condition
- func (c TimestampColumn) IsNull() Condition
- func (c TimestampColumn) Lt(v any) Condition
- func (c TimestampColumn) Lte(v any) Condition
- type UUIDColumn
- type ValidationRegistry
- type ValidatorFunc
- type VersionedRegistry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FormatValidationErrors ¶
FormatValidationErrors formats a map of field errors into a user-friendly string slice.
func SeedDataFromContext ¶
SeedDataFromContext returns the bytes referenced by the entity's SeedFS + SeedPath. Use inside a Seed function:
Seed: func(ctx context.Context, db *sql.DB) error {
data, err := entity.SeedDataFromContext(ctx)
if err != nil {
return err
}
var rows []FoodRow
if err := json.Unmarshal(data, &rows); err != nil {
return err
}
// ...insert rows...
}
Returns an error when no SeedFS was configured on the EntityConfig. Name matches the framework convention (TxFromContext, SessionFromContext, RegistryFromContext); the older *FromCtx shape is a battery/auth outlier.
func WithSeedDataContext ¶
WithSeedDataContext attaches a SeedFS + SeedPath pair to ctx for retrieval by SeedDataFromContext inside a Seed function. The framework calls this internally; hosts should not need to invoke it directly.
Types ¶
type AccessControl ¶
AccessControl declares the RBAC permission required for each CRUD operation on an entity. Each field holds a permission string (e.g. "posts:write"); blank means that operation is not RBAC-gated. Read covers both List and Get.
Permissions are plain strings here so the entity package stays decoupled from framework/access; the CRUD layer converts them to access.Permission and enforces them via access.Can against the policy + roles in the request context.
func (AccessControl) Declared ¶ added in v0.29.0
func (a AccessControl) Declared() bool
Declared reports whether any per-operation permission is set — i.e. whether the entity opted into RBAC gating at all. Used by framework/crud's secure-by-default session gate to tell "this entity declared an (possibly partial) access: block, defer to it as today" apart from "this entity declared nothing".
type AccessDeclaration ¶ added in v0.5.0
type AccessDeclaration struct {
Read string `json:"read,omitempty"`
Create string `json:"create,omitempty"`
Update string `json:"update,omitempty"`
Delete string `json:"delete,omitempty"`
}
AccessDeclaration is the JSON/YAML-friendly mirror of AccessControl — the per-operation RBAC permissions for a blueprint-declared entity. "read" covers both List and Get. The CRUD layer enforces these via access.Can against the policy + roles in the request context (403 on missing permission), exactly like a Go-declared EntityConfig.Access.
type BoolColumn ¶
type BoolColumn struct {
// contains filtered or unexported fields
}
BoolColumn represents a BOOLEAN column.
func NewBoolColumn ¶
func NewBoolColumn(name string) BoolColumn
func (BoolColumn) Eq ¶
func (c BoolColumn) Eq(v bool) Condition
func (BoolColumn) IsFalse ¶
func (c BoolColumn) IsFalse() Condition
func (BoolColumn) IsTrue ¶
func (c BoolColumn) IsTrue() Condition
type Condition ¶
type Condition struct {
// contains filtered or unexported fields
}
Condition is a where-clause fragment plus its bound arguments.
func And ¶
And combines conditions with AND. Useful inside Or(...) to nest a group of ANDed predicates: Or(And(a, b), And(c, d)).
func Or ¶
Or combines conditions with OR. Each conjunct keeps its own internal argument order; placeholders are renumbered at QueryBuilder.Build time so "$1" in a fragment doesn't collide with another fragment's "$1".
func (Condition) Apply ¶
func (c Condition) Apply(qb *query.QueryBuilder)
Apply appends this condition to the query builder.
type Endpoint ¶
type Endpoint struct {
Method string `json:"method"`
Path string `json:"path"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
MCP bool `json:"mcp,omitempty"`
InputSchema []schema.Field `json:"inputSchema,omitempty"`
OutputSchema []schema.Field `json:"outputSchema,omitempty"`
Handler http.Handler `json:"-"`
MCPHandler mcp.ToolHandler `json:"-"`
// MCPGate is an optional per-caller precondition for the MCP twin. It
// runs before MCPHandler on every tools/call, and decides whether the
// tool is visible to that caller in tools/list.
//
// It exists because the two front doors of one Endpoint do not get the
// same protection for free: Handler inherits the route's middleware
// chain, while MCPHandler is registered straight onto the MCP server and
// sees none of it. An endpoint behind auth.RequireRole("editor") was
// therefore role-checked over HTTP and ungated over MCP.
//
// When unset, the twin defaults to requiring an authenticated caller
// (framework.MCPRequireUser). Set MCPPublic to opt out of that default;
// set this to something stricter, e.g. auth.MCPRole("editor").
MCPGate func(ctx context.Context) error `json:"-"`
// MCPPublic opts the MCP twin out of the default authenticated-caller
// gate, for an endpoint that really is anonymous over HTTP too. Ignored
// when MCPGate is set.
MCPPublic bool `json:"mcpPublic,omitempty"`
}
Endpoint declares a custom route owned by an entity.
Path may be absolute ("/posts/{id}/publish") or relative to the entity table path ("{id}/publish"). Both Go 1.22 "{id}" and older ":id" parameter syntax are accepted. Handler is used for HTTP. MCPHandler is optional and is only registered when MCP is true.
Under framework.WithAPIPrefix a relative path resolves under the prefixed table path — WithAPIPrefix("/api") mounts "{id}/publish" on entity "posts" at POST /api/posts/{id}/publish, alongside that entity's CRUD routes. An absolute path bypasses the prefix entirely; use it to mount outside the entity's API namespace.
InputSchema and OutputSchema are OPTIONAL typed descriptions of the request body and the success (200) response, expressed as []schema.Field — the same representation the entity's own CRUD schema is built from, so OpenAPI and the generated MCP tool both consume one source. When unset (nil), the endpoint renders exactly as before: a shapeless {type:object} request/response in OpenAPI and a {type:object} MCP tool input schema. InputSchema is ignored for GET endpoints (which carry no request body).
type Entity ¶
type Entity struct {
Config EntityConfig
DB *sql.DB
PrimaryKey string // defaults to "id"
// Version identifies the API version this entity is mounted under, when
// registered via App.GroupEntity. It is the route group's full prefix
// (e.g. "/api/v1"). Empty for entities registered via App.Entity — those
// keep the historical single-version behaviour. The registry keys on
// (Config.Name, Version) so the same entity name can coexist under
// different versions; callers that don't care about version resolve the
// unversioned or sole entity via Registry.Get.
Version string
// OpenAPITag is the tag applied to this entity's operations in the
// generated OpenAPI document. Set from the route group's OpenAPITag
// when registered via App.GroupEntity; empty for App.Entity (the tag
// defaults to the entity name in that case).
OpenAPITag string
}
Entity represents a registered domain entity with its config and DB handle.
func Define ¶
func Define(name string, config EntityConfig) *Entity
Define creates a new Entity with the given name and configuration. It applies defaults (Table, Timestamps=true) and stores the name. It also injects system fields (id, timestamps) with AutoGenerate flags unless the user has already defined them.
func ResolveTarget ¶ added in v0.48.0
ResolveTarget resolves a relation target for a source entity, preferring the target registered at the SOURCE's own version.
Relation resolution drives the Hidden-column scrub, the owner/tenant scopes, the soft-delete filter and the scoped-filter allow-list. Resolving by name alone picks the unversioned declaration when one exists, so a request under /api/v1 could inherit an internal entity's visibility and scoping rules instead of v1's — disclosing columns v1 marks hidden and returning rows v1's scopes exclude.
Order: the source's own version first; then unversioned, which is the shared declaration a versioned entity legitimately points at; then a sole version when exactly one exists. Ambiguity is an ERROR, never a silent pick — the caller must fail closed.
type EntityConfig ¶
type EntityConfig struct {
Name string // entity name (e.g. "users")
Table string // DB table name (defaults to snake_case of Name)
Fields []schema.Field // typed field definitions
Relations []Relation // entity relationships
Endpoints []Endpoint // custom HTTP endpoints for this entity
Scope *ScopeConfig // ownership, tenancy, and soft-delete behavior
Pagination *PaginationConfig // list limits and keyset cursor shape
Exposure *ExposureConfig // generated HTTP/MCP and access posture
Timestamps *bool // add created_at / updated_at columns; nil defaults to true
Indices []Index // additional CREATE INDEX statements emitted by AutoMigrate
Unmanaged bool // when true, the migration system never emits DDL for this object (it is created elsewhere — e.g. a view, an FTS virtual table, or a legacy/external table). The ORM still queries it.
// Properties holds caller-owned metadata. The framework does not
// interpret any key; generators, plugins, and apps define their own keys.
Properties map[string]any
// SearchFields names the DB columns that ?q= free-text search operates
// on (e.g. []string{"title","body"}). When non-empty, a List request
// carrying ?q=<term> tokenizes the term on whitespace (deduped, capped
// at filter.MaxSearchTerms) and AND-composes one LOWER(col) LIKE
// pattern per token across the listed fields. Matching is
// ASCII-case-insensitive everywhere (Unicode-folding on Postgres).
// Leave nil to keep pre-existing behaviour (?q= is ignored). Column
// names must be known, non-Hidden, and String/Text-typed; Define panics
// otherwise. An entity WITHOUT SearchFields ignores ?q= exactly as
// before (back-compat).
SearchFields []string
// Seed runs once per entity after AutoMigrate creates the table. The
// framework tracks completion in the _gofastr_seeded ledger; subsequent
// App.Start() calls skip the entity. Errors abort App.Start.
//
// Go-only: function values cannot be expressed in a blueprint
// declaration. Apps whose entities come from a gofastr.yml blueprint
// must wire seeding from Go.
//
// Concurrency: RunSeeds is NOT safe for concurrent invocation across
// multiple processes. The framework assumes serialized startup (one
// process / replica calls App.Start at a time). For HA setups, gate
// seeding behind an external mechanism (init container, one-shot
// job, advisory lock). Seed implementations should be idempotent
// (INSERT … ON CONFLICT DO NOTHING) so accidental re-runs cannot
// duplicate data.
Seed func(ctx context.Context, db *sql.DB) error
// SeedFS is an optional fs.FS (typically a //go:embed embed.FS) that
// the framework attaches to the Seed function's context. Use with
// SeedPath to point at a single file within the FS.
//
// Go-only: like Seed itself, an fs.FS cannot be expressed in JSON
// entity declarations.
SeedFS fs.FS
// SeedPath is the path within SeedFS that Seed should consume.
// Ignored when SeedFS is nil.
SeedPath string
// LenientFilters opts the entity's auto-CRUD List endpoint OUT of strict
// filter parsing. By default an unknown top-level filter key (a typo like
// ?stauts=active) is REJECTED with a 400 rather than silently dropped —
// silently dropping it returns an UNFILTERED result set, which is a
// data-exposure and broken-client hazard. Set true only as a migration
// escape hatch for an endpoint that must tolerate arbitrary extra query
// params (e.g. legacy tracking params); prefer fixing the caller.
// Default false (strict).
LenientFilters bool
// AllowedFilterParams declares extra query-param keys that are NOT entity
// columns but are legitimately consumed elsewhere on the List request —
// typically read by a BeforeList hook or custom middleware (e.g. a
// bespoke "?region=eu" scope param). Strict filter parsing skips these
// instead of rejecting them, so the endpoint keeps typo-protection for
// real fields without falling back to LenientFilters (which disables it
// entirely). Reserved list controls are always allowed and need not be
// listed here.
AllowedFilterParams []string
// Renames declares column renames (old name → new name) so the schema
// diff emits a non-destructive ALTER TABLE … RENAME COLUMN instead of a
// data-losing DROP of the old column + ADD of the new one. Rename is
// otherwise indistinguishable from drop+add, so it requires this explicit
// declaration; auto-detection is unsafe. A rename only fires when the old
// column is present in the live schema and the new name is declared on the
// entity. Declare it in Go or under an entity's `renames:` key in a
// blueprint.
Renames map[string]string
}
EntityConfig holds the declarative configuration for an entity. Name is set via Define(); Fields declare the schema. Timestamps is nil by default; Define resolves nil to true.
func (EntityConfig) TenantColumn ¶
func (c EntityConfig) TenantColumn() string
TenantColumn returns the tenant-scoping column name for this entity: Scope.TenantField when set, otherwise "tenant_id".
func (EntityConfig) WithTimestamps ¶
func (c EntityConfig) WithTimestamps(v bool) EntityConfig
WithTimestamps returns a copy with timestamp columns enabled or disabled.
type EntityDeclaration ¶
type EntityDeclaration struct {
Name string `json:"name"`
Table string `json:"table,omitempty"`
Fields []FieldDeclaration `json:"fields"`
Relations []Relation `json:"relations,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty"`
Scope *ScopeDeclaration `json:"scope,omitempty"`
Pagination *PaginationDeclaration `json:"pagination,omitempty"`
Exposure *ExposureDeclaration `json:"exposure,omitempty"`
SearchFields []string `json:"search_fields,omitempty"`
Timestamps *bool `json:"timestamps,omitempty"`
Indices []Index `json:"indices,omitempty"`
Properties map[string]any `json:"properties,omitempty"`
Renames map[string]string `json:"renames,omitempty"`
}
EntityDeclaration is the grouped JSON/YAML shape used after blueprint decoding. The decoder also accepts flat shorthand keys and moves them into Scope, Pagination, or Exposure before returning the declaration.
func (EntityDeclaration) Config ¶
func (d EntityDeclaration) Config() (EntityConfig, error)
Config converts a declaration into an EntityConfig.
func (*EntityDeclaration) UnmarshalJSON ¶ added in v0.54.0
func (d *EntityDeclaration) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts grouped declarations and the documented flat shorthand. A flat key and its grouped key may both be present only when their values match.
type ExposureConfig ¶ added in v0.41.0
type ExposureConfig struct {
CRUD *bool // nil or true generates CRUD routes
MCP bool // register MCP CRUD tools
Public bool // allow anonymous CRUD when no scope or access rule applies
Access AccessControl // per-operation permissions
}
ExposureConfig groups generated routes and their access rules. CRUD is a pointer so nil keeps automatic route generation and false disables it.
type ExposureDeclaration ¶ added in v0.41.0
type ExposureDeclaration struct {
CRUD *bool `json:"crud,omitempty"`
MCP bool `json:"mcp,omitempty"`
Public bool `json:"public,omitempty"`
Access *AccessDeclaration `json:"access,omitempty"`
}
ExposureDeclaration is the JSON/YAML-friendly shape of ExposureConfig.
type FieldDeclaration ¶
type FieldDeclaration struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required,omitempty"`
Unique bool `json:"unique,omitempty"`
Default any `json:"default,omitempty"`
AutoGenerate string `json:"auto_generate,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
Hidden bool `json:"hidden,omitempty"`
NoQuery bool `json:"no_query,omitempty"`
Max *float64 `json:"max,omitempty"`
Min *float64 `json:"min,omitempty"`
Pattern string `json:"pattern,omitempty"`
Values []string `json:"values,omitempty"`
To string `json:"to,omitempty"`
Many bool `json:"many,omitempty"`
}
FieldDeclaration is a JSON-friendly schema.Field.
type FloatColumn ¶
type FloatColumn struct {
// contains filtered or unexported fields
}
FloatColumn represents a REAL/DOUBLE PRECISION/DECIMAL column.
func NewFloatColumn ¶
func NewFloatColumn(name string) FloatColumn
func (FloatColumn) Eq ¶
func (c FloatColumn) Eq(v float64) Condition
func (FloatColumn) Gt ¶
func (c FloatColumn) Gt(v float64) Condition
func (FloatColumn) Gte ¶
func (c FloatColumn) Gte(v float64) Condition
func (FloatColumn) Lt ¶
func (c FloatColumn) Lt(v float64) Condition
func (FloatColumn) Lte ¶
func (c FloatColumn) Lte(v float64) Condition
func (FloatColumn) Neq ¶
func (c FloatColumn) Neq(v float64) Condition
type Index ¶
type Index struct {
Name string `json:"name,omitempty"`
Columns []string `json:"columns,omitempty"`
Unique bool `json:"unique,omitempty"`
Expression string `json:"expression,omitempty"`
}
Index declares a secondary index on an entity. Both dialects accept the same CREATE INDEX syntax; AutoMigrate emits CREATE INDEX IF NOT EXISTS so re-runs are safe.
Name is optional — when empty, AutoMigrate synthesises one as "idx_<table>_<col1>_<col2>". Unique indices reject duplicate rows for the chosen column set; for single-column uniqueness prefer the Field-level Unique flag which lives on the column definition.
Expression covers the case the column-list form can't express: a functional or partial index, e.g. `UNIQUE(user_id, lower(food))` to dedupe case-insensitively. When non-empty, Expression is rendered verbatim inside the index body (replacing Columns) — Name is REQUIRED in that case because there's no safe deterministic slug for an arbitrary expression. Use Columns for plain identifier indices; reach for Expression when SQL functions or constants need to participate in the indexed key.
type IntColumn ¶
type IntColumn struct {
// contains filtered or unexported fields
}
IntColumn represents an INTEGER column.
func NewIntColumn ¶
type Order ¶
type Order struct {
// contains filtered or unexported fields
}
Order is an order-by-clause fragment.
func (Order) Apply ¶
func (o Order) Apply(qb *query.QueryBuilder)
Apply appends this order to the query builder.
type PaginationConfig ¶ added in v0.41.0
PaginationConfig groups list limits and keyset cursor configuration. A non-empty CursorFields composite takes precedence over CursorField.
type PaginationDeclaration ¶ added in v0.41.0
type PaginationDeclaration struct {
CursorField string `json:"cursor_field,omitempty"`
CursorFields []string `json:"cursor_fields,omitempty"`
MaxListLimit int `json:"max_list_limit,omitempty"`
}
PaginationDeclaration is the JSON/YAML-friendly shape of PaginationConfig.
type Registry ¶
type Registry interface {
// All returns a snapshot of every registered entity keyed by name.
// Map iteration order is randomised by Go; for stable iteration use
// AllSorted().
All() map[string]*Entity
// AllSorted returns every registered entity in alphabetical order
// by name. Use this when emitting bytes whose ordering matters
// (OpenAPI, generated code, golden-file tests, ETag-cached
// responses).
AllSorted() []*Entity
// Get retrieves one entity by name, or an error when no such entity
// is registered. When multiple versions of the name exist and none is
// unversioned, Get returns an ambiguity error.
//
// Get is NOT safe for resolving a relation target: it prefers the
// unversioned entity, so a v1 relation would resolve an unversioned
// declaration with different Hidden columns and different scopes. Use
// ResolveTarget for anything that drives visibility or scoping.
Get(name string) (*Entity, error)
}
Registry is the minimal contract subpackages need from the framework's entity registry: enumerate every registered entity.
All() returns the entities keyed by name. Go's map iteration is randomised, so callers that emit order-sensitive output (OpenAPI tags, LLM markdown, generated code) must use AllSorted() to keep output stable across runs. Callers that only care about presence (counts, hash lookups, contains-checks) can use All() directly.
The concrete *framework.Registry type satisfies this implicitly. Splitting it out here lets framework/migrate, framework/dsl, and others depend on the entity model without pulling in the full framework package.
type Relation ¶
type Relation struct {
Type RelationType `json:"type"`
Name string `json:"name"` // logical name for this relation (e.g. "author", "comments")
Entity string `json:"entity"` // target entity/table name
ForeignKey string `json:"foreign_key"` // FK column name
Through string `json:"through,omitempty"` // pivot table name (ManyToMany only)
LocalKey string `json:"local_key,omitempty"` // column on the local side of a ManyToMany pivot
ForeignKeyTarget string `json:"foreign_key_target,omitempty"`
}
Relation describes a relationship between two entities.
func BelongsTo ¶
BelongsTo declares a many-to-one relationship. The source entity holds a foreign-key column that references the target entity's primary key.
func HasMany ¶
HasMany declares a one-to-many relationship. The target entity holds a foreign-key column that references the source entity's primary key.
func HasOne ¶
HasOne declares a one-to-one relationship. The target entity holds a foreign-key column that references the source entity's primary key.
func ManyToMany ¶
ManyToMany declares a many-to-many relationship through a pivot/join table.
type RelationType ¶
type RelationType int
RelationType enumerates the kinds of entity relationships.
const ( RelHasOne RelationType = iota // target has a FK pointing back to us RelHasMany // target has a FK pointing back to us (many rows) RelManyToOne // we hold a FK pointing to the target (BelongsTo) RelManyToMany // linked through a pivot/join table )
type ScopeConfig ¶ added in v0.41.0
type ScopeConfig struct {
SoftDelete bool // add deleted_at and hide deleted rows by default
MultiTenant bool // scope rows to the tenant in the request context
TenantField string // tenant column; empty uses tenant_id
OwnerField string // owner column stamped and scoped by auto-CRUD
CrossOwnerRead string // permission that lifts owner scoping for reads only
}
ScopeConfig groups the rules that constrain which rows a request can read or change. Define always populates EntityConfig.Scope on the resolved entity.
type ScopeDeclaration ¶ added in v0.41.0
type ScopeDeclaration struct {
SoftDelete bool `json:"soft_delete,omitempty"`
MultiTenant bool `json:"multi_tenant,omitempty"`
TenantField string `json:"tenant_field,omitempty"`
OwnerField string `json:"owner_field,omitempty"`
CrossOwnerRead string `json:"cross_owner_read,omitempty"`
}
ScopeDeclaration is the JSON/YAML-friendly shape of ScopeConfig.
type StringColumn ¶
type StringColumn struct {
// contains filtered or unexported fields
}
StringColumn represents a TEXT/VARCHAR column. Use the methods to build Conditions: PostsTitle.Eq("hello"), PostsTitle.Like("%foo%"), etc.
func NewStringColumn ¶
func NewStringColumn(name string) StringColumn
NewStringColumn constructs a StringColumn for the given DB column name. Codegen calls this; user code rarely needs to.
func (StringColumn) Eq ¶
func (c StringColumn) Eq(v string) Condition
func (StringColumn) In ¶
func (c StringColumn) In(values ...string) Condition
func (StringColumn) Like ¶
func (c StringColumn) Like(pattern string) Condition
func (StringColumn) Neq ¶
func (c StringColumn) Neq(v string) Condition
func (StringColumn) NotLike ¶
func (c StringColumn) NotLike(pattern string) Condition
type TimestampColumn ¶
type TimestampColumn struct {
// contains filtered or unexported fields
}
TimestampColumn represents a TIMESTAMP/TIMESTAMPTZ column. Method semantics mirror IntColumn but accept any value the driver knows how to bind (time.Time, RFC3339 strings, etc.) so callers don't have to choose a canonical form here.
func NewTimestampColumn ¶
func NewTimestampColumn(name string) TimestampColumn
func (TimestampColumn) Eq ¶
func (c TimestampColumn) Eq(v any) Condition
func (TimestampColumn) Gt ¶
func (c TimestampColumn) Gt(v any) Condition
func (TimestampColumn) Gte ¶
func (c TimestampColumn) Gte(v any) Condition
func (TimestampColumn) Lt ¶
func (c TimestampColumn) Lt(v any) Condition
func (TimestampColumn) Lte ¶
func (c TimestampColumn) Lte(v any) Condition
type UUIDColumn ¶
type UUIDColumn struct {
// contains filtered or unexported fields
}
UUIDColumn represents a UUID/text-shaped identity column.
func NewUUIDColumn ¶
func NewUUIDColumn(name string) UUIDColumn
func (UUIDColumn) Eq ¶
func (c UUIDColumn) Eq(v string) Condition
func (UUIDColumn) In ¶
func (c UUIDColumn) In(values ...string) Condition
func (UUIDColumn) Neq ¶
func (c UUIDColumn) Neq(v string) Condition
type ValidationRegistry ¶
type ValidationRegistry struct {
// contains filtered or unexported fields
}
ValidationRegistry holds a chain of validator functions.
func NewValidationRegistry ¶
func NewValidationRegistry() *ValidationRegistry
NewValidationRegistry creates an empty ValidationRegistry.
func (*ValidationRegistry) RegisterValidator ¶
func (vr *ValidationRegistry) RegisterValidator(fn ValidatorFunc)
RegisterValidator appends a validator function to the chain.
func (*ValidationRegistry) Validate ¶
Validate runs all registered validators and collects every field error. The returned map is field name → error message. A nil/empty map means valid.
func (*ValidationRegistry) Validators ¶
func (vr *ValidationRegistry) Validators() int
Validators returns the number of registered validators (for testing).
type ValidatorFunc ¶
ValidatorFunc validates entity data and returns field-level errors. The returned map is field name → error message (empty map means valid).
func Custom ¶
func Custom(name string, fn func(ctx context.Context, data map[string]any) map[string]string) ValidatorFunc
Custom returns a validator with a given name that runs the provided function. The fn returns a map of field→error for any violations found.
func Required ¶
func Required(fields ...string) ValidatorFunc
Required returns a validator that checks the given fields are present and non-zero.
type VersionedRegistry ¶ added in v0.48.0
type VersionedRegistry interface {
// GetVersioned retrieves the entity registered under name at exactly
// version (the route-group prefix it was mounted at; "" for the
// unversioned App.Entity registration).
GetVersioned(name, version string) (*Entity, error)
}
VersionedRegistry is the optional capability a registry advertises when it can resolve a specific version of an entity name.
Deliberately NOT part of Registry: that interface has a dozen implementations (test stubs, package-local fakes), and a registry with no concept of versions cannot hold two versions of a name, so Get is already unambiguous for it. Requiring the method would break every implementor to describe a capability most of them cannot exercise.