dbgorm

package
v0.1.21 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

dbgorm

dbgorm is a thin wrapper around GORM. It does not replace GORM, hide *gorm.DB, or provide a repository framework. Its main purpose is to make database initialization consistent while keeping normal database operations in plain GORM.

Features

  • Common GORM configuration and connection pool setup.
  • Optional process-wide default database instance.
  • Driver adapters for MySQL, PostgreSQL, and SQLite.
  • Small helpers for common read/delete/not-found patterns.
  • GORM scopes for pagination and allow-listed sorting.
  • Raw SQL helpers with parameter binding.
  • Optional migration helper.

Package Layout

The root package does not import concrete database drivers:

import dbgorm "github.com/phcp-tech/common-library-golang/dbgorm"

Concrete drivers live in adapter packages:

import "github.com/phcp-tech/common-library-golang/dbgorm/mysql"
import "github.com/phcp-tech/common-library-golang/dbgorm/postgres"
import "github.com/phcp-tech/common-library-golang/dbgorm/sqlite"

This keeps the root package independent from driver imports. Applications should only import the adapter packages they actually use.

The adapter packages expose flat config structs for application code. The root package only keeps the lower-level GormConfig used by adapters and by callers that already have a gorm.Dialector.

Install

This package is part of github.com/phcp-tech/common-library-golang.

go get github.com/phcp-tech/common-library-golang

If your application uses a specific adapter, make sure the matching GORM driver is available in the application module:

go get gorm.io/driver/mysql
go get gorm.io/driver/postgres
go get gorm.io/driver/sqlite

Opening a Database

MySQL
package main

import (
    "github.com/phcp-tech/common-library-golang/dbgorm/mysql"
    "gorm.io/gorm"
)

func openMySQL() (*gorm.DB, error) {
    return mysql.NewMySQL(mysql.Config{
        Host:            "localhost",
        Port:            "3306",
        Database:        "risk",
        Username:        "risk",
        Password:        "secret",
        MaxOpenConns:    50,
        MaxIdleConns:    10,
        ConnMaxLifetime: 60,
        ConnMaxIdletime: 10,
    })
}
PostgreSQL
db, err := postgres.NewPostgres(postgres.Config{
    Host:            "localhost",
    Port:            "5432",
    Database:        "risk",
    Username:        "risk",
    Password:        "secret",
    SearchPath:      "public",
    MaxOpenConns:    50,
    MaxIdleConns:    10,
    ConnMaxLifetime: 60,
    ConnMaxIdletime: 10,
})
SQLite
db, err := sqlite.NewSQLite(sqlite.Config{
    Path: "file:risk.db?cache=shared",
})

SQLite always opens through dbgorm.Open with MaxOpenConns and MaxIdleConns set to 1 to reduce database is locked errors. Its adapter config accepts only Path and optional Logger.

For tests:

db, err := sqlite.NewSQLite(sqlite.Config{
    Path: "file::memory:?cache=shared",
})
Low-level Open

Use dbgorm.Open only when you already have a gorm.Dialector:

db, err := dbgorm.Open(dialector, &dbgorm.GormConfig{
    MaxOpenConns:    50,
    MaxIdleConns:    10,
    ConnMaxLifetime: 60,
    ConnMaxIdletime: 10,
    Logger:          slog.Default(),
})

ConnMaxLifetime and ConnMaxIdletime are expressed in minutes. If a GormConfig field is zero, dbgorm.Open uses the library default.

Default Instance

Use the default instance when the process has one primary database connection.

if err := mysql.InitDefault(mysql.Config{
    Host:     "localhost",
    Port:     "3306",
    Database: "risk",
    Username: "risk",
    Password: "secret",
}); err != nil {
    return err
}

db := dbgorm.Default()

The default instance is process-wide. It is not one default per driver. If an application uses multiple databases, prefer explicit *gorm.DB fields:

type Store struct {
    MainDB    *gorm.DB
    MetricsDB *gorm.DB
}

Useful default-instance helpers:

db := dbgorm.Default()
dbgorm.SetDefault(db)

Applications should close or ping the default database through the returned *gorm.DB:

db := dbgorm.Default()
if db != nil {
    sqlDB, err := db.DB()
    if err != nil {
        return err
    }
    if err := sqlDB.PingContext(ctx); err != nil {
        return err
    }
    defer sqlDB.Close()
}

Logging

By default, Open configures GORM SQL logging with the standard library slog.Default() logger.

To use the project logger, pass its *slog.Logger through Config.Logger:

import applog "github.com/phcp-tech/common-library-golang/log"

db, err := mysql.NewMySQL(mysql.Config{
    Host:     "localhost",
    Port:     "3306",
    Database: "risk",
    Username: "risk",
    Password: "secret",
    Logger:   applog.Instance().Logger,
})

To inspect the logger formats used by the package tests, run:

go test -count=1 -v ./dbgorm -run "TestOpenUses(DefaultSlogLogger|LibraryLogInstance)"

TestOpenUsesDefaultSlogLogger prints the JSON output captured from slog.Default(). TestOpenUsesLibraryLogInstance triggers the JSON slog handler configured by library-golang/log/slog.go.

Normal GORM Usage

After opening a database, use standard GORM APIs directly:

err := db.WithContext(ctx).Create(&user).Error
err := db.WithContext(ctx).
    Where("status = ?", "active").
    Order("created_at desc").
    Find(&users).Error

Transactions stay as normal GORM transactions:

err := db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
    if err := tx.Create(&order).Error; err != nil {
        return err
    }

    return dbgorm.DeleteWhere(ctx, tx, &CartItem{}, "user_id = ?", userID)
})

Helper Functions

Find by ID
user, err := dbgorm.FirstByID[User](ctx, db, userID)
if err != nil {
    if dbgorm.IsNotFound(err) {
        return nil, ErrUserNotFound
    }
    return nil, err
}
Find by Condition
user, err := dbgorm.FirstWhere[User](ctx, db, "email = ?", email)
Delete by ID

DeleteByID returns gorm.ErrRecordNotFound when no row is deleted.

err := dbgorm.DeleteByID[User](ctx, db, userID)
if dbgorm.IsNotFound(err) {
    return ErrUserNotFound
}
Delete by Condition

DeleteWhere treats zero affected rows as success.

err := dbgorm.DeleteWhere(ctx, db, &Session{}, "expires_at < ?", cutoff)

Pagination and Sorting

Use scopes for reusable query modifiers:

allowedSorts := map[string]string{
    "id":        "id",
    "createdAt": "created_at",
    "email":     "email",
}

err := db.WithContext(ctx).
    Scopes(
        dbgorm.OrderBy(allowedSorts, req.Sort, req.Direction),
        dbgorm.Paginate(req.Page, req.Limit),
    ).
    Find(&users).Error

OrderBy only accepts columns listed in the allow-list. This avoids directly injecting request values into ORDER BY.

Raw SQL

Use raw SQL helpers when a query is easier to express manually. Always pass values through arguments instead of string concatenation.

rows, err := dbgorm.ExecRaw(
    ctx,
    db,
    "update users set status = ? where id = ?",
    "disabled",
    userID,
)
var total int64
err := dbgorm.ScanRaw(
    ctx,
    db,
    &total,
    "select count(*) from users where status = ?",
    "active",
)

Error Handling

Use IsNotFound to check for GORM's not-found condition:

if dbgorm.IsNotFound(err) {
    // map to 404, domain error, or another application-specific response
}

Common package errors:

dbgorm.ErrNilDialector
dbgorm.ErrMissingConfig

Configuration Ownership

dbgorm does not read application environment variables. Load config in the application, then build the adapter config explicitly:

db, err := mysql.NewMySQL(mysql.Config{
    Host:            env.DBHost,
    Port:            env.DBPort,
    Database:        env.DBName,
    Username:        env.DBUser,
    Password:        env.DBPassword,
    MaxOpenConns:    env.DBMaxOpenConns,
    MaxIdleConns:    env.DBMaxIdleConns,
    ConnMaxLifetime: env.DBConnMaxLifetime,
    ConnMaxIdletime: env.DBConnMaxIdletime,
    Logger:          appLogger,
})

Testing

SQLite in-memory is convenient for tests:

db, err := sqlite.NewSQLite(sqlite.Config{
    Path: "file::memory:?cache=shared",
})

Run package tests:

go test ./dbgorm/...

Documentation

Index

Examples

Constants

View Source
const (
	MaxOpenConns    = 100              // MaxOpenConns is the maximum number of open database connections in the pool.
	MaxIdleConns    = 25               // MaxIdleConns is the maximum number of idle database connections (1/4 of MaxOpenConns).
	ConnMaxLifetime = 60 * time.Minute // ConnMaxLifetime is the maximum lifetime of a database connection in minutes.
	ConnMaxIdletime = 10 * time.Minute // ConnMaxIdletime is the maximum idle lifetime of a database connection in minutes.
)

Variables

View Source
var (
	// ErrNilDialector is returned when Open receives a nil GORM dialector.
	ErrNilDialector = errors.New("dbgorm: nil gorm dialector")
	// ErrMissingConfig is returned when an adapter lacks required connection fields.
	ErrMissingConfig = errors.New("dbgorm: missing connection fields")
)

Functions

func Close

func Close(db *gorm.DB) error

Close closes the underlying database/sql connection for db.

Example

ExampleClose shows how to close a GORM database obtained from an adapter. Close is a no-op when db is nil.

package main

import (
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	db := exDB()
	err := libgorm.Close(db)
	fmt.Println(err == nil)
}
Output:
true

func Default

func Default() *gorm.DB

Default returns the process-wide default GORM database instance.

Example

ExampleDefault shows how to retrieve the process-wide default *gorm.DB.

package main

import (
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
)

func main() {
	prev := libgorm.Default()
	libgorm.SetDefault(nil)
	defer libgorm.SetDefault(prev) // restore after example

	fmt.Println(libgorm.Default() == nil) // nil — not yet initialised
}
Output:
true

func DeleteByID

func DeleteByID[T any](ctx context.Context, db *gorm.DB, id any) error

DeleteByID deletes the record of type T matching the primary key id.

Example

ExampleDeleteByID shows how to delete a record by primary key. Returns gorm.ErrRecordNotFound when no row is deleted.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	p := &exProduct{Name: "bolt"}
	db.Create(p)

	err := libgorm.DeleteByID[exProduct](ctx, db, p.ID)
	fmt.Println(err == nil)

	// Deleting again returns not-found.
	fmt.Println(libgorm.IsNotFound(libgorm.DeleteByID[exProduct](ctx, db, p.ID)))
}
Output:
true
true

func DeleteWhere

func DeleteWhere(ctx context.Context, db *gorm.DB, model any, query any, args ...any) error

DeleteWhere deletes records for model matching query and args.

Example

ExampleDeleteWhere shows how to delete all records matching a condition. Zero affected rows is treated as success.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "nail", Category: "fasteners"})
	db.Create(&exProduct{Name: "screw", Category: "fasteners"})

	err := libgorm.DeleteWhere(ctx, db, &exProduct{}, "category = ?", "fasteners")
	fmt.Println(err == nil)
}
Output:
true

func ExecRaw

func ExecRaw(ctx context.Context, db *gorm.DB, sql string, args ...any) (int64, error)

ExecRaw executes a raw SQL statement with positional arguments.

Example

ExampleExecRaw shows how to execute a raw SQL statement with positional args.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	p := &exProduct{Name: "gear", Category: "parts"}
	db.Create(p)

	rows, err := libgorm.ExecRaw(ctx, db,
		"UPDATE ex_products SET category = ? WHERE id = ?", "machinery", p.ID)
	fmt.Println(err == nil)
	fmt.Println(rows) // 1 row updated
}
Output:
true
1

func FirstByID

func FirstByID[T any](ctx context.Context, db *gorm.DB, id any) (*T, error)

FirstByID returns the first record of type T matching the primary key id.

Example

ExampleFirstByID shows how to fetch a record by primary key. Returns gorm.ErrRecordNotFound when no row matches.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	p := &exProduct{Name: "widget", Category: "tools"}
	db.Create(p)

	found, err := libgorm.FirstByID[exProduct](ctx, db, p.ID)
	fmt.Println(err == nil)
	fmt.Println(found.Name)
}
Output:
true
widget

func FirstWhere

func FirstWhere[T any](ctx context.Context, db *gorm.DB, query any, args ...any) (*T, error)

FirstWhere returns the first record of type T matching query and args.

Example

ExampleFirstWhere shows how to fetch the first record matching a condition.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "hammer", Category: "tools"})
	db.Create(&exProduct{Name: "wrench", Category: "tools"})

	found, err := libgorm.FirstWhere[exProduct](ctx, db, "name = ?", "wrench")
	fmt.Println(err == nil)
	fmt.Println(found.Name)
}
Output:
true
wrench

func HealthChecker

func HealthChecker() health.Checker

HealthChecker returns a health.Checker that verifies database connectivity by pinging the default GORM database.

The Checker is dialect-agnostic — it works with any driver (MySQL, PostgreSQL, SQLite, …) that was used to initialise Default. Reports health.StatusUnhealthy when Default() is nil or when the ping fails; health.StatusHealthy when reachable.

Example

ExampleHealthChecker shows how to wire HealthChecker into a health.Check call for a /health HTTP endpoint.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/health"
)

func main() {
	prev := libgorm.Default()
	libgorm.SetDefault(nil)
	defer libgorm.SetDefault(prev)

	results := health.Check(context.Background(), libgorm.HealthChecker())
	fmt.Println(results[0].Name)
	fmt.Println(results[0].Status == health.StatusUnhealthy) // true — Default() is nil
}
Output:
database
true

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err represents GORM's record-not-found condition.

Example

ExampleIsNotFound shows how to distinguish a not-found error from other database errors. Use it instead of comparing directly against gorm.ErrRecordNotFound.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()

	_, err := libgorm.FirstByID[exProduct](ctx, db, 9999)
	fmt.Println(libgorm.IsNotFound(err)) // true — no row with id=9999
}
Output:
true

func Open

func Open(dialector gorm.Dialector, conf *GormConfig) (*gorm.DB, error)

Open opens a GORM database using the supplied dialector and common config.

Example

ExampleOpen shows the low-level Open API using a GORM dialector directly. Prefer the adapter packages (dbgorm/mysql, dbgorm/postgres, dbgorm/sqlite) for application code.

package main

import (
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
)

func main() {
	dialector, _ := sqlite.Dialector(&sqlite.Config{Path: ":memory:"})
	db, err := libgorm.Open(dialector, &libgorm.GormConfig{
		MaxOpenConns: 1,
		MaxIdleConns: 1,
	})
	fmt.Println(err == nil)
	fmt.Println(db != nil)
}
Output:
true
true

func OrderBy

func OrderBy(allowed map[string]string, sort, direction string) func(*gorm.DB) *gorm.DB

OrderBy returns a GORM scope that orders by an allow-listed column.

Example

ExampleOrderBy shows how to apply an allow-listed column sort as a GORM scope.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "zebra"})
	db.Create(&exProduct{Name: "apple"})
	db.Create(&exProduct{Name: "mango"})

	allowed := map[string]string{"name": "name"}
	var results []exProduct
	db.WithContext(ctx).Scopes(libgorm.OrderBy(allowed, "name", "ASC")).Find(&results)
	fmt.Println(results[0].Name)
	fmt.Println(results[2].Name)
}
Output:
apple
zebra

func PageSql

func PageSql(para *dto.PageParameter) string

PageSql builds a LIMIT/OFFSET SQL clause from the pagination fields in para. When Limit is -1, all records are returned without a LIMIT clause. Defaults to page 1 and the maxPageLimit when values are unset or invalid.

func Paginate

func Paginate(page, limit int) func(*gorm.DB) *gorm.DB

Paginate returns a GORM scope that applies limit and offset pagination.

Example

ExamplePaginate shows how to apply limit/offset pagination as a GORM scope.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	for i := range 5 {
		db.Create(&exProduct{Name: fmt.Sprintf("item-%d", i)})
	}

	var page []exProduct
	db.WithContext(ctx).Scopes(libgorm.Paginate(1, 3)).Find(&page)
	fmt.Println(len(page)) // page 1, limit 3
}
Output:
3

func ScanRaw

func ScanRaw(ctx context.Context, db *gorm.DB, dest any, sql string, args ...any) error

ScanRaw executes a raw SQL query and scans the result into dest.

Example

ExampleScanRaw shows how to scan a scalar result (e.g. COUNT) from a raw query.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "pin", Category: "fasteners"})
	db.Create(&exProduct{Name: "clip", Category: "fasteners"})

	var total int64
	err := libgorm.ScanRaw(ctx, db, &total,
		"SELECT COUNT(*) FROM ex_products WHERE category = ?", "fasteners")
	fmt.Println(err == nil)
	fmt.Println(total)
}
Output:
true
2
Example (MultipleRows)

ExampleScanRaw_multipleRows shows how to scan all matching rows into a slice. Pass a pointer to a slice as dest to collect every returned row.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "nail", Category: "fasteners"})
	db.Create(&exProduct{Name: "bolt", Category: "fasteners"})
	db.Create(&exProduct{Name: "screw", Category: "fasteners"})

	var products []exProduct
	err := libgorm.ScanRaw(ctx, db, &products,
		"SELECT * FROM ex_products WHERE category = ? ORDER BY name", "fasteners")
	fmt.Println(err == nil)
	fmt.Println(len(products))
	fmt.Println(products[0].Name)
}
Output:
true
3
bolt
Example (SingleRow)

ExampleScanRaw_singleRow shows how to scan the first matching row into a struct. Only the first row is populated; additional rows are discarded.

package main

import (
	"context"
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	ctx := context.Background()
	db := exDB()
	db.Create(&exProduct{Name: "hammer", Category: "tools"})

	var p exProduct
	err := libgorm.ScanRaw(ctx, db, &p,
		"SELECT * FROM ex_products WHERE name = ?", "hammer")
	fmt.Println(err == nil)
	fmt.Println(p.Name)
}
Output:
true
hammer

func SetDefault

func SetDefault(db *gorm.DB)

SetDefault replaces the process-wide default GORM database instance.

Example

ExampleSetDefault shows how to store a *gorm.DB as the process-wide default. Call SetDefault once at application startup after opening the database.

package main

import (
	"fmt"

	libgorm "github.com/phcp-tech/common-library-golang/dbgorm"
	"github.com/phcp-tech/common-library-golang/dbgorm/sqlite"
	"gorm.io/gorm"
)

// exProduct is a minimal GORM model used by the example functions.
type exProduct struct {
	ID       uint `gorm:"primaryKey"`
	Name     string
	Category string
}

// exDB opens a private in-memory SQLite database and migrates exProduct.
// Each call returns an independent database — no shared state between examples.
func exDB() *gorm.DB {
	db, err := sqlite.NewSQLite(&sqlite.Config{Path: ":memory:"})
	if err != nil {
		panic("exDB: " + err.Error())
	}
	if err := db.AutoMigrate(&exProduct{}); err != nil {
		panic("exDB migrate: " + err.Error())
	}
	return db
}

func main() {
	prev := libgorm.Default()
	defer libgorm.SetDefault(prev) // restore after example

	libgorm.SetDefault(exDB())
	fmt.Println(libgorm.Default() != nil)
}
Output:
true

func SortSql

func SortSql(para *dto.PageParameter) string

SortSql builds an ORDER BY SQL clause from the sort fields in para. Defaults to ordering by "id ASC" when Sort or Direction are empty. If para.Charset is set, the sort column is wrapped with convert_to for locale-aware ordering.

Types

type GormConfig

type GormConfig struct {
	MaxOpenConns    int
	MaxIdleConns    int
	ConnMaxLifetime int
	ConnMaxIdletime int
	Logger          *slog.Logger
}

GormConfig contains pool settings and logger for a GORM database connection.

Directories

Path Synopsis
component
Package component provides GORM ClickHouse lifecycle integration for bootstrap.
Package component provides GORM ClickHouse lifecycle integration for bootstrap.
component
Package component provides GORM MySQL lifecycle integration for bootstrap.
Package component provides GORM MySQL lifecycle integration for bootstrap.
component
Package component provides GORM PostgreSQL lifecycle integration for bootstrap.
Package component provides GORM PostgreSQL lifecycle integration for bootstrap.
component
Package component provides GORM SQLite lifecycle integration for bootstrap.
Package component provides GORM SQLite lifecycle integration for bootstrap.
vfs
Package vfs opens a SQLite database embedded inside a Go binary using modernc.org/sqlite/vfs and Go's embed.FS.
Package vfs opens a SQLite database embedded inside a Go binary using modernc.org/sqlite/vfs and Go's embed.FS.

Jump to

Keyboard shortcuts

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