Documentation
¶
Index ¶
- Variables
- func ConfigureConnectionPool(db *sql.DB, maxOpen, maxIdle int, maxLifetime, idleTimeout time.Duration)
- func ConfigureDBResolver(opts ...ResolverOption)
- func ConnectPostgres(dsn string, config *DBConfig) (*sql.DB, error)
- func GetStringBuilder() *strings.Builder
- func IsCheckViolation(err error) bool
- func IsConnectionError(err error) bool
- func IsConstraintViolation(err error) bool
- func IsDeadlock(err error) bool
- func IsDuplicateKey(err error) bool
- func IsForeignKeyViolation(err error) bool
- func IsNotFound(err error) bool
- func IsNotNullViolation(err error) bool
- func IsSchemaError(err error) bool
- func IsSerializationFailure(err error) bool
- func IsTimeout(err error) bool
- func MustValidateColumnName(name string)
- func PutStringBuilder(sb *strings.Builder)
- func ToSnakeCase(s string) string
- func Transaction(ctx context.Context, fn func(tx *Tx) error) error
- func ValidateColumnName(name string) error
- func WrapQueryError(operation, query string, args []any, err error) error
- func WrapRelationError(relation, modelType string, err error) error
- type BelongsTo
- type BelongsToMany
- type CTE
- type Cursor
- type DBConfig
- type DBResolver
- type FieldInfo
- type HasMany
- type HasOne
- type LoadBalancer
- type Model
- func (m *Model[T]) Attach(ctx context.Context, entity *T, relation string, ids []any, ...) error
- func (m *Model[T]) Avg(ctx context.Context, column string) (float64, error)
- func (m *Model[T]) Chunk(ctx context.Context, size int, callback func([]*T) error) error
- func (m *Model[T]) Clone() *Model[T]
- func (m *Model[T]) Count(ctx context.Context) (int64, error)
- func (m *Model[T]) CountOver(ctx context.Context, column string) (map[any]int64, error)
- func (m *Model[T]) Create(ctx context.Context, entity *T) error
- func (m *Model[T]) CreateMany(ctx context.Context, entities []*T) error
- func (m *Model[T]) Cursor(ctx context.Context) (*Cursor[T], error)
- func (m *Model[T]) Delete(ctx context.Context) error
- func (m *Model[T]) DeleteMany(ctx context.Context) error
- func (m *Model[T]) Detach(ctx context.Context, entity *T, relation string, ids []any) error
- func (m *Model[T]) Distinct() *Model[T]
- func (m *Model[T]) DistinctBy(columns ...string) *Model[T]
- func (m *Model[T]) Exec(ctx context.Context) (sql.Result, error)
- func (m *Model[T]) Exists(ctx context.Context) (bool, error)
- func (m *Model[T]) Find(ctx context.Context, id any) (*T, error)
- func (m *Model[T]) FindOrFail(ctx context.Context, id any) (*T, error)
- func (m *Model[T]) First(ctx context.Context) (*T, error)
- func (m *Model[T]) FirstOrCreate(ctx context.Context, attributes map[string]any, values map[string]any) (*T, error)
- func (m *Model[T]) Get(ctx context.Context) ([]*T, error)
- func (m *Model[T]) GetArgs() []any
- func (m *Model[T]) GetWheres() []string
- func (m *Model[T]) GroupBy(columns ...string) *Model[T]
- func (m *Model[T]) GroupByCube(columns ...string) *Model[T]
- func (m *Model[T]) GroupByGroupingSets(sets ...[]string) *Model[T]
- func (m *Model[T]) GroupByRollup(columns ...string) *Model[T]
- func (m *Model[T]) Having(query string, args ...any) *Model[T]
- func (m *Model[T]) Latest(columns ...string) *Model[T]
- func (m *Model[T]) Limit(n int) *Model[T]
- func (m *Model[T]) Load(ctx context.Context, entity *T, relations ...string) error
- func (m *Model[T]) LoadMorph(ctx context.Context, entities []*T, relation string, ...) error
- func (m *Model[T]) LoadSlice(ctx context.Context, entities []*T, relations ...string) error
- func (m *Model[T]) Lock(mode string) *Model[T]
- func (m *Model[T]) Offset(n int) *Model[T]
- func (m *Model[T]) Oldest(columns ...string) *Model[T]
- func (m *Model[T]) OrWhere(query any, args ...any) *Model[T]
- func (m *Model[T]) OrWhereNotNull(column string) *Model[T]
- func (m *Model[T]) OrWhereNull(column string) *Model[T]
- func (m *Model[T]) OrderBy(column, direction string) *Model[T]
- func (m *Model[T]) Paginate(ctx context.Context, page, perPage int) (*PaginationResult[T], error)
- func (m *Model[T]) Pluck(ctx context.Context, column string) ([]any, error)
- func (m *Model[T]) Print() (string, []any)
- func (m *Model[T]) Raw(query string, args ...any) *Model[T]
- func (m *Model[T]) Scope(fn func(*Model[T]) *Model[T]) *Model[T]
- func (m *Model[T]) Select(columns ...string) *Model[T]
- func (m *Model[T]) SetDB(db *sql.DB) *Model[T]
- func (m *Model[T]) SimplePaginate(ctx context.Context, page, perPage int) (*PaginationResult[T], error)
- func (m *Model[T]) Sum(ctx context.Context, column string) (float64, error)
- func (m *Model[T]) Sync(ctx context.Context, entity *T, relation string, ids []any, ...) error
- func (m *Model[T]) Table(name string) *Model[T]
- func (m *Model[T]) TableName() string
- func (m *Model[T]) Transaction(ctx context.Context, fn func(tx *Tx) error) error
- func (m *Model[T]) Update(ctx context.Context, entity *T) error
- func (m *Model[T]) UpdateMany(ctx context.Context, values map[string]any) error
- func (m *Model[T]) UpdateOrCreate(ctx context.Context, attributes map[string]any, values map[string]any) (*T, error)
- func (m *Model[T]) UsePrimary() *Model[T]
- func (m *Model[T]) UseReplica(index int) *Model[T]
- func (m *Model[T]) Where(query any, args ...any) *Model[T]
- func (m *Model[T]) WhereFullText(column, searchText string) *Model[T]
- func (m *Model[T]) WhereFullTextWithConfig(column, searchText, config string) *Model[T]
- func (m *Model[T]) WhereHas(relation string, callback any) *Model[T]
- func (m *Model[T]) WhereIn(column string, args []any) *Model[T]
- func (m *Model[T]) WhereNotNull(column string) *Model[T]
- func (m *Model[T]) WhereNull(column string) *Model[T]
- func (m *Model[T]) WherePhraseSearch(column, phrase string) *Model[T]
- func (m *Model[T]) WhereTsVector(tsvectorColumn, tsquery string) *Model[T]
- func (m *Model[T]) With(relations ...string) *Model[T]
- func (m *Model[T]) WithCTE(name string, query any) *Model[T]
- func (m *Model[T]) WithCallback(relation string, callback any) *Model[T]
- func (m *Model[T]) WithContext(ctx context.Context) *Model[T]
- func (m *Model[T]) WithMorph(relation string, typeMap map[string][]string) *Model[T]
- func (m *Model[T]) WithStmtCache(cache *StmtCache) *Model[T]
- func (m *Model[T]) WithTx(tx *Tx) *Model[T]
- type ModelInfo
- type MorphMany
- type MorphOne
- type MorphTo
- type PaginationResult
- type QueryError
- type RandomLoadBalancer
- type Relation
- type RelationDefinition
- type RelationError
- type RelationType
- type ResolverOption
- type RoundRobinLoadBalancer
- type StmtCache
- type TableOverrider
- type Tx
- type ValidationError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrRecordNotFound Query errors // ErrRecordNotFound is returned when a query returns no results ErrRecordNotFound = errors.New("zorm: record not found") // ErrInvalidModel Model errors // ErrInvalidModel is returned when the model type is invalid ErrInvalidModel = errors.New("zorm: invalid model") // ErrNilPointer is returned when a nil pointer is passed ErrNilPointer = errors.New("zorm: nil pointer") // ErrNoContext Context errors // ErrNoContext is returned when no context is provided ErrNoContext = errors.New("zorm: no context provided") // ErrRelationNotFound Relation errors // ErrRelationNotFound is returned when a relation method is not found ErrRelationNotFound = errors.New("zorm: relation not found") // ErrInvalidRelation is returned when relation type is invalid ErrInvalidRelation = errors.New("zorm: invalid relation type") // ErrInvalidConfig is returned when relation config is invalid ErrInvalidConfig = errors.New("zorm: invalid relation config") // ErrDuplicateKey Constraint violation errors // ErrDuplicateKey is returned for unique constraint violations ErrDuplicateKey = errors.New("zorm: duplicate key violation") // ErrForeignKey is returned for foreign key constraint violations ErrForeignKey = errors.New("zorm: foreign key constraint violation") // ErrCheckViolation is returned for CHECK constraint violations ErrCheckViolation = errors.New("zorm: check constraint violation") // ErrNotNullViolation is returned for NOT NULL constraint violations ErrNotNullViolation = errors.New("zorm: not null constraint violation") // ErrConnectionFailed Connection errors // ErrConnectionFailed is returned when database connection fails ErrConnectionFailed = errors.New("zorm: connection failed") // ErrConnectionLost is returned when connection is lost during operation ErrConnectionLost = errors.New("zorm: connection lost") // ErrTimeout is returned when a query or connection times out ErrTimeout = errors.New("zorm: operation timeout") // ErrTransactionDeadlock Transaction errors // ErrTransactionDeadlock is returned when a deadlock is detected ErrTransactionDeadlock = errors.New("zorm: transaction deadlock") // ErrSerializationFailure is returned for serialization failures ErrSerializationFailure = errors.New("zorm: serialization failure") // ErrColumnNotFound Schema errors // ErrColumnNotFound is returned when a column doesn't exist ErrColumnNotFound = errors.New("zorm: column not found") // ErrTableNotFound is returned when a table doesn't exist ErrTableNotFound = errors.New("zorm: table not found") // ErrInvalidSyntax is returned for SQL syntax errors ErrInvalidSyntax = errors.New("zorm: invalid SQL syntax") // ErrRequiresRawQuery Other errors // ErrRequiresRawQuery is returned when operation requires raw query ErrRequiresRawQuery = errors.New("zorm: operation requires raw query") )
Sentinel errors for common failure cases
var ErrInvalidColumnName = fmt.Errorf("zorm: invalid column name")
ErrInvalidColumnName is returned when a column name contains invalid characters.
var GlobalDB *sql.DB
GlobalDB is the global database connection pool. In a real app, this might be managed differently, but for this ORM style, we often have a global or a passed-in DB. For now, we'll allow setting it globally or per-instance.
Functions ¶
func ConfigureConnectionPool ¶
func ConfigureConnectionPool(db *sql.DB, maxOpen, maxIdle int, maxLifetime, idleTimeout time.Duration)
ConfigureConnectionPool configures the database connection pool.
func ConfigureDBResolver ¶
func ConfigureDBResolver(opts ...ResolverOption)
ConfigureDBResolver configures the global database resolver for primary/replica setup. Example:
ConfigureDBResolver(
WithPrimary(primaryDB),
WithReplicas(replica1, replica2),
WithLoadBalancer(RoundRobinLB),
)
func ConnectPostgres ¶
ConnectPostgres creates a new *sql.DB connection pool for PostgreSQL using pgx driver. dsn: "postgres://user:password@host:port/dbname?sslmode=disable"
func GetStringBuilder ¶
GetStringBuilder retrieves a strings.Builder from the pool.
func IsCheckViolation ¶
IsCheckViolation checks if the error is a CHECK constraint violation.
func IsConnectionError ¶
IsConnectionError checks if the error is a connection failure. This includes both connection refused and connection lost errors.
func IsConstraintViolation ¶
IsConstraintViolation checks if the error is any type of constraint violation. This includes unique, foreign key, not null, and check constraints.
func IsDeadlock ¶
IsDeadlock checks if the error is a transaction deadlock.
func IsDuplicateKey ¶
IsDuplicateKey checks if the error is a duplicate key violation.
func IsForeignKeyViolation ¶
IsForeignKeyViolation checks if the error is a foreign key violation.
func IsNotFound ¶
IsNotFound checks if the error is ErrRecordNotFound. It uses errors.Is to check the error chain.
func IsNotNullViolation ¶
IsNotNullViolation checks if the error is a NOT NULL constraint violation.
func IsSchemaError ¶
IsSchemaError checks if the error is a schema-related error. This includes missing columns, missing tables, and syntax errors.
func IsSerializationFailure ¶
IsSerializationFailure checks if the error is a serialization failure.
func MustValidateColumnName ¶ added in v0.5.0
func MustValidateColumnName(name string)
MustValidateColumnName validates a column name and panics if invalid. Use this for internal validation where invalid column names indicate programming errors.
func PutStringBuilder ¶
PutStringBuilder returns a strings.Builder to the pool after resetting it.
func ToSnakeCase ¶
ToSnakeCase converts a string to snake_case. Handles acronyms correctly (e.g., UserID -> user_id, HTTPClient -> http_client). Results are cached to avoid repeated conversions for the same input.
func Transaction ¶
Transaction executes a function within a transaction.
func ValidateColumnName ¶ added in v0.5.0
ValidateColumnName checks if a column name is safe to use in SQL queries. It uses a strict whitelist approach to prevent SQL injection. Allowed characters: alphanumeric, underscore, dot, asterisk, space, parens, comma. Dangerous characters like quotes, semicolons, and comments are rejected.
func WrapQueryError ¶
WrapQueryError wraps a database error with query context. It analyzes the error to categorize it and extract relevant information such as table names and constraint names where possible.
func WrapRelationError ¶
WrapRelationError wraps a relation error with context
Types ¶
type BelongsTo ¶
BelongsTo defines a BelongsTo relation.
func (BelongsTo[T]) GetOverrideTable ¶
func (BelongsTo[T]) NewRelated ¶
func (BelongsTo[T]) RelationType ¶
func (BelongsTo[T]) RelationType() RelationType
type BelongsToMany ¶
type BelongsToMany[T any] struct { PivotTable string ForeignKey string RelatedKey string LocalKey string RelatedPK string Table string }
BelongsToMany defines a BelongsToMany relation.
func (BelongsToMany[T]) NewRelated ¶
func (BelongsToMany[T]) NewRelated() any
func (BelongsToMany[T]) RelationType ¶
func (BelongsToMany[T]) RelationType() RelationType
type Cursor ¶
type Cursor[T any] struct { // contains filtered or unexported fields }
Cursor provides a typed, forward-only iterator over database query results. It wraps sql.Rows and maps each row into the generic model type T.
type DBConfig ¶
type DBConfig struct {
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime time.Duration
ConnMaxIdleTime time.Duration
}
DBConfig configures the connection pool settings.
type DBResolver ¶
type DBResolver struct {
// contains filtered or unexported fields
}
DBResolver manages primary and replica database connections. It automatically routes write operations to the primary and read operations to replicas.
var GlobalResolver *DBResolver
GlobalResolver is the global database resolver for primary/replica setup. If configured, it will automatically route read queries to replicas and write queries to the primary database.
func (*DBResolver) HasReplicas ¶
func (r *DBResolver) HasReplicas() bool
HasReplicas returns true if replicas are configured.
func (*DBResolver) Primary ¶
func (r *DBResolver) Primary() *sql.DB
Primary returns the primary database connection.
func (*DBResolver) Replica ¶
func (r *DBResolver) Replica() *sql.DB
Replica returns a replica based on the load balancer strategy.
type FieldInfo ¶
type FieldInfo struct {
Name string // Struct field name
Column string // DB column name
IsPrimary bool
IsAuto bool // Auto-increment or managed
FieldType reflect.Type
Index []int // Index path for nested fields (if we support embedding)
}
FieldInfo holds data about a single field in the model.
type HasMany ¶
HasMany defines a HasMany relation.
func (HasMany[T]) GetOverrideTable ¶
func (HasMany[T]) NewRelated ¶
func (HasMany[T]) RelationType ¶
func (HasMany[T]) RelationType() RelationType
type HasOne ¶
HasOne defines a HasOne relation.
func (HasOne[T]) GetOverrideTable ¶
func (HasOne[T]) NewRelated ¶
func (HasOne[T]) RelationType ¶
func (HasOne[T]) RelationType() RelationType
type LoadBalancer ¶
LoadBalancer is an interface for selecting a replica from a pool.
var RandomLB LoadBalancer = &RandomLoadBalancer{}
RandomLB is a convenience variable for random load balancing.
var RoundRobinLB LoadBalancer = &RoundRobinLoadBalancer{}
RoundRobinLB is a convenience variable for round-robin load balancing.
type Model ¶
type Model[T any] struct { // contains filtered or unexported fields }
Model provides a strongly typed ORM interface for working with the entity type T. It stores the active query state—including selected columns, filters, ordering, grouping, relation loading rules, and raw SQL segments—allowing the builder to compose complex queries in a structured and chainable manner.
The Model also tracks the execution context, database handle or transaction, and metadata derived from T that is used for mapping database rows into entities.
func (*Model[T]) Attach ¶
func (m *Model[T]) Attach(ctx context.Context, entity *T, relation string, ids []any, pivotData map[any]map[string]any) error
Attach inserts rows into the pivot table for a BelongsToMany relation. pivotData: map[any]map[string]any (RelatedID -> {Column: Value})
func (*Model[T]) Avg ¶
Avg calculates the average of a column. Returns 0 if no rows match or the average is null.
func (*Model[T]) Clone ¶
Clone creates a deep copy of the Model. This is useful for creating new queries based on an existing one without modifying it.
func (*Model[T]) CountOver ¶
CountOver returns count of records partitioned by the specified column. This uses window functions: COUNT(*) OVER (PARTITION BY column). Returns a map of column value -> count.
func (*Model[T]) CreateMany ¶
CreateMany inserts multiple records in a single query.
func (*Model[T]) Cursor ¶
Cursor returns a cursor for iterating over results one by one. Useful for large datasets to avoid loading everything into memory.
func (*Model[T]) Delete ¶
Delete deletes records matching the current query conditions. WARNING: Without WHERE conditions, this will delete ALL records in the table.
func (*Model[T]) DeleteMany ¶
DeleteMany deletes records matching the query.
func (*Model[T]) DistinctBy ¶
DistinctBy adds DISTINCT ON (columns) to the SELECT clause. This is a PostgreSQL-specific feature that returns the first row of each set of rows where the given columns match.
func (*Model[T]) Exists ¶ added in v0.4.0
Exists checks if any record matches the query conditions. It uses "SELECT 1 FROM table WHERE conditions LIMIT 1" for efficiency.
func (*Model[T]) FindOrFail ¶
FindOrFail finds a record by ID or returns an error. In Go, this is identical to Find, but added for API parity.
func (*Model[T]) FirstOrCreate ¶
func (m *Model[T]) FirstOrCreate(ctx context.Context, attributes map[string]any, values map[string]any) (*T, error)
FirstOrCreate finds the first record matching attributes or creates it with attributes+values. If found, returns the existing record. If not found, creates a new record with merged attributes+values.
func (*Model[T]) GroupBy ¶
GroupBy adds a GROUP BY clause. Column names are validated to prevent SQL injection.
func (*Model[T]) GroupByCube ¶
GroupByCube adds a GROUP BY CUBE clause.
func (*Model[T]) GroupByGroupingSets ¶
GroupByGroupingSets adds a GROUP BY GROUPING SETS clause. Each slice in sets represents a grouping set. Empty slice represents empty grouping set ().
func (*Model[T]) GroupByRollup ¶
GroupByRollup adds a GROUP BY ROLLUP clause.
func (*Model[T]) LoadMorph ¶
func (m *Model[T]) LoadMorph(ctx context.Context, entities []*T, relation string, typeMap map[string][]string) error
LoadMorph eager loads a polymorphic relation with constraints on a slice.
func (*Model[T]) Lock ¶
Lock adds a locking clause to the SELECT query. Common modes: "UPDATE", "NO KEY UPDATE", "SHARE", "KEY SHARE" This will generate: SELECT ... FOR [mode]
func (*Model[T]) OrWhereNotNull ¶
OrWhereNotNull adds an OR condition that checks whether the given column is NOT NULL.
Example:
Model[User]().OrWhereNotNull("verified_at")
// OR verified_at IS NOT NULL
func (*Model[T]) OrWhereNull ¶
OrWhereNull adds an OR condition that checks whether the given column is NULL.
Example:
Model[User]().OrWhereNull("deleted_at")
// OR deleted_at IS NULL
func (*Model[T]) OrderBy ¶
OrderBy adds an ORDER BY clause. Column names are validated to prevent SQL injection.
func (*Model[T]) Paginate ¶
Paginate executes the query with pagination. If page is less than 1, it defaults to 1. If perPage is less than 1, it defaults to 15.
func (*Model[T]) Print ¶
Print returns the SQL query and arguments that would be executed without running it. This is useful for debugging and logging the generated SQL. Example:
sql, args := m.Where("status", "active").Limit(10).Print()
fmt.Println(sql, args)
Output: "SELECT * FROM users WHERE 1=1 AND (status = $1) LIMIT 10" [active]
Example ¶
Example usage for documentation
m := New[TestModel]()
m.Where("status", "active").Limit(10)
sql, args := m.Print()
fmt.Println(sql)
fmt.Println(args)
Output: SELECT * FROM test_models WHERE 1=1 AND status = $1 LIMIT 10 [active]
func (*Model[T]) Scope ¶
Scope applies a function to the query builder. Useful for reusable query logic (Scopes).
func (*Model[T]) Select ¶
Select specifies which columns to select. Column names are validated to prevent SQL injection.
func (*Model[T]) SimplePaginate ¶
func (m *Model[T]) SimplePaginate(ctx context.Context, page, perPage int) (*PaginationResult[T], error)
SimplePaginate executes the query with pagination but skips the count query. Use this when you don't need the total count (e.g., "Load More" buttons). This is ~2x faster than Paginate() since it only runs 1 query. If page is less than 1, it defaults to 1. If perPage is less than 1, it defaults to 15.
func (*Model[T]) Sum ¶
Sum calculates the sum of a column. Returns 0 if no rows match or the sum is null.
func (*Model[T]) Sync ¶
func (m *Model[T]) Sync(ctx context.Context, entity *T, relation string, ids []any, pivotData map[any]map[string]any) error
Sync synchronizes the association with the given IDs. It attaches missing IDs and detaches IDs that are not in the new list. pivotData: map[any]map[string]any (RelatedID -> {Column: Value})
func (*Model[T]) Table ¶
Table sets a custom table name for the query. This overrides the table name derived from the struct type.
func (*Model[T]) TableName ¶
TableName returns the table name for the model. If a custom table name is set via Table(), it returns that. Otherwise, it returns the table name from the model info.
func (*Model[T]) Transaction ¶
Transaction executes a function within a transaction using the model's database connection.
func (*Model[T]) Update ¶
Update updates a single record based on its primary key. The entity must not be nil and must have a valid primary key value.
func (*Model[T]) UpdateMany ¶
UpdateMany updates records matching the query with values.
func (*Model[T]) UpdateOrCreate ¶
func (m *Model[T]) UpdateOrCreate(ctx context.Context, attributes map[string]any, values map[string]any) (*T, error)
UpdateOrCreate finds a record matching attributes and updates it with values, or creates it. If found, updates the record with values. If not found, creates a new record with merged attributes+values.
func (*Model[T]) UsePrimary ¶
UsePrimary forces the next query to use the primary database connection. This is useful when you need to read from primary for consistency, such as immediately after a write operation. Example: m.UsePrimary().Get()
func (*Model[T]) UseReplica ¶
UseReplica forces the next query to use a specific replica by index. This is useful for testing or when you want to target a specific replica. Example: m.UseReplica(0).Get()
func (*Model[T]) Where ¶
Where adds a WHERE clause. Supports multiple forms:
Where("column", value) -> column = ? (converted to $n at execution)
Where("column", ">", value) -> column > ?
Where(map[string]any{"name": "John", "age": 30}) -> name = ? AND age = ?
Where(&User{Name: "John"}) -> name = ?
Where(func(q *Model[T]) { ... }) -> nested group with parentheses
func (*Model[T]) WhereFullText ¶
WhereFullText adds a full-text search condition using tsvector and tsquery. Uses default 'english' configuration and plainto_tsquery for user-friendly search. Example: WhereFullText("content", "search terms") Generates: WHERE to_tsvector('english', content) @@ plainto_tsquery('english', ?)
func (*Model[T]) WhereFullTextWithConfig ¶
WhereFullTextWithConfig adds a full-text search condition with a custom text search configuration. Example: WhereFullTextWithConfig("content", "search terms", "spanish") Generates: WHERE to_tsvector('spanish', content) @@ plainto_tsquery('spanish', ?)
func (*Model[T]) WhereIn ¶
WhereIn adds a WHERE IN clause. Column names are validated to prevent SQL injection.
func (*Model[T]) WhereNotNull ¶
WhereNotNull adds an AND condition that checks whether the given column is NOT NULL.
Example:
Model[User]().WhereNotNull("verified_at")
// WHERE verified_at IS NOT NULL
func (*Model[T]) WhereNull ¶
WhereNull adds an AND condition that checks whether the given column is NULL.
Example:
Model[User]().WhereNull("deleted_at")
// WHERE deleted_at IS NULL
func (*Model[T]) WherePhraseSearch ¶
WherePhraseSearch adds an exact phrase search condition. Uses phraseto_tsquery which preserves word order. Example: WherePhraseSearch("content", "fat cat") Generates: WHERE to_tsvector('english', content) @@ phraseto_tsquery('english', ?)
func (*Model[T]) WhereTsVector ¶
WhereTsVector adds a full-text search condition on a pre-computed tsvector column. This is more efficient when you have an indexed tsvector column. Example: WhereTsVector("search_vector", "fat & rat") Generates: WHERE search_vector @@ to_tsquery('english', ?)
func (*Model[T]) With ¶
With adds relations to eager load. Multiple relation names can be specified, including nested relations.
Examples:
With("Posts") // Single relation
With("Posts", "Comments") // Multiple relations
With("Posts.Comments") // Nested relation
func (*Model[T]) WithCTE ¶
WithCTE adds a Common Table Expression (CTE) to the query. query can be a string or a *Model[T].
func (*Model[T]) WithCallback ¶
WithCallback adds a relation with a callback to apply constraints. The callback receives a query builder for the related model and can apply filters, ordering, limits, etc.
Example:
WithCallback("Posts", func(q *Model[Post]) {
q.Where("published", true).OrderBy("created_at", "DESC").Limit(10)
})
func (*Model[T]) WithContext ¶
WithContext sets the context for the query.
func (*Model[T]) WithMorph ¶
WithMorph adds a polymorphic relation to eager load with type-specific constraints. typeMap: map[string][]string{"events": {"Calendar"}, "posts": {"Author"}}
func (*Model[T]) WithStmtCache ¶
WithStmtCache enables statement caching for this model instance. The cache will be used to store and reuse prepared statements, improving performance by avoiding re-preparation of frequently used queries.
Example:
cache := NewStmtCache(100) defer cache.Close() model := New[User]().WithStmtCache(cache)
type ModelInfo ¶
type ModelInfo struct {
Type reflect.Type
TableName string
PrimaryKey string
Fields map[string]*FieldInfo // StructFieldName -> FieldInfo
Columns map[string]*FieldInfo // DBColumnName -> FieldInfo
Accessors []int // Indices of methods starting with "Get"
RelationMethods map[string]int // MethodName -> Index
}
ModelInfo holds the reflection data for a model struct.
func ParseModel ¶
ParseModel inspects the struct T and returns its metadata.
func ParseModelType ¶
ParseModelType inspects the type and returns its metadata.
type MorphMany ¶
type MorphMany[T any] struct { Type string // Column name in related table (e.g. imageable_type) ID string // Column name in related table (e.g. imageable_id) Table string }
MorphMany defines a polymorphic HasMany relation.
func (MorphMany[T]) GetOverrideTable ¶
func (MorphMany[T]) NewRelated ¶
func (MorphMany[T]) RelationType ¶
func (MorphMany[T]) RelationType() RelationType
type MorphOne ¶
type MorphOne[T any] struct { Type string // Column name in related table (e.g. imageable_type) ID string // Column name in related table (e.g. imageable_id) Table string }
MorphOne defines a polymorphic HasOne relation.
func (MorphOne[T]) GetOverrideTable ¶
func (MorphOne[T]) NewRelated ¶
func (MorphOne[T]) RelationType ¶
func (MorphOne[T]) RelationType() RelationType
type MorphTo ¶
type MorphTo[T any] struct { Type string // Column name for Type (e.g. imageable_type) ID string // Column name for ID (e.g. imageable_id) TypeMap map[string]any // Map of DB type string to empty struct instance (e.g. "posts": Post{}) }
MorphTo defines a polymorphic BelongsTo relation. T is usually `any` or a common interface, but in our generic system, the field in the struct will likely be `any` or an interface. However, `Relation` interface requires `NewRelated()`. For MorphTo, `NewRelated` is dynamic. We might need a special handling for MorphTo.
func (MorphTo[T]) NewRelated ¶
func (MorphTo[T]) RelationType ¶
func (MorphTo[T]) RelationType() RelationType
type PaginationResult ¶
type PaginationResult[T any] struct { Data []*T `json:"data"` Total int64 `json:"total"` PerPage int `json:"per_page"` CurrentPage int `json:"current_page"` LastPage int `json:"last_page"` }
PaginationResult holds pagination metadata and data.
type QueryError ¶
type QueryError struct {
Query string // The SQL query that failed
Args []any // The query arguments
Operation string // Operation type: SELECT, INSERT, UPDATE, DELETE, etc.
Err error // The underlying error
Table string // The table involved (if detectable)
Constraint string // The constraint name (if constraint violation)
}
QueryError wraps database errors with query context for better debugging. It provides detailed information about what went wrong including the query, arguments, operation type, and optionally the affected table and constraint.
func GetQueryError ¶
func GetQueryError(err error) *QueryError
GetQueryError extracts the underlying QueryError from an error if present. Returns nil if the error is not or does not wrap a QueryError. Use this to access query details like the SQL, args, table, and constraint.
func (*QueryError) Error ¶
func (e *QueryError) Error() string
func (*QueryError) Unwrap ¶
func (e *QueryError) Unwrap() error
type RandomLoadBalancer ¶
type RandomLoadBalancer struct{}
RandomLoadBalancer is a placeholder for future random load balancing. Currently not implemented, defaults to round-robin.
type Relation ¶
type Relation interface {
RelationType() RelationType
NewRelated() any
NewModel(ctx context.Context, db *sql.DB) any
}
Relation interface allows us to handle generics uniformly.
type RelationDefinition ¶
type RelationDefinition struct {
Type RelationType
Field string // The struct field name in the parent model
RelatedType reflect.Type
// Keys
ForeignKey string
LocalKey string
OwnerKey string // For BelongsTo
// Pivot (BelongsToMany)
PivotTable string
PivotForeign string
PivotRelated string
}
RelationDefinition holds metadata about a relation.
type RelationError ¶
type RelationError struct {
Relation string // Name of the relation
ModelType string // Type of the model
Err error // The underlying error
}
RelationError wraps relation loading failures with context
func (*RelationError) Error ¶
func (e *RelationError) Error() string
func (*RelationError) Unwrap ¶
func (e *RelationError) Unwrap() error
type RelationType ¶
type RelationType string
RelationType defines the type of relationship between two models in the ORM.
const ( // RelationHasOne represents a one-to-one relationship where the current // model owns a single related record. RelationHasOne RelationType = "HasOne" // RelationHasMany represents a one-to-many relationship where the current // model owns multiple related records. RelationHasMany RelationType = "HasMany" // RelationBelongsTo represents an inverse one-to-one or one-to-many // relationship where the current model references a parent record. RelationBelongsTo RelationType = "BelongsTo" // RelationBelongsToMany represents a many-to-many relationship between // two models, typically connected through a join table. RelationBelongsToMany RelationType = "BelongsToMany" )
const ( // RelationMorphTo represents a polymorphic inverse relationship where the // current model can belong to one of several different model types. The // actual target type and ID are determined by discriminator columns such as // "morph_type" and "morph_id". RelationMorphTo RelationType = "MorphTo" // RelationMorphOne represents a polymorphic one-to-one relationship where a // single related record can be associated with multiple possible parent // model types. RelationMorphOne RelationType = "MorphOne" // RelationMorphMany represents a polymorphic one-to-many relationship where // multiple related records can be associated with various parent model types. RelationMorphMany RelationType = "MorphMany" )
type ResolverOption ¶
type ResolverOption func(*DBResolver)
ResolverOption is a functional option for configuring DBResolver.
func WithLoadBalancer ¶
func WithLoadBalancer(lb LoadBalancer) ResolverOption
WithLoadBalancer sets the load balancer strategy. Default is RoundRobinLoadBalancer.
func WithPrimary ¶
func WithPrimary(db *sql.DB) ResolverOption
WithPrimary sets the primary database connection.
func WithReplicas ¶
func WithReplicas(dbs ...*sql.DB) ResolverOption
WithReplicas sets the replica database connections.
type RoundRobinLoadBalancer ¶
type RoundRobinLoadBalancer struct {
// contains filtered or unexported fields
}
RoundRobinLoadBalancer distributes load across replicas using round-robin.
type StmtCache ¶
type StmtCache struct {
// contains filtered or unexported fields
}
StmtCache provides a thread-safe LRU cache for prepared statements. It stores prepared SQL statements and automatically evicts the least recently used entries when the cache reaches its maximum capacity.
The cache is safe for concurrent use by multiple goroutines and helps improve performance by reusing prepared statements instead of re-preparing them on every execution.
func NewStmtCache ¶
NewStmtCache creates a new statement cache with the specified capacity. When the cache reaches capacity, the least recently used statement will be evicted to make room for new entries.
A capacity of 0 or negative value will default to 100.
func (*StmtCache) Clear ¶
func (c *StmtCache) Clear()
Clear closes all cached statements and clears the cache.
func (*StmtCache) Get ¶
Get retrieves a cached prepared statement for the given SQL query. Returns the statement and a release function. The caller MUST call the release function when finished using the statement. Returns nil, nil if the statement is not found in the cache.
func (*StmtCache) Put ¶
Put stores a prepared statement in the cache for the given SQL query. If the cache is at capacity, the least recently used statement will be evicted (and closed when no longer in use) before adding the new statement.
If a statement with the same query already exists, it will be replaced.
type TableOverrider ¶
type TableOverrider interface {
GetOverrideTable() string
}
TableOverrider interface allows relations to specify a custom table name.
type ValidationError ¶
type ValidationError struct {
Field string // Field name that failed validation
Value any // The invalid value
Message string // Human-readable error message
}
ValidationError represents a model validation failure
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string