Grove

Plugin System

Extend Grove with plugins for audit logging, metrics, and custom behavior.

Grove's plugin system lets you extend the ORM with custom behavior at lifecycle boundaries. Plugins are simpler than hooks — they respond to high-level events rather than intercepting individual queries.

Base Interface

Every plugin must implement the Plugin interface:

import "github.com/xraph/grove/plugin"

type Plugin interface {
    Name() string
}

Lifecycle Hooks

Plugins opt into events by implementing additional interfaces:

Model Events

type AfterRegisterModel interface {
    OnModelRegistered(ctx context.Context, table *schema.Table)
}

Connection Events

type AfterConnect interface {
    OnConnected(ctx context.Context, db *grove.DB)
}

type BeforeClose interface {
    OnClosing(ctx context.Context, db *grove.DB) error
}

Migration Events

type AfterMigrate interface {
    OnMigrated(ctx context.Context, migrations []migrate.AppliedMigration)
}

Registering Plugins

// Step 1: Create and connect the driver
pgdb := pgdriver.New()
pgdb.Open(ctx, "postgres://localhost:5432/mydb", driver.WithPoolSize(20))

// Step 2: Open grove.DB with plugins
db, _ := grove.Open(pgdb,
    grove.WithPlugin(&MyAuditPlugin{}),
    grove.WithPlugin(&MyMetricsPlugin{}),
)

Type-Assertion Discovery

The plugin registry uses type assertions to discover which events each plugin handles. Implement only the interfaces you need:

type MyPlugin struct{}

func (p *MyPlugin) Name() string { return "my-plugin" }

// Only implement OnConnected — other events are ignored
func (p *MyPlugin) OnConnected(ctx context.Context, db *grove.DB) {
    log.Printf("connected to database")
}

Built-in Plugins

Chronicle Audit Plugin

Emits database events to Chronicle for audit trails:

import "github.com/xraph/grove/audit"

auditPlugin := audit.New(chronicleClient)
db, _ := grove.Open(pgdb,
    grove.WithPlugin(auditPlugin),
)

Events emitted:

  • grove.query.select / grove.query.insert / grove.query.update / grove.query.delete
  • grove.migration.applied / grove.migration.rolled_back
  • grove.connection.opened / grove.connection.closed

Prometheus Metrics Plugin

Exports query performance metrics:

import "github.com/xraph/grove/observability"

metricsPlugin := observability.New()
db, _ := grove.Open(pgdb,
    grove.WithPlugin(metricsPlugin),
)

Metrics:

  • grove_queries_total — Total queries by operation and table
  • grove_query_duration_seconds — Query latency histogram
  • grove_connections_active — Active connection count
  • grove_migrations_total — Migration execution count

KV Store Plugin Compatibility

The KV module (grove/kv) uses the same grove/plugin package for plugin registration. The grove/hook package is shared between the ORM and KV store, so middleware written as hooks works seamlessly across both. See the KV Middleware Overview for KV-specific middleware patterns.

On this page