fxsql

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2024 License: MIT Imports: 12 Imported by: 1

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                                               # database driver (empty by default)
    dsn: "user:password@tcp(localhost:3306)/db?parseTime=true"  # 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"

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
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.

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 NewFxSQLDatabase

func NewFxSQLDatabase(p FxSQLDatabaseParam) (*sql.DB, error)

NewFxSQLDatabase returns a sql.DB instance.

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 shutodwn.

Types

type FxSQLDatabaseParam

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

FxSQLDatabaseParam allows injection of the required dependencies in NewFxSQLDatabase.

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 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
JackTT - Gopher 🇻🇳