Documentation
¶
Overview ¶
Package database provides unified database access with support for SQL (Postgres, MySQL, SQLite) and NoSQL (MongoDB) databases. It exposes native drivers for maximum flexibility while providing production-ready features like connection pooling, health checks, and observability.
Index ¶
- Constants
- Variables
- func AssertDatabaseError(t testing.TB, err error)
- func AssertNoDatabaseError(t testing.TB, err error)
- func AssertRecordCount[T any](t testing.TB, db *bun.DB, expected int)
- func AssertRecordCountWhere[T any](t testing.TB, db *bun.DB, expected int, where string, args ...any)
- func AssertRecordExists[T any](t testing.TB, db *bun.DB, id any)
- func AssertRecordNotExists[T any](t testing.TB, db *bun.DB, id any)
- func BulkDelete[T any](ctx context.Context, db bun.IDB, ids []any) error
- func BulkInsert[T any](ctx context.Context, db bun.IDB, records []T, batchSize int) error
- func BulkInsertWithOptions[T any](ctx context.Context, db bun.IDB, records []T, opts BulkInsertOptions) error
- func BulkInsertWithProgress[T any](ctx context.Context, db bun.IDB, records []T, batchSize int, ...) error
- func BulkSoftDelete[T any](ctx context.Context, db bun.IDB, ids []any) error
- func BulkUpdate[T any](ctx context.Context, db bun.IDB, records []T, columns []string, batchSize int) error
- func BulkUpdateWithProgress[T any](ctx context.Context, db bun.IDB, records []T, columns []string, batchSize int, ...) error
- func BulkUpsert[T any](ctx context.Context, db bun.IDB, records []T, conflictColumns []string, ...) error
- func ChunkSlice[T any](slice []T, chunkSize int) [][]T
- func CleanupDB(t testing.TB, db *bun.DB)
- func CreateTestModel[T any](t testing.TB, db *bun.DB, model T) T
- func CreateTestModels[T any](t testing.TB, db *bun.DB, models []T) []T
- func EnableAutoExplain(db *bun.DB, threshold time.Duration)
- func ErrConnectionFailed(dbName string, dbType DatabaseType, cause error) error
- func ErrDatabaseAlreadyExists(name string) error
- func ErrDatabaseNotFound(name string) error
- func ErrDatabaseNotOpened(name string) error
- func ErrInvalidDSN(dsn string) error
- func ErrInvalidDatabaseName(name string) error
- func ErrInvalidDatabaseType(dbType string) error
- func ErrInvalidDatabaseTypeOp(name string, expectedType, actualType DatabaseType) error
- func ErrInvalidPoolConfig(reason string) error
- func ErrNoDatabasesConfigured() error
- func ErrPanicRecovered(dbName string, dbType DatabaseType, panicValue any) error
- func ErrQueryFailed(dbName string, dbType DatabaseType, cause error) error
- func ErrTransactionFailed(dbName string, dbType DatabaseType, cause error) error
- func FilterSlice[T any](slice []T, predicate func(T) bool) []T
- func FormatQueryPlan(plan *QueryPlan) string
- func GetDB(ctx context.Context, defaultDB *bun.DB) bun.IDB
- func GetMongo(c forge.Container) (*mongo.Client, error)
- func GetMongoFromApp(app forge.App) (*mongo.Client, error)
- func GetNamedMongo(c forge.Container, name string) (*mongo.Client, error)
- func GetNamedMongoFromApp(app forge.App, name string) (*mongo.Client, error)
- func GetNamedRedis(c forge.Container, name string) (redis.UniversalClient, error)
- func GetNamedRedisFromApp(app forge.App, name string) (redis.UniversalClient, error)
- func GetNamedSQL(c forge.Container, name string) (*bun.DB, error)
- func GetNamedSQLFromApp(app forge.App, name string) (*bun.DB, error)
- func GetRedis(c forge.Container) (redis.UniversalClient, error)
- func GetRedisFromApp(app forge.App) (redis.UniversalClient, error)
- func GetSQL(c forge.Container) (*bun.DB, error)
- func GetSQLFromApp(app forge.App) (*bun.DB, error)
- func GetTransactionDepth(ctx context.Context) int32
- func GetUserID(ctx context.Context) (int64, bool)
- func GetXIDUserID(ctx context.Context) (xid.ID, bool)
- func GroupBy[T any, K comparable](slice []T, keyFn func(T) K) map[K][]T
- func IdempotentInsert[T any](ctx context.Context, db *bun.DB, records *[]T, conflictColumn string) error
- func IdempotentUpsert[T any](ctx context.Context, db *bun.DB, records *[]T, conflictColumn string) error
- func IndexBy[T any, K comparable](slice []T, keyFn func(T) K) map[K]T
- func IsInTransaction(ctx context.Context) bool
- func LoadAllFixtures[T any](t testing.TB, db *bun.DB) []T
- func LoadFixture[T any](t testing.TB, db *bun.DB, id any) *T
- func MapError[From, To any](from From, mapFn func(From) (To, error)) (To, error)
- func MapPointer[From, To any](from *From, mapFn func(From) To) *To
- func MapSlice[From, To any](from []From, mapFn func(From) To) []To
- func MapSliceError[From, To any](from []From, mapFn func(From) (To, error)) ([]To, error)
- func MapSlicePointers[From, To any](from []*From, mapFn func(From) To) []To
- func MapTo[From, To any](from From, mapFn func(From) To) To
- func MaskDSN(dsn string, dbType DatabaseType) string
- func MustGetDB(ctx context.Context, defaultDB *bun.DB) bun.IDB
- func MustGetMongo(c forge.Container) *mongo.Client
- func MustGetMongoFromApp(app forge.App) *mongo.Client
- func MustGetNamedMongo(c forge.Container, name string) *mongo.Client
- func MustGetNamedMongoFromApp(app forge.App, name string) *mongo.Client
- func MustGetNamedRedis(c forge.Container, name string) redis.UniversalClient
- func MustGetNamedRedisFromApp(app forge.App, name string) redis.UniversalClient
- func MustGetNamedSQL(c forge.Container, name string) *bun.DB
- func MustGetNamedSQLFromApp(app forge.App, name string) *bun.DB
- func MustGetRedis(c forge.Container) redis.UniversalClient
- func MustGetRedisFromApp(app forge.App) redis.UniversalClient
- func MustGetSQL(c forge.Container) *bun.DB
- func MustGetSQLFromApp(app forge.App) *bun.DB
- func NewExtension(opts ...ConfigOption) forge.Extension
- func NewExtensionWithConfig(config Config) forge.Extension
- func NewTestDB(t testing.TB, opts ...TestDBOption) *bun.DB
- func Partition[T any](slice []T, predicate func(T) bool) ([]T, []T)
- func Pluck[T any, R any](slice []T, fn func(T) R) []R
- func ResetTransactionStats()
- func SeedFixtures(t testing.TB, db *bun.DB, fixtures ...any) error
- func SetUserID(ctx context.Context, userID int64) context.Context
- func SetXIDUserID(ctx context.Context, userID xid.ID) context.Context
- func TruncateTables(t testing.TB, db *bun.DB, models ...any) error
- func Unique[T any, K comparable](slice []T, keyFn func(T) K) []T
- func WithNestedTransaction(ctx context.Context, fn TxFunc) error
- func WithReadOnlyTransaction(ctx context.Context, db *bun.DB, fn TxFunc) error
- func WithRepeatableReadTransaction(ctx context.Context, db *bun.DB, fn TxFunc) error
- func WithSerializableTransaction(ctx context.Context, db *bun.DB, fn TxFunc) error
- func WithTestTransaction(t testing.TB, db *bun.DB, fn func(txDB *bun.DB))
- func WithTransaction(ctx context.Context, db *bun.DB, fn TxFunc) error
- func WithTransactionFromApp(ctx context.Context, app forge.App, fn TxFunc) error
- func WithTransactionFromContainer(ctx context.Context, c forge.Container, fn TxFunc) error
- func WithTransactionOptions(ctx context.Context, db *bun.DB, opts *sql.TxOptions, fn TxFunc) error
- type AppliedMigration
- type AuditModel
- func (m *AuditModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
- func (m *AuditModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
- func (m *AuditModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
- func (m *AuditModel) IsDeleted() bool
- func (m *AuditModel) Restore()
- type BaseModel
- type BulkInsertOptions
- type BulkOperationProgress
- type Config
- type ConfigOption
- type ConnectionState
- type CursorPagination
- type CursorResult
- func MapCursor[From, To any](from *CursorResult[From], mapFn func(From) To) *CursorResult[To]
- func MapCursorError[From, To any](from *CursorResult[From], mapFn func(From) (To, error)) (*CursorResult[To], error)
- func PaginateCursor[T any](ctx context.Context, query *bun.SelectQuery, params CursorPagination) (*CursorResult[T], error)
- type Database
- func GetDatabase(c forge.Container) (Database, error)
- func GetDatabaseFromApp(app forge.App) (Database, error)
- func GetNamedDatabase(c forge.Container, name string) (Database, error)
- func GetNamedDatabaseFromApp(app forge.App, name string) (Database, error)
- func MustGetDatabase(c forge.Container) Database
- func MustGetDatabaseFromApp(app forge.App) Database
- func MustGetNamedDatabase(c forge.Container, name string) Database
- func MustGetNamedDatabaseFromApp(app forge.App, name string) Database
- type DatabaseConfig
- type DatabaseError
- type DatabaseManager
- func GetManager(c forge.Container) (*DatabaseManager, error)
- func GetManagerFromApp(app forge.App) (*DatabaseManager, error)
- func MustGetManager(c forge.Container) *DatabaseManager
- func MustGetManagerFromApp(app forge.App) *DatabaseManager
- func NewDatabaseManager(logger forge.Logger, metrics forge.Metrics) *DatabaseManager
- func (m *DatabaseManager) CloseAll(ctx context.Context) error
- func (m *DatabaseManager) Get(name string) (Database, error)
- func (m *DatabaseManager) Health(ctx context.Context) error
- func (m *DatabaseManager) HealthCheckAll(ctx context.Context) map[string]HealthStatus
- func (m *DatabaseManager) List() []string
- func (m *DatabaseManager) Mongo(name string) (*mongo.Client, error)
- func (m *DatabaseManager) MongoDatabase(name string) (*MongoDatabase, error)
- func (m *DatabaseManager) Name() string
- func (m *DatabaseManager) OpenAll(ctx context.Context) error
- func (m *DatabaseManager) Redis(name string) (redis.UniversalClient, error)
- func (m *DatabaseManager) RedisDatabase(name string) (*RedisDatabase, error)
- func (m *DatabaseManager) Register(name string, db Database) error
- func (m *DatabaseManager) SQL(name string) (*bun.DB, error)
- func (m *DatabaseManager) Start(ctx context.Context) error
- func (m *DatabaseManager) Stop(ctx context.Context) error
- type DatabaseStats
- type DatabaseType
- type ExampleSeeder
- type Extension
- type HealthStatus
- type IDB
- type Logger
- type MigrationManager
- func (m *MigrationManager) AutoMigrate(ctx context.Context, models ...any) error
- func (m *MigrationManager) CreateMigration(ctx context.Context) error
- func (m *MigrationManager) CreateTables(ctx context.Context) error
- func (m *MigrationManager) Migrate(ctx context.Context) error
- func (m *MigrationManager) Reset(ctx context.Context) error
- func (m *MigrationManager) Rollback(ctx context.Context) error
- func (m *MigrationManager) Status(ctx context.Context) (*MigrationStatusResult, error)
- type MigrationStatus
- type MigrationStatusResult
- type MongoDatabase
- func (d *MongoDatabase) Client() *mongo.Client
- func (d *MongoDatabase) Close(ctx context.Context) error
- func (d *MongoDatabase) Collection(name string) *mongo.Collection
- func (d *MongoDatabase) Database() *mongo.Database
- func (d *MongoDatabase) Driver() any
- func (d *MongoDatabase) Health(ctx context.Context) HealthStatus
- func (d *MongoDatabase) IsOpen() bool
- func (d *MongoDatabase) Name() string
- func (d *MongoDatabase) Open(ctx context.Context) error
- func (d *MongoDatabase) Ping(ctx context.Context) error
- func (d *MongoDatabase) State() ConnectionState
- func (d *MongoDatabase) Stats() DatabaseStats
- func (d *MongoDatabase) Transaction(ctx context.Context, fn func(sessCtx mongo.SessionContext) error) (err error)
- func (d *MongoDatabase) TransactionWithOptions(ctx context.Context, opts *options.TransactionOptions, ...) (err error)
- func (d *MongoDatabase) Type() DatabaseType
- type MultiError
- type ObservabilityQueryHook
- type OffsetPagination
- type PaginatedResult
- func MapPaginated[From, To any](from *PaginatedResult[From], mapFn func(From) To) *PaginatedResult[To]
- func MapPaginatedError[From, To any](from *PaginatedResult[From], mapFn func(From) (To, error)) (*PaginatedResult[To], error)
- func Paginate[T any](ctx context.Context, query *bun.SelectQuery, params OffsetPagination) (*PaginatedResult[T], error)
- type ProgressCallback
- type QueryHook
- type QueryOption
- func WhereActive() QueryOption
- func WhereDeleted() QueryOption
- func WithLimit(limit int) QueryOption
- func WithOffset(offset int) QueryOption
- func WithOrder(column string, direction ...string) QueryOption
- func WithRelation(relation string) QueryOption
- func WithRelations(relations ...string) QueryOption
- type QueryPlan
- type QueryStats
- type RedisCommandHook
- type RedisDatabase
- func (d *RedisDatabase) Client() redis.UniversalClient
- func (d *RedisDatabase) Close(ctx context.Context) error
- func (d *RedisDatabase) Driver() any
- func (d *RedisDatabase) Health(ctx context.Context) HealthStatus
- func (d *RedisDatabase) IsOpen() bool
- func (d *RedisDatabase) Name() string
- func (d *RedisDatabase) Open(ctx context.Context) error
- func (d *RedisDatabase) Ping(ctx context.Context) error
- func (d *RedisDatabase) Pipeline() redis.Pipeliner
- func (d *RedisDatabase) Pipelined(ctx context.Context, fn func(pipe redis.Pipeliner) error) (err error)
- func (d *RedisDatabase) State() ConnectionState
- func (d *RedisDatabase) Stats() DatabaseStats
- func (d *RedisDatabase) Transaction(ctx context.Context, watchKeys []string, fn func(tx *redis.Tx) error) (err error)
- func (d *RedisDatabase) TxPipeline() redis.Pipeliner
- func (d *RedisDatabase) TxPipelined(ctx context.Context, fn func(pipe redis.Pipeliner) error) (err error)
- func (d *RedisDatabase) Type() DatabaseType
- type RedisMode
- type Repository
- func (r *Repository[T]) Count(ctx context.Context, opts ...QueryOption) (int, error)
- func (r *Repository[T]) Create(ctx context.Context, entity *T) error
- func (r *Repository[T]) CreateMany(ctx context.Context, entities []T) error
- func (r *Repository[T]) DB() IDB
- func (r *Repository[T]) Delete(ctx context.Context, id any) error
- func (r *Repository[T]) DeleteMany(ctx context.Context, ids []any) error
- func (r *Repository[T]) Exists(ctx context.Context, id any) (bool, error)
- func (r *Repository[T]) FindAll(ctx context.Context, opts ...QueryOption) ([]T, error)
- func (r *Repository[T]) FindAllWithDeleted(ctx context.Context, opts ...QueryOption) ([]T, error)
- func (r *Repository[T]) FindByID(ctx context.Context, id any, opts ...QueryOption) (*T, error)
- func (r *Repository[T]) FindOne(ctx context.Context, opts ...QueryOption) (*T, error)
- func (r *Repository[T]) Query() *bun.SelectQuery
- func (r *Repository[T]) RestoreSoftDeleted(ctx context.Context, id any) error
- func (r *Repository[T]) SoftDelete(ctx context.Context, id any) error
- func (r *Repository[T]) Truncate(ctx context.Context) error
- func (r *Repository[T]) Update(ctx context.Context, entity *T) error
- func (r *Repository[T]) UpdateColumns(ctx context.Context, entity *T, columns ...string) error
- type SQLDatabase
- func (d *SQLDatabase) Bun() *bun.DB
- func (d *SQLDatabase) Close(ctx context.Context) error
- func (d *SQLDatabase) DB() *sql.DB
- func (d *SQLDatabase) Driver() any
- func (d *SQLDatabase) Health(ctx context.Context) HealthStatus
- func (d *SQLDatabase) IsOpen() bool
- func (d *SQLDatabase) Name() string
- func (d *SQLDatabase) Open(ctx context.Context) error
- func (d *SQLDatabase) Ping(ctx context.Context) error
- func (d *SQLDatabase) State() ConnectionState
- func (d *SQLDatabase) Stats() DatabaseStats
- func (d *SQLDatabase) Transaction(ctx context.Context, fn func(tx bun.Tx) error) (err error)
- func (d *SQLDatabase) TransactionWithOptions(ctx context.Context, opts *sql.TxOptions, fn func(tx bun.Tx) error) (err error)
- func (d *SQLDatabase) Type() DatabaseType
- type Seeder
- type SeederFunc
- type SeederRecord
- type SeederRunner
- func (r *SeederRunner) GetSeeder(name string) (Seeder, bool)
- func (r *SeederRunner) List() []string
- func (r *SeederRunner) Register(seeder Seeder)
- func (r *SeederRunner) RegisterMany(seeders ...Seeder)
- func (r *SeederRunner) Reset(ctx context.Context, name string) error
- func (r *SeederRunner) ResetAll(ctx context.Context) error
- func (r *SeederRunner) Run(ctx context.Context) error
- func (r *SeederRunner) RunSeeder(ctx context.Context, name string) error
- func (r *SeederRunner) WithTracking(enabled bool) *SeederRunner
- type SoftDeleteModel
- func (m *SoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
- func (m *SoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
- func (m *SoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
- func (m *SoftDeleteModel) IsDeleted() bool
- func (m *SoftDeleteModel) Restore()
- type TestDBOption
- type TimestampModel
- type TransactionStats
- type TxFunc
- type UUIDModel
- type UUIDSoftDeleteModel
- func (m *UUIDSoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
- func (m *UUIDSoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
- func (m *UUIDSoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
- func (m *UUIDSoftDeleteModel) IsDeleted() bool
- func (m *UUIDSoftDeleteModel) Restore()
- type XIDAuditModel
- func (m *XIDAuditModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
- func (m *XIDAuditModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
- func (m *XIDAuditModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
- func (m *XIDAuditModel) IsDeleted() bool
- func (m *XIDAuditModel) Restore()
- type XIDModel
- type XIDSoftDeleteModel
- func (m *XIDSoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
- func (m *XIDSoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
- func (m *XIDSoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
- func (m *XIDSoftDeleteModel) IsDeleted() bool
- func (m *XIDSoftDeleteModel) Restore()
Constants ¶
const ( // ManagerKey is the DI key for the database manager. ManagerKey = "forge.database.manager" // DatabaseKey is the DI key for the default database. DatabaseKey = "forge.database.database" // SQLKey is the DI key for the default SQL database (Bun DB). SQLKey = "forge.database.sql" // MongoKey is the DI key for the default MongoDB client. MongoKey = "forge.database.mongo" // RedisKey is the DI key for the default Redis client. RedisKey = "forge.database.redis" )
DI container keys for database extension services.
const ( CodeDatabaseError = "DATABASE_ERROR" CodeDatabaseNotFound = "DATABASE_NOT_FOUND" CodeDatabaseExists = "DATABASE_ALREADY_EXISTS" CodeDatabaseNotOpened = "DATABASE_NOT_OPENED" CodeDatabaseInvalidType = "DATABASE_INVALID_TYPE" CodeDatabaseConnection = "DATABASE_CONNECTION_ERROR" CodeDatabaseQuery = "DATABASE_QUERY_ERROR" CodeDatabaseTransaction = "DATABASE_TRANSACTION_ERROR" CodeDatabasePanic = "DATABASE_PANIC_RECOVERED" CodeDatabaseConfig = "DATABASE_CONFIG_ERROR" )
Error codes for database operations.
const DefaultBatchSize = 1000
DefaultBatchSize is the default number of records to process in a single batch. This balances between performance and parameter limits in SQL databases.
const MaxTransactionDepth = 10
MaxTransactionDepth is the maximum nesting level for transactions. This prevents infinite recursion and stack overflow.
Variables ¶
var ( // Migrations is the global migration collection // All migrations should register themselves here using init(). Migrations = migrate.Migrations // RegisterMigration is a helper to register a migration. RegisterMigration = migrate.RegisterMigration // RegisterModel adds a model to the auto-registration list. RegisterModel = migrate.RegisterModel // Models is the list of all models that should be auto-registered. Models = &migrate.Models )
Re-export migrate package for convenience This allows users to import "github.com/xraph/forge/extensions/database" and use database.Migrations instead of importing the migrate subpackage.
Functions ¶
func AssertDatabaseError ¶ added in v0.7.3
AssertDatabaseError is a helper to verify an error occurred.
func AssertNoDatabaseError ¶ added in v0.7.3
AssertNoDatabaseError is a helper to check for database errors in tests.
func AssertRecordCount ¶ added in v0.7.3
AssertRecordCount verifies the total number of records in a table.
Example:
database.AssertRecordCount[User](t, db, 5)
func AssertRecordCountWhere ¶ added in v0.7.3
func AssertRecordCountWhere[T any](t testing.TB, db *bun.DB, expected int, where string, args ...any)
AssertRecordCountWhere verifies the number of records matching a condition.
Example:
database.AssertRecordCountWhere[User](t, db, 3, "active = ?", true)
func AssertRecordExists ¶ added in v0.7.3
AssertRecordExists verifies that a record with the given ID exists.
Example:
database.AssertRecordExists[User](t, db, 123)
func AssertRecordNotExists ¶ added in v0.7.3
AssertRecordNotExists verifies that a record with the given ID does not exist.
Example:
database.AssertRecordNotExists[User](t, db, 999)
func BulkDelete ¶ added in v0.7.3
BulkDelete deletes multiple records by their IDs. More efficient than deleting one at a time.
Example:
ids := []int64{1, 2, 3, 4, 5}
err := database.BulkDelete[User](ctx, db, ids)
func BulkInsert ¶ added in v0.7.3
BulkInsert inserts multiple records in batches for optimal performance. This is significantly faster than inserting records one at a time.
Performance: ~50-100x faster than individual inserts for 1000 records.
Example:
users := []User{{Name: "Alice"}, {Name: "Bob"}, {Name: "Charlie"}}
err := database.BulkInsert(ctx, db, users, 0) // Use default batch size
func BulkInsertWithOptions ¶ added in v0.7.3
func BulkInsertWithOptions[T any](ctx context.Context, db bun.IDB, records []T, opts BulkInsertOptions) error
BulkInsertWithOptions inserts multiple records with custom options.
Example with conflict resolution:
opts := database.BulkInsertOptions{
BatchSize: 500,
OnConflict: "DO NOTHING",
}
err := database.BulkInsertWithOptions(ctx, db, users, opts)
func BulkInsertWithProgress ¶ added in v0.7.3
func BulkInsertWithProgress[T any](ctx context.Context, db bun.IDB, records []T, batchSize int, callback ProgressCallback) error
BulkInsertWithProgress inserts records in batches with progress updates. The callback is called after each batch completes.
Example:
err := database.BulkInsertWithProgress(ctx, db, users, 100, func(p database.BulkOperationProgress) {
fmt.Printf("Progress: %d/%d (%d failed)\n", p.Processed, p.Total, p.Failed)
})
func BulkSoftDelete ¶ added in v0.7.3
BulkSoftDelete soft deletes multiple records by their IDs. Only works with models that have a DeletedAt field with soft_delete tag.
Example:
ids := []int64{1, 2, 3, 4, 5}
err := database.BulkSoftDelete[User](ctx, db, ids)
func BulkUpdate ¶ added in v0.7.3
func BulkUpdate[T any](ctx context.Context, db bun.IDB, records []T, columns []string, batchSize int) error
BulkUpdate updates multiple records by their primary keys. Only the specified columns are updated.
Example:
users := []User{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}
err := database.BulkUpdate(ctx, db, users, []string{"name"}, 0)
func BulkUpdateWithProgress ¶ added in v0.7.3
func BulkUpdateWithProgress[T any](ctx context.Context, db bun.IDB, records []T, columns []string, batchSize int, callback ProgressCallback) error
BulkUpdateWithProgress updates records in batches with progress updates.
func BulkUpsert ¶ added in v0.7.3
func BulkUpsert[T any](ctx context.Context, db bun.IDB, records []T, conflictColumns []string, batchSize int) error
BulkUpsert performs bulk insert with conflict resolution (upsert). If a record with the same key exists, it's updated instead of inserted.
Example for Postgres:
err := database.BulkUpsert(ctx, db, users, []string{"email"}, 0)
// ON CONFLICT (email) DO UPDATE SET ...
func ChunkSlice ¶ added in v0.7.3
ChunkSlice splits a slice into chunks of the specified size. Useful for custom bulk operations.
Example:
chunks := database.ChunkSlice(records, 100)
for _, chunk := range chunks {
// Process chunk
}
func CleanupDB ¶ added in v0.7.3
CleanupDB closes the database connection and cleans up resources. This is automatically called by t.Cleanup() when using NewTestDB.
func CreateTestModel ¶ added in v0.7.3
CreateTestModel creates a single test record.
Example:
user := database.CreateTestModel(t, db, User{Name: "Alice"})
func CreateTestModels ¶ added in v0.7.3
CreateTestModels is a helper to create multiple test records at once.
Example:
users := database.CreateTestModels(t, db, []User{
{Name: "Alice"},
{Name: "Bob"},
})
func EnableAutoExplain ¶ added in v0.7.3
EnableAutoExplain is a convenience function to enable auto-EXPLAIN on a database. This should be called during database initialization.
Example:
db := database.MustGetSQL(c) database.EnableAutoExplain(db, 1*time.Second)
func ErrConnectionFailed ¶ added in v0.4.0
func ErrConnectionFailed(dbName string, dbType DatabaseType, cause error) error
func ErrDatabaseNotFound ¶
func ErrDatabaseNotOpened ¶
func ErrInvalidDSN ¶
func ErrInvalidDatabaseName ¶
func ErrInvalidDatabaseType ¶
func ErrInvalidDatabaseTypeOp ¶
func ErrInvalidDatabaseTypeOp(name string, expectedType, actualType DatabaseType) error
func ErrInvalidPoolConfig ¶
func ErrNoDatabasesConfigured ¶
func ErrNoDatabasesConfigured() error
Error constructors for common database errors.
func ErrPanicRecovered ¶ added in v0.4.0
func ErrPanicRecovered(dbName string, dbType DatabaseType, panicValue any) error
func ErrQueryFailed ¶ added in v0.4.0
func ErrQueryFailed(dbName string, dbType DatabaseType, cause error) error
func ErrTransactionFailed ¶ added in v0.4.0
func ErrTransactionFailed(dbName string, dbType DatabaseType, cause error) error
func FilterSlice ¶ added in v0.7.3
FilterSlice filters a slice based on a predicate function. Useful for post-query filtering.
Example:
activeUsers := database.FilterSlice(users, func(u User) bool {
return u.Active
})
func FormatQueryPlan ¶ added in v0.7.3
FormatQueryPlan formats a query plan for human-readable output.
func GetDB ¶ added in v0.7.3
GetDB returns the appropriate database connection from context. If a transaction is active in the context, it returns the transaction. Otherwise, it returns the provided default database.
This allows code to work seamlessly both inside and outside transactions.
Example:
func CreateUser(ctx context.Context, db *bun.DB, user *User) error {
// Works both in and out of transaction
repo := database.NewRepository[User](database.GetDB(ctx, db))
return repo.Create(ctx, user)
}
func GetMongo ¶ added in v0.5.0
GetMongo retrieves the default MongoDB client from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Returns error if:
- Database extension not registered
- Default database is not MongoDB (e.g., it's SQL)
func GetMongoFromApp ¶ added in v0.5.0
GetMongoFromApp retrieves the default MongoDB client from the app Returns error if not found, type assertion fails, or default is not MongoDB.
func GetNamedMongo ¶ added in v0.5.0
GetNamedMongo retrieves a named MongoDB database as mongo.Client Returns error if database not found or is not MongoDB.
func GetNamedMongoFromApp ¶ added in v0.5.0
GetNamedMongoFromApp retrieves a named MongoDB database from the app.
func GetNamedRedis ¶ added in v0.7.0
GetNamedRedis retrieves a named Redis database as redis.UniversalClient Returns error if database not found or is not Redis.
func GetNamedRedisFromApp ¶ added in v0.7.0
GetNamedRedisFromApp retrieves a named Redis database from the app.
func GetNamedSQL ¶ added in v0.5.0
GetNamedSQL retrieves a named SQL database as Bun DB Returns error if database not found or is not a SQL database.
func GetNamedSQLFromApp ¶ added in v0.5.0
GetNamedSQLFromApp retrieves a named SQL database from the app.
func GetRedis ¶ added in v0.7.0
func GetRedis(c forge.Container) (redis.UniversalClient, error)
GetRedis retrieves the default Redis client from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Returns error if:
- Database extension not registered
- Default database is not Redis (e.g., it's SQL or MongoDB)
func GetRedisFromApp ¶ added in v0.7.0
func GetRedisFromApp(app forge.App) (redis.UniversalClient, error)
GetRedisFromApp retrieves the default Redis client from the app Returns error if not found, type assertion fails, or default is not Redis.
func GetSQL ¶ added in v0.5.0
GetSQL retrieves the default Bun SQL database from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Returns error if:
- Database extension not registered
- Default database is not a SQL database (e.g., it's MongoDB)
func GetSQLFromApp ¶ added in v0.5.0
GetSQLFromApp retrieves the default Bun SQL database from the app Returns error if not found, type assertion fails, or default is not a SQL database.
func GetTransactionDepth ¶ added in v0.7.3
GetTransactionDepth returns the current nesting depth of transactions. Returns 0 if not in a transaction.
Example:
depth := database.GetTransactionDepth(ctx)
fmt.Printf("Transaction nesting level: %d\n", depth)
func GroupBy ¶ added in v0.7.3
func GroupBy[T any, K comparable](slice []T, keyFn func(T) K) map[K][]T
GroupBy groups a slice by a key function. Returns a map where each key maps to a slice of items with that key.
Example:
byStatus := database.GroupBy(users, func(u User) string {
return u.Status
})
activeUsers := byStatus["active"]
func IdempotentInsert ¶ added in v0.7.3
func IdempotentInsert[T any](ctx context.Context, db *bun.DB, records *[]T, conflictColumn string) error
IdempotentInsert inserts records only if they don't already exist. This is useful for making seeders idempotent.
Example:
users := []User{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}
err := database.IdempotentInsert(ctx, db, &users, "id")
func IdempotentUpsert ¶ added in v0.7.3
func IdempotentUpsert[T any](ctx context.Context, db *bun.DB, records *[]T, conflictColumn string) error
IdempotentUpsert inserts or updates records based on conflict columns. This ensures seeders can be run multiple times safely.
Example:
users := []User{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}
err := database.IdempotentUpsert(ctx, db, &users, "id")
func IndexBy ¶ added in v0.7.3
func IndexBy[T any, K comparable](slice []T, keyFn func(T) K) map[K]T
IndexBy creates a map from a slice using a key function. If multiple items have the same key, the last one wins.
Example:
usersByID := database.IndexBy(users, func(u User) int64 {
return u.ID
})
user := usersByID[123]
func IsInTransaction ¶ added in v0.7.3
IsInTransaction returns true if the context contains an active transaction.
Example:
if database.IsInTransaction(ctx) {
// We're in a transaction
}
func LoadAllFixtures ¶ added in v0.7.3
LoadAllFixtures loads all records of a given type.
Example:
users := database.LoadAllFixtures[User](t, db) assert.Len(t, users, 5)
func LoadFixture ¶ added in v0.7.3
LoadFixture loads a single record by ID and returns it. Useful for verifying record state in tests.
Example:
user := database.LoadFixture[User](t, db, 1) assert.Equal(t, "Alice", user.Name)
func MapError ¶ added in v0.7.3
MapError applies a mapper function and returns both the result and any error. Useful when the mapping function can fail.
Example:
dto, err := database.MapError(user, func(u User) (UserDTO, error) {
if u.Email == "" {
return UserDTO{}, fmt.Errorf("email is required")
}
return UserDTO{ID: u.ID, Name: u.Name, Email: u.Email}, nil
})
func MapPointer ¶ added in v0.7.3
func MapPointer[From, To any](from *From, mapFn func(From) To) *To
MapPointer transforms a pointer value, handling nil safely.
Example:
userDTO := database.MapPointer(userPtr, func(u User) UserDTO {
return UserDTO{ID: u.ID, Name: u.Name}
})
func MapSlice ¶ added in v0.7.3
func MapSlice[From, To any](from []From, mapFn func(From) To) []To
MapSlice transforms a slice of values from one type to another. This eliminates the need for manual loops when converting query results.
Example:
users, err := repo.FindAll(ctx)
dtos := database.MapSlice(users, func(u User) UserDTO {
return UserDTO{ID: u.ID, Name: u.Name}
})
func MapSliceError ¶ added in v0.7.3
MapSliceError transforms a slice with a fallible mapper function. If any mapping fails, the function returns immediately with the error.
Example:
dtos, err := database.MapSliceError(users, func(u User) (UserDTO, error) {
if u.Email == "" {
return UserDTO{}, fmt.Errorf("user %d: email is required", u.ID)
}
return UserDTO{ID: u.ID, Name: u.Name, Email: u.Email}, nil
})
func MapSlicePointers ¶ added in v0.7.3
func MapSlicePointers[From, To any](from []*From, mapFn func(From) To) []To
MapSlicePointers transforms a slice of pointers.
Example:
dtos := database.MapSlicePointers(userPtrs, func(u User) UserDTO {
return UserDTO{ID: u.ID, Name: u.Name}
})
func MapTo ¶ added in v0.7.3
func MapTo[From, To any](from From, mapFn func(From) To) To
MapTo transforms a single value from one type to another using a mapper function. This is useful for converting database models to DTOs.
Example:
userDTO := database.MapTo(user, func(u User) UserDTO {
return UserDTO{
ID: u.ID,
Name: u.Name,
Email: u.Email,
}
})
func MaskDSN ¶ added in v0.4.0
func MaskDSN(dsn string, dbType DatabaseType) string
MaskDSN masks sensitive information in DSN for logging.
func MustGetDB ¶ added in v0.7.3
MustGetDB returns the database connection from context. Panics if no default database is provided and no transaction is in context.
func MustGetMongo ¶ added in v0.5.0
MustGetMongo retrieves the default MongoDB client from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Panics if:
- Database extension not registered
- Default database is not MongoDB (e.g., it's SQL)
func MustGetMongoFromApp ¶ added in v0.5.0
MustGetMongoFromApp retrieves the default MongoDB client from the app Panics if not found, type assertion fails, or default is not MongoDB.
func MustGetNamedMongo ¶ added in v0.5.0
MustGetNamedMongo retrieves a named MongoDB database as mongo.Client Panics if database not found or is not MongoDB.
func MustGetNamedMongoFromApp ¶ added in v0.5.0
MustGetNamedMongoFromApp retrieves a named MongoDB database from the app Panics if not found.
func MustGetNamedRedis ¶ added in v0.7.0
func MustGetNamedRedis(c forge.Container, name string) redis.UniversalClient
MustGetNamedRedis retrieves a named Redis database as redis.UniversalClient Panics if database not found or is not Redis.
func MustGetNamedRedisFromApp ¶ added in v0.7.0
func MustGetNamedRedisFromApp(app forge.App, name string) redis.UniversalClient
MustGetNamedRedisFromApp retrieves a named Redis database from the app Panics if not found.
func MustGetNamedSQL ¶ added in v0.5.0
MustGetNamedSQL retrieves a named SQL database as Bun DB Panics if database not found or is not a SQL database.
func MustGetNamedSQLFromApp ¶ added in v0.5.0
MustGetNamedSQLFromApp retrieves a named SQL database from the app Panics if not found.
func MustGetRedis ¶ added in v0.7.0
func MustGetRedis(c forge.Container) redis.UniversalClient
MustGetRedis retrieves the default Redis client from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Panics if:
- Database extension not registered
- Default database is not Redis (e.g., it's SQL or MongoDB)
func MustGetRedisFromApp ¶ added in v0.7.0
func MustGetRedisFromApp(app forge.App) redis.UniversalClient
MustGetRedisFromApp retrieves the default Redis client from the app Panics if not found, type assertion fails, or default is not Redis.
func MustGetSQL ¶ added in v0.5.0
MustGetSQL retrieves the default Bun SQL database from the container.
Safe to call anytime - automatically ensures DatabaseManager is started first.
Panics if:
- Database extension not registered
- Default database is not a SQL database (e.g., it's MongoDB)
func MustGetSQLFromApp ¶ added in v0.5.0
MustGetSQLFromApp retrieves the default Bun SQL database from the app Panics if not found, type assertion fails, or default is not a SQL database.
func NewExtension ¶
func NewExtension(opts ...ConfigOption) forge.Extension
NewExtension creates a new database extension with variadic options.
func NewExtensionWithConfig ¶ added in v0.4.0
NewExtensionWithConfig creates a new database extension with a complete config.
func NewTestDB ¶ added in v0.7.3
func NewTestDB(t testing.TB, opts ...TestDBOption) *bun.DB
NewTestDB creates a test database instance with automatic cleanup. By default, it uses an in-memory SQLite database.
Example:
func TestUserRepo(t *testing.T) {
db := database.NewTestDB(t,
database.WithAutoMigrate(&User{}),
)
repo := database.NewRepository[User](db)
// Test repo methods
}
func Partition ¶ added in v0.7.3
Partition splits a slice into two slices based on a predicate. The first slice contains items where predicate returns true, the second contains items where it returns false.
Example:
active, inactive := database.Partition(users, func(u User) bool {
return u.Active
})
func Pluck ¶ added in v0.7.3
Pluck extracts a specific field from each item in a slice.
Example:
ids := database.Pluck(users, func(u User) int64 {
return u.ID
})
func ResetTransactionStats ¶ added in v0.7.3
func ResetTransactionStats()
ResetTransactionStats resets global transaction statistics. Primarily useful for testing.
func SeedFixtures ¶ added in v0.7.3
SeedFixtures inserts test data into the database. Records are inserted as-is without modification.
Example:
users := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
err := database.SeedFixtures(t, db, &users)
func SetUserID ¶ added in v0.4.0
SetUserID is a helper to set user ID in context for audit tracking.
func SetXIDUserID ¶ added in v0.4.0
func TruncateTables ¶ added in v0.7.3
TruncateTables removes all data from the specified model tables. Useful for cleaning up between tests.
Example:
err := database.TruncateTables(t, db, (*User)(nil), (*Post)(nil))
func Unique ¶ added in v0.7.3
func Unique[T any, K comparable](slice []T, keyFn func(T) K) []T
Unique removes duplicate values from a slice based on a key function.
Example:
uniqueUsers := database.Unique(users, func(u User) int64 {
return u.ID
})
func WithNestedTransaction ¶ added in v0.7.3
WithNestedTransaction explicitly creates a nested transaction using savepoints. This must be called within an existing transaction context.
Example:
database.WithTransaction(ctx, db, func(ctx1 context.Context) error {
// Outer transaction
repo.Create(ctx1, &user)
// Inner transaction with savepoint
err := database.WithNestedTransaction(ctx1, func(ctx2 context.Context) error {
// This can be rolled back independently
return repo.Create(ctx2, &profile)
})
return err
})
func WithReadOnlyTransaction ¶ added in v0.7.3
WithReadOnlyTransaction runs a function in a read-only transaction. This is useful for complex queries that need a consistent view.
func WithRepeatableReadTransaction ¶ added in v0.7.3
WithRepeatableReadTransaction runs a function in a repeatable read transaction. This prevents non-repeatable reads but allows phantom reads.
func WithSerializableTransaction ¶ added in v0.7.3
WithSerializableTransaction runs a function in a serializable transaction. This provides the highest isolation level.
func WithTestTransaction ¶ added in v0.7.3
WithTestTransaction runs a test function within a transaction that's rolled back. This is useful for tests that need isolation without affecting the database.
Example:
database.WithTestTransaction(t, db, func(txDB *bun.DB) {
// All database operations here will be rolled back
repo := database.NewRepository[User](txDB)
repo.Create(ctx, &user)
})
func WithTransaction ¶ added in v0.7.3
WithTransaction executes a function within a database transaction. If the function returns an error, the transaction is rolled back. If the function panics, the transaction is rolled back and the panic is converted to an error. If the function succeeds, the transaction is committed.
For nested calls, savepoints are used to support partial rollbacks.
Example:
err := database.WithTransaction(ctx, db, func(txCtx context.Context) error {
// Use GetDB to get the transaction-aware database
repo := database.NewRepository[User](database.GetDB(txCtx, db))
return repo.Create(txCtx, &user)
})
func WithTransactionFromApp ¶ added in v0.7.3
WithTransactionFromApp is a convenience wrapper that gets the DB from app.
func WithTransactionFromContainer ¶ added in v0.7.3
WithTransactionFromContainer is a convenience wrapper that gets the DB from container.
Example:
err := database.WithTransactionFromContainer(ctx, c, func(txCtx context.Context) error {
// Transaction code
return nil
})
func WithTransactionOptions ¶ added in v0.7.3
WithTransactionOptions executes a function within a transaction with custom options. This allows control over isolation level and read-only mode.
Example:
opts := &sql.TxOptions{
Isolation: sql.LevelSerializable,
ReadOnly: false,
}
err := database.WithTransactionOptions(ctx, db, opts, func(txCtx context.Context) error {
// Transaction code
return nil
})
Types ¶
type AppliedMigration ¶ added in v0.4.0
AppliedMigration represents an applied migration.
type AuditModel ¶ added in v0.4.0
type AuditModel struct {
ID int64 `bun:"id,pk,autoincrement" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
CreatedBy *int64 `bun:"created_by" json:"created_by,omitempty"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
UpdatedBy *int64 `bun:"updated_by" json:"updated_by,omitempty"`
DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at,omitempty"`
DeletedBy *int64 `bun:"deleted_by" json:"deleted_by,omitempty"`
}
AuditModel provides comprehensive audit trail with user tracking Use this when you need to track who created/updated records.
func (*AuditModel) BeforeDelete ¶ added in v0.4.0
func (m *AuditModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
BeforeDelete hook - performs soft delete and tracks deleter.
func (*AuditModel) BeforeInsert ¶ added in v0.4.0
func (m *AuditModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - sets timestamps and tracks creator.
func (*AuditModel) BeforeUpdate ¶ added in v0.4.0
func (m *AuditModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt and tracks updater.
func (*AuditModel) IsDeleted ¶ added in v0.4.0
func (m *AuditModel) IsDeleted() bool
IsDeleted checks if the record is soft deleted.
func (*AuditModel) Restore ¶ added in v0.4.0
func (m *AuditModel) Restore()
Restore restores a soft-deleted record.
type BaseModel ¶ added in v0.4.0
type BaseModel struct {
ID int64 `bun:"id,pk,autoincrement" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
}
BaseModel provides common fields and hooks for all models Use this for models that need ID, timestamps, and standard hooks.
func (*BaseModel) BeforeInsert ¶ added in v0.4.0
BeforeInsert hook - sets timestamps on insert.
func (*BaseModel) BeforeUpdate ¶ added in v0.4.0
BeforeUpdate hook - updates UpdatedAt on every update.
type BulkInsertOptions ¶ added in v0.7.3
type BulkInsertOptions struct {
// BatchSize is the number of records to insert per query. Defaults to 1000.
BatchSize int
// OnConflict specifies the conflict resolution strategy.
// Example: "DO NOTHING", "DO UPDATE SET name = EXCLUDED.name"
OnConflict string
}
BulkInsertOptions configures bulk insert behavior.
type BulkOperationProgress ¶ added in v0.7.3
type BulkOperationProgress struct {
Total int // Total number of records to process
Processed int // Number of records processed so far
Failed int // Number of records that failed
}
BulkOperationProgress provides progress updates during bulk operations.
type Config ¶
type Config struct {
// List of database configurations
Databases []DatabaseConfig `json:"databases" mapstructure:"databases" yaml:"databases"`
// Default database name (first one if not specified)
Default string `json:"default" mapstructure:"default" yaml:"default"`
// Config loading flags
RequireConfig bool `json:"-" yaml:"-"`
}
Config is the configuration for the database extension.
type ConfigOption ¶ added in v0.4.0
type ConfigOption func(*Config)
ConfigOption is a functional option for Config.
func WithConfig ¶ added in v0.4.0
func WithConfig(config Config) ConfigOption
WithConfig replaces the entire config.
func WithDatabase ¶ added in v0.4.0
func WithDatabase(db DatabaseConfig) ConfigOption
WithDatabase adds a single database configuration.
func WithDatabases ¶ added in v0.4.0
func WithDatabases(databases ...DatabaseConfig) ConfigOption
WithDatabases sets the list of database configurations.
func WithDefault ¶ added in v0.4.0
func WithDefault(name string) ConfigOption
WithDefault sets the default database name.
func WithRequireConfig ¶ added in v0.4.0
func WithRequireConfig(require bool) ConfigOption
WithRequireConfig requires config from YAML.
type ConnectionState ¶ added in v0.4.0
type ConnectionState int32
ConnectionState represents the state of a database connection.
const ( StateDisconnected ConnectionState = iota StateConnecting StateConnected StateError StateReconnecting )
func (ConnectionState) String ¶ added in v0.4.0
func (s ConnectionState) String() string
type CursorPagination ¶ added in v0.7.3
type CursorPagination struct {
// Cursor is the base64-encoded position to start from.
// Empty string starts from the beginning (forward) or end (backward).
Cursor string `json:"cursor,omitempty"`
// PageSize is the number of records to return. Defaults to 20.
PageSize int `json:"page_size"`
// Sort is the column to sort by. Required for cursor pagination.
Sort string `json:"sort"`
// Direction is either "forward" (next page) or "backward" (previous page).
// Defaults to "forward".
Direction string `json:"direction,omitempty"`
}
CursorPagination configures cursor-based pagination. This approach is more efficient for large datasets and provides stable pagination even when data changes between requests.
Cursor format: base64(sort_value:id)
Example:
params := database.CursorPagination{
Cursor: "eyJjcmVhdGVkX2F0IjoiMjAyNC0wMS0wMVQxMDowMDowMFoiLCJpZCI6MTIzfQ==",
PageSize: 20,
Sort: "created_at",
Direction: "forward",
}
func (*CursorPagination) Normalize ¶ added in v0.7.3
func (c *CursorPagination) Normalize()
Normalize ensures cursor pagination parameters are valid.
type CursorResult ¶ added in v0.7.3
type CursorResult[T any] struct { // Data contains the records for the current page Data []T `json:"data"` // NextCursor is the cursor for the next page (nil if no next page) NextCursor *string `json:"next_cursor,omitempty"` // PrevCursor is the cursor for the previous page (nil if no previous page) PrevCursor *string `json:"prev_cursor,omitempty"` // HasNext indicates if there's a next page HasNext bool `json:"has_next"` // HasPrev indicates if there's a previous page HasPrev bool `json:"has_prev"` }
CursorResult contains cursor-paginated data and navigation cursors.
func MapCursor ¶ added in v0.7.3
func MapCursor[From, To any](from *CursorResult[From], mapFn func(From) To) *CursorResult[To]
MapCursor transforms a CursorResult from one type to another. The cursor metadata is preserved while the data is transformed.
Example:
result, err := database.PaginateCursor[User](ctx, query, params)
dtoResult := database.MapCursor(result, func(u User) UserDTO {
return UserDTO{ID: u.ID, Name: u.Name}
})
func MapCursorError ¶ added in v0.7.3
func MapCursorError[From, To any](from *CursorResult[From], mapFn func(From) (To, error)) (*CursorResult[To], error)
MapCursorError transforms a CursorResult with a fallible mapper.
Example:
dtoResult, err := database.MapCursorError(result, func(u User) (UserDTO, error) {
return toDTO(u)
})
func PaginateCursor ¶ added in v0.7.3
func PaginateCursor[T any](ctx context.Context, query *bun.SelectQuery, params CursorPagination) (*CursorResult[T], error)
PaginateCursor performs cursor-based pagination on a Bun SelectQuery. This is more efficient for large datasets and provides stable pagination.
Example:
query := db.NewSelect().Model((*User)(nil))
result, err := database.PaginateCursor[User](ctx, query, database.CursorPagination{
Cursor: cursor,
PageSize: 20,
Sort: "created_at",
Direction: "forward",
})
type Database ¶
type Database interface {
// Identity
Name() string
Type() DatabaseType
// Lifecycle
Open(ctx context.Context) error
Close(ctx context.Context) error
Ping(ctx context.Context) error
// State
IsOpen() bool
State() ConnectionState
// Health
Health(ctx context.Context) HealthStatus
Stats() DatabaseStats
// Access to native driver/ORM
Driver() any
}
Database represents a database connection.
func GetDatabase ¶ added in v0.5.0
GetDatabase retrieves the default Database from the container Returns error if not found or type assertion fails. Automatically ensures DatabaseManager is started before resolving.
func GetDatabaseFromApp ¶ added in v0.5.0
GetDatabaseFromApp retrieves the default Database from the app Returns error if not found or type assertion fails.
func GetNamedDatabase ¶ added in v0.5.0
GetNamedDatabase retrieves a named database through the DatabaseManager This is useful when you have multiple databases configured.
func GetNamedDatabaseFromApp ¶ added in v0.5.0
GetNamedDatabaseFromApp retrieves a named database from the app.
func MustGetDatabase ¶ added in v0.5.0
MustGetDatabase retrieves the default Database from the container Panics if not found or type assertion fails. Automatically ensures DatabaseManager is started before resolving.
func MustGetDatabaseFromApp ¶ added in v0.5.0
MustGetDatabaseFromApp retrieves the default Database from the app Panics if not found or type assertion fails.
func MustGetNamedDatabase ¶ added in v0.5.0
MustGetNamedDatabase retrieves a named database through the DatabaseManager Panics if manager not found or database not found.
type DatabaseConfig ¶
type DatabaseConfig struct {
Name string `json:"name" yaml:"name" mapstructure:"name"`
Type DatabaseType `json:"type" yaml:"type" mapstructure:"type"`
DSN string `json:"dsn" yaml:"dsn" mapstructure:"dsn"`
// Connection pool settings
MaxOpenConns int `default:"25" json:"max_open_conns" yaml:"max_open_conns" mapstructure:"max_open_conns"`
MaxIdleConns int `default:"5" json:"max_idle_conns" yaml:"max_idle_conns" mapstructure:"max_idle_conns"`
ConnMaxLifetime time.Duration `default:"5m" json:"conn_max_lifetime" yaml:"conn_max_lifetime" mapstructure:"conn_max_lifetime"`
ConnMaxIdleTime time.Duration `default:"5m" json:"conn_max_idle_time" yaml:"conn_max_idle_time" mapstructure:"conn_max_idle_time"`
// Retry settings
MaxRetries int `default:"3" json:"max_retries" yaml:"max_retries" mapstructure:"max_retries"`
RetryDelay time.Duration `default:"1s" json:"retry_delay" yaml:"retry_delay" mapstructure:"retry_delay"`
// Timeout settings
ConnectionTimeout time.Duration `default:"10s" json:"connection_timeout" yaml:"connection_timeout" mapstructure:"connection_timeout"`
QueryTimeout time.Duration `default:"30s" json:"query_timeout" yaml:"query_timeout" mapstructure:"query_timeout"`
// Observability settings
SlowQueryThreshold time.Duration `default:"100ms" json:"slow_query_threshold" yaml:"slow_query_threshold" mapstructure:"slow_query_threshold"`
DisableSlowQueryLogging bool `default:"false" json:"disable_slow_query_logging" yaml:"disable_slow_query_logging" mapstructure:"disable_slow_query_logging"`
AutoExplainThreshold time.Duration `default:"0" json:"auto_explain_threshold" yaml:"auto_explain_threshold" mapstructure:"auto_explain_threshold"` // 0 = disabled
// Health check
HealthCheckInterval time.Duration `default:"30s" json:"health_check_interval" yaml:"health_check_interval" mapstructure:"health_check_interval"`
// Additional config (database-specific)
Config map[string]any `json:"config" yaml:"config" mapstructure:"config"`
}
DatabaseConfig is the configuration for a database connection.
type DatabaseError ¶ added in v0.4.0
type DatabaseError struct {
DBName string
DBType DatabaseType
Operation string
Code string
Err error
}
DatabaseError wraps database-specific errors with context.
func NewDatabaseError ¶ added in v0.4.0
func NewDatabaseError(dbName string, dbType DatabaseType, operation string, err error) *DatabaseError
NewDatabaseError creates a new database error with context.
func (*DatabaseError) Error ¶ added in v0.4.0
func (e *DatabaseError) Error() string
func (*DatabaseError) Unwrap ¶ added in v0.4.0
func (e *DatabaseError) Unwrap() error
type DatabaseManager ¶
type DatabaseManager struct {
// contains filtered or unexported fields
}
DatabaseManager manages multiple database connections.
func GetManager ¶ added in v0.5.0
func GetManager(c forge.Container) (*DatabaseManager, error)
GetManager retrieves the DatabaseManager from the container Returns error if not found or type assertion fails.
func GetManagerFromApp ¶ added in v0.5.0
func GetManagerFromApp(app forge.App) (*DatabaseManager, error)
GetManagerFromApp retrieves the DatabaseManager from the app Returns error if not found or type assertion fails.
func MustGetManager ¶ added in v0.5.0
func MustGetManager(c forge.Container) *DatabaseManager
MustGetManager retrieves the DatabaseManager from the container Panics if not found or type assertion fails.
func MustGetManagerFromApp ¶ added in v0.5.0
func MustGetManagerFromApp(app forge.App) *DatabaseManager
MustGetManagerFromApp retrieves the DatabaseManager from the app Panics if not found or type assertion fails.
func NewDatabaseManager ¶
func NewDatabaseManager(logger forge.Logger, metrics forge.Metrics) *DatabaseManager
NewDatabaseManager creates a new database manager.
func (*DatabaseManager) CloseAll ¶
func (m *DatabaseManager) CloseAll(ctx context.Context) error
CloseAll closes all registered databases, collecting errors without stopping.
func (*DatabaseManager) Get ¶
func (m *DatabaseManager) Get(name string) (Database, error)
Get retrieves a database by name.
func (*DatabaseManager) Health ¶ added in v0.4.0
func (m *DatabaseManager) Health(ctx context.Context) error
func (*DatabaseManager) HealthCheckAll ¶
func (m *DatabaseManager) HealthCheckAll(ctx context.Context) map[string]HealthStatus
HealthCheckAll performs health checks on all databases.
func (*DatabaseManager) List ¶
func (m *DatabaseManager) List() []string
List returns the names of all registered databases.
func (*DatabaseManager) Mongo ¶
func (m *DatabaseManager) Mongo(name string) (*mongo.Client, error)
Mongo retrieves a MongoDB client by name.
func (*DatabaseManager) MongoDatabase ¶
func (m *DatabaseManager) MongoDatabase(name string) (*MongoDatabase, error)
MongoDatabase retrieves a MongoDB database wrapper by name.
func (*DatabaseManager) Name ¶ added in v0.8.0
func (m *DatabaseManager) Name() string
Name returns the service name for the DI container. Implements shared.Service interface.
func (*DatabaseManager) OpenAll ¶
func (m *DatabaseManager) OpenAll(ctx context.Context) error
OpenAll opens all registered databases, collecting errors without stopping.
func (*DatabaseManager) Redis ¶ added in v0.7.0
func (m *DatabaseManager) Redis(name string) (redis.UniversalClient, error)
Redis retrieves a Redis client by name.
func (*DatabaseManager) RedisDatabase ¶ added in v0.7.0
func (m *DatabaseManager) RedisDatabase(name string) (*RedisDatabase, error)
RedisDatabase retrieves a Redis database wrapper by name.
func (*DatabaseManager) Register ¶
func (m *DatabaseManager) Register(name string, db Database) error
Register adds a database to the manager.
func (*DatabaseManager) SQL ¶
func (m *DatabaseManager) SQL(name string) (*bun.DB, error)
SQL retrieves an SQL database with Bun ORM by name.
type DatabaseStats ¶
type DatabaseStats struct {
OpenConnections int `json:"open_connections"`
InUse int `json:"in_use"`
Idle int `json:"idle"`
WaitCount int64 `json:"wait_count"`
WaitDuration time.Duration `json:"wait_duration"`
MaxIdleClosed int64 `json:"max_idle_closed"`
MaxLifetimeClosed int64 `json:"max_lifetime_closed"`
}
DatabaseStats provides connection pool statistics.
type DatabaseType ¶
type DatabaseType string
DatabaseType represents the type of database.
const ( TypePostgres DatabaseType = "postgres" TypeMySQL DatabaseType = "mysql" TypeSQLite DatabaseType = "sqlite" TypeMongoDB DatabaseType = "mongodb" TypeRedis DatabaseType = "redis" )
type ExampleSeeder ¶ added in v0.7.3
type ExampleSeeder struct {
}
ExampleSeeder demonstrates how to create a seeder. This can be used as a template for your own seeders.
func (*ExampleSeeder) Name ¶ added in v0.7.3
func (s *ExampleSeeder) Name() string
Name returns the unique identifier for this seeder.
type Extension ¶
type Extension struct {
*forge.BaseExtension
// contains filtered or unexported fields
}
Extension implements the database extension.
type HealthStatus ¶
type HealthStatus struct {
Healthy bool `json:"healthy"`
Message string `json:"message"`
Latency time.Duration `json:"latency"`
CheckedAt time.Time `json:"checked_at"`
}
HealthStatus provides database health status.
type IDB ¶ added in v0.7.3
IDB is an interface that both *bun.DB and bun.Tx implement. This allows Repository to work with both direct database access and transactions.
type Logger ¶ added in v0.4.0
type Logger interface {
Info(msg string, fields ...any)
Error(msg string, fields ...any)
Warn(msg string, fields ...any)
}
Logger interface for migration logging.
type MigrationManager ¶ added in v0.4.0
type MigrationManager struct {
// contains filtered or unexported fields
}
MigrationManager manages database migrations.
func NewMigrationManager ¶ added in v0.4.0
func NewMigrationManager(db *bun.DB, migrations *migrate.Migrations, logger Logger) *MigrationManager
NewMigrationManager creates a new migration manager.
func (*MigrationManager) AutoMigrate ¶ added in v0.4.0
func (m *MigrationManager) AutoMigrate(ctx context.Context, models ...any) error
AutoMigrate automatically creates/updates tables for registered models This is a development convenience - use migrations for production.
func (*MigrationManager) CreateMigration ¶ added in v0.4.0
func (m *MigrationManager) CreateMigration(ctx context.Context) error
CreateMigration creates the migration tables and initial structure.
func (*MigrationManager) CreateTables ¶ added in v0.4.0
func (m *MigrationManager) CreateTables(ctx context.Context) error
CreateTables creates the migrations table.
func (*MigrationManager) Migrate ¶ added in v0.4.0
func (m *MigrationManager) Migrate(ctx context.Context) error
Migrate runs all pending migrations.
func (*MigrationManager) Reset ¶ added in v0.4.0
func (m *MigrationManager) Reset(ctx context.Context) error
Reset drops all tables and re-runs all migrations.
func (*MigrationManager) Rollback ¶ added in v0.4.0
func (m *MigrationManager) Rollback(ctx context.Context) error
Rollback rolls back the last migration group.
func (*MigrationManager) Status ¶ added in v0.4.0
func (m *MigrationManager) Status(ctx context.Context) (*MigrationStatusResult, error)
Status returns the current migration status.
type MigrationStatus ¶
type MigrationStatus struct {
ID int64 `json:"id"`
Applied bool `json:"applied"`
AppliedAt time.Time `json:"applied_at"`
}
MigrationStatus provides migration status.
type MigrationStatusResult ¶ added in v0.4.0
type MigrationStatusResult struct {
Applied []AppliedMigration
Pending []string
}
MigrationStatusResult represents the current state of migrations.
type MongoDatabase ¶
type MongoDatabase struct {
// contains filtered or unexported fields
}
MongoDatabase wraps MongoDB client.
func NewMongoDatabase ¶
func NewMongoDatabase(config DatabaseConfig, logger forge.Logger, metrics forge.Metrics) (*MongoDatabase, error)
NewMongoDatabase creates a new MongoDB database instance.
func (*MongoDatabase) Client ¶
func (d *MongoDatabase) Client() *mongo.Client
Client returns the MongoDB client.
func (*MongoDatabase) Close ¶
func (d *MongoDatabase) Close(ctx context.Context) error
Close closes the MongoDB connection.
func (*MongoDatabase) Collection ¶
func (d *MongoDatabase) Collection(name string) *mongo.Collection
Collection returns a MongoDB collection.
func (*MongoDatabase) Database ¶
func (d *MongoDatabase) Database() *mongo.Database
Database returns the MongoDB database.
func (*MongoDatabase) Driver ¶
func (d *MongoDatabase) Driver() any
Driver returns the *mongo.Client for native driver access.
func (*MongoDatabase) Health ¶
func (d *MongoDatabase) Health(ctx context.Context) HealthStatus
Health returns the health status.
func (*MongoDatabase) IsOpen ¶ added in v0.4.0
func (d *MongoDatabase) IsOpen() bool
IsOpen returns whether the database is connected.
func (*MongoDatabase) Open ¶
func (d *MongoDatabase) Open(ctx context.Context) error
Open establishes the MongoDB connection with retry logic.
func (*MongoDatabase) Ping ¶
func (d *MongoDatabase) Ping(ctx context.Context) error
Ping checks MongoDB connectivity.
func (*MongoDatabase) State ¶ added in v0.4.0
func (d *MongoDatabase) State() ConnectionState
State returns the current connection state.
func (*MongoDatabase) Stats ¶
func (d *MongoDatabase) Stats() DatabaseStats
Stats returns MongoDB statistics.
func (*MongoDatabase) Transaction ¶
func (d *MongoDatabase) Transaction(ctx context.Context, fn func(sessCtx mongo.SessionContext) error) (err error)
Transaction executes a function in a MongoDB transaction with panic recovery.
func (*MongoDatabase) TransactionWithOptions ¶
func (d *MongoDatabase) TransactionWithOptions(ctx context.Context, opts *options.TransactionOptions, fn func(sessCtx mongo.SessionContext) error) (err error)
TransactionWithOptions executes a function in a MongoDB transaction with options and panic recovery.
func (*MongoDatabase) Type ¶
func (d *MongoDatabase) Type() DatabaseType
Type returns the database type.
type MultiError ¶ added in v0.4.0
MultiError represents multiple database errors.
func (*MultiError) Error ¶ added in v0.4.0
func (e *MultiError) Error() string
func (*MultiError) HasErrors ¶ added in v0.4.0
func (e *MultiError) HasErrors() bool
HasErrors returns true if there are any errors.
type ObservabilityQueryHook ¶ added in v0.7.3
type ObservabilityQueryHook struct {
// contains filtered or unexported fields
}
ObservabilityQueryHook is an enhanced query hook that can automatically EXPLAIN slow queries.
func NewObservabilityQueryHook ¶ added in v0.7.3
func NewObservabilityQueryHook(logger forge.Logger, metrics forge.Metrics, dbName string, dbType DatabaseType, slowQueryThreshold time.Duration, disableSlowQueryLogging bool) *ObservabilityQueryHook
NewObservabilityQueryHook creates a new observability query hook.
func (*ObservabilityQueryHook) AfterQuery ¶ added in v0.7.3
func (h *ObservabilityQueryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent)
AfterQuery is called after query execution.
func (*ObservabilityQueryHook) BeforeQuery ¶ added in v0.7.3
func (h *ObservabilityQueryHook) BeforeQuery(ctx context.Context, event *bun.QueryEvent) context.Context
BeforeQuery is called before query execution.
func (*ObservabilityQueryHook) WithAutoExplain ¶ added in v0.7.3
func (h *ObservabilityQueryHook) WithAutoExplain(threshold time.Duration) *ObservabilityQueryHook
WithAutoExplain enables automatic EXPLAIN for queries slower than the threshold.
type OffsetPagination ¶ added in v0.7.3
type OffsetPagination struct {
// Page number (1-indexed). Defaults to 1 if not specified.
Page int `json:"page"`
// Number of records per page. Defaults to 20 if not specified.
PageSize int `json:"page_size"`
// Column to sort by. If empty, no ordering is applied.
Sort string `json:"sort,omitempty"`
// Sort order: "asc" or "desc". Defaults to "asc".
Order string `json:"order,omitempty"`
}
OffsetPagination configures offset-based pagination. This is the traditional page number approach, suitable for most use cases with moderate data sizes (up to hundreds of thousands of records).
Example:
params := database.OffsetPagination{
Page: 1,
PageSize: 20,
Sort: "created_at",
Order: "desc",
}
func (*OffsetPagination) Normalize ¶ added in v0.7.3
func (p *OffsetPagination) Normalize()
Normalize ensures pagination parameters are within valid ranges.
func (*OffsetPagination) Offset ¶ added in v0.7.3
func (p *OffsetPagination) Offset() int
Offset calculates the SQL OFFSET value from page and page size.
type PaginatedResult ¶ added in v0.7.3
type PaginatedResult[T any] struct { // Data contains the records for the current page Data []T `json:"data"` // Page is the current page number (1-indexed) Page int `json:"page"` // PageSize is the number of records per page PageSize int `json:"page_size"` // TotalPages is the total number of pages TotalPages int `json:"total_pages"` // TotalCount is the total number of records across all pages TotalCount int64 `json:"total_count"` // HasNext indicates if there's a next page HasNext bool `json:"has_next"` // HasPrev indicates if there's a previous page HasPrev bool `json:"has_prev"` }
PaginatedResult contains the paginated data and metadata.
func MapPaginated ¶ added in v0.7.3
func MapPaginated[From, To any](from *PaginatedResult[From], mapFn func(From) To) *PaginatedResult[To]
MapPaginated transforms a PaginatedResult from one type to another. The pagination metadata is preserved while the data is transformed.
Example:
result, err := database.Paginate[User](ctx, query, params)
dtoResult := database.MapPaginated(result, func(u User) UserDTO {
return UserDTO{ID: u.ID, Name: u.Name}
})
func MapPaginatedError ¶ added in v0.7.3
func MapPaginatedError[From, To any](from *PaginatedResult[From], mapFn func(From) (To, error)) (*PaginatedResult[To], error)
MapPaginatedError transforms a PaginatedResult with a fallible mapper.
Example:
dtoResult, err := database.MapPaginatedError(result, func(u User) (UserDTO, error) {
return toDTO(u)
})
func Paginate ¶ added in v0.7.3
func Paginate[T any](ctx context.Context, query *bun.SelectQuery, params OffsetPagination) (*PaginatedResult[T], error)
Paginate performs offset-based pagination on a Bun SelectQuery. It executes two queries: one for the total count and one for the data.
Example:
query := db.NewSelect().Model((*User)(nil))
result, err := database.Paginate[User](ctx, query, database.OffsetPagination{
Page: 2,
PageSize: 20,
Sort: "created_at",
Order: "desc",
})
if err != nil {
return err
}
// result.Data contains the users for page 2
// result.TotalCount contains the total number of users
type ProgressCallback ¶ added in v0.7.3
type ProgressCallback func(progress BulkOperationProgress)
ProgressCallback is called periodically during bulk operations.
type QueryHook ¶
type QueryHook struct {
// contains filtered or unexported fields
}
QueryHook provides observability for Bun queries.
func (*QueryHook) AfterQuery ¶
func (h *QueryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent)
AfterQuery is called after query execution.
func (*QueryHook) BeforeQuery ¶
BeforeQuery is called before query execution.
type QueryOption ¶ added in v0.7.3
type QueryOption func(*bun.SelectQuery) *bun.SelectQuery
QueryOption is a function that modifies a SelectQuery. This pattern allows flexible, composable query building.
Example:
func WhereActive() QueryOption {
return func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("deleted_at IS NULL")
}
}
func WhereActive ¶ added in v0.7.3
func WhereActive() QueryOption
WhereActive returns a QueryOption that filters out soft-deleted records. This is explicit - records are NOT filtered automatically.
func WhereDeleted ¶ added in v0.7.3
func WhereDeleted() QueryOption
WhereDeleted returns a QueryOption that only returns soft-deleted records.
func WithLimit ¶ added in v0.7.3
func WithLimit(limit int) QueryOption
WithLimit returns a QueryOption that limits the number of results.
func WithOffset ¶ added in v0.7.3
func WithOffset(offset int) QueryOption
WithOffset returns a QueryOption that skips the first n results.
func WithOrder ¶ added in v0.7.3
func WithOrder(column string, direction ...string) QueryOption
WithOrder returns a QueryOption that orders results by the specified column.
func WithRelation ¶ added in v0.7.3
func WithRelation(relation string) QueryOption
WithRelation returns a QueryOption that eager loads a relation.
func WithRelations ¶ added in v0.7.3
func WithRelations(relations ...string) QueryOption
WithRelations returns a QueryOption that eager loads multiple relations.
type QueryPlan ¶ added in v0.7.3
type QueryPlan struct {
// Query is the SQL query that was analyzed
Query string `json:"query"`
// Plan is the formatted execution plan
Plan string `json:"plan"`
// Cost is the estimated query cost (database-specific)
Cost float64 `json:"cost"`
// Duration is how long the query took to execute
Duration time.Duration `json:"duration"`
// Database type (postgres, mysql, sqlite)
DBType DatabaseType `json:"db_type"`
}
QueryPlan represents the execution plan for a query.
func ExplainQuery ¶ added in v0.7.3
ExplainQuery executes EXPLAIN on a query and returns the execution plan. This is useful for debugging slow queries and optimizing performance.
Example:
query := db.NewSelect().Model((*User)(nil)).Where("email = ?", "test@example.com")
plan, err := database.ExplainQuery(ctx, db, query)
if err != nil {
log.Error("failed to explain query", err)
}
log.Info("Query plan", "plan", plan.Plan, "cost", plan.Cost)
type QueryStats ¶ added in v0.7.3
type QueryStats struct {
TotalQueries int64 `json:"total_queries"`
SlowQueries int64 `json:"slow_queries"`
FailedQueries int64 `json:"failed_queries"`
AverageDuration time.Duration `json:"average_duration"`
MaxDuration time.Duration `json:"max_duration"`
}
QueryStats provides statistics about query execution.
type RedisCommandHook ¶ added in v0.7.0
type RedisCommandHook struct {
// contains filtered or unexported fields
}
RedisCommandHook provides observability for Redis commands.
func (*RedisCommandHook) DialHook ¶ added in v0.7.0
func (h *RedisCommandHook) DialHook(next redis.DialHook) redis.DialHook
DialHook is called when a new connection is established.
func (*RedisCommandHook) ProcessHook ¶ added in v0.7.0
func (h *RedisCommandHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook
ProcessHook is called for each command.
func (*RedisCommandHook) ProcessPipelineHook ¶ added in v0.7.0
func (h *RedisCommandHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook
ProcessPipelineHook is called for pipelined commands.
type RedisDatabase ¶ added in v0.7.0
type RedisDatabase struct {
// contains filtered or unexported fields
}
RedisDatabase wraps go-redis client with support for standalone, cluster, and sentinel modes.
func NewRedisDatabase ¶ added in v0.7.0
func NewRedisDatabase(config DatabaseConfig, logger forge.Logger, metrics forge.Metrics) (*RedisDatabase, error)
NewRedisDatabase creates a new Redis database instance.
func (*RedisDatabase) Client ¶ added in v0.7.0
func (d *RedisDatabase) Client() redis.UniversalClient
Client returns the Redis universal client.
func (*RedisDatabase) Close ¶ added in v0.7.0
func (d *RedisDatabase) Close(ctx context.Context) error
Close closes the Redis connection.
func (*RedisDatabase) Driver ¶ added in v0.7.0
func (d *RedisDatabase) Driver() any
Driver returns the redis.UniversalClient for native driver access.
func (*RedisDatabase) Health ¶ added in v0.7.0
func (d *RedisDatabase) Health(ctx context.Context) HealthStatus
Health returns the health status.
func (*RedisDatabase) IsOpen ¶ added in v0.7.0
func (d *RedisDatabase) IsOpen() bool
IsOpen returns whether the database is connected.
func (*RedisDatabase) Name ¶ added in v0.7.0
func (d *RedisDatabase) Name() string
Name returns the database name.
func (*RedisDatabase) Open ¶ added in v0.7.0
func (d *RedisDatabase) Open(ctx context.Context) error
Open establishes the Redis connection with retry logic.
func (*RedisDatabase) Ping ¶ added in v0.7.0
func (d *RedisDatabase) Ping(ctx context.Context) error
Ping checks Redis connectivity.
func (*RedisDatabase) Pipeline ¶ added in v0.7.0
func (d *RedisDatabase) Pipeline() redis.Pipeliner
Pipeline creates a Redis pipeline for batching commands.
func (*RedisDatabase) Pipelined ¶ added in v0.7.0
func (d *RedisDatabase) Pipelined(ctx context.Context, fn func(pipe redis.Pipeliner) error) (err error)
Pipelined executes commands in a pipeline with panic recovery.
func (*RedisDatabase) State ¶ added in v0.7.0
func (d *RedisDatabase) State() ConnectionState
State returns the current connection state.
func (*RedisDatabase) Stats ¶ added in v0.7.0
func (d *RedisDatabase) Stats() DatabaseStats
Stats returns connection pool statistics.
func (*RedisDatabase) Transaction ¶ added in v0.7.0
func (d *RedisDatabase) Transaction(ctx context.Context, watchKeys []string, fn func(tx *redis.Tx) error) (err error)
Transaction executes a function in a Redis transaction with panic recovery. Uses WATCH/MULTI/EXEC pattern for optimistic locking.
func (*RedisDatabase) TxPipeline ¶ added in v0.7.0
func (d *RedisDatabase) TxPipeline() redis.Pipeliner
TxPipeline creates a Redis transaction pipeline (MULTI/EXEC).
func (*RedisDatabase) TxPipelined ¶ added in v0.7.0
func (d *RedisDatabase) TxPipelined(ctx context.Context, fn func(pipe redis.Pipeliner) error) (err error)
TxPipelined executes commands in a transaction pipeline (MULTI/EXEC) with panic recovery.
func (*RedisDatabase) Type ¶ added in v0.7.0
func (d *RedisDatabase) Type() DatabaseType
Type returns the database type.
type RedisMode ¶ added in v0.7.0
type RedisMode string
RedisMode represents the Redis connection mode.
type Repository ¶ added in v0.7.3
type Repository[T any] struct { // contains filtered or unexported fields }
Repository provides a generic, type-safe repository pattern for database operations. It eliminates boilerplate CRUD code while maintaining flexibility through QueryOptions.
Example usage:
type User struct {
ID int64 `bun:"id,pk,autoincrement"`
Name string `bun:"name"`
}
repo := database.NewRepository[User](db)
user, err := repo.FindByID(ctx, 123)
users, err := repo.FindAll(ctx, WhereActive())
func NewRepository ¶ added in v0.7.3
func NewRepository[T any](db IDB) *Repository[T]
NewRepository creates a new repository instance for type T. The db parameter can be either *bun.DB or bun.Tx, allowing repositories to work seamlessly in and out of transactions.
func NewRepositoryFromApp ¶ added in v0.7.3
func NewRepositoryFromApp[T any](app forge.App) *Repository[T]
NewRepositoryFromApp creates a repository using the database from the app.
func NewRepositoryFromContainer ¶ added in v0.7.3
func NewRepositoryFromContainer[T any](c forge.Container) *Repository[T]
NewRepositoryFromContainer creates a repository using the database from the container. This is a convenience wrapper for the common pattern of getting DB and creating a repo.
Example:
func NewUserService(c forge.Container) *UserService {
return &UserService{
userRepo: database.NewRepositoryFromContainer[User](c),
}
}
func (*Repository[T]) Count ¶ added in v0.7.3
func (r *Repository[T]) Count(ctx context.Context, opts ...QueryOption) (int, error)
Count returns the number of records matching the query options.
Example:
count, err := repo.Count(ctx, func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("age > ?", 18)
})
func (*Repository[T]) Create ¶ added in v0.7.3
func (r *Repository[T]) Create(ctx context.Context, entity *T) error
Create inserts a new record into the database. The entity's BeforeInsert hook will be called if it implements it.
Example:
user := &User{Name: "John"}
err := repo.Create(ctx, user)
// user.ID is now populated
func (*Repository[T]) CreateMany ¶ added in v0.7.3
func (r *Repository[T]) CreateMany(ctx context.Context, entities []T) error
CreateMany inserts multiple records in a single query. Much more efficient than calling Create in a loop.
Example:
users := []User{{Name: "John"}, {Name: "Jane"}}
err := repo.CreateMany(ctx, users)
func (*Repository[T]) DB ¶ added in v0.7.3
func (r *Repository[T]) DB() IDB
DB returns the underlying database connection. Useful when you need direct access to Bun's query builder.
func (*Repository[T]) Delete ¶ added in v0.7.3
func (r *Repository[T]) Delete(ctx context.Context, id any) error
Delete permanently deletes a record by ID. For soft deletes, use SoftDelete instead.
Example:
err := repo.Delete(ctx, 123)
func (*Repository[T]) DeleteMany ¶ added in v0.7.3
func (r *Repository[T]) DeleteMany(ctx context.Context, ids []any) error
DeleteMany permanently deletes multiple records by IDs.
Example:
err := repo.DeleteMany(ctx, []int64{1, 2, 3})
func (*Repository[T]) Exists ¶ added in v0.7.3
Exists checks if a record with the given ID exists.
Example:
exists, err := repo.Exists(ctx, 123)
func (*Repository[T]) FindAll ¶ added in v0.7.3
func (r *Repository[T]) FindAll(ctx context.Context, opts ...QueryOption) ([]T, error)
FindAll retrieves all records matching the query options. Returns an empty slice if no records found (not an error).
Example:
users, err := repo.FindAll(ctx,
func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("age > ?", 18).Order("created_at DESC")
},
)
func (*Repository[T]) FindAllWithDeleted ¶ added in v0.7.3
func (r *Repository[T]) FindAllWithDeleted(ctx context.Context, opts ...QueryOption) ([]T, error)
FindAllWithDeleted retrieves all records including soft-deleted ones. Only works with models that have a DeletedAt field with soft_delete tag.
Example:
allUsers, err := repo.FindAllWithDeleted(ctx)
func (*Repository[T]) FindByID ¶ added in v0.7.3
func (r *Repository[T]) FindByID(ctx context.Context, id any, opts ...QueryOption) (*T, error)
FindByID retrieves a single record by its primary key. Returns ErrRecordNotFound if no record exists.
Example:
user, err := repo.FindByID(ctx, 123)
if errors.Is(err, database.ErrRecordNotFound(123)) {
// Handle not found
}
func (*Repository[T]) FindOne ¶ added in v0.7.3
func (r *Repository[T]) FindOne(ctx context.Context, opts ...QueryOption) (*T, error)
FindOne retrieves a single record based on query options. Returns ErrRecordNotFound if no record exists.
Example:
user, err := repo.FindOne(ctx, func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("email = ?", "user@example.com")
})
func (*Repository[T]) Query ¶ added in v0.7.3
func (r *Repository[T]) Query() *bun.SelectQuery
Query returns a new SelectQuery for the repository's model type. This is useful when you need to build custom queries that aren't covered by the standard repository methods.
Example:
query := repo.Query().
Where("age > ?", 18).
Order("created_at DESC").
Limit(10)
var users []User
err := query.Scan(ctx, &users)
func (*Repository[T]) RestoreSoftDeleted ¶ added in v0.7.3
func (r *Repository[T]) RestoreSoftDeleted(ctx context.Context, id any) error
RestoreSoftDeleted restores a soft-deleted record. Only works with models that have a DeletedAt field with soft_delete tag.
Example:
err := repo.RestoreSoftDeleted(ctx, 123)
func (*Repository[T]) SoftDelete ¶ added in v0.7.3
func (r *Repository[T]) SoftDelete(ctx context.Context, id any) error
SoftDelete marks a record as deleted by setting its DeletedAt field. Only works with models that have a DeletedAt field with soft_delete tag.
Example:
err := repo.SoftDelete(ctx, 123)
func (*Repository[T]) Truncate ¶ added in v0.7.3
func (r *Repository[T]) Truncate(ctx context.Context) error
Truncate removes all records from the table. WARNING: This is a destructive operation and cannot be undone. Use with extreme caution, typically only in tests.
Example:
err := repo.Truncate(ctx)
func (*Repository[T]) Update ¶ added in v0.7.3
func (r *Repository[T]) Update(ctx context.Context, entity *T) error
Update updates an existing record. The entity's BeforeUpdate hook will be called if it implements it. By default, all non-zero fields are updated.
Example:
user.Name = "Jane" err := repo.Update(ctx, user)
func (*Repository[T]) UpdateColumns ¶ added in v0.7.3
func (r *Repository[T]) UpdateColumns(ctx context.Context, entity *T, columns ...string) error
UpdateColumns updates only specific columns of a record. Useful when you only want to update certain fields.
Example:
err := repo.UpdateColumns(ctx, user, "name", "email")
type SQLDatabase ¶
type SQLDatabase struct {
// contains filtered or unexported fields
}
SQLDatabase wraps Bun ORM for SQL databases.
func NewSQLDatabase ¶
func NewSQLDatabase(config DatabaseConfig, logger forge.Logger, metrics forge.Metrics) (*SQLDatabase, error)
NewSQLDatabase creates a new SQL database instance.
func (*SQLDatabase) Close ¶
func (d *SQLDatabase) Close(ctx context.Context) error
Close closes the database connection.
func (*SQLDatabase) Driver ¶
func (d *SQLDatabase) Driver() any
Driver returns the raw *sql.DB for native driver access.
func (*SQLDatabase) Health ¶
func (d *SQLDatabase) Health(ctx context.Context) HealthStatus
Health returns the health status.
func (*SQLDatabase) IsOpen ¶ added in v0.4.0
func (d *SQLDatabase) IsOpen() bool
IsOpen returns whether the database is connected.
func (*SQLDatabase) Open ¶
func (d *SQLDatabase) Open(ctx context.Context) error
Open establishes the database connection with retry logic.
func (*SQLDatabase) Ping ¶
func (d *SQLDatabase) Ping(ctx context.Context) error
Ping checks database connectivity.
func (*SQLDatabase) State ¶ added in v0.4.0
func (d *SQLDatabase) State() ConnectionState
State returns the current connection state.
func (*SQLDatabase) Stats ¶
func (d *SQLDatabase) Stats() DatabaseStats
Stats returns connection pool statistics.
func (*SQLDatabase) Transaction ¶
Transaction executes a function in a SQL transaction with panic recovery.
func (*SQLDatabase) TransactionWithOptions ¶
func (d *SQLDatabase) TransactionWithOptions(ctx context.Context, opts *sql.TxOptions, fn func(tx bun.Tx) error) (err error)
TransactionWithOptions executes a function in a SQL transaction with options and panic recovery.
func (*SQLDatabase) Type ¶
func (d *SQLDatabase) Type() DatabaseType
Type returns the database type.
type Seeder ¶ added in v0.7.3
type Seeder interface {
// Name returns a unique identifier for this seeder.
Name() string
// Seed executes the seeding logic.
// Should return an error if seeding fails.
Seed(ctx context.Context, db *bun.DB) error
}
Seeder defines the interface for database seeders. Seeders populate the database with initial or test data.
Seeders should be idempotent - safe to run multiple times.
type SeederFunc ¶ added in v0.7.3
type SeederFunc struct {
// contains filtered or unexported fields
}
SeederFunc is a function type that implements the Seeder interface. This allows you to create seeders from functions.
func NewSeederFunc ¶ added in v0.7.3
NewSeederFunc creates a seeder from a function.
Example:
seeder := database.NewSeederFunc("users", func(ctx context.Context, db *bun.DB) error {
users := []User{{Name: "Alice"}, {Name: "Bob"}}
return database.BulkInsert(ctx, db, users, 0)
})
func (*SeederFunc) Name ¶ added in v0.7.3
func (s *SeederFunc) Name() string
Name implements Seeder interface.
type SeederRecord ¶ added in v0.7.3
type SeederRecord struct {
bun.BaseModel `bun:"table:seeders"`
ID int64 `bun:"id,pk,autoincrement"`
Name string `bun:"name,unique,notnull"`
RunAt time.Time `bun:"run_at,notnull"`
Duration int64 `bun:"duration"` // Duration in milliseconds
Success bool `bun:"success"`
ErrorMsg string `bun:"error_msg"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
}
SeederRecord tracks which seeders have been run.
type SeederRunner ¶ added in v0.7.3
type SeederRunner struct {
// contains filtered or unexported fields
}
SeederRunner manages and executes database seeders.
func NewSeederRunner ¶ added in v0.7.3
func NewSeederRunner(db *bun.DB, logger forge.Logger) *SeederRunner
NewSeederRunner creates a new seeder runner.
Example:
runner := database.NewSeederRunner(db, logger)
runner.Register(&UserSeeder{})
runner.Register(&ProductSeeder{})
err := runner.Run(ctx)
func (*SeederRunner) GetSeeder ¶ added in v0.7.3
func (r *SeederRunner) GetSeeder(name string) (Seeder, bool)
GetSeeder returns a seeder by name.
func (*SeederRunner) List ¶ added in v0.7.3
func (r *SeederRunner) List() []string
List returns the names of all registered seeders.
func (*SeederRunner) Register ¶ added in v0.7.3
func (r *SeederRunner) Register(seeder Seeder)
Register adds a seeder to the runner.
func (*SeederRunner) RegisterMany ¶ added in v0.7.3
func (r *SeederRunner) RegisterMany(seeders ...Seeder)
RegisterMany registers multiple seeders at once.
func (*SeederRunner) Reset ¶ added in v0.7.3
func (r *SeederRunner) Reset(ctx context.Context, name string) error
Reset clears the seeder tracking for a specific seeder. This allows the seeder to be run again.
Example:
err := runner.Reset(ctx, "users")
func (*SeederRunner) ResetAll ¶ added in v0.7.3
func (r *SeederRunner) ResetAll(ctx context.Context) error
ResetAll clears all seeder tracking. This allows all seeders to be run again.
Example:
err := runner.ResetAll(ctx)
func (*SeederRunner) Run ¶ added in v0.7.3
func (r *SeederRunner) Run(ctx context.Context) error
Run executes all registered seeders that haven't been run yet. If a seeder has already been run successfully, it's skipped.
Example:
err := runner.Run(ctx)
if err != nil {
log.Fatal(err)
}
func (*SeederRunner) RunSeeder ¶ added in v0.7.3
func (r *SeederRunner) RunSeeder(ctx context.Context, name string) error
RunSeeder executes a specific seeder by name. Unlike Run(), this always executes the seeder even if it has run before.
Example:
err := runner.RunSeeder(ctx, "users")
func (*SeederRunner) WithTracking ¶ added in v0.7.3
func (r *SeederRunner) WithTracking(enabled bool) *SeederRunner
WithTracking enables or disables tracking of seeder execution. When enabled, seeder runs are recorded in the database.
type SoftDeleteModel ¶ added in v0.4.0
type SoftDeleteModel struct {
ID int64 `bun:"id,pk,autoincrement" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at,omitempty"`
}
SoftDeleteModel provides soft delete functionality with timestamps Soft-deleted records are not permanently removed, just marked as deleted.
func (*SoftDeleteModel) BeforeDelete ¶ added in v0.4.0
func (m *SoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
BeforeDelete hook - performs soft delete.
func (*SoftDeleteModel) BeforeInsert ¶ added in v0.4.0
func (m *SoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - sets timestamps.
func (*SoftDeleteModel) BeforeUpdate ¶ added in v0.4.0
func (m *SoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt.
func (*SoftDeleteModel) IsDeleted ¶ added in v0.4.0
func (m *SoftDeleteModel) IsDeleted() bool
IsDeleted checks if the record is soft deleted.
func (*SoftDeleteModel) Restore ¶ added in v0.4.0
func (m *SoftDeleteModel) Restore()
Restore restores a soft-deleted record.
type TestDBOption ¶ added in v0.7.3
type TestDBOption func(*testDBConfig)
TestDBOption configures test database behavior.
func WithAutoMigrate ¶ added in v0.7.3
func WithAutoMigrate(models ...any) TestDBOption
WithAutoMigrate automatically creates tables for the provided models.
func WithInMemory ¶ added in v0.7.3
func WithInMemory() TestDBOption
WithInMemory creates an in-memory SQLite database (default).
func WithLogging ¶ added in v0.7.3
func WithLogging() TestDBOption
WithLogging enables query logging for debugging.
func WithTransactionRollback ¶ added in v0.7.3
func WithTransactionRollback() TestDBOption
WithTransactionRollback wraps each test in a transaction that's rolled back. This is faster than truncating tables between tests.
type TimestampModel ¶ added in v0.4.0
type TimestampModel struct {
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
}
TimestampModel provides only timestamp fields without ID Use this when you want to add your own ID field type.
func (*TimestampModel) BeforeInsert ¶ added in v0.4.0
func (m *TimestampModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - sets timestamps.
func (*TimestampModel) BeforeUpdate ¶ added in v0.4.0
func (m *TimestampModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt.
type TransactionStats ¶ added in v0.7.3
type TransactionStats struct {
Active int32 // Number of active transactions
Committed int64 // Total committed transactions
RolledBack int64 // Total rolled back transactions
Panics int64 // Total panics recovered
}
TransactionStats tracks transaction statistics.
func GetTransactionStats ¶ added in v0.7.3
func GetTransactionStats() TransactionStats
GetTransactionStats returns global transaction statistics. Useful for monitoring and debugging.
type TxFunc ¶ added in v0.7.3
TxFunc is a function that runs within a transaction. The context passed to the function contains the active transaction, which can be retrieved using GetDB.
type UUIDModel ¶ added in v0.4.0
type UUIDModel struct {
ID uuid.UUID `bun:"id,pk,type:uuid,default:gen_random_uuid()" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
}
UUIDModel provides UUID-based primary key with timestamps Use this for distributed systems or when you need globally unique IDs.
func (*UUIDModel) BeforeInsert ¶ added in v0.4.0
BeforeInsert hook - generates UUID and sets timestamps.
func (*UUIDModel) BeforeUpdate ¶ added in v0.4.0
BeforeUpdate hook - updates UpdatedAt.
type UUIDSoftDeleteModel ¶ added in v0.4.0
type UUIDSoftDeleteModel struct {
ID uuid.UUID `bun:"id,pk,type:uuid,default:gen_random_uuid()" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at,omitempty"`
}
UUIDSoftDeleteModel combines UUID primary key with soft delete.
func (*UUIDSoftDeleteModel) BeforeDelete ¶ added in v0.4.0
func (m *UUIDSoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
BeforeDelete hook - performs soft delete.
func (*UUIDSoftDeleteModel) BeforeInsert ¶ added in v0.4.0
func (m *UUIDSoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - generates UUID and sets timestamps.
func (*UUIDSoftDeleteModel) BeforeUpdate ¶ added in v0.4.0
func (m *UUIDSoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt.
func (*UUIDSoftDeleteModel) IsDeleted ¶ added in v0.4.0
func (m *UUIDSoftDeleteModel) IsDeleted() bool
IsDeleted checks if the record is soft deleted.
func (*UUIDSoftDeleteModel) Restore ¶ added in v0.4.0
func (m *UUIDSoftDeleteModel) Restore()
Restore restores a soft-deleted record.
type XIDAuditModel ¶ added in v0.4.0
type XIDAuditModel struct {
ID xid.ID `bun:"id,pk,type:varchar(20)" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
CreatedBy *xid.ID `bun:"created_by,type:varchar(20)" json:"created_by,omitempty"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
UpdatedBy *xid.ID `bun:"updated_by,type:varchar(20)" json:"updated_by,omitempty"`
DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at,omitempty"`
DeletedBy *xid.ID `bun:"deleted_by,type:varchar(20)" json:"deleted_by,omitempty"`
}
XIDAuditModel provides comprehensive audit trail with XID primary key and user tracking Combines XID with full audit capabilities: tracks who created/updated/deleted records.
func (*XIDAuditModel) BeforeDelete ¶ added in v0.4.0
func (m *XIDAuditModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
BeforeDelete hook - performs soft delete and tracks deleter.
func (*XIDAuditModel) BeforeInsert ¶ added in v0.4.0
func (m *XIDAuditModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - generates XID, sets timestamps and tracks creator.
func (*XIDAuditModel) BeforeUpdate ¶ added in v0.4.0
func (m *XIDAuditModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt and tracks updater.
func (*XIDAuditModel) IsDeleted ¶ added in v0.4.0
func (m *XIDAuditModel) IsDeleted() bool
IsDeleted checks if the record is soft deleted.
func (*XIDAuditModel) Restore ¶ added in v0.4.0
func (m *XIDAuditModel) Restore()
Restore restores a soft-deleted record.
type XIDModel ¶ added in v0.4.0
type XIDModel struct {
ID xid.ID `bun:"id,pk,type:varchar(20)" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
}
XIDModel provides XID primary key with timestamps XID is a globally unique, sortable, compact, URL-safe identifier It's shorter than UUID (20 bytes vs 36) and sortable by creation time.
func (*XIDModel) BeforeInsert ¶ added in v0.4.0
BeforeInsert hook - generates XID and sets timestamps.
func (*XIDModel) BeforeUpdate ¶ added in v0.4.0
BeforeUpdate hook - updates UpdatedAt.
type XIDSoftDeleteModel ¶ added in v0.4.0
type XIDSoftDeleteModel struct {
ID xid.ID `bun:"id,pk,type:varchar(20)" json:"id"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at,omitempty"`
}
XIDSoftDeleteModel combines XID primary key with soft delete.
func (*XIDSoftDeleteModel) BeforeDelete ¶ added in v0.4.0
func (m *XIDSoftDeleteModel) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error
BeforeDelete hook - performs soft delete.
func (*XIDSoftDeleteModel) BeforeInsert ¶ added in v0.4.0
func (m *XIDSoftDeleteModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error
BeforeInsert hook - generates XID and sets timestamps.
func (*XIDSoftDeleteModel) BeforeUpdate ¶ added in v0.4.0
func (m *XIDSoftDeleteModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error
BeforeUpdate hook - updates UpdatedAt.
func (*XIDSoftDeleteModel) IsDeleted ¶ added in v0.4.0
func (m *XIDSoftDeleteModel) IsDeleted() bool
IsDeleted checks if the record is soft deleted.
func (*XIDSoftDeleteModel) Restore ¶ added in v0.4.0
func (m *XIDSoftDeleteModel) Restore()
Restore restores a soft-deleted record.