Documentation
¶
Overview ¶
Package orm provides a generics-based ORM with auto-registration, auto-serialization of underscore fields, lifecycle hooks, and optional KV cache. It is designed to be extracted from and remain backward-compatible with github.com/hanzoai/commerce.
Index ¶
- Constants
- Variables
- func ApplyDefaults[T any](entity *T)
- func CloneFromJSON[T any](data []byte) (*T, error)
- func DeserializeFields(entity interface{}) error
- func EntityCacheKey(namespace, kind, id string) string
- func Get[T any](db DB, id string) (*T, error)
- func GetForUpdate[T any](db DB, id string) (*T, error)
- func GetOrCreate[T any](db DB, id string, defaults func(*T)) (*T, bool, error)
- func GetOrUpdate[T any](db DB, id string, fn func(*T)) (*T, error)
- func HashQuery(queryStr string) string
- func Kind[T any]() string
- func Kinds() []string
- func MustGet[T any](db DB, id string) *T
- func MustSafeHashExp(m map[string]any) query.HashExp
- func New[T any](db DB) *T
- func QueryCacheKey(namespace, kind, queryHash string) string
- func Register[T any](kind string, opts ...Option[T])
- func SafeHashExp(m map[string]any) (query.HashExp, error)
- func SerializeFields(entity interface{}) error
- func SetCache(cache CacheLayer)
- func Zero[T any]() *T
- type AfterCreator
- type AfterDeleter
- type AfterUpdater
- type BeforeCreator
- type BeforeDeleter
- type BeforeUpdater
- type CacheConfig
- type CacheLayer
- type DB
- type Defaulter
- type IsolationLevel
- type Iterator
- type KVCache
- func (c *KVCache) Close() error
- func (c *KVCache) GetEntity(ctx context.Context, kind, id string) ([]byte, bool, error)
- func (c *KVCache) GetQuery(ctx context.Context, kind, queryHash string) ([]byte, bool, error)
- func (c *KVCache) InvalidateEntity(ctx context.Context, kind, id string) error
- func (c *KVCache) InvalidateKind(ctx context.Context, kind string) error
- func (c *KVCache) SetEntity(ctx context.Context, kind, id string, data []byte, ttl time.Duration) error
- func (c *KVCache) SetQuery(ctx context.Context, kind, queryHash string, data []byte, ttl time.Duration) error
- type KVCacheConfig
- type Key
- type LegacyEntity
- type LegacyKind
- type MemoryCache
- func (c *MemoryCache) Close() error
- func (c *MemoryCache) GetEntity(_ context.Context, kind, id string) ([]byte, bool, error)
- func (c *MemoryCache) GetQuery(_ context.Context, kind, queryHash string) ([]byte, bool, error)
- func (c *MemoryCache) InvalidateEntity(_ context.Context, kind, id string) error
- func (c *MemoryCache) InvalidateKind(_ context.Context, kind string) error
- func (c *MemoryCache) Len() int
- func (c *MemoryCache) SetEntity(_ context.Context, kind, id string, data []byte, ttl time.Duration) error
- func (c *MemoryCache) SetQuery(_ context.Context, kind, queryHash string, data []byte, ttl time.Duration) error
- type Model
- func (m *Model[T]) Clone() *T
- func (m *Model[T]) Create() error
- func (m *Model[T]) CreateCtx(ctx context.Context) error
- func (m *Model[T]) Created() bool
- func (m *Model[T]) DB() DB
- func (m *Model[T]) Delete() error
- func (m *Model[T]) DeleteCtx(ctx context.Context) error
- func (m *Model[T]) Exists() (bool, error)
- func (m *Model[T]) Get(key Key) error
- func (m *Model[T]) GetById(id string) error
- func (m *Model[T]) GetByIdForUpdate(id string) error
- func (m *Model[T]) Id() string
- func (m *Model[T]) Init(db DB)
- func (m *Model[T]) IsMock() bool
- func (m *Model[T]) JSON() []byte
- func (m *Model[T]) JSONString() string
- func (m *Model[T]) Key() Key
- func (m Model[T]) Kind() string
- func (m *Model[T]) MustCreate()
- func (m *Model[T]) MustDelete()
- func (m *Model[T]) MustUpdate()
- func (m *Model[T]) Namespace() string
- func (m *Model[T]) Parent() Key
- func (m *Model[T]) Put() error
- func (m *Model[T]) PutCtx(ctx context.Context) error
- func (m *Model[T]) Query() *ModelQuery[T]
- func (m *Model[T]) SetDB(db DB)
- func (m *Model[T]) SetId(id string)
- func (m *Model[T]) SetKey(key Key)
- func (m *Model[T]) SetMock(mock bool)
- func (m *Model[T]) SetNamespace(ns string)
- func (m *Model[T]) SetParent(parent Key)
- func (m *Model[T]) Update() error
- func (m *Model[T]) UpdateCtx(ctx context.Context) error
- type ModelMeta
- type ModelQuery
- func (q *ModelQuery[T]) Ancestor(key Key) *ModelQuery[T]
- func (q *ModelQuery[T]) ById(id string) (bool, error)
- func (q *ModelQuery[T]) Count(ctx context.Context) (int, error)
- func (q *ModelQuery[T]) Filter(filterStr string, value interface{}) *ModelQuery[T]
- func (q *ModelQuery[T]) First() (*T, error)
- func (q *ModelQuery[T]) Get() (bool, error)
- func (q *ModelQuery[T]) GetAll(ctx context.Context) ([]*T, error)
- func (q *ModelQuery[T]) IdExists(id string) (Key, bool, error)
- func (q *ModelQuery[T]) Inner() Query
- func (q *ModelQuery[T]) KeyExists(key Key) (bool, error)
- func (q *ModelQuery[T]) Limit(limit int) *ModelQuery[T]
- func (q *ModelQuery[T]) Offset(offset int) *ModelQuery[T]
- func (q *ModelQuery[T]) Order(fieldPath string) *ModelQuery[T]
- type NoopCache
- func (c *NoopCache) Close() error
- func (c *NoopCache) GetEntity(_ context.Context, _, _ string) ([]byte, bool, error)
- func (c *NoopCache) GetQuery(_ context.Context, _, _ string) ([]byte, bool, error)
- func (c *NoopCache) InvalidateEntity(_ context.Context, _, _ string) error
- func (c *NoopCache) InvalidateKind(_ context.Context, _ string) error
- func (c *NoopCache) SetEntity(_ context.Context, _, _ string, _ []byte, _ time.Duration) error
- func (c *NoopCache) SetQuery(_ context.Context, _, _ string, _ []byte, _ time.Duration) error
- type Option
- type Query
- type TxOptions
- type Typed
- func (t *Typed[T]) All(ctx context.Context) ([]T, error)
- func (t *Typed[T]) AndWhere(e query.Expression) *Typed[T]
- func (t *Typed[T]) Clone() *Typed[T]
- func (t *Typed[T]) Count(ctx context.Context) (int64, error)
- func (t *Typed[T]) First(ctx context.Context) (T, bool, error)
- func (t *Typed[T]) Limit(n int64) *Typed[T]
- func (t *Typed[T]) Offset(n int64) *Typed[T]
- func (t *Typed[T]) One(ctx context.Context) (*T, error)
- func (t *Typed[T]) OrWhere(e query.Expression) *Typed[T]
- func (t *Typed[T]) OrderBy(cols ...string) *Typed[T]
- func (t *Typed[T]) Query() *query.SelectQuery
- func (t *Typed[T]) Where(e query.Expression) *Typed[T]
Constants ¶
const CacheKeyPrefix = "orm"
CacheKeyPrefix is prepended to all cache keys.
const DefaultEntityTTL = 5 * time.Minute
DefaultEntityTTL is the default TTL for cached entities.
const DefaultQueryTTL = 1 * time.Minute
DefaultQueryTTL is the default TTL for cached query results.
Variables ¶
var ( // ErrNotFound is returned when an entity is not found. ErrNotFound = errors.New("orm: entity not found") // ErrAlreadyRegistered is returned when a kind is registered twice. ErrAlreadyRegistered = errors.New("orm: kind already registered") // ErrTxPanic is the sentinel returned from RunInTransactionWith when // the callback panicked. The ORM rolls back the transaction, logs // the panic with the attempt index, and re-panics to the caller so // the defect surfaces in logs with the full goroutine trace. // Consumers should never see this error directly — it is followed // immediately by a re-panic. ErrTxPanic = errors.New("orm: tx callback panicked") )
var ErrNilDB = errors.New("orm: nil database handle")
ErrNilDB is returned by terminators when the Typed[T] was constructed with a nil *query.DB or nil *query.SelectQuery. The constructor does not panic — it captures the precondition failure and defers it to the terminator so callers get a proper error value instead of a nil-pointer dereference on a hot path.
var ErrSerializationFailure = errors.New("orm: serialization failure")
ErrSerializationFailure wraps a driver error the ORM recognized as a transient SQLITE_BUSY / SQLITE_LOCKED. Callers may wrap their CAS-conflict sentinels with this to piggyback retry, but typically they should let RunInTransactionWith do the retrying itself.
Functions ¶
func ApplyDefaults ¶
func ApplyDefaults[T any](entity *T)
ApplyDefaults sets default values on entity from: 1. orm:"default:value" struct tags (parsed at registration) 2. Defaulter interface (custom Defaults() method)
func CloneFromJSON ¶ added in v0.3.0
CloneFromJSON creates a new T from JSON data.
func DeserializeFields ¶
func DeserializeFields(entity interface{}) error
DeserializeFields unmarshals all registered serialized fields (Foo_ → Foo). Called automatically after Get/GetById.
For each pair in ModelMeta.Serialized:
- Read the string from the underscore field
- Unmarshal into the JSON field
func EntityCacheKey ¶
EntityCacheKey returns the cache key for an entity.
func GetForUpdate ¶ added in v0.4.0
GetForUpdate retrieves an entity of type T by ID AND acquires a row-level lock for the duration of the enclosing transaction. Only valid when db is a transaction (i.e. invoked inside RunInTransactionWith). CAS patterns against a shared row must use this instead of plain Get to defeat serialization anomalies in Postgres.
func GetOrCreate ¶ added in v0.3.0
GetOrCreate retrieves an entity by ID, or creates it with defaults if not found. Returns (entity, created, error).
func GetOrUpdate ¶ added in v0.3.0
GetOrUpdate retrieves an entity by ID, applies fn, and updates it.
func MustSafeHashExp ¶ added in v0.5.1
MustSafeHashExp is SafeHashExp that panics on error. Use in static call sites where the key set is known-safe and a runtime error would indicate a programming bug.
func New ¶
New creates a new instance of T, wired to db, with defaults applied. This replaces the per-model New() function and model.go boilerplate.
func QueryCacheKey ¶
QueryCacheKey returns the cache key for a query.
func Register ¶
Register records type T under the given kind string. Must be called from init() or before any ORM operations.
func SafeHashExp ¶ added in v0.5.1
SafeHashExp validates the keys of m against a strict column-identifier regex and returns a query.HashExp on success. An invalid key yields an error identifying the offending input — no partial map is returned.
Use SafeHashExp whenever the map keys can come from untrusted input (HTTP query params, user-supplied field names, config flags). For developer-controlled keys, query.HashExp is fine; SafeHashExp is the defense-in-depth boundary between application code and the builder.
Background:
dbx.SqliteBuilder.QuoteSimpleColumnName passes any string containing a backtick through unchanged, so a key like
id`, (SELECT 1), `x
is emitted into SQL verbatim as
id`, (SELECT 1), `x={:p0}
— a SQL injection. SafeHashExp rejects the key before it reaches the builder.
func SerializeFields ¶
func SerializeFields(entity interface{}) error
SerializeFields marshals all registered serialized fields (Foo → Foo_). Called automatically before Put().
For each pair in ModelMeta.Serialized:
- Marshal the JSON field value to a JSON string
- Store the string in the underscore field
Types ¶
type AfterCreator ¶
type AfterCreator interface {
AfterCreate() error
}
AfterCreator is called after a new entity is persisted.
type AfterDeleter ¶
type AfterDeleter interface {
AfterDelete() error
}
AfterDeleter is called after an entity is deleted.
type AfterUpdater ¶
AfterUpdater is called after an entity update, receiving a clone of the previous state.
type BeforeCreator ¶
type BeforeCreator interface {
BeforeCreate() error
}
BeforeCreator is called before a new entity is persisted.
type BeforeDeleter ¶
type BeforeDeleter interface {
BeforeDelete() error
}
BeforeDeleter is called before an entity is deleted.
type BeforeUpdater ¶
BeforeUpdater is called before an entity update, receiving a clone of the previous state. The type parameter allows strongly-typed prev values.
type CacheConfig ¶
type CacheConfig struct {
Enabled bool
EntityTTL int // seconds, 0 = use global default
QueryTTL int // seconds, 0 = use global default
}
CacheConfig controls per-model caching behavior.
type CacheLayer ¶
type CacheLayer interface {
// GetEntity returns a cached entity, or false if not found.
GetEntity(ctx context.Context, kind, id string) ([]byte, bool, error)
// SetEntity caches an entity.
SetEntity(ctx context.Context, kind, id string, data []byte, ttl time.Duration) error
// InvalidateEntity removes a cached entity and all queries for its kind.
InvalidateEntity(ctx context.Context, kind, id string) error
// InvalidateKind removes all cached queries for a kind.
InvalidateKind(ctx context.Context, kind string) error
// GetQuery returns cached query results, or false if not found.
GetQuery(ctx context.Context, kind, queryHash string) ([]byte, bool, error)
// SetQuery caches query results.
SetQuery(ctx context.Context, kind, queryHash string, data []byte, ttl time.Duration) error
// Close releases resources.
Close() error
}
CacheLayer provides read-through/write-through caching for entities and queries.
type DB ¶
type DB interface {
// Get loads the entity identified by key into dst.
Get(ctx context.Context, key Key, dst interface{}) error
// Put persists src under key, returning the (possibly updated) key.
Put(ctx context.Context, key Key, src interface{}) (Key, error)
// Delete removes the entity identified by key.
Delete(ctx context.Context, key Key) error
// Query returns a new query builder for the given kind.
Query(kind string) Query
// NewKey creates a key with the given kind, string ID, int ID, and parent.
NewKey(kind string, stringID string, intID int64, parent Key) Key
// NewIncompleteKey creates an incomplete key (ID allocated on put).
NewIncompleteKey(kind string, parent Key) Key
// AllocateIDs pre-allocates n IDs for the given kind.
AllocateIDs(kind string, parent Key, n int) ([]Key, error)
// RunInTransaction executes fn inside a transaction.
RunInTransaction(ctx context.Context, fn func(tx DB) error) error
// RunInTransactionWith executes fn inside a transaction with explicit
// retry semantics. SQLite serializes every write through its reserved
// lock; on SQLITE_BUSY / SQLITE_LOCKED the callback is retried up to
// opts.MaxAttempts times. IsolationLevel is kept in the signature for
// API stability but is a compile-time hint only — SQLite has a single
// isolation model.
RunInTransactionWith(ctx context.Context, opts *TxOptions, fn func(tx DB) error) error
// GetForUpdate is Get + row-level exclusive lock for the duration of the
// enclosing transaction. Under SQLite the write mutex + BEGIN IMMEDIATE
// path already holds the reserved lock across the entire tx, so
// GetForUpdate becomes a regular Get that is strictly serialized against
// other writers. Calling GetForUpdate OUTSIDE a transaction is an error.
GetForUpdate(ctx context.Context, key Key, dst interface{}) error
// Close releases resources.
Close() error
}
DB is the minimal database interface the ORM requires. Implementations exist for SQLite, PostgreSQL, MongoDB, and the legacy Hanzo Datastore. Commerce's datastore.Datastore satisfies this via a thin adapter.
func OpenDatastore ¶ added in v0.4.0
OpenDatastore creates an orm.DB backed by ZAP to hanzo/datastore (ClickHouse).
func OpenDocumentDB ¶ added in v0.4.0
OpenDocumentDB creates an orm.DB backed by ZAP to hanzo/documentdb. For clients who prefer MongoDB-style document semantics.
func OpenSQLite ¶
func OpenSQLite(cfg *ormdb.SQLiteDBConfig) (DB, error)
OpenSQLite creates an orm.DB backed by SQLite.
type Defaulter ¶
type Defaulter interface {
Defaults()
}
Defaulter is implemented by models that need custom default values beyond what orm:"default:..." tags provide.
type IsolationLevel ¶ added in v0.4.0
type IsolationLevel int
IsolationLevel is kept for API stability. SQLite has a single isolation model — every writer holds the reserved lock for the full transaction — so the enum is a compile-time hint, not a runtime switch. Zero value (IsolationDefault) is the only meaningful value.
const ( IsolationDefault IsolationLevel = iota // Retained for API stability. All values collapse to the SQLite default // isolation at runtime. IsolationReadCommitted IsolationRepeatableRead IsolationSerializable )
type KVCache ¶
type KVCache struct {
// contains filtered or unexported fields
}
KVCache is a Redis/Valkey-backed cache layer using hanzoai/kv-go.
func NewKVCache ¶
func NewKVCache(cfg KVCacheConfig) (*KVCache, error)
NewKVCache creates a new Redis/Valkey cache layer.
func NewKVCacheFromClient ¶
NewKVCacheFromClient creates a KVCache from an existing kv.Client.
func (*KVCache) InvalidateEntity ¶
func (*KVCache) InvalidateKind ¶
type KVCacheConfig ¶
type KVCacheConfig struct {
Addr string
Password string
DB int
Prefix string // key prefix, default "orm"
PoolSize int
}
KVCacheConfig configures the Redis/Valkey cache backend.
type Key ¶
type Key interface {
Kind() string
StringID() string
IntID() int64
Parent() Key
Namespace() string
Encode() string
}
Key identifies an entity in the datastore.
type LegacyEntity ¶
type LegacyEntity interface {
LegacyKind
Id() string
JSON() []byte
JSONString() string
}
LegacyEntity matches the subset of mixin.Entity needed for interop. Commerce's REST layer and query system use this interface.
type LegacyKind ¶
type LegacyKind interface {
Kind() string
}
LegacyKind matches the mixin.Kind interface.
type MemoryCache ¶
type MemoryCache struct {
// contains filtered or unexported fields
}
MemoryCache is an in-memory LRU cache layer.
func NewMemoryCache ¶
func NewMemoryCache(maxSize int) *MemoryCache
NewMemoryCache creates a new in-memory cache with the given maximum number of entries.
func (*MemoryCache) Close ¶
func (c *MemoryCache) Close() error
func (*MemoryCache) InvalidateEntity ¶
func (c *MemoryCache) InvalidateEntity(_ context.Context, kind, id string) error
func (*MemoryCache) InvalidateKind ¶
func (c *MemoryCache) InvalidateKind(_ context.Context, kind string) error
func (*MemoryCache) Len ¶
func (c *MemoryCache) Len() int
Len returns the number of entries in the cache.
type Model ¶
type Model[T any] struct { // Persisted fields Id_ string `json:"id,omitempty"` CreatedAt time.Time `json:"createdAt,omitempty"` UpdatedAt time.Time `json:"updatedAt,omitempty"` Deleted bool `json:"deleted,omitempty"` // contains filtered or unexported fields }
Model is a generic mixin embedded in every ORM entity. It replaces mixin.Model from commerce with type-safe generics.
Usage:
type PaymentIntent struct {
orm.Model[PaymentIntent]
Amount int64 `json:"amount"`
Currency string `json:"currency" orm:"default:usd"`
}
func init() { orm.Register[PaymentIntent]("payment-intent") }
func (*Model[T]) Clone ¶
func (m *Model[T]) Clone() *T
Clone creates a deep copy of the entity via JSON round-trip.
func (*Model[T]) CreateCtx ¶ added in v0.3.0
CreateCtx persists a new entity with context, executing Before/AfterCreate hooks.
func (*Model[T]) DeleteCtx ¶ added in v0.3.0
DeleteCtx removes the entity with context, executing Before/AfterDelete hooks.
func (*Model[T]) GetByIdForUpdate ¶ added in v0.4.0
GetByIdForUpdate is GetById + row-level exclusive lock. Only valid inside an enclosing RunInTransactionWith block. The lock is held for the lifetime of the transaction; concurrent GetByIdForUpdate callers block until commit.
func (*Model[T]) Init ¶
Init wires the model to a database. Called by New[T] and by the compat layer.
func (*Model[T]) JSONString ¶
JSONString serializes the entity to a JSON string.
func (*Model[T]) MustCreate ¶ added in v0.3.0
func (m *Model[T]) MustCreate()
MustCreate persists a new entity or panics.
func (*Model[T]) MustDelete ¶ added in v0.3.0
func (m *Model[T]) MustDelete()
MustDelete removes the entity or panics.
func (*Model[T]) MustUpdate ¶ added in v0.3.0
func (m *Model[T]) MustUpdate()
MustUpdate persists changes or panics.
func (*Model[T]) Namespace ¶ added in v0.3.0
Namespace returns the entity's namespace for multi-tenant isolation.
func (*Model[T]) PutCtx ¶ added in v0.3.0
PutCtx persists the entity with context, setting timestamps.
func (*Model[T]) Query ¶
func (m *Model[T]) Query() *ModelQuery[T]
Query returns a typed model query for this entity.
func (*Model[T]) SetNamespace ¶ added in v0.3.0
SetNamespace sets the entity's namespace for multi-tenant isolation.
type ModelMeta ¶
type ModelMeta struct {
Kind string
Type reflect.Type // the concrete struct type T (not *T)
StringKey bool
ParentFn func(DB) Key // optional parent key factory
InitFn func(DB, interface{}) // optional custom init
DefaultsFn func(interface{}) // optional custom defaults
Defaults map[string]string // field name → default value from tags
Serialized map[string]string // JSON field name → underscore field name
CacheConfig *CacheConfig // per-model cache settings (nil = use global)
}
ModelMeta holds parsed metadata for a registered model type.
func LookupType ¶
LookupType returns the metadata for the given type.
func MustLookup ¶
MustLookup returns the metadata for kind or panics.
type ModelQuery ¶
type ModelQuery[T any] struct { // contains filtered or unexported fields }
ModelQuery is a typed query wrapper for a single model type. It provides a fluent interface for filtering, ordering, and retrieving entities.
func TypedQuery ¶
func TypedQuery[T any](db DB) *ModelQuery[T]
TypedQuery returns a new query builder for type T.
func (*ModelQuery[T]) Ancestor ¶
func (q *ModelQuery[T]) Ancestor(key Key) *ModelQuery[T]
Ancestor restricts the query to descendants of the given key.
func (*ModelQuery[T]) ById ¶
func (q *ModelQuery[T]) ById(id string) (bool, error)
ById retrieves an entity by its string ID.
func (*ModelQuery[T]) Count ¶ added in v0.3.0
func (q *ModelQuery[T]) Count(ctx context.Context) (int, error)
Count returns the number of matching entities.
func (*ModelQuery[T]) Filter ¶
func (q *ModelQuery[T]) Filter(filterStr string, value interface{}) *ModelQuery[T]
Filter adds a filter condition.
func (*ModelQuery[T]) First ¶ added in v0.3.0
func (q *ModelQuery[T]) First() (*T, error)
First returns the first matching entity as a new instance, or ErrNotFound.
func (*ModelQuery[T]) Get ¶
func (q *ModelQuery[T]) Get() (bool, error)
Get retrieves the first matching entity into the model.
func (*ModelQuery[T]) GetAll ¶ added in v0.3.0
func (q *ModelQuery[T]) GetAll(ctx context.Context) ([]*T, error)
GetAll returns all matching entities.
func (*ModelQuery[T]) IdExists ¶
func (q *ModelQuery[T]) IdExists(id string) (Key, bool, error)
IdExists checks if the given ID exists.
func (*ModelQuery[T]) Inner ¶
func (q *ModelQuery[T]) Inner() Query
Inner returns the underlying Query for advanced operations.
func (*ModelQuery[T]) KeyExists ¶
func (q *ModelQuery[T]) KeyExists(key Key) (bool, error)
KeyExists checks if the given key exists.
func (*ModelQuery[T]) Limit ¶
func (q *ModelQuery[T]) Limit(limit int) *ModelQuery[T]
Limit sets the maximum number of results.
func (*ModelQuery[T]) Offset ¶
func (q *ModelQuery[T]) Offset(offset int) *ModelQuery[T]
Offset sets the number of results to skip.
func (*ModelQuery[T]) Order ¶
func (q *ModelQuery[T]) Order(fieldPath string) *ModelQuery[T]
Order adds an ordering clause.
type NoopCache ¶
type NoopCache struct{}
NoopCache is a cache layer that does nothing. Used when caching is disabled.
func (*NoopCache) InvalidateEntity ¶
func (*NoopCache) InvalidateKind ¶
type Option ¶
type Option[T any] interface { // contains filtered or unexported methods }
Option configures model registration.
func WithCache ¶
func WithCache[T any](cfg CacheConfig) Option[T]
WithCache configures per-model cache settings.
func WithDefaults ¶
WithDefaults sets a custom defaults function called on New().
func WithParent ¶
WithParent sets a function that returns the parent key for new entities.
func WithStringKey ¶
WithStringKey configures the model to use string IDs instead of auto-allocated int64 IDs.
type Query ¶
type Query interface {
Filter(filterStr string, value interface{}) Query
Order(fieldPath string) Query
Limit(limit int) Query
Offset(offset int) Query
Ancestor(ancestor Key) Query
KeysOnly() Query
// GetAll executes the query, populating dst (pointer to slice).
// Returns the matching keys.
GetAll(ctx context.Context, dst interface{}) ([]Key, error)
// First returns the first matching entity.
First(dst interface{}) (Key, bool, error)
// Count returns the number of matching entities.
Count(ctx context.Context) (int, error)
// ById finds an entity by its encoded ID.
ById(id string, dst interface{}) (Key, bool, error)
// IdExists checks whether the given ID exists.
IdExists(id string) (Key, bool, error)
// KeyExists checks whether the given key exists.
KeyExists(key Key) (bool, error)
}
Query is a fluent query builder.
type TxOptions ¶ added in v0.4.0
type TxOptions struct {
Isolation IsolationLevel
ReadOnly bool
MaxAttempts int
}
TxOptions configures a transaction. MaxAttempts includes the first attempt; set to 1 to disable retry. MaxAttempts == 0 defaults to 5.
type Typed ¶ added in v0.5.0
type Typed[T any] struct { // contains filtered or unexported fields }
Typed is a generic wrapper over a SQL SelectQuery that binds result rows to a known Go type T. It exists so callers don't need to thread untyped interface{} values through dbx's All/One API.
Construct a Typed with NewTyped(selectQuery) or via the Select[T] helper. Chain Where / AndWhere / OrderBy / Limit / Offset to shape the query, then terminate with All, One, First, or Count.
Typed[T] is effectively immutable: every chain method returns a NEW Typed[T] wrapping a cloned *query.SelectQuery. Sharing a *Typed[T] across goroutines is safe — no terminator or chain method mutates the receiver. This is a hard contract enforced by the -race regression test TestTypedConcurrentSafe.
func NewTyped ¶ added in v0.5.0
func NewTyped[T any](q *query.SelectQuery) *Typed[T]
NewTyped wraps an existing *query.SelectQuery so its rows bind to T. The SelectQuery must already have its FROM / columns configured by the caller (or be configured via further chaining before termination).
Passing nil returns a Typed[T] whose terminators fail with ErrNilDB rather than panicking on first use.
func Select ¶ added in v0.5.0
Select builds a `SELECT cols FROM table` SelectQuery on db and wraps it as Typed[T]. Pass the columns and table name explicitly; for dynamic field selection, construct the SelectQuery manually and use NewTyped.
A nil db is captured as a deferred error (see NewTyped) — no panic.
func (*Typed[T]) All ¶ added in v0.5.0
All executes the query and returns all rows bound to []T. A nil slice is returned on empty result; callers should check len() rather than comparing to nil.
ctx is threaded through the underlying *SelectQuery via WithContext so cancellation / deadline is respected by the driver.
func (*Typed[T]) AndWhere ¶ added in v0.5.0
func (t *Typed[T]) AndWhere(e query.Expression) *Typed[T]
AndWhere returns a Typed[T] whose underlying query conjoins e with the existing WHERE. The receiver is unchanged.
func (*Typed[T]) Clone ¶ added in v0.5.1
Clone returns an independent Typed[T] whose underlying SelectQuery is a deep-copy of the receiver's. Further chain calls on the clone do not affect the original.
func (*Typed[T]) Count ¶ added in v0.5.0
Count executes the query as `SELECT COUNT(*)` and returns the row count. All other clauses (WHERE, JOIN, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET) are preserved on a CLONE of the underlying *SelectQuery — the receiver's column list is never mutated, so subsequent .All() / .One() calls return rows with the caller's original projection intact.
func (*Typed[T]) First ¶ added in v0.5.0
First executes the query and returns the first row, a found flag, and any error. An empty result set returns (zero, false, nil) — it is not an error condition, mirroring Go's map-lookup idiom.
func (*Typed[T]) Limit ¶ added in v0.5.0
Limit returns a Typed[T] whose underlying query has the given LIMIT. Pass -1 to clear. The receiver is unchanged.
func (*Typed[T]) Offset ¶ added in v0.5.0
Offset returns a Typed[T] whose underlying query has the given OFFSET. The receiver is unchanged.
func (*Typed[T]) One ¶ added in v0.5.0
One executes the query and binds the first row to *T. Returns ErrNotFound if the result set is empty, and propagates any other error from the underlying driver.
func (*Typed[T]) OrWhere ¶ added in v0.5.0
func (t *Typed[T]) OrWhere(e query.Expression) *Typed[T]
OrWhere returns a Typed[T] whose underlying query disjoins e with the existing WHERE. The receiver is unchanged.
func (*Typed[T]) OrderBy ¶ added in v0.5.0
OrderBy returns a Typed[T] whose underlying query has the given ORDER BY columns. The receiver is unchanged.
func (*Typed[T]) Query ¶ added in v0.5.0
func (t *Typed[T]) Query() *query.SelectQuery
Query returns the underlying *query.SelectQuery. Use this to apply dbx-specific methods (Join, GroupBy, Having, Distinct, …) not mirrored on Typed, then continue chaining on Typed if desired.
Mutating the returned *SelectQuery mutates the Typed[T] it came from — the escape hatch opts out of the immutable chain contract. Use Typed[T].Clone().Query() if you need to mutate in isolation.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package db provides a multi-layer database abstraction supporting: - User-level SQLite with sqlite-vec for personal data and vector search - Organization-level SQLite for shared tenant data - PostgreSQL with pgvector for scalable deployments - MongoDB/FerretDB for document storage - Hanzo Datastore (ClickHouse) for deep analytics
|
Package db provides a multi-layer database abstraction supporting: - User-level SQLite with sqlite-vec for personal data and vector search - Organization-level SQLite for shared tenant data - PostgreSQL with pgvector for scalable deployments - MongoDB/FerretDB for document storage - Hanzo Datastore (ClickHouse) for deep analytics |
|
Package engine provides an xorm-compatible API layer for hanzo/orm.
|
Package engine provides an xorm-compatible API layer for hanzo/orm. |
|
internal
|
|
|
json
Package json provides JSON encoding/decoding utilities.
|
Package json provides JSON encoding/decoding utilities. |
|
reflect
Package reflect provides reflection utilities for struct manipulation.
|
Package reflect provides reflection utilities for struct manipulation. |
|
Package names provides naming convention mappers for converting between Go struct field names and database column/table names.
|
Package names provides naming convention mappers for converting between Go struct field names and database column/table names. |
|
Package query re-exports the SQL AST primitives from hanzoai/dbx under the canonical orm namespace.
|
Package query re-exports the SQL AST primitives from hanzoai/dbx under the canonical orm namespace. |
|
Package val provides struct field validation utilities.
|
Package val provides struct field validation utilities. |