orm

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDestructiveOperation is returned when attempting a destructive operation without permission
	ErrDestructiveOperation = errors.New("orm: destructive operation not allowed")

	// ErrUnsupportedOperation is returned when a dialect doesn't support an operation
	ErrUnsupportedOperation = errors.New("orm: operation not supported by dialect")

	// ErrIncompatibleTypes is returned when column types cannot be safely converted
	ErrIncompatibleTypes = errors.New("orm: incompatible column types")
)

Diff errors

View Source
var (
	// ErrNoRows is returned when a query returns no rows
	ErrNoRows = sql.ErrNoRows

	// ErrTxDone is returned when a transaction is already committed or rolled back
	ErrTxDone = sql.ErrTxDone

	// ErrConnDone is returned when the connection is already closed
	ErrConnDone = sql.ErrConnDone

	// ErrNoPrimaryKey is returned when attempting operations on a message without a primary key
	ErrNoPrimaryKey = errors.New("orm: message has no primary key defined")

	// ErrInvalidDialect is returned when an invalid or unregistered dialect is specified
	ErrInvalidDialect = errors.New("orm: invalid or unregistered dialect")

	// ErrNilContext is returned when a nil context is provided
	ErrNilContext = errors.New("orm: nil context provided")

	// ErrSchemaValidationFailed is returned when schema validation fails
	ErrSchemaValidationFailed = errors.New("orm: schema validation failed")
)

Common ORM errors

Functions

func DecodeCursor

func DecodeCursor(token string) (string, error)

DecodeCursor decodes a page cursor token back into the primary key value. Returns an error if the token is empty or not valid base64url.

func EmptyIfNil

func EmptyIfNil[T any](s []T) []T

EmptyIfNil returns an empty (non-nil) slice when s is nil, else s. Used at generated write sites so a nil repeated field binds as an empty array literal, not NULL, against `NOT NULL DEFAULT '{}'` columns.

func EncodeCursor

func EncodeCursor(id string) string

EncodeCursor encodes a primary key value into an opaque page cursor token. The cursor is base64url-encoded (no padding) for safe use in query strings.

func GenerateAlterSQL

func GenerateAlterSQL(diff SchemaDiff, dialect Dialect, allowDestructive bool) ([]string, error)

GenerateAlterSQL generates ALTER TABLE statements to apply the schema diff GenerateAlterSQL generates ALTER TABLE statements for the given schema diff.

Following the protobuf philosophy, this function ONLY generates ADD and DROP statements. Column modifications (type changes, constraint changes, etc.) are NOT supported.

To modify a column, use a multi-step migration with PairedMigration:

  1. ADD new column with desired schema
  2. Migrate data from old column to new column (using DataMigration)
  3. DROP old column (in a separate migration after verification)

This approach:

  • Works on all databases (SQLite, PostgreSQL, MySQL, etc.)
  • Forces explicit thinking about data transformations
  • Prevents accidental data loss
  • Follows protobuf's additive-only philosophy

func GenerateCreateTableSQL

func GenerateCreateTableSQL(schema TableSchema) string

GenerateCreateTableSQL generates a CREATE TABLE statement

func JSON

func JSON(v any) driver.Valuer

JSON wraps a Go value for storage as a JSON column value. The generated ORM code uses it for repeated scalar entity fields (e.g. `repeated string tags`): the value is marshalled to JSON text on write, which both postgres (a jsonb column accepts an untyped text parameter) and sqlite (a TEXT-affinity column) store natively — one generated code path, two dialects.

A nil/empty slice round-trips as SQL NULL so the column stays cleanly nullable and scans back to the zero value.

func ListDialects

func ListDialects() []string

ListDialects returns a list of all registered dialect names.

func NewQueryError

func NewQueryError(query string, err error) error

NewQueryError creates a new QueryError

func NewSchemaError

func NewSchemaError(table, message string, err error) error

NewSchemaError creates a new SchemaError

func NewTransactionError

func NewTransactionError(operation string, err error) error

NewTransactionError creates a new TransactionError

func RegisterDialect

func RegisterDialect(dialect Dialect)

RegisterDialect registers a dialect for use with the ORM. This should be called from init() functions in dialect packages.

func ScanJSON

func ScanJSON(dst any) sql.Scanner

ScanJSON returns a sql.Scanner that unmarshals a JSON column into dst (a pointer, e.g. *[]string). NULL / empty values leave dst at its zero value. It accepts []byte (postgres jsonb) and string (sqlite TEXT) sources.

func ValidateIdentifier

func ValidateIdentifier(name string) error

ValidateIdentifier checks that a string is a safe SQL identifier (letters, digits, underscores only). Returns an error if the identifier contains characters that could be used for SQL injection.

func ValidateOrderBy

func ValidateOrderBy(clause string, allowedColumns []string) error

ValidateOrderBy validates a comma-separated ORDER BY clause against a column allowlist.

Two layers:

  1. Shape: only identifier characters (letters, digits, underscores) in column names, with an optional ASC/DESC direction token.
  2. Allowlist: when allowedColumns is non-empty, every column must be one of the declared columns. Shape validation alone is NOT enough: an undeclared-but-identifier-shaped column (order_by=password_hash) reaches the database where it can be a silent ordering no-op.

Generated entity code exports its declared column list (db.<Entity>Columns) precisely so handlers can pass it here.

func ValidateSchema

func ValidateSchema(ctx context.Context, client *Client, schema TableSchema) error

ValidateSchema validates that the database schema matches the expected schema. It uses IntrospectTable and CompareSchemas to check for differences.

Types

type Client

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

Client is the forge ORM handle. Post-Phase-2 it is a thin wrapper over a *bun.DB (uptrace/bun, postgres-pinned): generated CRUD ops reach the engine via Bun(); the kept schema-truth machinery (introspect/differ/ migration) still consults Dialect() and the raw Exec/Query/QueryRow seam. forge is postgres-only — the dialect argument is retained on the constructors for call-site compatibility and must be "postgres".

func NewClient

func NewClient(dialectName, dsn string) (*Client, error)

NewClient opens a new ORM client. dialectName must be "postgres".

func NewClientWithDB

func NewClientWithDB(db *sql.DB, dialectName string) (*Client, error)

NewClientWithDB wraps an existing *sql.DB into an ORM client. This is the seam the generated bootstrap/setup and pkg/testkit use: open a postgres *sql.DB, hand it here. dialectName must be "postgres".

func (*Client) BeginTx

func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)

BeginTx starts a transaction.

func (*Client) Bun

func (c *Client) Bun() bun.IDB

Bun returns the underlying *bun.DB as a bun.IDB.

func (*Client) BunDB

func (c *Client) BunDB() *bun.DB

BunDB returns the concrete *bun.DB (for advanced callers that need connection-pool control or BeginTx with bun's transaction type).

func (*Client) Close

func (c *Client) Close() error

Close closes the database connection.

func (*Client) DB

func (c *Client) DB() *sql.DB

DB returns the underlying *sql.DB for advanced usage and for the kept schema-truth machinery's database/sql seam.

func (*Client) Dialect

func (c *Client) Dialect() Dialect

Dialect returns the SQL dialect (postgres). Consumed by the kept schema-truth machinery (introspect/differ/migration), not by the runtime CRUD engine.

func (*Client) Exec

func (c *Client) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

Exec runs a raw SQL statement (escape hatch). It goes straight to the underlying *sql.DB, NOT through bun's query formatter: callers write native postgres SQL with $1/$2 placeholders, and bun's `?`-rewriting must not touch it. (Generated code uses db.Bun()'s typed builders, which handle their own placeholders.)

func (*Client) Query

func (c *Client) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

Query runs a raw SQL query (escape hatch). See Exec for the raw-passthrough rationale.

func (*Client) QueryRow

func (c *Client) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row

QueryRow runs a raw SQL query returning at most one row (escape hatch).

func (*Client) RunTransaction

func (c *Client) RunTransaction(ctx context.Context, fn func(ctx Context) error) error

RunTransaction executes fn within a transaction, committing on success and rolling back on error or panic. The transaction Context is passed to fn so generated ORM ops transparently use it.

func (*Client) RunTransactionWithOptions

func (c *Client) RunTransactionWithOptions(ctx context.Context, opts *sql.TxOptions, fn func(ctx Context) error) error

RunTransactionWithOptions is RunTransaction with custom tx options.

type ColumnDiff

type ColumnDiff struct {
	ColumnName string
	OldType    string
	NewType    FieldType
	OldNotNull bool
	NewNotNull bool
	OldDefault sql.NullString
	NewDefault string
}

ColumnDiff represents a difference in a column definition

type Context

type Context interface {
	// Bun returns the underlying bun.IDB. Generated CRUD functions build
	// their queries on it (db.Bun().NewSelect()/NewInsert()/...). It is
	// also the raw-SQL escape hatch: bun.IDB exposes NewRaw plus the
	// IConn methods below.
	Bun() bun.IDB

	// Exec executes a query without returning any rows. Thin wrapper over
	// bun's ExecContext — the raw-SQL path for user handlers.
	Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

	// Query executes a query that returns rows (raw-SQL path).
	Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

	// QueryRow executes a query expected to return at most one row
	// (raw-SQL path).
	QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row

	// Dialect returns the SQL dialect (postgres — forge is postgres-pinned).
	// The raw-SQL escape hatch needs it: a hand-written handler that builds
	// its own SQL string calls db.Dialect().Placeholder(i) for $N parameter
	// markers and db.Dialect().QuoteIdentifier(name) for safe identifiers,
	// instead of hardcoding postgres syntax. Available on both *Client and
	// *Tx so raw SQL composes the same way inside and outside a transaction.
	Dialect() Dialect
}

Context is the unified database handle the generated ORM layer and forge/pkg/crud operate against. It can represent either a direct connection (*Client) or a transaction (*Tx), so the same generated CRUD functions work inside and outside transactions.

Bun engine (epic Phase 2): the query/CRUD engine is uptrace/bun. The canonical accessor is Bun(), which returns a bun.IDB — generated ops build their SELECT/INSERT/UPDATE/DELETE on Bun's typed query builders off this handle. The raw escape hatch (Exec/Query/QueryRow) wraps Bun's IConn, preserved here so user-owned handlers can run hand-written SQL and so the kept schema-truth machinery (introspect/differ/ migration) keeps a database/sql seam.

type Dialect

type Dialect interface {
	// Name returns the name of the dialect (e.g., "postgres", "sqlite")
	Name() string

	// DriverName returns the name of the database driver to use with sql.Open
	DriverName() string

	// Placeholder returns the placeholder string for a given parameter index (0-based)
	// PostgreSQL uses $1, $2, etc.
	// SQLite and MySQL use ?
	Placeholder(index int) string

	// QuoteIdentifier quotes an identifier (table name, column name) for the dialect
	QuoteIdentifier(identifier string) string

	// MapFieldType maps an ORM FieldType to the dialect-specific SQL type
	MapFieldType(fieldType FieldType) string

	// SupportsReturning returns true if the dialect supports RETURNING clause
	SupportsReturning() bool

	// OnConflictClause returns the dialect-specific ON CONFLICT or equivalent clause
	// for upserts. Takes the conflict column and update columns.
	OnConflictClause(conflictColumn string, updateColumns []string) string

	// TableExistsQuery returns a SQL query to check if a table exists
	TableExistsQuery(tableName string) string

	// ListTablesQuery returns a SQL query to list all tables in the current schema
	ListTablesQuery() string

	// IntrospectColumnsQuery returns a SQL query to introspect columns of a table
	IntrospectColumnsQuery(tableName string) string

	// IntrospectIndexesQuery returns a SQL query to introspect indexes of a table
	IntrospectIndexesQuery(tableName string) string

	// ParseColumnType converts a database-specific type string to FieldType
	ParseColumnType(dbType string) (FieldType, error)

	// ScanColumn scans a row from IntrospectColumnsQuery into an IntrospectedColumn
	ScanColumn(rows *sql.Rows) (IntrospectedColumn, error)

	// ScanIndex scans a row from IntrospectIndexesQuery into index information
	ScanIndex(rows *sql.Rows) (indexName, columnName string, isUnique bool, err error)
}

Dialect defines the interface for database-specific implementations. Each supported database (PostgreSQL, SQLite, MySQL, etc.) should implement this interface.

func GetDialect

func GetDialect(name string) (Dialect, error)

GetDialect returns the dialect with the given name. Returns nil if the dialect is not registered.

type FieldSchema

type FieldSchema struct {
	Name         string
	Type         FieldType
	PrimaryKey   bool
	Unique       bool
	NotNull      bool
	DefaultValue string
}

FieldSchema represents a database field schema

type FieldType

type FieldType string

FieldType represents a database field type

const (
	TypeText        FieldType = "TEXT"
	TypeVarchar     FieldType = "VARCHAR"
	TypeInteger     FieldType = "INTEGER"
	TypeBigInt      FieldType = "BIGINT"
	TypeBoolean     FieldType = "BOOLEAN"
	TypeTimestampTZ FieldType = "TIMESTAMPTZ"
	TypeJSONB       FieldType = "JSONB"
	TypeBytea       FieldType = "BYTEA"
	TypeSerial      FieldType = "SERIAL"
	TypeBigSerial   FieldType = "BIGSERIAL"
	// TypeReal stores a single-precision floating point value (IEEE 754
	// 32-bit). Maps to PostgreSQL REAL and to SQLite REAL (which is 8-byte
	// internally — SQLite has no float32 column type). Used for proto
	// `float` / `google.protobuf.FloatValue` fields.
	TypeReal FieldType = "REAL"
	// TypeDoublePrecision stores a double-precision floating point value
	// (IEEE 754 64-bit). Maps to PostgreSQL DOUBLE PRECISION and to
	// SQLite REAL. Used for proto `double` / `google.protobuf.DoubleValue`
	// fields. Before TypeDoublePrecision landed, protoc-gen-forge emitted
	// orm.TypeText for double columns; the runtime Scan still worked
	// because Scan uses *float64, but anything that consults
	// TableSchema() (DDL introspection / contract sync) saw TEXT for
	// numeric columns. See orm-typetext-for-double in FORGE_BACKLOG.
	TypeDoublePrecision FieldType = "DOUBLE PRECISION"
)

type IndexSchema

type IndexSchema struct {
	Name   string
	Fields []string
	Unique bool
}

IndexSchema represents a database index

type Int64Array

type Int64Array []int64

Int64Array scans an integer-array column from either encoding.

func (*Int64Array) Scan

func (a *Int64Array) Scan(src any) error

Scan implements sql.Scanner.

type IntrospectedColumn

type IntrospectedColumn struct {
	Name         string
	Type         FieldType
	Nullable     bool
	DefaultValue *string
	IsPrimaryKey bool
	IsUnique     bool
}

IntrospectedColumn represents a database column discovered through introspection

type IntrospectedIndex

type IntrospectedIndex struct {
	Name     string
	Columns  []string
	IsUnique bool
}

IntrospectedIndex represents a database index discovered through introspection

type Migration

type Migration struct {
	// Version is a unique identifier for this migration (e.g., "20240101_001", "v1.0.0")
	Version string

	// Description is a human-readable description of the migration
	Description string

	// Up is the function to apply the migration
	Up func(ctx context.Context, db Context) error

	// Down is the function to rollback the migration (optional)
	Down func(ctx context.Context, db Context) error
}

Migration represents a database migration

func NewSQLMigration

func NewSQLMigration(version, description, upSQL, downSQL string) *Migration

Helper function to create a simple schema migration from a SQL string

func NewSchemaCreateMigration

func NewSchemaCreateMigration(version string, schemas ...TableSchema) *Migration

Helper to create a migration that generates schema from protobuf

type MigrationManager

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

MigrationManager manages database migrations

func NewMigrationManager

func NewMigrationManager(client *Client) *MigrationManager

NewMigrationManager creates a new migration manager

func (*MigrationManager) AutoMigrate

func (m *MigrationManager) AutoMigrate(ctx context.Context, schemas []TableSchema) error

AutoMigrate is a convenience function that automatically generates and applies migrations for the provided schemas WARNING: This is a DANGEROUS operation that should ONLY be used in development environments. - It automatically modifies your database schema without explicit review - There is no automatic rollback mechanism - It may cause data loss if destructive operations are allowed - Production databases should use explicit migrations instead

Returns error early if schema diff, SQL generation, or database operations fail.

func (*MigrationManager) GenerateMigration

func (m *MigrationManager) GenerateMigration(ctx context.Context, schemas []TableSchema) (*Migration, error)

GenerateMigration diffs the provided schemas against the database and generates ALTER statements Returns a Migration with the generated SQL. Returns error early if schema diff or SQL generation fails.

func (*MigrationManager) Migrate

func (m *MigrationManager) Migrate(ctx context.Context) error

Migrate runs all pending migrations

func (*MigrationManager) MigrateTo

func (m *MigrationManager) MigrateTo(ctx context.Context, targetVersion string) error

MigrateTo migrates to a specific version

func (*MigrationManager) PlanMigration

func (m *MigrationManager) PlanMigration(ctx context.Context, schemas []TableSchema) (string, error)

PlanMigration is a dry-run function that returns the SQL that would be executed without executing it Returns the SQL statements as a string. Returns error early if schema diff or SQL generation fails.

func (*MigrationManager) Register

func (m *MigrationManager) Register(migration *Migration) error

Register registers a migration

func (*MigrationManager) RegisterMany

func (m *MigrationManager) RegisterMany(migrations ...*Migration) error

RegisterMany registers multiple migrations

func (*MigrationManager) RegisterPairedMigration

func (m *MigrationManager) RegisterPairedMigration(paired *PairedMigration) error

RegisterPairedMigration registers a paired migration that combines schema changes with optional data migrations Schema changes are executed first, then data migrations, all in the same transaction. Returns error early if version conflicts are detected or if migrations are invalid.

func (*MigrationManager) Rollback

func (m *MigrationManager) Rollback(ctx context.Context, steps int) error

Rollback rolls back the last N migrations

func (*MigrationManager) SetTableName

func (m *MigrationManager) SetTableName(name string)

SetTableName sets the name of the migrations tracking table

func (*MigrationManager) Status

Status returns the status of all migrations

type MigrationStatus

type MigrationStatus struct {
	Version     string
	Description string
	Applied     bool
	AppliedAt   time.Time
}

MigrationStatus represents the status of a migration

type NullTime

type NullTime struct {
	Time  time.Time
	Valid bool
}

NullTime is a nullable timestamp scanner that tolerates every representation forge's supported engines hand back for a timestamp column:

  • time.Time (Postgres via pgx/stdlib; SQLite when the declared type is one the driver recognizes),
  • string / []byte (SQLite for declared types like TIMESTAMPTZ, which mattn/go-sqlite3 does NOT auto-convert — it only recognizes "timestamp", "datetime" and "date" verbatim),
  • nil (NULL column).

database/sql's own sql.NullTime rejects the string forms, which made generated entity scans fail at runtime against the SQLite test harness. Generated *_orm.go scan code uses this type instead.

func (*NullTime) Scan

func (n *NullTime) Scan(value any) error

Scan implements sql.Scanner.

func (NullTime) Value

func (n NullTime) Value() (driver.Value, error)

Value implements driver.Valuer so NullTime round-trips on writes too.

type Operator

type Operator string

Operator represents a SQL comparison operator used by WithWhere and the Where* convenience helpers. Postgres semantics (ILIKE is native).

const (
	Eq              Operator = "="
	NotEq           Operator = "!="
	GreaterThan     Operator = ">"
	GreaterThanOrEq Operator = ">="
	LessThan        Operator = "<"
	LessThanOrEq    Operator = "<="
	Like            Operator = "LIKE"
	ILike           Operator = "ILIKE"
	In              Operator = "IN"
	NotIn           Operator = "NOT IN"
	IsNull          Operator = "IS NULL"
	IsNotNull       Operator = "IS NOT NULL"
)

type Order

type Order string

Order represents sort direction.

const (
	Asc  Order = "ASC"
	Desc Order = "DESC"
)

type PairedMigration

type PairedMigration struct {
	// Version is a unique identifier for this migration (e.g., "20240101_001", "v1.0.0")
	Version string

	// Description is a human-readable description of the migration
	Description string

	// SchemaChanges are the proto-based table schemas to migrate to
	SchemaChanges []TableSchema

	// DataMigration is an optional raw SQL migration to run after schema changes
	// This is executed in the same transaction as the schema changes
	DataMigration *Migration
}

PairedMigration represents a migration that combines schema changes with optional data migrations

type PostgresDialect

type PostgresDialect struct{}

PostgresDialect implements the Dialect interface for PostgreSQL

func (*PostgresDialect) DriverName

func (d *PostgresDialect) DriverName() string

func (*PostgresDialect) IntrospectColumnsQuery

func (d *PostgresDialect) IntrospectColumnsQuery(tableName string) string

IntrospectColumnsQuery returns a query to introspect columns of a table

func (*PostgresDialect) IntrospectIndexesQuery

func (d *PostgresDialect) IntrospectIndexesQuery(tableName string) string

IntrospectIndexesQuery returns a query to introspect indexes of a table

func (*PostgresDialect) ListTablesQuery

func (d *PostgresDialect) ListTablesQuery() string

ListTablesQuery returns a query to list all tables in the public schema

func (*PostgresDialect) MapFieldType

func (d *PostgresDialect) MapFieldType(fieldType FieldType) string

func (*PostgresDialect) Name

func (d *PostgresDialect) Name() string

func (*PostgresDialect) OnConflictClause

func (d *PostgresDialect) OnConflictClause(conflictColumn string, updateColumns []string) string

func (*PostgresDialect) ParseColumnType

func (d *PostgresDialect) ParseColumnType(dbType string) (FieldType, error)

ParseColumnType converts a PostgreSQL type to FieldType

func (*PostgresDialect) Placeholder

func (d *PostgresDialect) Placeholder(index int) string

func (*PostgresDialect) QuoteIdentifier

func (d *PostgresDialect) QuoteIdentifier(identifier string) string

func (*PostgresDialect) ScanColumn

func (d *PostgresDialect) ScanColumn(rows *sql.Rows) (IntrospectedColumn, error)

ScanColumn scans a row from IntrospectColumnsQuery into an IntrospectedColumn

func (*PostgresDialect) ScanIndex

func (d *PostgresDialect) ScanIndex(rows *sql.Rows) (indexName, columnName string, isUnique bool, err error)

ScanIndex scans a row from IntrospectIndexesQuery into index information

func (*PostgresDialect) SupportsReturning

func (d *PostgresDialect) SupportsReturning() bool

func (*PostgresDialect) TableExistsQuery

func (d *PostgresDialect) TableExistsQuery(tableName string) string

TableExistsQuery returns a query to check if a table exists in PostgreSQL

type QueryError

type QueryError struct {
	Query string
	Err   error
}

QueryError represents an error that occurred during a query execution

func (*QueryError) Error

func (e *QueryError) Error() string

func (*QueryError) Unwrap

func (e *QueryError) Unwrap() error

type QueryOption

type QueryOption func(*bun.SelectQuery)

QueryOption is a composable mutation of a Bun SELECT query. The generated List/Count/Get ops and forge/pkg/crud build their filters, ordering, and pagination as a slice of these and apply them to a *bun.SelectQuery.

Phase-2 note: pre-Bun this was func(*QueryBuilder) over forge's hand-rolled builder. The signature now targets *bun.SelectQuery — the engine is Bun, and there is no hand-rolled builder left.

func WhereEq

func WhereEq(column string, value any) QueryOption

func WhereGt

func WhereGt(column string, value any) QueryOption

func WhereGte

func WhereGte(column string, value any) QueryOption

func WhereILike

func WhereILike(column string, value any) QueryOption

func WhereILikeAny

func WhereILikeAny(columns []string, value any) QueryOption

WhereILikeAny matches value case-insensitively against ANY of the given columns: (c1 ILIKE ? OR c2 ILIKE ? ...), AND-ed with the other WHERE clauses. This is the canonical mapping for a `search` filter field: it spans the entity's declared string columns instead of inventing a phantom `search` column.

The OR group is grouped with WhereGroup so it composes correctly with surrounding AND clauses (tenant scope, soft-delete, pagination cursor).

func WhereIn

func WhereIn(column string, values any) QueryOption

func WhereIsNotNull

func WhereIsNotNull(column string) QueryOption

func WhereIsNull

func WhereIsNull(column string) QueryOption

func WhereLike

func WhereLike(column string, value any) QueryOption

func WhereLt

func WhereLt(column string, value any) QueryOption

func WhereLte

func WhereLte(column string, value any) QueryOption

func WhereNotEq

func WhereNotEq(column string, value any) QueryOption

func WhereNotIn

func WhereNotIn(column string, values any) QueryOption

func WithLimit

func WithLimit(limit int) QueryOption

WithLimit sets the LIMIT.

func WithOffset

func WithOffset(offset int) QueryOption

WithOffset sets the OFFSET.

func WithOrderBy

func WithOrderBy(clause string, order Order) QueryOption

WithOrderBy adds an ORDER BY clause. The clause may carry one or more comma-separated columns (validate user input with ValidateOrderBy first). order applies to the whole clause.

func WithWhere

func WithWhere(column string, op Operator, value any) QueryOption

WithWhere adds a WHERE clause. Identifiers are bound via Bun's `?` placeholders with bun.Ident, so column names are safely quoted and values safely parameterized.

type SchemaDiff

type SchemaDiff struct {
	TableName       string
	MissingColumns  []FieldSchema // Columns in proto but not in DB
	ExtraColumns    []string      // Columns in DB but not in proto
	ModifiedColumns []ColumnDiff  // Columns with type/constraint changes
	MissingIndexes  []IndexSchema // Indexes in proto but not in DB
	ExtraIndexes    []string      // Indexes in DB but not in proto
}

SchemaDiff represents all differences between expected and actual schema for a table

func CompareSchemas

func CompareSchemas(expected, actual TableSchema) (SchemaDiff, error)

CompareSchemas compares expected schema against actual schema and returns differences

func DiffDatabase

func DiffDatabase(ctx context.Context, db Context, dialect Dialect, expectedSchemas []TableSchema) ([]SchemaDiff, error)

DiffDatabase compares expected schemas against the actual database schema

func (*SchemaDiff) HasChanges

func (d *SchemaDiff) HasChanges() bool

HasChanges returns true if there are any differences between schemas

func (*SchemaDiff) IsDestructive

func (d *SchemaDiff) IsDestructive() bool

IsDestructive returns true if the diff contains destructive changes

type SchemaError

type SchemaError struct {
	Table   string
	Message string
	Err     error
}

SchemaError represents a schema-related error

func (*SchemaError) Error

func (e *SchemaError) Error() string

func (*SchemaError) Unwrap

func (e *SchemaError) Unwrap() error

type StringArray

type StringArray []string

StringArray scans a string-array column from either encoding.

func (*StringArray) Scan

func (a *StringArray) Scan(src any) error

Scan implements sql.Scanner.

type TableSchema

type TableSchema struct {
	Name    string
	Fields  []FieldSchema
	Indexes []IndexSchema
}

TableSchema represents a database table schema

func IntrospectAllTables

func IntrospectAllTables(ctx context.Context, db Context, dialect Dialect) ([]TableSchema, error)

IntrospectAllTables retrieves schemas for all user tables in the database. It returns a slice of TableSchema objects, one for each table. Returns NewSchemaError if the query fails or any table introspection fails.

func IntrospectTable

func IntrospectTable(ctx context.Context, db Context, dialect Dialect, tableName string) (TableSchema, error)

IntrospectTable retrieves the actual schema of a table from the database. It returns detailed information about columns and indexes. Returns NewSchemaError if the table doesn't exist or any operation fails.

type TransactionError

type TransactionError struct {
	Operation string
	Err       error
}

TransactionError represents an error that occurred during a transaction

func (*TransactionError) Error

func (e *TransactionError) Error() string

func (*TransactionError) Unwrap

func (e *TransactionError) Unwrap() error

type Tx

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

Tx wraps a bun transaction as an orm.Context, so the same generated CRUD functions run transparently inside a transaction.

func (*Tx) Bun

func (t *Tx) Bun() bun.IDB

Bun returns the transaction as a bun.IDB.

func (*Tx) Commit

func (t *Tx) Commit() error

Commit commits the transaction.

func (*Tx) Dialect

func (t *Tx) Dialect() Dialect

Dialect returns the SQL dialect (postgres), so raw-SQL handlers running inside a transaction get the same Placeholder()/QuoteIdentifier() seam as on *Client. Carried from the parent Client at BeginTx time.

func (*Tx) Exec

func (t *Tx) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

Exec runs a raw SQL statement within the transaction. Like Client.Exec it bypasses bun's query formatter (native $1/$2 placeholders) by going to the embedded *sql.Tx.

func (*Tx) Query

func (t *Tx) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

Query runs a raw SQL query within the transaction (raw passthrough).

func (*Tx) QueryRow

func (t *Tx) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row

QueryRow runs a raw SQL query within the transaction (raw passthrough).

func (*Tx) Rollback

func (t *Tx) Rollback() error

Rollback rolls back the transaction.

type UnknownFieldError

type UnknownFieldError struct {
	Field string
}

UnknownFieldError is returned by the generated Update<Entity>Masked helpers when an update_mask path names a column that is not in the entity's updatable set — unknown columns, the primary key, the tenant key, and immutable bookkeeping columns (created_at, deleted_at) all qualify. pkg/crud maps it to CodeInvalidArgument with a clean, SQL-free message naming the path.

func (*UnknownFieldError) Error

func (e *UnknownFieldError) Error() string

Jump to

Keyboard shortcuts

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