feat(03-01): add shared postgres pool and plugin migrations
Open one pgx stdlib *sql.DB, hand it to GORM, and run per-plugin gormigrate sets with isolated history tables after an ICU pl-PL check. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"io/fs"
|
||||
|
||||
"git.golem15.com/golem15/summercms/bonfire"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
)
|
||||
|
||||
// HasCommands is implemented by plugins that register console commands.
|
||||
@@ -18,19 +19,24 @@ type HasConfig interface {
|
||||
ConfigFS() fs.FS
|
||||
}
|
||||
|
||||
// HasMigrations is implemented by plugins that ship an ordered gormigrate
|
||||
// set. The kernel runs each set in party.Activate order with a separate
|
||||
// history table per plugin ID.
|
||||
type HasMigrations interface {
|
||||
Migrations() []*gormigrate.Migration
|
||||
}
|
||||
|
||||
// OptionalMessage is a service an optional plugin may publish so other
|
||||
// plugins can integrate without importing that plugin's package.
|
||||
type OptionalMessage interface {
|
||||
Message() string
|
||||
}
|
||||
|
||||
// Future KERN-03 capability families are type-asserted when their first
|
||||
// consumer packages exist. Method payloads are not declared here so pact
|
||||
// does not import surf, lagoon, festival, or other packages that Phase 1
|
||||
// does not yet ship:
|
||||
// Future capability families are type-asserted when their first consumer
|
||||
// packages exist. Method payloads for HTTP/model surfaces are declared in
|
||||
// the phase that ships surf:
|
||||
//
|
||||
// HasModels
|
||||
// HasMigrations
|
||||
// HasRoutes
|
||||
// HasMiddleware
|
||||
// HasJobs
|
||||
@@ -42,5 +48,5 @@ type OptionalMessage interface {
|
||||
// HasMailTemplates
|
||||
// HasLang
|
||||
//
|
||||
// Phase 1 type-asserts only HasConfig (party, before Register) and
|
||||
// HasCommands (generated app main, after Boot).
|
||||
// The kernel type-asserts HasConfig (party, before Register), HasCommands
|
||||
// (generated app main, after Boot), and HasMigrations (lagoon migrate).
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing/fstest"
|
||||
|
||||
"git.golem15.com/golem15/summercms/bonfire"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
)
|
||||
|
||||
type configOnly struct{}
|
||||
@@ -27,14 +28,21 @@ type bothCaps struct {
|
||||
|
||||
type neither struct{}
|
||||
|
||||
func TestOptionalCapabilitiesDiscoveredByTypeAssertion(t *testing.T) {
|
||||
plugins := []any{configOnly{}, commandsOnly{}, bothCaps{}, neither{}, extraMessage{}}
|
||||
type migrationsOnly struct{}
|
||||
|
||||
var configs, commands, messages, none int
|
||||
func (migrationsOnly) Migrations() []*gormigrate.Migration {
|
||||
return []*gormigrate.Migration{{ID: "202609170001_create_users"}}
|
||||
}
|
||||
|
||||
func TestOptionalCapabilitiesDiscoveredByTypeAssertion(t *testing.T) {
|
||||
plugins := []any{configOnly{}, commandsOnly{}, bothCaps{}, neither{}, extraMessage{}, migrationsOnly{}}
|
||||
|
||||
var configs, commands, messages, migrations, none int
|
||||
for _, p := range plugins {
|
||||
_, hasCfg := p.(HasConfig)
|
||||
_, hasCmd := p.(HasCommands)
|
||||
_, hasMsg := p.(OptionalMessage)
|
||||
_, hasMig := p.(HasMigrations)
|
||||
if hasCfg {
|
||||
configs++
|
||||
}
|
||||
@@ -44,7 +52,10 @@ func TestOptionalCapabilitiesDiscoveredByTypeAssertion(t *testing.T) {
|
||||
if hasMsg {
|
||||
messages++
|
||||
}
|
||||
if !hasCfg && !hasCmd && !hasMsg {
|
||||
if hasMig {
|
||||
migrations++
|
||||
}
|
||||
if !hasCfg && !hasCmd && !hasMsg && !hasMig {
|
||||
none++
|
||||
}
|
||||
}
|
||||
@@ -57,11 +68,22 @@ func TestOptionalCapabilitiesDiscoveredByTypeAssertion(t *testing.T) {
|
||||
if messages != 1 {
|
||||
t.Fatalf("OptionalMessage count = %d, want 1", messages)
|
||||
}
|
||||
if migrations != 1 {
|
||||
t.Fatalf("HasMigrations count = %d, want 1", migrations)
|
||||
}
|
||||
if none != 1 {
|
||||
t.Fatalf("neither count = %d, want 1", none)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasMigrationsReturnsOrderedSet(t *testing.T) {
|
||||
var p HasMigrations = migrationsOnly{}
|
||||
set := p.Migrations()
|
||||
if len(set) != 1 || set[0].ID != "202609170001_create_users" {
|
||||
t.Fatalf("Migrations = %+v", set)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasConfigReturnsFilesystem(t *testing.T) {
|
||||
var p HasConfig = configOnly{}
|
||||
fsys := p.ConfigFS()
|
||||
|
||||
Reference in New Issue
Block a user