fxsql

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Dec 15, 2025 License: MIT Imports: 12 Imported by: 2

README

Fx SQL Module

ci go report codecov Deps PkgGoDev

Fx module for sql.

Installation

go get github.com/ankorstore/yokai/fxsql

Features

This module provides a *sql.DB to your Fx application with:

  • automatic SQL requests logging and tracing
  • possibility to define and apply database migrations (based on Goose)
  • possibility to register database hooks
  • possibility to register and execute database seeds

Documentation

Dependencies

This module is intended to be used alongside:

Loading

To load the module in your Fx application:

package main

import (
	"database/sql"
	
	"github.com/ankorstore/yokai/fxconfig"
	"github.com/ankorstore/yokai/fxlog"
	"github.com/ankorstore/yokai/fxsql"
	"github.com/ankorstore/yokai/fxtrace"
	"go.uber.org/fx"
)

func main() {
	fx.New(
		fxconfig.FxConfigModule, // load the module dependencies
		fxlog.FxLogModule,
		fxtrace.FxTraceModule,
		fxsql.FxSQLModule,       // load the module
		fx.Invoke(func(db *sql.DB) {
			// use the DB
			res, _ := db.Exec(...)
		}),
	).Run()
}
Configuration

This module provides the possibility to configure the SQL driver:

Configuration reference:

# ./configs/config.yaml
app:
  name: app
  env: dev
  version: 0.1.0
  debug: false
modules:
  sql:
    driver: mysql                                               # primary database driver (empty by default)
    dsn: "user:password@tcp(localhost:3306)/db?parseTime=true"  # primary database DSN (empty by default)
    migrations: 
      path: db/migrations       # migrations path (empty by default)
      stdout: true              # to print in stdout the migration logs (disabled by default)
    log:
      enabled: true             # to enable SQL queries logging (disabled by default)
      level: debug              # to configure SQL queries logs level (debug by default)
      arguments: true           # to add SQL queries arguments to logs (disabled by default)
      exclude:                  # to exclude SQL operations from logging (empty by default)
        - "connection:ping"
    trace:
      enabled: true             # to enable SQL queries tracing (disabled by default)
      arguments: true           # to add SQL queries arguments to trace spans (disabled by default)
      exclude:                  # to exclude SQL operations from tracing (empty by default)
        - "connection:ping"
    auxiliaries:                # auxiliary databases configurations (empty by default)
      postgres:
        driver: postgres
        dsn: "postgres://user:password@localhost:5432/db?sslmode=disable"
      sqlite:
        driver: sqlite
        dsn: ":memory:"

For security reasons, you should avoid to hardcode DSN sensible parts (like the password) in your config files, you can use the env vars placeholders instead:

# ./configs/config.yaml
modules:
  sql:
    driver: mysql
    dsn: "${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}?parseTime=True"

Available SQL operations:

  • connection:begin
  • connection:begin-tx
  • connection:exec
  • connection:exec-context
  • connection:query
  • connection:query-context
  • connection:prepare
  • connection:prepare-context
  • connection:ping
  • connection:reset-session
  • connection:close
  • statement:exec
  • statement:exec-context
  • statement:query
  • statement:query-context
  • transaction:commit
  • transaction:rollback
Pool

This module offers the possibility to handle optionally several databases connections, via the DatabasePool:

  • the primary database connection can be retrieved via Primary()
  • auxiliary databases connections can be retrieved via Auxiliary(name string)

This module automatically injects the primary database connection into your Fx application as *sql.DB.

To retrieve auxiliary databases connections, inject the DatabasePool where required, and use Auxiliary(name string) to retrieve the desired connection.

For example:

# ./configs/config.yaml
modules:
  sql:
    auxiliaries:
      postgres:
        driver: postgres
        dsn: "postgres://user:password@localhost:5432/db?sslmode=disable"
      sqlite:
        driver: sqlite
        dsn: ":memory:"
  • to retrieve the postgres auxiliary database connection, inject the DatabasePool and use Auxiliary("postgres")
  • to retrieve the sqlite auxiliary database connection, inject the DatabasePool and use Auxiliary("sqlite")
Migrations

This module provides the possibility to run your DB schemas migrations, using Goose under the hood.

First, configure the path for your migration files:

# ./configs/config.yaml
modules:
  sql:
    migrations: db/migrations

You can then create a migration file in this path.

For example, db/migrations/00001_create_foo_table.sql:

-- +goose Up
CREATE TABLE foo (
    id  INTEGER NOT NULL PRIMARY KEY,
    bar VARCHAR(255)
);

-- +goose Down
DROP TABLE IF EXISTS foo;

You can then run the migrations with RunFxSQLMigration, by specifying a migration command:

package main

import (
	"database/sql"

	"github.com/ankorstore/yokai/fxconfig"
	"github.com/ankorstore/yokai/fxlog"
	"github.com/ankorstore/yokai/fxsql"
	"github.com/ankorstore/yokai/fxtrace"
	"go.uber.org/fx"
)

func main() {
	fx.New(
		fxconfig.FxConfigModule,       // load the module dependencies
		fxlog.FxLogModule,
		fxtrace.FxTraceModule,
		fxsql.FxSQLModule,             // load the module
		fxsql.RunFxSQLMigration("up"), // run migration command "up"
	).Run()
}

Available migration commands:

  • up: migrate the DB to the most recent version available
  • up-by-one: migrate the DB up by 1
  • up-to VERSION: migrate the DB to a specific VERSION
  • down: roll back the version by 1
  • down-to VERSION: roll back to a specific VERSION
  • redo: re-run the latest migration
  • reset: roll back all migrations
  • status: dump the migration status for the current DB
  • version: print the current version of the database
  • create NAME [sql|go]: creates new migration file with the current timestamp
  • fix: apply sequential ordering to migrations
  • validate: check migration files without running them

If you want to automatically shut down your Fx application after the migrations, you can use RunFxSQLMigrationAndShutdown.

Seeds

This module provides the possibility to register several Seed implementations to seed the database.

This is done via:

  • the AsSQLSeed() function to register seeds
  • the RunFxSQLSeeds() function to execute seeds
package main

import (
	"context"
	"database/sql"

	"github.com/ankorstore/yokai/fxconfig"
	"github.com/ankorstore/yokai/fxlog"
	"github.com/ankorstore/yokai/fxsql"
	"github.com/ankorstore/yokai/fxtrace"
	"go.uber.org/fx"
)

// example SQL seed
type ExampleSeed struct{}

func NewExampleSeed() *ExampleSeed {
	return &ExampleSeed{}
}

func (s *ExampleSeed) Name() string {
	return "example-seed"
}

func (s *ExampleSeed) Run(ctx context.Context, db *sql.DB) error {
  _, err := db.ExecContext(ctx, "INSERT INTO foo (bar) VALUES (?)", "baz")

  return err
}

// usage
func main() {
	fx.New(
		fxconfig.FxConfigModule,          // load the module dependencies
		fxlog.FxLogModule,
		fxtrace.FxTraceModule,
		fxsql.FxSQLModule,                // load the module
		fxsql.AsSQLHook(NewExampleSeed),  // register the ExampleSeed
		fxsql.RunFxSQLSeeds(),            // run all registered seeds
	).Run()
}

You can also use AsSQLSeeds() to register several seeds at once.

You can also call for example RunFxSQLSeeds("example-seed", "other-seed") to run specific seeds, in provided order.

The dependencies of your seeds constructors will be autowired.

Hooks

This module provides the possibility to register several Hook implementations to extend the logic around the SQL operations.

This is done via the AsSQLHook() function:

package main

import (
	"context"

	"github.com/ankorstore/yokai/fxconfig"
	"github.com/ankorstore/yokai/fxlog"
	"github.com/ankorstore/yokai/fxsql"
	"github.com/ankorstore/yokai/fxtrace"
	"github.com/ankorstore/yokai/sql"
	"go.uber.org/fx"
)

// example SQL hook
type ExampleHook struct{}

func NewExampleHook() *ExampleHook {
	return &ExampleHook{}
}

func (h *ExampleHook) Before(ctx context.Context, event *sql.HookEvent) context.Context {
	// before SQL operation logic

	return ctx
}

func (h *ExampleHook) After(ctx context.Context, event *sql.HookEvent) {
	// after SQL operation logic
}

// usage
func main() {
	fx.New(
		fxconfig.FxConfigModule,         // load the module dependencies
		fxlog.FxLogModule,
		fxtrace.FxTraceModule,
		fxsql.FxSQLModule,               // load the module
		fxsql.AsSQLHook(NewExampleHook), // register the ExampleHook
	).Run()
}

You can also use AsSQLHooks() to register several hooks at once.

The dependencies of your hooks constructors will be autowired.

Testing

This module supports the sqlite driver, allowing the usage of an in-memory database, avoiding your tests to require a real database instance to run.

In your testing configuration:

# ./configs/config.test.yaml
modules:
  sql:
    driver: sqlite
    dsn: ":memory:"

In test mode, the module won't automatically close the database connection on shutdown, to allow database manipulation after the RunTest() execution.

You can find tests examples in this module own tests.

Documentation

Index

Constants

View Source
const ModuleName = "sql"

ModuleName is the module name.

View Source
const PrimaryDatabaseName = "primary"

Variables

FxSQLModule is the Fx SQL module.

Functions

func AsSQLHook

func AsSQLHook(constructor any) fx.Option

AsSQLHook registers a [sql.Hook] into Fx.

func AsSQLHooks

func AsSQLHooks(constructors ...any) fx.Option

AsSQLHooks registers a list of [sql.Hook] into Fx.

func AsSQLSeed

func AsSQLSeed(constructor any) fx.Option

AsSQLSeed registers a Seed into Fx.

func AsSQLSeeds

func AsSQLSeeds(constructors ...any) fx.Option

AsSQLSeeds registers a list of Seed into Fx.

func NewFxSQLPrimaryDatabase added in v1.4.0

func NewFxSQLPrimaryDatabase(p FxSQLPrimaryDatabaseParam) *sql.DB

NewFxSQLPrimaryDatabase returns the primary database.

func RunFxSQLMigration

func RunFxSQLMigration(command string, args ...string) fx.Option

RunFxSQLMigration runs database migrations with a context.

func RunFxSQLMigrationAndShutdown

func RunFxSQLMigrationAndShutdown(command string, args ...string) fx.Option

RunFxSQLMigrationAndShutdown runs database migrations with a context and shutdown.

func RunFxSQLSeeds

func RunFxSQLSeeds(names ...string) fx.Option

RunFxSQLSeeds runs database seeds with a context.

func RunFxSQLSeedsAndShutdown added in v1.3.0

func RunFxSQLSeedsAndShutdown(names ...string) fx.Option

RunFxSQLSeedsAndShutdown runs database seeds with a context and shutdown.

Types

type Database added in v1.4.0

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

func NewDatabase added in v1.4.0

func NewDatabase(name string, db *sql.DB) *Database

func (*Database) DB added in v1.4.0

func (d *Database) DB() *sql.DB

func (*Database) Name added in v1.4.0

func (d *Database) Name() string

type DatabasePool added in v1.4.0

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

func NewDatabasePool added in v1.4.0

func NewDatabasePool(primary *Database, auxiliaries ...*Database) *DatabasePool

func NewFxSQLDatabasePool added in v1.4.0

func NewFxSQLDatabasePool(p FxSQLDatabasePoolParam) (*DatabasePool, error)

NewFxSQLDatabasePool returns a DatabasePool instance.

func (*DatabasePool) Auxiliaries added in v1.4.0

func (p *DatabasePool) Auxiliaries() map[string]*Database

func (*DatabasePool) Auxiliary added in v1.4.0

func (p *DatabasePool) Auxiliary(name string) (*Database, error)

func (*DatabasePool) Primary added in v1.4.0

func (p *DatabasePool) Primary() *Database

type FxSQLDatabasePoolParam added in v1.4.0

type FxSQLDatabasePoolParam struct {
	fx.In
	LifeCycle fx.Lifecycle
	Config    *config.Config
	Logger    *log.Logger
	Hooks     []yokaisql.Hook `group:"sql-hooks"`
}

FxSQLDatabasePoolParam allows injection of the required dependencies in NewFxSQLDatabasePool.

type FxSQLMigratorParam

type FxSQLMigratorParam struct {
	fx.In
	Db     *sql.DB
	Config *config.Config
	Logger *log.Logger
}

FxSQLMigratorParam allows injection of the required dependencies in NewFxSQLMigrator.

type FxSQLPrimaryDatabaseParam added in v1.4.0

type FxSQLPrimaryDatabaseParam struct {
	fx.In
	Pool *DatabasePool
}

FxSQLPrimaryDatabaseParam allows injection of the required dependencies in [FxSQLPrimaryDatabase].

type FxSQLSeederParam

type FxSQLSeederParam struct {
	fx.In
	Db     *sql.DB
	Logger *log.Logger
	Seeds  []Seed `group:"sql-seeds"`
}

FxSQLSeederParam allows injection of the required dependencies in NewFxSQLSeeder.

type Migrator

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

Migrator is a database migrator based on Goose.

func NewFxSQLMigrator

func NewFxSQLMigrator(p FxSQLMigratorParam) *Migrator

NewFxSQLMigrator returns a Migrator instance.

func NewMigrator

func NewMigrator(db *sql.DB, logger *log.Logger) *Migrator

NewMigrator returns a new Migrator instance.

func (*Migrator) Run

func (m *Migrator) Run(ctx context.Context, dialect string, dir string, command string, args ...string) error

Run executes a database migration command.

type MigratorLogger added in v1.1.0

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

MigratorLogger is a logger compatible with Goose.

func NewMigratorLogger added in v1.1.0

func NewMigratorLogger(logger *log.Logger, stdout bool) *MigratorLogger

NewMigratorLogger returns a new MigratorLogger instance.

func (*MigratorLogger) Fatalf added in v1.1.0

func (l *MigratorLogger) Fatalf(format string, v ...interface{})

Fatalf logs with fatal level, and prints to stdout if configured to do so.

func (*MigratorLogger) Printf added in v1.1.0

func (l *MigratorLogger) Printf(format string, v ...interface{})

Printf logs with info level, and prints to stdout if configured to do so.

type Seed

type Seed interface {
	Name() string
	Run(ctx context.Context, db *sql.DB) error
}

Seed is the interface to implement to provide seeds.

type Seeder

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

Seeder is a database seeder.

func NewFxSQLSeeder

func NewFxSQLSeeder(p FxSQLSeederParam) *Seeder

NewFxSQLSeeder returns a Seeder instance.

func NewSeeder

func NewSeeder(db *sql.DB, logger *log.Logger, seeds ...Seed) *Seeder

NewSeeder returns a new Seeder instance.

func (*Seeder) Run

func (m *Seeder) Run(ctx context.Context, names ...string) error

Run executes the Seed list matching to the provided list of names, or all of them if the list of names is empty.

Jump to

Keyboard shortcuts

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