Documentation
¶
Overview ¶
Package orm is a generic query builder and model mapper over database/sql. Queries are typed (Query[T] returns T values), always use bound parameters, and validate column names against the model so input can never become SQL (A05). Models are plain structs; persistence functions take an Executor (*database.DB or *database.Tx), so there is no Active Record handle hidden in models.
Index ¶
- Variables
- func Columns[T any]() []string
- func Create[T any](ctx context.Context, ex database.Executor, model *T) error
- func Delete[T any](ctx context.Context, ex database.Executor, model *T) error
- func ForceDelete[T any](ctx context.Context, ex database.Executor, model *T) error
- func Restore[T any](ctx context.Context, ex database.Executor, model *T) error
- func TableOf[T any]() string
- func Update[T any](ctx context.Context, ex database.Executor, model *T) error
- func WithClock(ctx context.Context, now func() time.Time) context.Context
- type AfterCreater
- type AfterUpdater
- type BeforeCreater
- type BeforeDeleter
- type BeforeUpdater
- type CursorPage
- type Direction
- type JSON
- type Keyer
- type Model
- type Page
- type Query
- func (q Query[T]) Chunk(ctx context.Context, size int, fn func([]T) error) error
- func (q Query[T]) Count(ctx context.Context) (int64, error)
- func (q Query[T]) CursorPaginate(ctx context.Context, cursor string, perPage int, dir Direction) (CursorPage[T], error)
- func (q Query[T]) Delete(ctx context.Context) (int64, error)
- func (q Query[T]) Each(ctx context.Context) iter.Seq2[T, error]
- func (q Query[T]) Exists(ctx context.Context) (bool, error)
- func (q Query[T]) Find(ctx context.Context, id any) (T, error)
- func (q Query[T]) First(ctx context.Context) (T, error)
- func (q Query[T]) Get(ctx context.Context) ([]T, error)
- func (q Query[T]) Latest() Query[T]
- func (q Query[T]) Limit(n int) Query[T]
- func (q Query[T]) Offset(n int) Query[T]
- func (q Query[T]) OnlyTrashed() Query[T]
- func (q Query[T]) OrWhere(col string, args ...any) Query[T]
- func (q Query[T]) OrderBy(colName string, dir Direction) Query[T]
- func (q Query[T]) Paginate(ctx context.Context, page, perPage int) (Page[T], error)
- func (q Query[T]) Pluck[V any](ctx context.Context, colName string) ([]V, error)
- func (q Query[T]) SQL() (string, []any, error)
- func (q Query[T]) Scope(fns ...func(Query[T]) Query[T]) Query[T]
- func (q Query[T]) Select(cols ...string) Query[T]
- func (q Query[T]) Update(ctx context.Context, set Set) (int64, error)
- func (q Query[T]) Where(col string, args ...any) Query[T]
- func (q Query[T]) WhereBetween(colName string, low, high any) Query[T]
- func (q Query[T]) WhereGroup(fn func(g Query[T]) Query[T]) Query[T]
- func (q Query[T]) WhereIn(col string, values ...any) Query[T]
- func (q Query[T]) WhereNotIn(col string, values ...any) Query[T]
- func (q Query[T]) WhereNotNull(col string) Query[T]
- func (q Query[T]) WhereNull(col string) Query[T]
- func (q Query[T]) WhereRaw(sqlFrag string, args ...any) Query[T]
- func (q Query[T]) WithTrashed() Query[T]
- type Set
- type SoftDeletes
- type Tabler
Constants ¶
This section is empty.
Variables ¶
var ErrConflict error = &conflictError{}
ErrConflict is returned (wrapped) when a write violates a unique constraint; it reports HTTP status 409 so handlers answer Conflict.
var ErrInvalidCursor = &errs.HTTPError{Status: 400, Message: "Invalid pagination cursor."}
ErrInvalidCursor is returned (400) when a cursor cannot be decoded.
var ErrNotFound = &errs.HTTPError{Status: 404, Message: "Record not found."}
ErrNotFound is returned when First/Find match no row. It matches errs.ErrNotFound, so handlers answer 404 by returning it.
Functions ¶
func ForceDelete ¶
ForceDelete removes model even when it uses soft deletes.
Types ¶
type AfterCreater ¶
AfterCreater runs after INSERT.
type AfterUpdater ¶
AfterUpdater runs after UPDATE.
type BeforeCreater ¶
BeforeCreater runs before INSERT.
type BeforeDeleter ¶
BeforeDeleter runs before DELETE (or soft delete).
type BeforeUpdater ¶
BeforeUpdater runs before UPDATE.
type CursorPage ¶
type CursorPage[T any] struct { Items []T `json:"data"` PerPage int `json:"per_page"` NextCursor string `json:"next_cursor,omitempty"` }
CursorPage is one page of keyset pagination. NextCursor is empty on the last page.
type JSON ¶
type JSON[T any] struct { V T }
JSON stores T as JSON text in one column.
func (JSON[T]) MarshalJSON ¶
MarshalJSON encodes the inner value.
func (*JSON[T]) UnmarshalJSON ¶
UnmarshalJSON decodes into the inner value.
type Keyer ¶
type Keyer interface{ PrimaryKey() string }
Keyer overrides the primary key column (default "id").
type Model ¶
type Model struct {
ID int64 `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
Model provides an auto-increment id and timestamps; embed it in models.
type Page ¶
type Page[T any] struct { Items []T `json:"data"` Total int64 `json:"total"` Page int `json:"page"` PerPage int `json:"per_page"` LastPage int `json:"last_page"` }
Page is one page of results.
type Query ¶
type Query[T any] struct { // contains filtered or unexported fields }
Query builds a SELECT for model T. Builders are values: every method returns a modified copy, so a base query can be shared and refined.
func (Query[T]) Chunk ¶
Chunk processes rows in batches of size ordered by primary key; fn may stop early by returning an error.
func (Query[T]) CursorPaginate ¶
func (q Query[T]) CursorPaginate( ctx context.Context, cursor string, perPage int, dir Direction, ) (CursorPage[T], error)
CursorPaginate returns perPage rows after cursor, ordered by the primary key in dir. Unlike Paginate it needs no COUNT and stays fast and stable on large or changing tables. Pass "" for the first page and the returned NextCursor for the following ones. The query must not have its own OrderBy: the keyset order is the primary key.
func (Query[T]) Delete ¶
Delete removes every matching row (soft-deleting for SoftDeletes models unless WithTrashed/OnlyTrashed was used, which deletes for real) and returns the count.
func (Query[T]) Each ¶
Each streams rows without loading them all; breaking out of the loop closes the rows.
for post, err := range orm.QueryOf[Post](db).Each(ctx) { ... }
func (Query[T]) OnlyTrashed ¶
OnlyTrashed returns only soft-deleted rows.
func (Query[T]) Update ¶
Update sets columns on every matching row and returns the count. updated_at is refreshed unless set explicitly.
func (Query[T]) Where ¶
Where adds "col = value", or "col op value" when three arguments are given: Where("age", ">=", 18). Operators are allow-listed.
func (Query[T]) WhereBetween ¶
WhereBetween adds "col BETWEEN low AND high".
func (Query[T]) WhereGroup ¶
WhereGroup adds a parenthesised group built by fn.
func (Query[T]) WhereNotIn ¶
WhereNotIn adds "col NOT IN (...)". An empty list matches everything.
func (Query[T]) WhereNotNull ¶
WhereNotNull adds "col IS NOT NULL".
func (Query[T]) WhereRaw ¶
WhereRaw adds a raw condition. It must use "?" placeholders for every value; never concatenate input into sql.
func (Query[T]) WithTrashed ¶
WithTrashed includes soft-deleted rows.
type SoftDeletes ¶
SoftDeletes makes Delete set deleted_at instead of removing rows; queries exclude deleted rows unless WithTrashed or OnlyTrashed is used.