Configuration¶
How to open a Den database, configure backends, and customize document behavior.
Opening a Database¶
OpenURL (recommended)¶
OpenURL takes a context.Context as its first argument, a URL-style DSN as the second, and zero or more functional options as the third (variadic) argument — see the Options table below. Backend packages must be imported for side-effect registration.
import (
"context"
"github.com/oliverandrich/den"
_ "github.com/oliverandrich/den/backend/sqlite"
_ "github.com/oliverandrich/den/backend/postgres"
)
ctx := context.Background()
// SQLite: relative path (three slashes)
db, err := den.OpenURL(ctx, "sqlite:///data.db")
// SQLite: absolute path (four slashes)
db, err := den.OpenURL(ctx, "sqlite:////var/lib/myapp/data.db")
// SQLite: in-memory
db, err := den.OpenURL(ctx, "sqlite://:memory:")
// PostgreSQL
db, err := den.OpenURL(ctx, "postgres://user:pass@localhost:5432/mydb")
// PostgreSQL (alias scheme)
db, err := den.OpenURL(ctx, "postgresql://user:pass@localhost/mydb")
Important: Backend packages register themselves via
init(). You must import the backend package even if you don't reference it directly -- use the blank identifier_.
Options¶
OpenURL accepts functional options:
| Option | Package | Description |
|---|---|---|
den.WithTypes(types...) |
den |
Register the listed document types during Open instead of a separate Register call. Zero-value struct pointers, e.g. den.WithTypes(&Product{}, &Order{}) |
den.WithStorage(s) |
den |
Install a Storage for documents carrying document.Attachment fields |
Struct-tag validation (validate:"...") runs automatically on every insert and update — no option required. See Validation.
DSN Formats¶
| Backend | Scheme | Format | Example |
|---|---|---|---|
| SQLite (relative) | sqlite |
sqlite:///relative/path.db |
sqlite:///data/myapp.db |
| SQLite (absolute) | sqlite |
sqlite:////absolute/path.db |
sqlite:////var/lib/myapp/data.db |
| SQLite (memory) | sqlite |
sqlite://:memory: |
sqlite://:memory: |
| PostgreSQL | postgres |
postgres://user:pass@host:port/dbname |
postgres://admin:secret@localhost:5432/myapp |
| PostgreSQL | postgresql |
postgresql://user:pass@host:port/dbname |
postgresql://admin:secret@db.example.com/myapp |
Registering Document Types¶
All document types must be registered before use. Registration creates the collection table and indexes.
Registration performs:
- Reflection-based analysis of the struct (fields, types, tags)
- Collection table creation (or verification if it already exists)
- Index creation based on
denstruct tags (additive -- new indexes are created, existing ones are kept)
DenSettings¶
Document types can customize their behavior by implementing the DenSettable interface:
Settings Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
CollectionName |
string |
lowercase struct name | Override the auto-derived collection name |
UseRevision |
bool |
false |
Enable optimistic concurrency control via _rev field |
Indexes |
[]IndexDefinition |
nil |
Additional indexes (for compound indexes not expressible via struct tags) |
Each IndexDefinition has Name string, Fields []string, and Unique bool — set Unique: true for compound unique indexes that struct tags can't express.
Example¶
type Product struct {
document.Base
Name string `json:"name" den:"index"`
Category string `json:"category" den:"index"`
Price float64 `json:"price" den:"index"`
}
func (p Product) DenSettings() den.Settings {
return den.Settings{
CollectionName: "products", // override: default would be "product"
UseRevision: true, // enable optimistic concurrency
Indexes: []den.IndexDefinition{
{
Name: "idx_category_price",
Fields: []string{"category", "price"}, // compound index
},
},
}
}
Collection Naming¶
By default, Den derives the collection name from the struct name:
- Lowercase, no pluralization
ProductbecomesproductBlogPostbecomesblogpost
Override via DenSettings().CollectionName:
Index Definition¶
Indexes can be defined in two ways:
Via Struct Tags¶
type Product struct {
document.Base
Name string `json:"name" den:"index"` // secondary index
SKU string `json:"sku" den:"unique"` // unique index
Body string `json:"body" den:"fts"` // full-text search index
}
Via Settings (compound indexes)¶
func (p Product) DenSettings() den.Settings {
return den.Settings{
Indexes: []den.IndexDefinition{
{Name: "idx_category_price", Fields: []string{"category", "price"}},
},
}
}
Both approaches are additive. Struct tag indexes and Settings indexes are created together during registration.