- 0001_init.sql: projax.items + projax.item_links tables with indices, partial-unique root slug, updated_at trigger, schema grants to the application role. - 0002_path_trigger.sql: BEFORE-write trigger maintains items.path via recursive parent walk; rejects cycles and structural-rule violations (areas at root, projects not at root). AFTER trigger rewrites descendant paths on slug rename or re-parent. - 0003_seed_areas.sql: dev, sports, home, work, health, finances, social. - db/migrate.go: embed.FS-backed sequential runner. - db/migrate_test.go: integration suite covering idempotency, nest, rename propagation, re-parent propagation, cycle rejection, and structural rules. Skips when no DB env var is set. Also ignores .m/events.log and .m/locks (per-worker scratch).
47 lines
1.1 KiB
Go
47 lines
1.1 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"embed"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
//go:embed migrations/*.sql
|
|
var migrations embed.FS
|
|
|
|
// EmbeddedMigrations exposes the raw embedded FS for tests.
|
|
var EmbeddedMigrations = migrations
|
|
|
|
// ApplyMigrations runs every embedded migration file in lexicographic order.
|
|
// Idempotent because each migration is written as CREATE ... IF NOT EXISTS /
|
|
// CREATE OR REPLACE / ON CONFLICT DO NOTHING.
|
|
func ApplyMigrations(ctx context.Context, pool *pgxpool.Pool) error {
|
|
entries, err := migrations.ReadDir("migrations")
|
|
if err != nil {
|
|
return fmt.Errorf("read migrations dir: %w", err)
|
|
}
|
|
names := make([]string, 0, len(entries))
|
|
for _, e := range entries {
|
|
if e.IsDir() || !strings.HasSuffix(e.Name(), ".sql") {
|
|
continue
|
|
}
|
|
names = append(names, e.Name())
|
|
}
|
|
sort.Strings(names)
|
|
|
|
for _, name := range names {
|
|
body, err := migrations.ReadFile("migrations/" + name)
|
|
if err != nil {
|
|
return fmt.Errorf("read %s: %w", name, err)
|
|
}
|
|
if _, err := pool.Exec(ctx, string(body)); err != nil {
|
|
return fmt.Errorf("apply %s: %w", name, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|