Database Oro
Use Oro ORM as Runa's SQL database driver
database/oro connects Oro ORM to Runa’s database capability. Runa manages lifecycle concerns such as driver registration, config loading, opening, closing, and commands. Oro handles ORM concerns such as models, queries, relations, transactions, schema sync, and SQL execution
Install
go get github.com/duxweb/runa/database github.com/duxweb/runa/database/oro
SQLite examples also need a concrete SQL driver:
go get modernc.org/sqlite
For MySQL, PostgreSQL, DSN formats, relations, and advanced queries, read the Oro docs:
Minimal setup
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("file:app.db"),
dboro.Dialect("sqlite"),
)),
))
if err := app.Freeze(context.Background()); err != nil {
panic(err)
}
db := database.Default().MustGet("default")
orm := dboro.From(db)
_ = orm
}
database.Provider opens connections during Boot, so call database.Default().MustGet(...) after Freeze or Run
Config file
# config/database.toml
[connections.default]
dsn = "file:app.db"
dialect = "sqlite"
max_open = 10
max_idle = 2
debug = true
Code:
app.Install(database.Provider(
database.RegisterDriver("default", dboro.Driver()),
))
Default config path is database.connections.<connection name>
Multiple connections
app.Install(database.Provider(
database.RegisterDriver("default", dboro.Driver(
dboro.Config("database.connections.default"),
)),
database.RegisterDriver("report", dboro.Driver(
dboro.Config("database.connections.report"),
)),
))
mainORM := dboro.From(database.Default().MustGet("default"))
reportORM := dboro.From(database.Default().MustGet("report"))
Define an Oro model
import oro "github.com/duxweb/oro"
type User struct {
oro.Model
Name string
Email string
Status int
}
func (User) Define(s *oro.SchemaBuilder) {
s.Table("users")
s.Field("Name").String().Size(120)
s.Field("Email").String().Size(180).Unique()
s.Field("Status").Int()
}
Model fields, indexes, relations, and soft deletes are Oro ORM features. See the Oro docs for details
Register models and sync schema
orm := dboro.From(database.Default().MustGet("default"))
if err := orm.Register(User{}); err != nil {
panic(err)
}
if err := orm.Sync(context.Background()); err != nil {
panic(err)
}
Sync is useful for development and prototypes. In production, decide based on your migration policy
Basic queries
ctx := context.Background()
orm := dboro.From(database.Default().MustGet("default"))
created, err := orm.Use[User]().Create(ctx, &User{Name: "Runa", Email: "hi@example.com"})
if err != nil {
return err
}
found, err := orm.Use[User]().Where("Email", "hi@example.com").First(ctx)
items, err := orm.Use[User]().Where("Status", 1).OrderByDesc("ID").Limit(20).Get(ctx)
_ = created
_ = found
_ = items
Use in HTTP handlers
route.Default().Get("/users", func(ctx *route.Context) error {
orm := dboro.From(database.Default().MustGet("default"))
users, err := orm.Use[User]().Limit(20).Get(ctx.Context())
if err != nil {
return err
}
return ctx.JSON(users)
})
In real applications, prefer injecting orm into services instead of reading it in every handler. The direct form keeps the example short
Standalone driver usage
driver := dboro.Driver(
dboro.DSN(":memory:"),
dboro.Dialect("sqlite"),
)
runtime, err := driver.Open(context.Background(), database.Config{Name: "default"})
if err != nil {
panic(err)
}
defer runtime.Close(context.Background())
orm := dboro.From(runtime)
Use this for tests, scripts, or one-off jobs. Application services should usually use database.Provider
Commands
database.Provider registers database commands:
go run . database:list
go run . database:ping
Options
| Option | Description |
|---|---|
dboro.DSN(value) |
Set database DSN |
dboro.Dialect(name) |
Set dialect, commonly sqlite, mysql, or postgres |
dboro.Config(path) |
Read config from a custom path |
dboro.MaxOpen(value) |
Max open connections |
dboro.MaxIdle(value) |
Max idle connections |
dboro.MaxLifetime(duration) |
Connection max lifetime |
dboro.Debug(true) |
Enable SQL debug logs |
dboro.Logger(name) |
Set Runa log channel, default orm |
dboro.Location(loc) |
Set the timezone used by Oro, defaulting to the application timezone |
dboro.Meta(key, value) |
Attach runtime metadata |
Timezone
The Oro driver passes Runa’s application timezone to Oro config by default. After setting runa.Timezone("Asia/Shanghai") or timezone in config/app.toml, the Oro driver uses the same timezone.
If one connection needs a separate timezone, pass it explicitly:
dboro.Driver(
dboro.Location(time.UTC),
)
Common mistakes
oro database default dsn is requiredmeans no DSN was provided by code or configdatabase default is not openusually means you read the registry beforeFreezedboro.From(db)returns nil when the database was not opened by the Oro driver- Runa does not replace Oro docs. Runa only connects Oro to the application lifecycle