summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-09 20:33:31 +0300
committerPaul Buetow <paul@buetow.org>2026-05-09 20:33:31 +0300
commit914092f4d519aa7107439d48b882d149ddff1118 (patch)
tree1b7fc3963d7f80579c4ea39da6e6781e726527ed
parentcbaa2bf0137790c525c888e4e6363833a1d7cbc7 (diff)
t1: remove repository migration shim
-rw-r--r--internal/repository/schema.go (renamed from internal/repository/migrate.go)26
-rw-r--r--internal/repository/sqlite.go6
-rw-r--r--internal/repository/sqlite_test.go70
3 files changed, 74 insertions, 28 deletions
diff --git a/internal/repository/migrate.go b/internal/repository/schema.go
index 3c4702f..9ab8284 100644
--- a/internal/repository/migrate.go
+++ b/internal/repository/schema.go
@@ -5,7 +5,7 @@ import (
"fmt"
)
-// tablesSchema defines all CREATE TABLE statements.
+// tablesSchema defines all CREATE TABLE statements for a fresh database.
const tablesSchema = `
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -196,34 +196,14 @@ func enableForeignKeys(db *sql.DB) error {
return nil
}
-// addPodcastColumn ensures the sets table has the is_podcast column.
-// It safely ignores the error if the column already exists.
-func addPodcastColumn(db *sql.DB) error {
- _, err := db.Exec(`ALTER TABLE sets ADD COLUMN is_podcast INTEGER NOT NULL DEFAULT 0;`)
- if err != nil {
- // SQLite returns a generic error message for duplicate columns.
- if err.Error() == "duplicate column name: is_podcast" ||
- err.Error() == "SQL logic error: duplicate column name: is_podcast (1)" {
- return nil
- }
- return fmt.Errorf("add is_podcast column: %w", err)
- }
- return nil
-}
-
-// Migrate creates the database schema if it does not exist.
-func Migrate(db *sql.DB) error {
+// initializeSchema creates the database schema for a fresh database.
+func initializeSchema(db *sql.DB) error {
if err := enableForeignKeys(db); err != nil {
return err
}
if err := execSchema(db, "tables", tablesSchema); err != nil {
return err
}
- // Backward-compatibility: older databases may have a sets table
- // without the is_podcast column. Add it before creating the index.
- if err := addPodcastColumn(db); err != nil {
- return err
- }
if err := execSchema(db, "indexes", indexesSchema); err != nil {
return err
}
diff --git a/internal/repository/sqlite.go b/internal/repository/sqlite.go
index d324f8c..08a902c 100644
--- a/internal/repository/sqlite.go
+++ b/internal/repository/sqlite.go
@@ -14,10 +14,10 @@ type SQLite struct {
db *sql.DB
}
-// New creates a SQLite store from an existing *sql.DB after migrating the schema.
+// New creates a SQLite store from an existing *sql.DB after initializing the schema.
func New(db *sql.DB) (*SQLite, error) {
- if err := Migrate(db); err != nil {
- return nil, fmt.Errorf("migrate: %w", err)
+ if err := initializeSchema(db); err != nil {
+ return nil, fmt.Errorf("initialize schema: %w", err)
}
return &SQLite{db: db}, nil
}
diff --git a/internal/repository/sqlite_test.go b/internal/repository/sqlite_test.go
index fa15a80..eaf142f 100644
--- a/internal/repository/sqlite_test.go
+++ b/internal/repository/sqlite_test.go
@@ -1115,7 +1115,7 @@ func TestSQLite_OpenFailures(t *testing.T) {
}
})
- t.Run("closed db migrate failure", func(t *testing.T) {
+ t.Run("closed db schema initialization failure", func(t *testing.T) {
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("open: %v", err)
@@ -1123,7 +1123,73 @@ func TestSQLite_OpenFailures(t *testing.T) {
db.Close()
_, err = New(db)
if err == nil {
- t.Fatal("expected error when migrating closed db")
+ t.Fatal("expected error when initializing schema on closed db")
+ }
+ })
+}
+
+func TestSQLite_SchemaInitialization(t *testing.T) {
+ t.Run("fresh database includes podcast column and foreign keys", func(t *testing.T) {
+ s := newTestStore(t)
+ defer s.Close()
+
+ var isPodcastColumn int
+ rows, err := s.db.Query(`PRAGMA table_info(sets)`)
+ if err != nil {
+ t.Fatalf("table info: %v", err)
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var cid int
+ var name, typ string
+ var notNull int
+ var defaultValue sql.NullString
+ var pk int
+ if err := rows.Scan(&cid, &name, &typ, &notNull, &defaultValue, &pk); err != nil {
+ t.Fatalf("scan column: %v", err)
+ }
+ if name == "is_podcast" {
+ isPodcastColumn++
+ }
+ }
+ if err := rows.Err(); err != nil {
+ t.Fatalf("rows: %v", err)
+ }
+ if isPodcastColumn != 1 {
+ t.Fatalf("expected one is_podcast column, got %d", isPodcastColumn)
+ }
+
+ var foreignKeys int
+ if err := s.db.QueryRow(`PRAGMA foreign_keys`).Scan(&foreignKeys); err != nil {
+ t.Fatalf("foreign_keys pragma: %v", err)
+ }
+ if foreignKeys != 1 {
+ t.Fatalf("expected foreign keys enabled, got %d", foreignKeys)
+ }
+ })
+
+ t.Run("stale pre-podcast sets schema is not upgraded", func(t *testing.T) {
+ db, err := sql.Open("sqlite", ":memory:")
+ if err != nil {
+ t.Fatalf("open: %v", err)
+ }
+ defer db.Close()
+
+ _, err = db.Exec(`
+CREATE TABLE sets (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL,
+ root_path TEXT UNIQUE NOT NULL,
+ cover_thumbnail_path TEXT,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
+);`)
+ if err != nil {
+ t.Fatalf("create stale schema: %v", err)
+ }
+
+ _, err = New(db)
+ if err == nil {
+ t.Fatal("expected stale schema initialization to fail")
}
})
}