feat(backend): establish gin sqlite service skeleton

This commit is contained in:
QiuSW
2026-07-25 22:29:56 +08:00
parent 84f2da3cf7
commit ab21219a07
32 changed files with 1854 additions and 42 deletions
@@ -0,0 +1,57 @@
package migration
import (
"context"
"database/sql"
"cmroubao/backend-api/migrations"
"github.com/pressly/goose/v3"
)
type Status struct {
Version int64
Applied bool
}
type Runner struct {
provider *goose.Provider
}
func New(db *sql.DB) (*Runner, error) {
provider, err := goose.NewProvider(
goose.DialectSQLite3,
db,
migrations.Files,
goose.WithDisableGlobalRegistry(true),
)
if err != nil {
return nil, err
}
return &Runner{provider: provider}, nil
}
func (r *Runner) Up(ctx context.Context) (int, error) {
results, err := r.provider.Up(ctx)
return len(results), err
}
func (r *Runner) Down(ctx context.Context) error {
_, err := r.provider.Down(ctx)
return err
}
func (r *Runner) Status(ctx context.Context) ([]Status, error) {
results, err := r.provider.Status(ctx)
if err != nil {
return nil, err
}
statuses := make([]Status, 0, len(results))
for _, result := range results {
statuses = append(statuses, Status{
Version: result.Source.Version,
Applied: result.State == goose.StateApplied,
})
}
return statuses, nil
}
@@ -0,0 +1,69 @@
package migration
import (
"context"
"path/filepath"
"testing"
"cmroubao/backend-api/internal/platform/database"
)
func TestRunnerSupportsUpStatusDownAndIdempotentUp(t *testing.T) {
db, err := database.Open(
context.Background(),
filepath.Join(t.TempDir(), "migration.db"),
)
if err != nil {
t.Fatalf("database.Open() error = %v", err)
}
t.Cleanup(func() { _ = db.Close() })
runner, err := New(db)
if err != nil {
t.Fatalf("New() error = %v", err)
}
applied, err := runner.Up(context.Background())
if err != nil {
t.Fatalf("Up() error = %v", err)
}
if applied != 1 {
t.Fatalf("Up() applied = %d, want 1", applied)
}
assertStatus(t, runner, true)
applied, err = runner.Up(context.Background())
if err != nil {
t.Fatalf("second Up() error = %v", err)
}
if applied != 0 {
t.Fatalf("second Up() applied = %d, want 0", applied)
}
if err := runner.Down(context.Background()); err != nil {
t.Fatalf("Down() error = %v", err)
}
assertStatus(t, runner, false)
applied, err = runner.Up(context.Background())
if err != nil {
t.Fatalf("final Up() error = %v", err)
}
if applied != 1 {
t.Fatalf("final Up() applied = %d, want 1", applied)
}
}
func assertStatus(t *testing.T, runner *Runner, applied bool) {
t.Helper()
statuses, err := runner.Status(context.Background())
if err != nil {
t.Fatalf("Status() error = %v", err)
}
if len(statuses) != 1 {
t.Fatalf("Status() count = %d, want 1", len(statuses))
}
if statuses[0].Version != 1 || statuses[0].Applied != applied {
t.Fatalf("Status() = %+v", statuses[0])
}
}