Help us shape the future of Go! Take the 2026 Go Developer Survey

ormconnector

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 16 Imported by: 1

README

ormconnector

Wires the Lemmego ORM into the application lifecycle.

Usage

Register it like any other provider, in bootstrap/providers.go:

func LoadProviders() []app.Provider {
    return []app.Provider{
        &fs.Provider{},
        &session.Provider{},
        &ormconnector.Provider{},
        // ...
    }
}

Then reach the connection from a handler or service:

db := app.Get[*orm.DB](a)          // or ormconnector.Get(a)
users, err := db.Model[User]().Where(orm.Eq("active", true)).All(ctx)

It reads the same sql configuration tree gormconnector reads, so swapping connectors needs no configuration changes.

Running alongside GPA

Set UseGPA to also register a gpaorm provider, so existing code written against gpa.Repository[T] keeps working while it migrates:

&ormconnector.Provider{UseGPA: true}
Options
Field Meaning
UseGPA also register a gpaorm provider as the GPA default
Connection pick a named connection instead of the configured default
Config supply a gpa.Config directly, bypassing the config tree

Driver and DSN parity with migrations

The DSN is built by the migration module's DataSource, and the driver names are the migration module's constants (sqlite, mysql, postgres). That is deliberate: the ORM and lemmego migrate must resolve the same database from the same settings, and the ORM dialect is derived from the same driver name, so placeholders and quoting cannot drift apart.

DialectFor is asserted in tests to return a dialect whose Name() equals the driver it was given.

The supported set is therefore the same as the migration module's — SQLite, MySQL and PostgreSQL. SQL Server is absent from both. Aliases (sqlite3, postgresql, pgsql, mariadb) are normalised.

*sql.DB from SQLDB() can be handed straight to migration.Init, since both open the same database under the same driver name.

Register your driver

This module does not import a database/sql driver, so your application does:

import _ "github.com/lib/pq"              // postgres
import _ "github.com/glebarez/go-sqlite"  // sqlite
import _ "github.com/go-sql-driver/mysql" // mysql

lemmego new writes the one your project chose. If you are adding a database to an existing project, add it yourself — a missing driver fails when the connection opens, with database/sql's own message naming the forgotten import. That is at boot, on every environment, so it is not a mistake you can ship.

It used to import all three, so every project linked the two it had never configured; the pure-Go sqlite driver alone is twenty-nine packages of translated libc.

The orm:fields command

The provider contributes the descriptor generator as a CLI command:

go run ./cmd/app orm:fields ./internal/models
go run ./cmd/app orm:fields --type User,Post ./internal/models

It lives here rather than in the CLI module because generation must use the ORM's own naming rules, and /cli does not depend on the ORM. The framework's CommandProvider hook is exactly the seam for that.

MySQL connection parameters

The connector supplies parseTime=true and loc=UTC unless you set them yourself. Without parseTime the driver returns DATETIME columns as []byte and every model with a time.Time field fails to scan with "unsupported Scan, storing driver.Value type []uint8 into type *time.Time" — a confusing error a long way from its cause. loc=UTC matches the UTC the ORM stamps automatic timestamps in. An explicitly configured value is always respected.

Verification

cd ormconnector
go build ./... && go vet ./... && go test ./... && go test -race ./...

The test suite includes an end-to-end check that opens a database through the connector, builds the schema with the migration module, writes through the ORM, and reads the same rows back through the GPA adapter.

Integration tests against real servers

SQLite cannot exercise $N placeholders, RETURNING, or the driver error text the dialects parse. Those paths are covered by integration tests that run only when a DSN is configured, against an isolated database:

createdb lemmego_orm_test
mysql -u root -e "CREATE DATABASE lemmego_orm_test"

export ORM_POSTGRES_DSN="postgres://$USER@127.0.0.1:5432/lemmego_orm_test?sslmode=disable"
export ORM_MYSQL_DSN="root@tcp(127.0.0.1:3306)/lemmego_orm_test"

go test -run TestIntegration ./...

They are skipped when the variables are unset, so the default suite stays hermetic. The same assertions run against every configured backend, so a dialect that diverges shows up as a failure rather than a surprise in production.

Documentation

Overview

Package ormconnector wires the Lemmego ORM into the application lifecycle.

It opens the connection, publishes *orm.DB to the service container, and optionally registers a GPA provider so code written against gpa.Repository[T] keeps working.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Connect

func Connect(settings gpa.Config) (*orm.DB, error)

Connect opens a connection and wraps it in an ORM handle.

The DSN is built by the migration module so that the ORM and `lemmego migrate` always resolve the same database from the same settings.

func ConnectWith added in v0.3.0

func ConnectWith(settings gpa.Config, open string) (*orm.DB, error)

ConnectWith opens the connection through a named database/sql driver, rather than the one the dialect is named after.

For an instrumented driver. A wrapper is registered under a name of its own — sql.Register panics on a duplicate, so it cannot take "postgres" — and Connect opens the canonical name, so there was no way to reach one. The dialect still comes from the configured driver, which is what keeps `lemmego migrate` and the ORM generating the same SQL.

sql.Register("postgres-observed", observe.Wrap(&pq.Driver{}))
&ormconnector.Provider{Driver: "postgres-observed"}

An empty name means the canonical one, so this is Connect.

func DialectFor

func DialectFor(driver string) (orm.Dialect, error)

DialectFor maps a driver name onto an ORM dialect. The names match those the migration module uses, which is what keeps the two in step.

func Get

func Get(a app.App) *orm.DB

Get returns the ORM handle from the service container.

func SupportedDrivers

func SupportedDrivers() []string

SupportedDrivers lists the drivers the connector can open. It is deliberately the same set the migration module supports; SQL Server is absent from both.

Types

type Provider

type Provider struct {
	// UseGPA additionally registers a gpaorm provider, so repositories
	// resolved through gpa.MustGet keep working while code migrates over.
	UseGPA bool

	// Connection selects a named connection from the sql config tree.
	// Empty means the configured default.
	Connection string

	// Config overrides the configuration read from the app when set.
	Config gpa.Config

	// Driver is the registered database/sql driver name to open, when it is
	// not the one the dialect is named after.
	//
	// For an instrumented driver — see ConnectWith. The dialect still comes
	// from configuration, so `lemmego migrate` and the ORM stay in step.
	Driver string
	// contains filtered or unexported fields
}

Provider connects the ORM during application bootstrap.

func (*Provider) AddCommands

func (p *Provider) AddCommands() []app.Command

AddCommands contributes the descriptor generator as a CLI command, so the framework gains `orm:fields` without the CLI module needing to depend on the ORM.

func (*Provider) DB

func (p *Provider) DB() *orm.DB

DB returns the ORM handle, once Provide has run.

func (*Provider) Dialect added in v0.1.3

func (p *Provider) Dialect() db.Dialect

Dialect reports the SQL flavour of the open connection, completing db.Connection along with Name.

func (*Provider) Name added in v0.1.3

func (p *Provider) Name() string

Name reports which sql.connections key this connection was built from.

func (*Provider) Provide

func (p *Provider) Provide(a app.App) error

Provide opens the connection and registers it with the application.

func (*Provider) SQLDB

func (p *Provider) SQLDB() *sql.DB

SQLDB returns the underlying connection, which is what the migration module takes. It is also half of db.Connection.

func (*Provider) Shutdown

func (p *Provider) Shutdown(ctx context.Context) error

Shutdown closes the connection.

Jump to

Keyboard shortcuts

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