feat(03-03): add typed path params and per-plugin rollback

Compile regex and enum constraints at route registration so malformed and unknown IDs share a 404, and named rollback errors isolate one plugin's history.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-09-17 20:19:59 +02:00
parent a9c3e7690f
commit 8e3bf266d8
10 changed files with 354 additions and 58 deletions

View File

@@ -1,6 +1,7 @@
package lagoon
import (
"errors"
"fmt"
"strings"
"unicode"
@@ -13,6 +14,13 @@ import (
const historyTablePrefix = "summer_migrations_"
var (
// ErrUnknownPlugin is returned when migrate:rollback names a plugin that is not activated.
ErrUnknownPlugin = errors.New("lagoon: plugin is not activated")
// ErrNoMigrations is returned when there is no plugin migration set to roll back.
ErrNoMigrations = errors.New("lagoon: no plugin migrations to roll back")
)
// HistoryTableName returns the isolated gormigrate table for pluginID.
func HistoryTableName(pluginID string) (string, error) {
if err := validatePluginID(pluginID); err != nil {
@@ -83,26 +91,30 @@ func RollbackLast(gdb *gorm.DB, plugins []party.Plugin, pluginID string) error {
pluginID = lastMigrationPlugin(plugins)
}
if pluginID == "" {
return fmt.Errorf("lagoon: no plugin migrations to roll back")
return ErrNoMigrations
}
var target party.Plugin
for _, p := range plugins {
if p.ID() != pluginID {
continue
if p.ID() == pluginID {
target = p
break
}
hm, ok := p.(pact.HasMigrations)
if !ok {
return fmt.Errorf("lagoon: plugin %q has no migrations", pluginID)
}
m, err := migrator(gdb, p.ID(), hm.Migrations())
if err != nil {
return err
}
if err := m.RollbackLast(); err != nil {
return fmt.Errorf("lagoon: rollback %s: %w", pluginID, err)
}
return nil
}
return fmt.Errorf("lagoon: plugin %q is not activated", pluginID)
if target == nil {
return fmt.Errorf("%w: %q", ErrUnknownPlugin, pluginID)
}
hm, ok := target.(pact.HasMigrations)
if !ok || len(hm.Migrations()) == 0 {
return fmt.Errorf("%w: %q", ErrNoMigrations, pluginID)
}
m, err := migrator(gdb, target.ID(), hm.Migrations())
if err != nil {
return err
}
if err := m.RollbackLast(); err != nil {
return fmt.Errorf("lagoon: rollback %s: %w", pluginID, err)
}
return nil
}
func lastMigrationPlugin(plugins []party.Plugin) string {