RRuna

Database

Manage multiple database runtimes through one registry

database registers database drivers, opens connections during startup, and releases them during shutdown. It only defines the runtime contract. Concrete SQL or Redis data sources are provided by driver modules.

Install

go get github.com/duxweb/runa/database

Common drivers are installed on demand:

go get github.com/duxweb/runa/database/oro
go get github.com/duxweb/runa/database/redis

database/oro is for SQL databases. database/redis brings a Redis client into the unified database lifecycle.

Connect to an application

package main

import (
    "context"

    "github.com/duxweb/runa"
    "github.com/duxweb/runa/database"
    dboro "github.com/duxweb/runa/database/oro"
    _ "modernc.org/sqlite"
)

func main() {
    app := runa.New()
    app.Install(database.Provider(
        database.RegisterDriver("default", dboro.Driver(
            dboro.DSN(":memory:"),
            dboro.Dialect("sqlite"),
        )),
    ))

    if err := app.Freeze(context.Background()); err != nil {
        panic(err)
    }

    db := database.Default().MustGet("default")
    _ = db
}

database.Provider() calls Registry.Open during Boot, so database connections open during application startup and are closed through Shutdown when DI closes.

Standalone New usage

registry := database.New()
registry.RegisterDriver("default", dboro.Driver(dboro.DSN(":memory:"), dboro.Dialect("sqlite")))

if err := registry.Open(context.Background(), nil); err != nil {
    panic(err)
}
defer registry.Close(context.Background())

db := registry.MustGet("default")
_ = db

Standalone usage requires calling Open and Close yourself.

Config

database itself does not scan a fixed [database] config table. Drivers read database.connections.<name> by default, or they can choose another path through their own Config(path) option.

# config/database.toml
[connections.default]
dsn = "file:app.db"
dialect = "sqlite"
max_open = 10
max_idle = 2
max_lifetime = "1h"
debug = true
app.Install(database.Provider(
    database.RegisterDriver("default", dboro.Driver()),
))

If you want full control over config structure, read runa.Config("database") in your business Provider and construct the driver yourself.

Oro driver

For complete model, query, and config examples, see Database Oro.

import dboro "github.com/duxweb/runa/database/oro"

driver := dboro.Driver(
    dboro.DSN("file:app.db"),
    dboro.Dialect("sqlite"),
    dboro.MaxOpen(20),
    dboro.Debug(true),
)

Get the native Oro object:

db := database.Default().MustGet("default")
orm := dboro.From(db)
_ = orm

In an HTTP handler, you can also use the default registry directly:

route.Default().Get("/users", func(ctx *route.Context) error {
    db := database.Default().MustGet("default")
    orm := dboro.From(db)
    _ = orm
    return ctx.JSON(runa.Map{"ok": true})
})

Redis driver

import dbredis "github.com/duxweb/runa/database/redis"

app.Install(database.Provider(
    database.RegisterDriver("cache", dbredis.Driver(
        dbredis.Addr("127.0.0.1:6379"),
        dbredis.DB(1),
    )),
))

Commands

After installing database.Provider(), these commands are registered:

go run . database:list
go run . database:ping default

Common mistakes

Installing database without a concrete driver

database manages database runtimes. You still need a driver such as database/oro or database/redis for actual connections.

Forgetting the underlying database driver

SQL drivers may require their own underlying driver import. Follow the selected driver documentation.

Reading a connection before Boot

Configure database connections through Provider options and config. Read them after the application is frozen or inside handlers, commands, and lifecycle code that runs after registration.

API quick reference

  • database.New() creates a standalone registry.
  • database.Provider(...) connects to the framework lifecycle.
  • database.Default() reads *database.Registry from default DI.
  • database.RegisterDriver(name, driver) registers a database driver.
  • registry.MustGet(name) gets an opened database runtime.
  • registry.Ping(ctx, name) checks a connection.
  • registry.Close(ctx) closes all databases.
Edit this page