orm

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 22 Imported by: 1

README

orm

orm is a typed ORM/model layer for Go built on top of dbx.

The package focuses on:

  • metadata-driven mapping (struct -> table/columns)
  • typed CRUD and query builder
  • explicit relations and preload
  • predictable error model
  • hooks/interceptors/plugins
  • soft-delete, timestamps, transactions
  • observability, routing, migration/codegen scaffolds

Installation

go get github.com/pafthang/orm

Requirements

  • Go 1.25+
  • Supported drivers depend on dbx driver usage
    • SQLite examples use modernc.org/sqlite
    • PostgreSQL integration tests use pgx

Quick Example

package main

import (
	"context"
	"log"
	"time"

	"github.com/pafthang/dbx"
	"github.com/pafthang/orm"
	_ "modernc.org/sqlite"
)

type User struct {
	ID        int64      `db:"id,pk"`
	Email     string     `db:"email"`
	Name      string     `db:"name"`
	DeletedAt *time.Time `db:"deleted_at,soft_delete"`
	CreatedAt time.Time  `db:"created_at,created_at"`
	UpdatedAt time.Time  `db:"updated_at,updated_at"`
}

func (User) TableName() string { return "users" }

func main() {
	ctx := context.Background()
	db, err := dbx.Open("sqlite", ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	_, _ = db.NewQuery(`
		CREATE TABLE users (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			email TEXT NOT NULL,
			name TEXT NOT NULL,
			deleted_at TIMESTAMP NULL,
			created_at TIMESTAMP NOT NULL,
			updated_at TIMESTAMP NOT NULL
		);
	`).Execute()

	u := User{Email: "a@example.com", Name: "Alice"}
	if err := orm.Insert(ctx, db, &u); err != nil {
		log.Fatal(err)
	}

	rows, err := orm.Query[User](db).
		WhereEq("email", "a@example.com").
		All(ctx)
	if err != nil {
		log.Fatal(err)
	}
	_ = rows
}

Documentation

Current Scope

Implemented:

  • metadata/registry/naming
  • CRUD/query/preload
  • hooks/interceptors/plugins
  • soft delete/timestamps
  • transactions/savepoints
  • upsert/batch/patch
  • observability + metrics callbacks
  • migration/codegen scaffolds
  • migration safety (checksum + db lock + dirty state)
  • automatic schema diff generation from models (via snapshot + ormtool migrate diff)
  • zero-downtime online migration choreography (expand/backfill/contract)
  • sharding router + routed helpers
  • migration lifecycle tooling (plan/validate/goto/force)
  • config-driven codegen pipeline
  • health-aware weighted shard cluster resolver

Out of scope for now:

  • automatic schema conflict resolution for semantic renames
  • autonomous deploy orchestration across independent services

Testing

go test ./...
make test-matrix
make bench-assert

For PostgreSQL integration tests:

export ORM_TEST_POSTGRES_DSN='postgres://orm:orm@localhost:5432/orm?sslmode=disable'
make test-matrix

CI/CD

  • ci: unit tests, go vet, race tests, PostgreSQL integration tests
  • perf: benchmark assertions (scheduled/manual and on main)
  • release: triggered by tags v*, runs verification and publishes GitHub Release

Contributing

See CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SECURITY.md.

License

This project is licensed under the MIT License. See LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound          = &Error{Code: CodeNotFound}
	ErrMultipleRows      = &Error{Code: CodeMultipleRows}
	ErrConflict          = &Error{Code: CodeConflict}
	ErrInvalidModel      = &Error{Code: CodeInvalidModel}
	ErrMissingPrimaryKey = &Error{Code: CodeMissingPrimaryKey}
	ErrNoRowsAffected    = &Error{Code: CodeNoRowsAffected}
	ErrRelationNotFound  = &Error{Code: CodeRelationNotFound}
	ErrUnsupportedType   = &Error{Code: CodeUnsupportedType}
	ErrInvalidField      = &Error{Code: CodeInvalidField}
	ErrInvalidQuery      = &Error{Code: CodeInvalidQuery}
	ErrSoftDeleted       = &Error{Code: CodeSoftDeleted}
)
View Source
var DefaultRegistry = NewRegistry()
View Source
var SharedTypeRegistry = typemeta.NewRegistry()

SharedTypeRegistry exposes transport-neutral type metadata cache.

Functions

func AddAfterInterceptor

func AddAfterInterceptor(fn AfterInterceptor)

AddAfterInterceptor registers a global after interceptor.

func AddBeforeInterceptor

func AddBeforeInterceptor(fn BeforeInterceptor)

AddBeforeInterceptor registers a global before interceptor.

func AttachDBXObserver

func AttachDBXObserver(db *dbx.DB, opts DBXObserverOptions)

AttachDBXObserver installs ORM-aware hooks on a dbx DB instance. Existing dbx log hooks are preserved and called before observer hooks.

func AttachMetricsObserver

func AttachMetricsObserver(db *dbx.DB, opts MetricsObserverOptions)

AttachMetricsObserver attaches metric callbacks using ORM-aware query events.

func AttachRuntimeMetrics

func AttachRuntimeMetrics(opts RuntimeMetricsOptions)

AttachRuntimeMetrics configures callbacks for runtime-level metrics.

func AttachTraceObserver

func AttachTraceObserver(opts TraceObserverOptions)

AttachTraceObserver registers tracing callbacks as global interceptors.

func ByPK

func ByPK[T any](ctx context.Context, db DB, id any) (*T, error)

ByPK fetches a row by primary key.

func ByPKRouted

func ByPKRouted[T any](ctx context.Context, base DB, resolver ShardResolver, key any) (*T, error)

func Count

func Count[T any](ctx context.Context, db DB) (int64, error)

Count returns total rows for model T, excluding soft-deleted rows by default.

func CountRouted

func CountRouted[T any](ctx context.Context, base DB, resolver ShardResolver) (int64, error)

func Delete

func Delete[T any](ctx context.Context, db DB, model *T) error

Delete deletes one model row by primary key. Soft delete is applied when configured.

func DeleteAll

func DeleteAll[T any](ctx context.Context, db DB, scopes ...QueryScope[T]) (int64, error)

DeleteAll performs bulk delete with optional query scopes and returns affected rows.

func DeleteByPK

func DeleteByPK[T any](ctx context.Context, db DB, id any) error

DeleteByPK deletes by primary key. Soft delete is applied when configured.

func DeleteByPKRouted

func DeleteByPKRouted[T any](ctx context.Context, base DB, resolver ShardResolver, key any) error

func DeleteRouted

func DeleteRouted[T any](ctx context.Context, base DB, resolver ShardResolver, model *T) error

func Exists

func Exists[T any](ctx context.Context, db DB, scopes ...QueryScope[T]) (bool, error)

Exists checks whether at least one row exists for model T with optional query scopes.

func ExistsByPK

func ExistsByPK[T any](ctx context.Context, db DB, id any) (bool, error)

ExistsByPK checks existence by primary key.

func ExistsByPKRouted

func ExistsByPKRouted[T any](ctx context.Context, base DB, resolver ShardResolver, key any) (bool, error)

func FindAll

func FindAll[T any](ctx context.Context, db DB) ([]T, error)

FindAll fetches all rows for model T (excluding soft-deleted by default).

func FindByPK

func FindByPK[T any](ctx context.Context, db DB, id any) (*T, error)

FindByPK is an alias for ByPK.

func GenerateColumnsConst

func GenerateColumnsConst(meta *ModelMeta) (string, error)

GenerateColumnsConst returns Go snippet with sorted DB columns for model.

func GenerateColumnsConstFromSpec

func GenerateColumnsConstFromSpec(modelName string, columns []string) (string, error)

GenerateColumnsConstFromSpec generates columns const snippet without reflection metadata.

func GenerateRepositoryStub

func GenerateRepositoryStub(meta *ModelMeta) (string, error)

GenerateRepositoryStub generates a typed repository skeleton.

func GenerateRepositoryStubFromSpec

func GenerateRepositoryStubFromSpec(modelName, pkType string) (string, error)

GenerateRepositoryStubFromSpec generates repository skeleton from explicit names.

func GetByPK

func GetByPK[T any](ctx context.Context, db DB, id any) (*T, error)

GetByPK is an alias for ByPK.

func HasCode

func HasCode(err error, code ErrorCode) bool

HasCode checks whether wrapped error contains target ORM code.

func Insert

func Insert[T any](ctx context.Context, db DB, model *T) error

Insert inserts one model row.

func InsertBatch

func InsertBatch[T any](ctx context.Context, db DB, models []*T) (int64, error)

InsertBatch inserts multiple models in a single multi-row statement. Returns affected rows when available.

func InsertBatchRouted

func InsertBatchRouted[T any](ctx context.Context, base DB, resolver ShardResolver, rows []*T) (int64, error)

func InsertRouted

func InsertRouted[T any](ctx context.Context, base DB, resolver ShardResolver, model *T) error

InsertRouted resolves shard DB and then performs Insert.

func RegisterCodec

func RegisterCodec[T any](c Codec) error

RegisterCodec registers codec for Go type T.

func RegisterPlugin

func RegisterPlugin(p Plugin) error

RegisterPlugin installs plugin once by unique name.

func RegisteredPlugins

func RegisteredPlugins() []string

RegisteredPlugins returns sorted plugin names.

func ResetCodecs

func ResetCodecs()

ResetCodecs clears codec registry.

func ResetInterceptors

func ResetInterceptors()

ResetInterceptors removes all global interceptors.

func ResetPlugins

func ResetPlugins()

ResetPlugins clears plugin registry and global interceptor lists.

func ResetRuntimeMetrics

func ResetRuntimeMetrics()

ResetRuntimeMetrics clears runtime-level metric callbacks.

func RunCodegenPipeline

func RunCodegenPipeline(configPath string) error

RunCodegenPipeline generates all files described by JSON config.

func SaveSchemaSnapshot

func SaveSchemaSnapshot(path string, snapshot *SchemaSnapshot) error

SaveSchemaSnapshot writes schema snapshot to JSON file.

func TypeMetadata

func TypeMetadata[T any]() (*typemeta.TypeMeta, error)

TypeMetadata returns shared metadata for model T.

func Update

func Update[T any](ctx context.Context, db DB, model *T) error

Update updates one model row by primary key.

func UpdateAll

func UpdateAll[T any](ctx context.Context, db DB, set map[string]any, scopes ...QueryScope[T]) (int64, error)

UpdateAll performs bulk update with optional query scopes and returns affected rows.

func UpdateByPK

func UpdateByPK[T any](ctx context.Context, db DB, key any, fields map[string]any) (int64, error)

UpdateByPK updates selected fields by single/composite PK key.

func UpdateByPKRouted

func UpdateByPKRouted[T any](ctx context.Context, base DB, resolver ShardResolver, key any, fields map[string]any) (int64, error)

func UpdateFields

func UpdateFields[T any](ctx context.Context, db DB, model *T, fields ...string) error

UpdateFields updates only explicitly listed fields by primary key.

func UpdateFieldsRouted

func UpdateFieldsRouted[T any](ctx context.Context, base DB, resolver ShardResolver, model *T, fields ...string) error

func UpdatePatchByPK

func UpdatePatchByPK[T any, P any](ctx context.Context, db DB, key any, patch *P) error

UpdatePatchByPK applies partial update by composite/single PK using Optional fields from patch struct.

func UpdateRouted

func UpdateRouted[T any](ctx context.Context, base DB, resolver ShardResolver, model *T) error

func Upsert

func Upsert[T any](ctx context.Context, db DB, model *T, opts ...UpsertOptions) error

Upsert inserts or updates a row based on conflict target.

func UpsertRouted

func UpsertRouted[T any](ctx context.Context, base DB, resolver ShardResolver, model *T, opts ...UpsertOptions) error

func Validate

func Validate() error

Validate validates global registry.

func WithSavepoint

func WithSavepoint(tx *Tx, name string, fn func() error) error

WithSavepoint runs fn inside a named savepoint. On fn error, it rolls back to savepoint and releases it.

func WithShardKey

func WithShardKey(ctx context.Context, shardKey string) context.Context

WithShardKey stores shard key in context.

func WithTenant

func WithTenant(ctx context.Context, column string, value any) context.Context

WithTenant returns context with tenant filter for query/update/delete operations.

func WithTenantValue

func WithTenantValue(ctx context.Context, value any) context.Context

WithTenantValue sets tenant value and lets ORM resolve tenant column from model metadata.

func WithTx

func WithTx(ctx context.Context, db *dbx.DB, fn func(tx *Tx) error) error

WithTx runs fn inside a transaction. When fn returns error, transaction is rolled back.

func WriteColumnsConstFile

func WriteColumnsConstFile(path string, meta *ModelMeta) error

WriteColumnsConstFile writes generated columns snippet into a file.

func WriteDiffMigrationFiles

func WriteDiffMigrationFiles(dir string, version int64, name string, diff *SchemaDiff) error

WriteDiffMigrationFiles writes one migration pair from a schema diff.

func WriteRepositoryStubFile

func WriteRepositoryStubFile(path string, meta *ModelMeta) error

WriteRepositoryStubFile writes repository scaffold source into file.

func WriteZeroDowntimeMigrationFiles

func WriteZeroDowntimeMigrationFiles(dir string, baseVersion int64, name string, plan *ZeroDowntimePlan) error

WriteZeroDowntimeMigrationFiles writes expand/backfill/contract migration triplet.

Types

type AfterDeleteHook

type AfterDeleteHook interface {
	AfterDelete(ctx context.Context) error
}

AfterDeleteHook runs after successful Delete.

type AfterFindHook

type AfterFindHook interface {
	AfterFind(ctx context.Context) error
}

AfterFindHook runs after a model is loaded from DB.

type AfterInsertHook

type AfterInsertHook interface {
	AfterInsert(ctx context.Context) error
}

AfterInsertHook runs after successful Insert.

type AfterInterceptor

type AfterInterceptor func(ctx context.Context, info OperationInfo, opErr error) error

AfterInterceptor runs after operation execution (success or failure).

type AfterUpdateHook

type AfterUpdateHook interface {
	AfterUpdate(ctx context.Context) error
}

AfterUpdateHook runs after successful Update/UpdateFields.

type BeforeDeleteHook

type BeforeDeleteHook interface {
	BeforeDelete(ctx context.Context) error
}

BeforeDeleteHook runs before Delete.

type BeforeInsertHook

type BeforeInsertHook interface {
	BeforeInsert(ctx context.Context) error
}

BeforeInsertHook runs before Insert.

type BeforeInterceptor

type BeforeInterceptor func(ctx context.Context, info OperationInfo) (context.Context, error)

BeforeInterceptor can mutate context and abort execution.

type BeforeUpdateHook

type BeforeUpdateHook interface {
	BeforeUpdate(ctx context.Context) error
}

BeforeUpdateHook runs before Update/UpdateFields.

type ClusterResolvePolicy

type ClusterResolvePolicy struct {
	PreferReadReplicas     bool
	AllowUnhealthyFallback bool
	AllowWriteToReadOnly   bool
}

ClusterResolvePolicy configures replica selection and fallback behavior.

type ClusterResolver

type ClusterResolver struct {
	Policy ClusterResolvePolicy
	// contains filtered or unexported fields
}

ClusterResolver routes shard key to a weighted, health-aware replica.

func NewClusterResolver

func NewClusterResolver() *ClusterResolver

NewClusterResolver creates a new resolver for shard orchestration.

func (*ClusterResolver) Register

func (r *ClusterResolver) Register(shardKey string, replica ShardReplica) error

Register adds or replaces replica in shard group.

func (*ClusterResolver) ResolveShard

func (r *ClusterResolver) ResolveShard(ctx context.Context, shardKey string, info OperationInfo) (DB, error)

ResolveShard resolves db node for shard key and operation.

func (*ClusterResolver) SetHealthy

func (r *ClusterResolver) SetHealthy(shardKey, replicaName string, healthy bool) error

SetHealthy updates replica health flag.

type Codec

type Codec interface {
	Encode(value any) (any, error)
	Decode(value any) (any, error)
}

Codec transforms field values between model and DB representations.

type CodegenConfig

type CodegenConfig struct {
	Package       string             `json:"package"`
	OutputDir     string             `json:"output_dir"`
	ORMImport     string             `json:"orm_import"`
	Header        string             `json:"header"`
	Models        []CodegenModelSpec `json:"models"`
	GenerateIndex bool               `json:"generate_index"`
}

CodegenConfig is an input file for multi-file code generation.

func LoadCodegenConfig

func LoadCodegenConfig(path string) (*CodegenConfig, error)

LoadCodegenConfig loads JSON codegen config from file.

type CodegenModelSpec

type CodegenModelSpec struct {
	Name               string   `json:"name"`
	Columns            []string `json:"columns"`
	PKType             string   `json:"pk_type"`
	GenerateColumns    bool     `json:"generate_columns"`
	GenerateRepository bool     `json:"generate_repository"`
}

CodegenModelSpec defines one model entry for pipeline generation.

type ColumnSchema

type ColumnSchema struct {
	Name       string `json:"name"`
	Type       string `json:"type"`
	Nullable   bool   `json:"nullable"`
	PrimaryKey bool   `json:"primary_key"`
}

type DB

type DB interface {
	NewQuery(sql string) *dbx.Query
	Select(cols ...string) *dbx.SelectQuery
	Insert(table string, cols dbx.Params) *dbx.Query
	InsertMany(table string, rows []dbx.Params) *dbx.Query
	InsertReturning(table string, cols dbx.Params, returning ...string) *dbx.Query
	Update(table string, cols dbx.Params, where dbx.Expression) *dbx.Query
	Delete(table string, where dbx.Expression) *dbx.Query
	Upsert(table string, cols dbx.Params, constraints ...string) *dbx.Query
	UpsertOnConflict(table string, cols dbx.Params, conflict dbx.OnConflict) *dbx.Query
}

DB is the dbx-based contract accepted by ORM operations.

func SelectDB

func SelectDB(ctx context.Context, base DB, resolver ShardResolver, info OperationInfo) (DB, error)

SelectDB resolves shard DB from context and falls back to base DB.

type DBXObserverOptions

type DBXObserverOptions struct {
	RedactSQL func(sql string) string
	OnEvent   func(QueryEvent)
}

DBXObserverOptions configures DB-level ORM-aware observability hooks.

type DefaultNamingStrategy

type DefaultNamingStrategy struct{}

DefaultNamingStrategy uses snake_case names and basic English pluralization.

func (DefaultNamingStrategy) ColumnName

func (DefaultNamingStrategy) ColumnName(fieldName string) string

func (DefaultNamingStrategy) TableName

func (DefaultNamingStrategy) TableName(typeName string) string

type Error

type Error struct {
	Code  ErrorCode
	Op    string
	Model string
	Field string
	Err   error
}

Error is a machine-readable ORM error.

func AsError

func AsError(err error) (*Error, bool)

AsError unwraps ORM error from arbitrary wrapped error.

func (*Error) Details

func (e *Error) Details() ErrorDetails

Details returns structured context payload.

func (*Error) Error

func (e *Error) Error() string

func (*Error) ErrorCode

func (e *Error) ErrorCode() ErrorCode

ErrorCode returns stable category code.

func (*Error) Is

func (e *Error) Is(target error) bool

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorCode

type ErrorCode string

ErrorCode identifies stable ORM error categories.

const (
	CodeNotFound          ErrorCode = "not_found"
	CodeMultipleRows      ErrorCode = "multiple_rows"
	CodeConflict          ErrorCode = "conflict"
	CodeInvalidModel      ErrorCode = "invalid_model"
	CodeMissingPrimaryKey ErrorCode = "missing_primary_key"
	CodeNoRowsAffected    ErrorCode = "no_rows_affected"
	CodeRelationNotFound  ErrorCode = "relation_not_found"
	CodeUnsupportedType   ErrorCode = "unsupported_type"
	CodeInvalidField      ErrorCode = "invalid_field"
	CodeInvalidQuery      ErrorCode = "invalid_query"
	CodeSoftDeleted       ErrorCode = "soft_deleted"
)

type ErrorDetails

type ErrorDetails struct {
	Op    string
	Model string
	Field string
}

ErrorDetails is a stable, machine-readable error context payload.

type FieldExtender

type FieldExtender interface {
	ExtendField(sf reflect.StructField, field *FieldMeta) error
}

FieldExtender allows custom tags/field behavior during metadata parsing.

type FieldMeta

type FieldMeta struct {
	GoName       string
	DBName       string
	JSONName     string
	Type         reflect.Type
	Index        []int
	EmbeddedPath []string

	IsPK           bool
	IsNullable     bool
	IsIgnored      bool
	IsReadOnly     bool
	IsWriteOnly    bool
	HasDefault     bool
	IsGenerated    bool
	IsSoftDelete   bool
	IsCreatedAt    bool
	IsUpdatedAt    bool
	IsRelation     bool
	IsEmbeddedRoot bool
	Attributes     map[string]string
	Codec          Codec
}

FieldMeta describes one model field mapped to DB.

type JSONValue

type JSONValue[T any] struct {
	V T
}

JSONValue stores arbitrary Go value as JSON in DB. It implements sql.Scanner and driver.Valuer.

func (*JSONValue[T]) Scan

func (j *JSONValue[T]) Scan(src any) error

func (JSONValue[T]) Value

func (j JSONValue[T]) Value() (driver.Value, error)

type ListResult

type ListResult[T any] struct {
	Items   []T
	Total   int64
	Page    int64
	PerPage int64
}

ListResult is a paginated query response.

func List

func List[T any](ctx context.Context, db DB, page, perPage int64) (*ListResult[T], error)

List is a top-level helper for paginated query results.

type MetricsObserverOptions

type MetricsObserverOptions struct {
	OnQueryCount   func(kind string, op Operation, model, table string)
	OnError        func(kind string, op Operation, model, table string, err error)
	OnLatency      func(kind string, op Operation, model, table string, d time.Duration)
	OnRowsAffected func(op Operation, model, table string, rows int64)
	RedactSQL      func(sql string) string
}

MetricsObserverOptions defines callbacks for high-level query metrics.

type Migration

type Migration struct {
	Version int64
	Name    string
	UpSQL   string
	DownSQL string
}

Migration is an ordered DB migration unit.

func LoadMigrationsDir

func LoadMigrationsDir(dir string) ([]Migration, error)

LoadMigrationsDir loads migrations from *.up.sql/*.down.sql files. Filename format: <version>_<name>.up.sql and <version>_<name>.down.sql

type MigrationPlan

type MigrationPlan struct {
	CurrentVersion int64
	TargetVersion  int64
	Up             []Migration
	Down           []Migration
	Dirty          bool
	LastError      string
}

MigrationPlan describes directional migration actions from current state.

type MigrationRunner

type MigrationRunner struct {
	DB              DB
	TableName       string
	LockName        string
	LockTTL         time.Duration
	UseDBLock       bool
	UseProcessMutex bool
}

MigrationRunner executes SQL migrations over orm.DB.

func NewMigrationRunner

func NewMigrationRunner(db DB) *MigrationRunner

NewMigrationRunner creates a new migration runner.

func (*MigrationRunner) ClearDirty

func (r *MigrationRunner) ClearDirty(ctx context.Context) error

ClearDirty resets migration dirty flag and last error manually.

func (*MigrationRunner) ForceVersion

func (r *MigrationRunner) ForceVersion(ctx context.Context, migrations []Migration, targetVersion int64) error

ForceVersion rewrites migration history table to match targetVersion without executing SQL.

func (*MigrationRunner) MigrateDown

func (r *MigrationRunner) MigrateDown(ctx context.Context, migrations []Migration, steps int) error

MigrateDown rolls back latest `steps` applied migrations.

func (*MigrationRunner) MigrateTo

func (r *MigrationRunner) MigrateTo(ctx context.Context, migrations []Migration, targetVersion int64) error

MigrateTo moves schema state to targetVersion by applying up/down migrations.

func (*MigrationRunner) MigrateUp

func (r *MigrationRunner) MigrateUp(ctx context.Context, migrations []Migration) error

MigrateUp applies all pending migrations in ascending version order.

func (*MigrationRunner) Plan

func (r *MigrationRunner) Plan(ctx context.Context, migrations []Migration, targetVersion int64) (*MigrationPlan, error)

Plan computes migration steps required to reach targetVersion.

func (*MigrationRunner) Status

func (r *MigrationRunner) Status(ctx context.Context, migrations []Migration) (*MigrationStatus, error)

Status returns current migration status for provided migration set.

func (*MigrationRunner) Validate

func (r *MigrationRunner) Validate(migrations []Migration) error

Validate checks migration definition consistency.

type MigrationStatus

type MigrationStatus struct {
	CurrentVersion int64
	Applied        []int64
	Pending        []Migration
	Dirty          bool
	LastError      string
	Locked         bool
	LockOwner      string
}

MigrationStatus contains migration state snapshot.

type ModelConfig

type ModelConfig struct {
	Table         string
	Naming        NamingStrategy
	Relations     map[string]RelationConfig
	Extenders     []FieldExtender
	TenantField   string
	FieldCodecs   map[string]Codec
	RequireTenant *bool
}

ModelConfig overrides inferred model metadata.

type ModelMeta

type ModelMeta struct {
	Type  reflect.Type
	Name  string
	Table string

	Fields      []*FieldMeta
	FieldsByGo  map[string]*FieldMeta
	FieldsByDB  map[string]*FieldMeta
	PrimaryKeys []*FieldMeta

	SoftDeleteField *FieldMeta
	CreatedAtField  *FieldMeta
	UpdatedAtField  *FieldMeta
	TenantField     *FieldMeta
	RequireTenant   bool
	Relations       map[string]*RelationMeta
}

ModelMeta describes one registered model.

func Meta

func Meta[T any]() (*ModelMeta, error)

Meta returns model metadata for T from global registry.

func Register

func Register[T any](cfg ...ModelConfig) (*ModelMeta, error)

Register registers model T in global registry.

type ModelQuery

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

ModelQuery is a typed query builder for model T.

func Query

func Query[T any](db DB) *ModelQuery[T]

Query creates a typed model query.

func QueryRouted

func QueryRouted[T any](ctx context.Context, base DB, resolver ShardResolver) (*ModelQuery[T], error)

QueryRouted resolves shard DB and returns typed query builder.

func QueryWithRouter

func QueryWithRouter[T any](ctx context.Context, r *Router) (*ModelQuery[T], error)

QueryWithRouter creates a routed query using router policy.

func (*ModelQuery[T]) All

func (q *ModelQuery[T]) All(ctx context.Context) ([]T, error)

func (*ModelQuery[T]) Count

func (q *ModelQuery[T]) Count(ctx context.Context) (int64, error)

func (*ModelQuery[T]) Delete

func (q *ModelQuery[T]) Delete(ctx context.Context) (int64, error)

Delete executes bulk delete for filtered rows.

func (*ModelQuery[T]) Exclude

func (q *ModelQuery[T]) Exclude(fields ...string) *ModelQuery[T]

func (*ModelQuery[T]) Exists

func (q *ModelQuery[T]) Exists(ctx context.Context) (bool, error)

func (*ModelQuery[T]) FindAll

func (q *ModelQuery[T]) FindAll(ctx context.Context) ([]T, error)

FindAll is an alias for All.

func (*ModelQuery[T]) FindOne

func (q *ModelQuery[T]) FindOne(ctx context.Context) (*T, error)

FindOne expects exactly one row.

func (*ModelQuery[T]) First

func (q *ModelQuery[T]) First(ctx context.Context) (*T, error)

func (*ModelQuery[T]) HardDelete

func (q *ModelQuery[T]) HardDelete() *ModelQuery[T]

HardDelete forces physical delete in Delete(ctx), even for soft-delete models.

func (*ModelQuery[T]) JoinRelation

func (q *ModelQuery[T]) JoinRelation(name string) *ModelQuery[T]

JoinRelation adds INNER JOIN by relation metadata.

func (*ModelQuery[T]) LeftJoinRelation

func (q *ModelQuery[T]) LeftJoinRelation(name string) *ModelQuery[T]

LeftJoinRelation adds LEFT JOIN by relation metadata.

func (*ModelQuery[T]) Limit

func (q *ModelQuery[T]) Limit(v int64) *ModelQuery[T]

func (*ModelQuery[T]) List

func (q *ModelQuery[T]) List(ctx context.Context, page, perPage int64) (*ListResult[T], error)

List returns paginated items with total count.

func (*ModelQuery[T]) Offset

func (q *ModelQuery[T]) Offset(v int64) *ModelQuery[T]

func (*ModelQuery[T]) One

func (q *ModelQuery[T]) One(ctx context.Context) (*T, error)

func (*ModelQuery[T]) OnlyDeleted

func (q *ModelQuery[T]) OnlyDeleted() *ModelQuery[T]

OnlyDeleted limits query to soft-deleted rows only.

func (*ModelQuery[T]) OrderBy

func (q *ModelQuery[T]) OrderBy(field string) *ModelQuery[T]

func (*ModelQuery[T]) OrderByDesc

func (q *ModelQuery[T]) OrderByDesc(field string) *ModelQuery[T]

func (*ModelQuery[T]) OrderByRelation

func (q *ModelQuery[T]) OrderByRelation(path string) *ModelQuery[T]

OrderByRelation adds metadata-aware ASC order by relation field path: "Relation.Field".

func (*ModelQuery[T]) OrderByRelationDesc

func (q *ModelQuery[T]) OrderByRelationDesc(path string) *ModelQuery[T]

OrderByRelationDesc adds metadata-aware DESC order by relation field path: "Relation.Field".

func (*ModelQuery[T]) Page

func (q *ModelQuery[T]) Page(page, perPage int64) *ModelQuery[T]

func (*ModelQuery[T]) Preload

func (q *ModelQuery[T]) Preload(name string, opts ...PreloadOption) *ModelQuery[T]

Preload eagerly loads an explicit relation by name.

func (*ModelQuery[T]) PreloadChunkSize

func (q *ModelQuery[T]) PreloadChunkSize(n int) *ModelQuery[T]

PreloadChunkSize customizes chunk size for relation preload IN/OR batches.

func (*ModelQuery[T]) Select

func (q *ModelQuery[T]) Select(fields ...string) *ModelQuery[T]

func (*ModelQuery[T]) Set

func (q *ModelQuery[T]) Set(field string, value any) *ModelQuery[T]

Set adds one field assignment for query-based Update(ctx).

func (*ModelQuery[T]) UnsafeWhereExpr

func (q *ModelQuery[T]) UnsafeWhereExpr(sqlExpr string, params dbx.Params) *ModelQuery[T]

UnsafeWhereExpr adds a raw SQL expression. Use cautiously.

func (*ModelQuery[T]) Update

func (q *ModelQuery[T]) Update(ctx context.Context) (int64, error)

Update executes bulk update for filtered rows.

func (*ModelQuery[T]) WhereEq

func (q *ModelQuery[T]) WhereEq(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereExpr

func (q *ModelQuery[T]) WhereExpr(sqlExpr string, params dbx.Params) *ModelQuery[T]

WhereExpr adds a low-level SQL expression. Use cautiously. Deprecated: use UnsafeWhereExpr to make low-level behavior explicit.

func (*ModelQuery[T]) WhereGT

func (q *ModelQuery[T]) WhereGT(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereGTE

func (q *ModelQuery[T]) WhereGTE(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereIn

func (q *ModelQuery[T]) WhereIn(field string, values any) *ModelQuery[T]

func (*ModelQuery[T]) WhereLT

func (q *ModelQuery[T]) WhereLT(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereLTE

func (q *ModelQuery[T]) WhereLTE(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereLike

func (q *ModelQuery[T]) WhereLike(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereNotEq

func (q *ModelQuery[T]) WhereNotEq(field string, value any) *ModelQuery[T]

func (*ModelQuery[T]) WhereNotNull

func (q *ModelQuery[T]) WhereNotNull(field string) *ModelQuery[T]

func (*ModelQuery[T]) WhereNull

func (q *ModelQuery[T]) WhereNull(field string) *ModelQuery[T]

func (*ModelQuery[T]) WhereRelationEq

func (q *ModelQuery[T]) WhereRelationEq(path string, value any) *ModelQuery[T]

WhereRelationEq adds metadata-aware equality filter by relation field path: "Relation.Field".

func (*ModelQuery[T]) WhereRelationIn

func (q *ModelQuery[T]) WhereRelationIn(path string, values any) *ModelQuery[T]

WhereRelationIn adds metadata-aware IN filter by relation field path: "Relation.Field".

func (*ModelQuery[T]) WhereRelationLike

func (q *ModelQuery[T]) WhereRelationLike(path string, value any) *ModelQuery[T]

WhereRelationLike adds metadata-aware LIKE filter by relation field path: "Relation.Field".

func (*ModelQuery[T]) WithDeleted

func (q *ModelQuery[T]) WithDeleted() *ModelQuery[T]

type NamingStrategy

type NamingStrategy interface {
	TableName(typeName string) string
	ColumnName(fieldName string) string
}

NamingStrategy controls model and field naming.

type Nullable

type Nullable[T any] = optional.Nullable[T]

func Null

func Null[T any]() Nullable[T]

func SomeNullable

func SomeNullable[T any](v T) Nullable[T]

func Unset

func Unset[T any]() Nullable[T]

type Operation

type Operation string

Operation identifies high-level ORM operations.

const (
	OpInsert       Operation = "insert"
	OpUpdate       Operation = "update"
	OpUpdateFields Operation = "update_fields"
	OpDelete       Operation = "delete"
	OpByPK         Operation = "by_pk"
	OpDeleteByPK   Operation = "delete_by_pk"
	OpExistsByPK   Operation = "exists_by_pk"
	OpCount        Operation = "count"
	OpQueryAll     Operation = "query_all"
	OpQueryOne     Operation = "query_one"
	OpQueryCount   Operation = "query_count"
	OpQueryUpdate  Operation = "query_update"
	OpQueryDelete  Operation = "query_delete"
)

type OperationInfo

type OperationInfo struct {
	Operation      Operation
	Model          string
	Table          string
	Fields         []string
	ConflictFields []string
	Relations      []string
	Preloads       []string
	HasWhere       bool
	Limit          int64
	Offset         int64
}

OperationInfo describes one ORM operation for interceptor hooks.

type Optional

type Optional[T any] = optional.Value[T]

Optional represents patch field with explicit presence marker.

func None

func None[T any]() Optional[T]

None creates Optional without value.

func Some

func Some[T any](v T) Optional[T]

Some creates Optional with explicit value.

type Plugin

type Plugin interface {
	Name() string
	Install(host *PluginHost) error
}

Plugin installs cross-cutting behavior (interceptors, observers, etc.).

type PluginHost

type PluginHost struct{}

PluginHost exposes extension points available for plugins.

func (*PluginHost) AddAfterInterceptor

func (h *PluginHost) AddAfterInterceptor(fn AfterInterceptor)

func (*PluginHost) AddBeforeInterceptor

func (h *PluginHost) AddBeforeInterceptor(fn BeforeInterceptor)

type PreloadOption

type PreloadOption func(*preloadOptions)

PreloadOption configures relation preloading behavior.

func PreloadConfigure

func PreloadConfigure(fn func(*PreloadScope)) PreloadOption

PreloadConfigure applies callback-style preload config.

func PreloadLimit

func PreloadLimit(n int64) PreloadOption

PreloadLimit applies LIMIT to relation preload query.

func PreloadOrderBy

func PreloadOrderBy(orderExpr string) PreloadOption

PreloadOrderBy adds ORDER BY expression to relation preload query. Deprecated: use UnsafePreloadOrderBy to make low-level behavior explicit.

func PreloadOrderByField

func PreloadOrderByField(field string, dir SortDirection) PreloadOption

PreloadOrderByField adds metadata-aware ORDER BY field for preload query.

func PreloadWhereEq

func PreloadWhereEq(field string, value any) PreloadOption

PreloadWhereEq adds equality predicate to relation preload query.

func PreloadWhereExpr

func PreloadWhereExpr(sqlExpr string, params dbx.Params) PreloadOption

PreloadWhereExpr adds low-level SQL expression to relation preload query. Deprecated: use UnsafePreloadWhereExpr to make low-level behavior explicit.

func PreloadWhereGT

func PreloadWhereGT(field string, value any) PreloadOption

PreloadWhereGT adds metadata-aware > predicate for relation preload query.

func PreloadWhereGTE

func PreloadWhereGTE(field string, value any) PreloadOption

PreloadWhereGTE adds metadata-aware >= predicate for relation preload query.

func PreloadWhereIn

func PreloadWhereIn(field string, values any) PreloadOption

PreloadWhereIn adds metadata-aware IN predicate for relation preload query.

func PreloadWhereLT

func PreloadWhereLT(field string, value any) PreloadOption

PreloadWhereLT adds metadata-aware < predicate for relation preload query.

func PreloadWhereLTE

func PreloadWhereLTE(field string, value any) PreloadOption

PreloadWhereLTE adds metadata-aware <= predicate for relation preload query.

func PreloadWhereLike

func PreloadWhereLike(field string, value any) PreloadOption

PreloadWhereLike adds metadata-aware LIKE predicate for relation preload query.

func PreloadWhereNotNull

func PreloadWhereNotNull(field string) PreloadOption

PreloadWhereNotNull adds metadata-aware IS NOT NULL predicate for relation preload query.

func PreloadWhereNull

func PreloadWhereNull(field string) PreloadOption

PreloadWhereNull adds metadata-aware IS NULL predicate for relation preload query.

func PreloadWithDeleted

func PreloadWithDeleted() PreloadOption

PreloadWithDeleted includes soft-deleted rows for the target preload relation.

func UnsafePreloadOrderBy

func UnsafePreloadOrderBy(orderExpr string) PreloadOption

UnsafePreloadOrderBy adds raw ORDER BY expression to relation preload query.

func UnsafePreloadWhereExpr

func UnsafePreloadWhereExpr(sqlExpr string, params dbx.Params) PreloadOption

UnsafePreloadWhereExpr adds raw SQL expression to relation preload query.

type PreloadScope

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

PreloadScope allows callback-style preload configuration.

func (*PreloadScope) Limit

func (s *PreloadScope) Limit(n int64)

func (*PreloadScope) OrderBy

func (s *PreloadScope) OrderBy(expr string)

func (*PreloadScope) OrderByField

func (s *PreloadScope) OrderByField(field string, dir SortDirection)

func (*PreloadScope) WhereEq

func (s *PreloadScope) WhereEq(field string, v any)

func (*PreloadScope) WhereExpr

func (s *PreloadScope) WhereExpr(sqlExpr string, params dbx.Params)

func (*PreloadScope) WhereGT

func (s *PreloadScope) WhereGT(field string, v any)

func (*PreloadScope) WhereGTE

func (s *PreloadScope) WhereGTE(field string, v any)

func (*PreloadScope) WhereIn

func (s *PreloadScope) WhereIn(field string, v any)

func (*PreloadScope) WhereLT

func (s *PreloadScope) WhereLT(field string, v any)

func (*PreloadScope) WhereLTE

func (s *PreloadScope) WhereLTE(field string, v any)

func (*PreloadScope) WhereLike

func (s *PreloadScope) WhereLike(field string, v any)

func (*PreloadScope) WhereNotNull

func (s *PreloadScope) WhereNotNull(field string)

func (*PreloadScope) WhereNull

func (s *PreloadScope) WhereNull(field string)

func (*PreloadScope) WithDeleted

func (s *PreloadScope) WithDeleted()

type QueryEvent

type QueryEvent struct {
	Kind         string
	Operation    Operation
	Model        string
	Table        string
	SQL          string
	Duration     time.Duration
	RowsAffected int64
	Err          error
}

QueryEvent is a single DB query execution event.

type QueryScope

type QueryScope[T any] func(*ModelQuery[T]) *ModelQuery[T]

QueryScope mutates/returns query chain for top-level helpers.

type Registry

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

Registry holds parsed model metadata.

func NewRegistry

func NewRegistry(opts ...RegistryOption) *Registry

NewRegistry creates a metadata registry.

func (*Registry) Models

func (r *Registry) Models() []*ModelMeta

Models returns a stable snapshot of all currently registered model metadata.

func (*Registry) RegisterType

func (r *Registry) RegisterType(model any, cfg ...ModelConfig) (*ModelMeta, error)

RegisterType registers a model type using optional config override.

func (*Registry) Resolve

func (r *Registry) Resolve(model any) (*ModelMeta, error)

Resolve returns model metadata, lazy-registering when needed.

func (*Registry) ResolveByName

func (r *Registry) ResolveByName(name string) (*ModelMeta, bool)

ResolveByName resolves metadata by model name.

func (*Registry) Validate

func (r *Registry) Validate() error

Validate checks that all registered models are internally consistent.

type RegistryOption

type RegistryOption func(*Registry)

RegistryOption mutates registry defaults.

func WithFieldExtender

func WithFieldExtender(ext FieldExtender) RegistryOption

WithFieldExtender adds global metadata field extender for this registry.

func WithNamingStrategy

func WithNamingStrategy(n NamingStrategy) RegistryOption

WithNamingStrategy sets default naming strategy for a registry.

func WithTenantRequiredDefault

func WithTenantRequiredDefault(required bool) RegistryOption

WithTenantRequiredDefault sets default tenant-required policy for all models in registry.

type RelationConfig

type RelationConfig struct {
	Kind           RelationKind
	LocalField     string
	ForeignRef     string
	JoinTable      string
	JoinLocalKey   string
	JoinForeignKey string
}

RelationConfig overrides inferred relation metadata.

type RelationKind

type RelationKind string

RelationKind describes supported relation types.

const (
	RelationBelongsTo  RelationKind = "belongs_to"
	RelationHasMany    RelationKind = "has_many"
	RelationManyToMany RelationKind = "many_to_many"
)

type RelationMeta

type RelationMeta struct {
	Name           string
	Kind           RelationKind
	FieldIndex     []int
	TargetType     reflect.Type
	LocalField     string
	ForeignRef     string
	JoinTable      string
	JoinLocalKey   string
	JoinForeignKey string
}

RelationMeta describes relation mapping for explicit preload.

type Router

type Router struct {
	Base     DB
	Resolver ShardResolver
	Policy   RoutingPolicy
}

Router is a policy-driven sharding router.

func NewRouter

func NewRouter(base DB, resolver ShardResolver) *Router

NewRouter creates a sharding router with sane defaults.

func (*Router) SelectDB

func (r *Router) SelectDB(ctx context.Context, info OperationInfo) (DB, error)

SelectDB resolves DB based on router policy and context shard/tenant info.

type RoutingPolicy

type RoutingPolicy struct {
	RequireShard      bool
	RequireFor        map[Operation]bool
	UseTenantFallback bool
	TenantToShard     func(tenant any) (string, error)
}

RoutingPolicy configures router behavior for shard resolution.

func (RoutingPolicy) Requires

func (p RoutingPolicy) Requires(op Operation) bool

type RuntimeMetricsOptions

type RuntimeMetricsOptions struct {
	OnRowsScanned func(op Operation, model, table string, rows int64)
	OnTxCount     func(event string)
}

RuntimeMetricsOptions defines callbacks emitted by ORM runtime paths.

type SQLDialect

type SQLDialect string
const (
	DialectAuto     SQLDialect = "auto"
	DialectSQLite   SQLDialect = "sqlite"
	DialectPostgres SQLDialect = "postgres"
)

type SchemaChange

type SchemaChange struct {
	Kind       SchemaChangeKind `json:"kind"`
	Table      string           `json:"table"`
	Column     string           `json:"column,omitempty"`
	FromType   string           `json:"from_type,omitempty"`
	ToType     string           `json:"to_type,omitempty"`
	UpSQL      string           `json:"up_sql"`
	DownSQL    string           `json:"down_sql"`
	Breaking   bool             `json:"breaking"`
	Reversible bool             `json:"reversible"`
}

type SchemaChangeKind

type SchemaChangeKind string
const (
	ChangeCreateTable SchemaChangeKind = "create_table"
	ChangeDropTable   SchemaChangeKind = "drop_table"
	ChangeAddColumn   SchemaChangeKind = "add_column"
	ChangeDropColumn  SchemaChangeKind = "drop_column"
	ChangeAlterType   SchemaChangeKind = "alter_type"
	ChangeSetNotNull  SchemaChangeKind = "set_not_null"
	ChangeDropNotNull SchemaChangeKind = "drop_not_null"
)

type SchemaDiff

type SchemaDiff struct {
	Dialect  SQLDialect     `json:"dialect"`
	Changes  []SchemaChange `json:"changes"`
	Warnings []string       `json:"warnings,omitempty"`
}

func DiffLiveSchemaFromSnapshot

func DiffLiveSchemaFromSnapshot(ctx context.Context, db DB, desired *SchemaSnapshot, opts SchemaDiffOptions) (*SchemaDiff, error)

DiffLiveSchemaFromSnapshot compares live DB schema against desired snapshot.

type SchemaDiffOptions

type SchemaDiffOptions struct {
	Dialect            SQLDialect
	IncludeDestructive bool
}

type SchemaSnapshot

type SchemaSnapshot struct {
	Dialect SQLDialect              `json:"dialect"`
	Tables  map[string]*TableSchema `json:"tables"`
}

func BuildSchemaSnapshotFromModels

func BuildSchemaSnapshotFromModels(models ...any) (*SchemaSnapshot, error)

BuildSchemaSnapshotFromModels builds canonical schema from model types.

func LoadSchemaSnapshot

func LoadSchemaSnapshot(path string) (*SchemaSnapshot, error)

LoadSchemaSnapshot reads schema snapshot from JSON file.

type ShardReplica

type ShardReplica struct {
	Name     string
	DB       DB
	Weight   int
	ReadOnly bool
	Healthy  bool
}

ShardReplica is a single DB node in shard cluster.

type ShardResolver

type ShardResolver interface {
	ResolveShard(ctx context.Context, shardKey string, info OperationInfo) (DB, error)
}

ShardResolver returns DB instance for provided shard key.

type SortDirection

type SortDirection string

SortDirection controls ASC/DESC ordering.

const (
	SortAsc  SortDirection = "ASC"
	SortDesc SortDirection = "DESC"
)

type TableNamer

type TableNamer interface {
	TableName() string
}

TableNamer allows model types to override table name.

type TableSchema

type TableSchema struct {
	Name       string                   `json:"name"`
	Columns    map[string]*ColumnSchema `json:"columns"`
	PrimaryKey []string                 `json:"primary_key,omitempty"`
}

type TenantPlugin

type TenantPlugin struct {
	NameStr     string
	Required    bool
	Column      string
	PerModel    bool
	RegistryRef *Registry
}

TenantPlugin validates tenant context presence for selected operations.

func (TenantPlugin) Install

func (p TenantPlugin) Install(host *PluginHost) error

func (TenantPlugin) Name

func (p TenantPlugin) Name() string

type TraceObserverOptions

type TraceObserverOptions struct {
	OnStart  func(ctx context.Context, info OperationInfo) context.Context
	OnFinish func(ctx context.Context, info OperationInfo, opErr error)
}

TraceObserverOptions configures tracing integration via interceptor layer.

type Tx

type Tx = dbx.Tx

Tx is an alias for dbx transaction wrapper.

type UpsertOptions

type UpsertOptions struct {
	ConflictFields []string
	UpdateFields   []string
	DoNothing      bool
}

UpsertOptions controls conflict/update behavior for Upsert.

type ZeroDowntimePlan

type ZeroDowntimePlan struct {
	Dialect  SQLDialect     `json:"dialect"`
	Expand   []SchemaChange `json:"expand"`
	Backfill []string       `json:"backfill"`
	Contract []SchemaChange `json:"contract"`
	Warnings []string       `json:"warnings,omitempty"`
}

func BuildZeroDowntimePlan

func BuildZeroDowntimePlan(diff *SchemaDiff) *ZeroDowntimePlan

BuildZeroDowntimePlan classifies schema changes into expand/backfill/contract phases.

Directories

Path Synopsis
cmd
ormtool command

Jump to

Keyboard shortcuts

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