Documentation
¶
Overview ¶
Package extension adapts Grove as a Forge extension.
Index ¶
- Constants
- type Config
- type DBManager
- func (m *DBManager) Add(name string, db *grove.DB)
- func (m *DBManager) All() map[string]*grove.DB
- func (m *DBManager) Close() error
- func (m *DBManager) Default() (*grove.DB, error)
- func (m *DBManager) DefaultName() string
- func (m *DBManager) Get(name string) (*grove.DB, error)
- func (m *DBManager) Len() int
- func (m *DBManager) SetDefault(name string) error
- type DatabaseConfig
- type DriverFactory
- type ExtOption
- func WithBasePath(path string) ExtOption
- func WithCRDT(plugin *crdt.Plugin, scope ...hook.Scope) ExtOption
- func WithCRDTDatabase(dbName string) ExtOption
- func WithCentralMigrations() ExtOption
- func WithDSN(driver, dsn string) ExtOption
- func WithDatabase(name string, drv grove.GroveDriver) ExtOption
- func WithDatabaseDSN(name, driver, dsn string) ExtOption
- func WithDefaultDatabase(name string) ExtOption
- func WithDisableMigrate() ExtOption
- func WithDisableRoutes() ExtOption
- func WithDriver(drv grove.GroveDriver) ExtOption
- func WithDriverFactory(name string, factory DriverFactory) ExtOption
- func WithHook(h any, scope ...hook.Scope) ExtOption
- func WithHookFor(dbName string, h any, scope ...hook.Scope) ExtOption
- func WithLockTimeout(d time.Duration) ExtOption
- func WithMigrations(groups ...*migrate.Group) ExtOption
- func WithMigrationsFor(dbName string, groups ...*migrate.Group) ExtOption
- func WithRequireConfig(require bool) ExtOption
- func WithSyncController(opts ...crdt.SyncControllerOption) ExtOption
- func WithSyncer(syncer *crdt.Syncer) ExtOption
- type Extension
- func (e *Extension) DB() *grove.DB
- func (e *Extension) Health(_ context.Context) error
- func (e *Extension) Init(_ forge.App) error
- func (e *Extension) Manager() *DBManager
- func (e *Extension) Migrate(ctx context.Context) (*forge.MigrationResult, error)
- func (e *Extension) MigrationGroups() []*migrate.Group
- func (e *Extension) MigrationStatus(ctx context.Context) ([]*forge.MigrationGroupInfo, error)
- func (e *Extension) Register(fapp forge.App) error
- func (e *Extension) Rollback(ctx context.Context) (*forge.MigrationResult, error)
- func (e *Extension) Start(ctx context.Context) error
- func (e *Extension) Stop(_ context.Context) error
- type MigrationRegistry
- func (r *MigrationRegistry) Contribute(dbKey string, drv grove.GroveDriver, groups ...*migrate.Group)
- func (r *MigrationRegistry) RollbackAll(ctx context.Context) (*forge.MigrationResult, error)
- func (r *MigrationRegistry) RunAll(ctx context.Context) (*forge.MigrationResult, error)
- func (r *MigrationRegistry) StatusAll(ctx context.Context) ([]*forge.MigrationGroupInfo, error)
- type RegistryOption
Constants ¶
const ExtensionDescription = "Polyglot Go ORM with native query syntax per database"
ExtensionDescription is the human-readable description.
const ExtensionName = "grove"
ExtensionName is the name registered with Forge.
const ExtensionVersion = "0.1.0"
ExtensionVersion is the semantic version.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Driver name: "postgres", "sqlite", "mysql", "mongodb", "turso", "clickhouse".
Driver string `json:"driver" mapstructure:"driver" yaml:"driver"`
// DSN is the data source name / connection string.
DSN string `json:"dsn" mapstructure:"dsn" yaml:"dsn"`
// Databases defines additional named database connections.
// When set, each entry creates a separate grove.DB registered in DI.
Databases []DatabaseConfig `json:"databases" mapstructure:"databases" yaml:"databases"`
// Default is the name of the default database when using multi-DB.
// If empty, the first entry in Databases is the default.
Default string `json:"default" mapstructure:"default" yaml:"default"`
// DisableRoutes skips CRDT sync route registration.
DisableRoutes bool `json:"disable_routes" mapstructure:"disable_routes" yaml:"disable_routes"`
// DisableMigrate disables automatic migration execution.
DisableMigrate bool `json:"disable_migrate" mapstructure:"disable_migrate" yaml:"disable_migrate"`
// BasePath is the URL prefix for CRDT sync routes (default: "/sync").
BasePath string `json:"base_path" mapstructure:"base_path" yaml:"base_path"`
// LockTimeout caps how long migrations wait for the database migration
// lock. 0 uses migrate.DefaultLockTimeout. Negative means wait until the
// context deadline (maps to migrate's 0).
LockTimeout time.Duration `json:"lock_timeout" mapstructure:"lock_timeout" yaml:"lock_timeout"`
// CentralMigrations opts this extension into the shared MigrationRegistry
// instead of running its own per-extension migration pass. When true, the
// extension contributes its groups to the registry during Register and
// Migrate/Rollback become no-ops (the registry's RunAll trigger owns
// execution). Default false — existing apps are unaffected.
CentralMigrations bool `json:"central_migrations" mapstructure:"central_migrations" yaml:"central_migrations"`
// RequireConfig requires config to be present in YAML files.
// If true and no config is found, Register returns an error.
RequireConfig bool `json:"-" yaml:"-"`
}
Config holds the Grove extension configuration. Fields can be set programmatically via ExtOption functions or loaded from YAML configuration files (under "extensions.grove" or "grove" keys).
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default configuration. Driver and DSN are empty — callers must provide them via WithDriver(), WithDSN(), or YAML configuration.
type DBManager ¶
type DBManager struct {
// contains filtered or unexported fields
}
DBManager manages multiple named grove.DB instances. It provides named access, a default database, and bulk close.
func (*DBManager) Add ¶
Add registers a named database. The first database added becomes the default unless SetDefault is called explicitly.
func (*DBManager) Close ¶
Close closes all registered databases and returns the first error encountered.
func (*DBManager) DefaultName ¶
DefaultName returns the name of the default database.
func (*DBManager) SetDefault ¶
SetDefault sets the default database by name. Returns an error if the name is not registered.
type DatabaseConfig ¶
type DatabaseConfig struct {
// Name is the unique identifier for this database.
Name string `json:"name" mapstructure:"name" yaml:"name"`
// Driver name: "postgres", "sqlite", "mysql", "mongodb", "turso", "clickhouse".
Driver string `json:"driver" mapstructure:"driver" yaml:"driver"`
// DSN is the data source name / connection string.
DSN string `json:"dsn" mapstructure:"dsn" yaml:"dsn"`
}
DatabaseConfig defines a single named database connection.
type DriverFactory ¶
DriverFactory builds a fully-opened grove driver from a DSN. Used by WithDriverFactory to let callers override the registry-based factory for a given driver name (e.g. inject MongoDB pool tuning, postgres pool sizing, etc.) without baking driver-specific imports into the extension package.
type ExtOption ¶
type ExtOption func(*Extension)
ExtOption is a functional option for the Forge extension.
func WithBasePath ¶
WithBasePath sets the URL prefix for CRDT sync routes.
func WithCRDT ¶
WithCRDT enables the CRDT plugin and registers the sync controller. The plugin's hooks are automatically added to the Grove DB, and the SyncController is registered with the Forge router for sync endpoints.
In multi-DB mode, CRDT hooks are applied to the default database unless WithCRDTDatabase is also used.
Example:
ext := extension.New(
extension.WithDriver(pgdb),
extension.WithCRDT(crdtPlugin, hook.Scope{Tables: []string{"documents"}}),
)
func WithCRDTDatabase ¶
WithCRDTDatabase attaches the CRDT plugin to a specific named database instead of the default. Requires WithCRDT and multi-DB mode.
func WithCentralMigrations ¶
func WithCentralMigrations() ExtOption
WithCentralMigrations opts this extension into central migration mode. Instead of running its own migration pass, the extension contributes its groups to the shared MigrationRegistry. A single RunAll trigger (registered by the first contributing extension) runs them all in one ordered pass.
This option is OPT-IN and defaults off. It should remain off until forge CentralMigrator (Phase 3) support is in place. On forge ≤ 1.7.1 it is effectively unsafe: the central migration trigger fires on PhaseAfterRegister, which on that version runs after all extensions have started — schema is NOT guaranteed before Start, making this worse than the default per-extension path for any extension that seeds or queries during Start. Additionally, central rollback is not available until the forge CentralMigrator split-phase lands; calling Rollback while in central mode returns an explicit error.
func WithDSN ¶
WithDSN sets the driver name and DSN for the extension. The driver will be created from the registry during Register(). If WithDriver() is also set, it takes precedence.
func WithDatabase ¶
func WithDatabase(name string, drv grove.GroveDriver) ExtOption
WithDatabase adds a named database with a pre-configured driver. Multiple calls create multiple named databases.
Example:
ext := extension.New(
extension.WithDatabase("primary", pgDriver),
extension.WithDatabase("analytics", chDriver),
extension.WithDefaultDatabase("primary"),
)
func WithDatabaseDSN ¶
WithDatabaseDSN adds a named database using a driver name and DSN. The driver will be created from the registry during Register().
Example:
ext := extension.New(
extension.WithDatabaseDSN("primary", "postgres", "postgres://localhost/app"),
extension.WithDatabaseDSN("analytics", "clickhouse", "clickhouse://localhost/analytics"),
)
func WithDefaultDatabase ¶
WithDefaultDatabase sets which named database is the default. The default is used for backward-compatible DB() access and unnamed DI injection.
func WithDisableMigrate ¶
func WithDisableMigrate() ExtOption
WithDisableMigrate disables automatic migration execution.
func WithDisableRoutes ¶
func WithDisableRoutes() ExtOption
WithDisableRoutes disables CRDT sync route registration.
func WithDriver ¶
func WithDriver(drv grove.GroveDriver) ExtOption
WithDriver sets a pre-configured database driver for the extension. When set, this takes precedence over YAML driver/dsn configuration.
func WithDriverFactory ¶
func WithDriverFactory(name string, factory DriverFactory) ExtOption
WithDriverFactory overrides the driver-construction step for one specific driver name. When the extension resolves a driver via YAML config or WithDSN / WithDatabaseDSN, it consults the override map first; only unknown names fall through to the global registry.
Use this to inject driver-specific tuning (mongo pool size, postgres pool sizing, etc.) without dragging the driver package into grove/extension. Multiple calls merge; later registrations win on the same driver name.
Example (twinos tuning the mongo driver's pool):
ext := extension.New(
extension.WithDSN("mongo", "mongodb://localhost:27017/twinos"),
extension.WithDriverFactory("mongo", func(ctx context.Context, dsn string) (grove.GroveDriver, error) {
m := mongodriver.New()
if err := m.Open(ctx, dsn,
mongodriver.WithMaxPoolSize(200),
mongodriver.WithMinPoolSize(10),
mongodriver.WithMaxConnecting(4),
); err != nil {
return nil, err
}
return m, nil
}),
)
func WithHookFor ¶
WithHookFor adds a hook scoped to a specific named database.
func WithLockTimeout ¶
WithLockTimeout sets how long migrations wait for the migration lock. 0 uses migrate.DefaultLockTimeout. Negative means wait until the context deadline.
func WithMigrations ¶
WithMigrations adds migration groups to the extension.
func WithMigrationsFor ¶
WithMigrationsFor adds migration groups for a specific named database.
func WithRequireConfig ¶
WithRequireConfig requires config to be present in YAML files. If true and no config is found, Register returns an error.
func WithSyncController ¶
func WithSyncController(opts ...crdt.SyncControllerOption) ExtOption
WithSyncController overrides the default sync controller options. These options configure the sync endpoints (poll interval, keep-alive, hooks).
Example:
ext := extension.New(
extension.WithDriver(pgdb),
extension.WithCRDT(crdtPlugin),
extension.WithSyncController(
crdt.WithStreamPollInterval(2 * time.Second),
crdt.WithStreamKeepAlive(30 * time.Second),
),
)
func WithSyncer ¶
WithSyncer configures the CRDT background syncer. Requires WithCRDT. The syncer is started in the extension's Start method and runs until the context is cancelled.
Example:
ext := extension.New(
extension.WithDriver(pgdb),
extension.WithCRDT(crdtPlugin),
extension.WithSyncer(syncer),
)
type Extension ¶
type Extension struct {
*forge.BaseExtension
// contains filtered or unexported fields
}
Extension adapts Grove as a Forge extension.
func (*Extension) Health ¶
Health implements forge.Extension.
func (*Extension) Init ¶
Init builds the DB and registers hooks. Can be called standalone outside Forge.
func (*Extension) Manager ¶
Manager returns the DBManager for multi-DB mode. Returns nil in single-DB mode.
func (*Extension) Migrate ¶
Migrate runs all pending migrations forward. In single-DB mode, runs migrations from e.groups. In multi-DB mode, runs migrations for each named database from e.dbMigrations.
func (*Extension) MigrationGroups ¶
MigrationGroups returns all registered migration groups (single-DB mode).
func (*Extension) MigrationStatus ¶
MigrationStatus returns the current state of all migrations grouped by their owning module/extension.
func (*Extension) Register ¶
Register implements forge.Extension.
func (*Extension) Rollback ¶
Rollback rolls back the last batch of applied migrations. In single-DB mode, rolls back from e.groups. In multi-DB mode, rolls back for each named database from e.dbMigrations.
func (*Extension) Start ¶
Start implements forge.Extension.
type MigrationRegistry ¶
type MigrationRegistry struct {
// contains filtered or unexported fields
}
MigrationRegistry collects migration groups contributed by every extension and runs them as a single ordered pass per database. Putting every group into one orchestrator lets grove's topological sort resolve cross-extension DependsOn declarations (which fail when each extension runs its own orchestrator), and collapses N per-extension lock cycles into one acquire/release per database.
func NewMigrationRegistry ¶
func NewMigrationRegistry(opts ...RegistryOption) *MigrationRegistry
NewMigrationRegistry creates an empty registry.
func (*MigrationRegistry) Contribute ¶
func (r *MigrationRegistry) Contribute(dbKey string, drv grove.GroveDriver, groups ...*migrate.Group)
Contribute adds migration groups for a database. dbKey "" is the default database. The first driver contributed for a dbKey wins; later contributions for the same dbKey append their groups (callers must contribute the same driver instance for a given database).
func (*MigrationRegistry) RollbackAll ¶
func (r *MigrationRegistry) RollbackAll(ctx context.Context) (*forge.MigrationResult, error)
RollbackAll rolls back the last batch per database, databases in reverse order.
func (*MigrationRegistry) RunAll ¶
func (r *MigrationRegistry) RunAll(ctx context.Context) (*forge.MigrationResult, error)
RunAll runs one ordered migration pass per contributed database.
func (*MigrationRegistry) StatusAll ¶
func (r *MigrationRegistry) StatusAll(ctx context.Context) ([]*forge.MigrationGroupInfo, error)
StatusAll returns migration status across all contributed databases.
type RegistryOption ¶
type RegistryOption func(*MigrationRegistry)
RegistryOption configures a MigrationRegistry.
func WithRegistryLockTimeout ¶
func WithRegistryLockTimeout(d time.Duration) RegistryOption
WithRegistryLockTimeout sets the lock-wait budget for every orchestrator the registry runs. 0 uses migrate.DefaultLockTimeout.