Documentation
¶
Overview ¶
package dbmap is a lightweight, struct based ORM for Go that simplifies database interactions without completely abstracting SQL.
All methods use named paramters instead of driver specific placeholders in SQL queries/fragments. For example, a simple SELECT statement will look like:
var user User
db.Select(&user, "WHERE name = $name AND age > $age", micorm.Args{"name": "Fox", "age": 32})
This enables more readable queries while avoiding the boilerplate+pitfalls of positional query arguments.
Index ¶
- Variables
- type Args
- type DB
- func (d *DB) Close() error
- func (d *DB) Count(ctx context.Context, structType any, queryFragment string, args Args) (int64, error)
- func (d *DB) Delete(ctx context.Context, modelRef any, queryFragment string, args Args) (int64, error)
- func (d *DB) DeleteRecord(ctx context.Context, model any) (int64, error)
- func (d *DB) DeleteRecords(ctx context.Context, models any) (int64, error)
- func (d *DB) Exec(ctx context.Context, sql string, args map[string]any) (sql.Result, error)
- func (d *DB) Exists(ctx context.Context, structType any, queryFragment string, args Args) (bool, error)
- func (d *DB) InsertRecord(ctx context.Context, model any) error
- func (d *DB) Query(ctx context.Context, sql string, args map[string]any) (*sql.Rows, error)
- func (d *DB) Select(ctx context.Context, model any, queryFragment string, args Args) error
- func (d *DB) Transaction(ctx context.Context, fn func(tx *DB) error) error
- func (d *DB) Update(ctx context.Context, structType any, queryFragment string, args Args, ...) (int64, error)
- func (d *DB) UpdateRecord(ctx context.Context, model any, updates Updates) error
- type Pluralizer
- type TableNamer
- type Updates
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoUpdates is returned when no updates are provided to an update operation ErrNoUpdates = errors.New("no updates provided") )
Functions ¶
This section is empty.
Types ¶
type DB ¶
type DB struct {
// Pluralizer is used to pluralize table names. You can provide your own
// pluralizer by overriding this field.
Pluralizer Pluralizer
// contains filtered or unexported fields
}
DB is a wrapper around sql.DB that provides lightweight ORM-like functionality.
func (*DB) Delete ¶
func (d *DB) Delete(ctx context.Context, modelRef any, queryFragment string, args Args) (int64, error)
Delete deletes records from the database based on the provided struct type and SQL fragment with named parameters. The model argument should be a pointer to a struct type representing the table to delete from.
It returns the number of rows affected
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Delete users
rowsAffected, err := db.Delete(ctx, &User{}, "WHERE email LIKE $pattern AND active = $active", dbmap.Args{
"pattern": "%@xfiles.gov",
"active": false,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted %d users\n", rowsAffected)
Output: Deleted 1 users
func (*DB) DeleteRecord ¶
DeleteRecord deletes a single record from the database based on the provided struct. The dest parameter should be a pointer to a struct representing the record to delete.
It returns the number of rows affected, or an error if the operation fails.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Get an existing user to delete
var user User
err := db.Select(ctx, &user, "WHERE email = $email", dbmap.Args{
"email": "[email protected]",
})
if err != nil {
log.Fatal(err)
}
// Delete the specific user record
rowsAffected, err := db.DeleteRecord(ctx, &user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted %d user\n", rowsAffected)
Output: Deleted 1 user
func (*DB) DeleteRecords ¶
DeleteRecords deletes multiple records from the database based on the provided slice of structs. The dest parameter should be a pointer to a slice of structs representing the records to delete. It deletes each record by its ID inside of a transaction. If you need to delete in a single statement, use `DB.Delete`.
It returns the number of rows affected, or an error if the operation fails.
func (*DB) Exec ¶
Exec calls the underlying sql.DB Exec method, but uses named parameters like other dbmap methods.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Execute a raw SQL statement
result, err := db.Exec(ctx, `
UPDATE users
SET active = $active
WHERE email LIKE $pattern
`, dbmap.Args{
"active": false,
"pattern": "%@xfiles.gov",
})
if err != nil {
log.Fatal(err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Updated %d users\n", rowsAffected)
Output: Updated 3 users
func (*DB) InsertRecord ¶
InsertRecord inserts a new record into the database based on the provided struct.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Insert a new user - ID and timestamps will be set automatically
user := &User{
Name: "C.G.B Spender",
Email: "[email protected]",
Active: true,
}
err := db.InsertRecord(ctx, user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted user with ID: %d\n", user.ID)
fmt.Printf("Active: %t\n", user.Active)
Output: Inserted user with ID: 5 Active: true
func (*DB) Query ¶
Query calls the underlying sql.DB Query method, but uses named parameters like other dbmap methods. Query returns sql.Rows, which the caller is responsible for closing.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Execute a raw query with named parameters
rows, err := db.Query(ctx, `
SELECT name, email
FROM users
WHERE email LIKE $pattern AND active = $active
ORDER BY name LIMIT 2
`, dbmap.Args{
"pattern": "%@xfiles.gov",
"active": true,
})
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name, email string
if err := rows.Scan(&name, &email); err != nil {
log.Fatal(err)
}
fmt.Printf("%s (%s)\n", name, email)
}
Output: Dana Scully ([email protected]) Fox Mulder ([email protected])
func (*DB) Select ¶
Select executes a query and scans the result into the provided model struct or slice of structs.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Select a single user by email
var user User
err := db.Select(ctx, &user, "WHERE email = $email", dbmap.Args{
"email": "[email protected]",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found user: %s (%s)\n", user.Name, user.Email)
// Select multiple active users
var activeUsers []User
err = db.Select(ctx, &activeUsers, "WHERE email LIKE $pattern AND active = $active ORDER BY name LIMIT 2", dbmap.Args{
"pattern": "%@xfiles.gov",
"active": true,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d active users\n", len(activeUsers))
Output: Found user: Fox Mulder ([email protected]) Found 2 active users
func (*DB) Transaction ¶
Transaction executes the provided function within a database transaction. If the function returns an error, the transaction is rolled back, otherwise it is committed.
Transactions can not be nested at this time.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
err := db.Transaction(ctx, func(tx *dbmap.DB) error {
// Insert a new user
user := &User{
Name: "Monica Reyes",
Email: "[email protected]",
Active: true,
}
if err := tx.InsertRecord(ctx, user); err != nil {
return err
}
// Update another user in the same transaction
_, err := tx.Update(ctx, &User{}, "WHERE email = $email", dbmap.Args{
"email": "[email protected]",
}, dbmap.Updates{
"Active": false,
})
return err
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Transaction completed successfully")
Output: Transaction completed successfully
func (*DB) Update ¶
func (d *DB) Update(ctx context.Context, structType any, queryFragment string, args Args, updates Updates) (int64, error)
Update updates records in the database based on the provided struct type, SQL fragment with named parameters, and a map of field-value pairs to update. The structType parameter should be a pointer to a struct type representing the table to update.
It returns the number of rows affected, or an error if the operation fails.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Update user status
rowsAffected, err := db.Update(ctx, &User{}, "WHERE email = $email", dbmap.Args{
"email": "[email protected]",
}, dbmap.Updates{
"Active": true,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Activated %d users\n", rowsAffected)
Output: Activated 1 users
func (*DB) UpdateRecord ¶
UpdateRecord updates a single record in the database based on the provided struct. The dest parameter should be a pointer to a struct of the record to update.
Example ¶
sqlDB, cleanup := setupDB()
defer cleanup()
db := dbmap.New(sqlDB)
ctx := context.Background()
// Get an existing user
var user User
err := db.Select(ctx, &user, "WHERE email = $email", dbmap.Args{
"email": "[email protected]",
})
if err != nil {
log.Fatal(err)
}
// Update the user record - UpdatedAt will be set automatically
err = db.UpdateRecord(ctx, &user, dbmap.Updates{
"Name": "Fox Mulder (FBI Agent)",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Updated user: %s\n", user.Name)
Output: Updated user: Fox Mulder (FBI Agent)
type Pluralizer ¶
Pluralizer is an interface for pluralizing words
type TableNamer ¶
type TableNamer interface {
TableName() string
}
TableNamer is an interface models can implement to override the default `snake_case`d, pluralized table name.
*Warning*: This value will be cached, so do not return dynamic values.