Move schema_migrations table creation into 000.sql #36

Open
clawbot wants to merge 5 commits from feature/migrations-table-schema-file into main
Collaborator

Summary

Moves the schema_migrations table definition from inline Go code into internal/database/schema/000.sql, so the migration tracking table schema lives alongside all other schema files.

closes #29

Changes

New file: internal/database/schema/000.sql

  • Contains the CREATE TABLE IF NOT EXISTS schema_migrations DDL
  • This is applied as a bootstrap step before the normal migration loop

Refactored: internal/database/database.go

  • Removed the inline CREATE TABLE IF NOT EXISTS schema_migrations SQL from both runMigrations and ApplyMigrations
  • Added bootstrapMigrationsTable() which:
    • Checks sqlite_master to see if the table already exists
    • If missing: reads and executes 000.sql to create it, then records version 000
    • If present (backwards compat with existing DBs created by old inline code): back-fills version 000 so the normal loop skips the bootstrap file
  • Deduplicated: both Database.runMigrations() and the exported ApplyMigrations() now delegate to a single applyMigrations() helper
  • Added logInfo/logDebug helpers to handle the optional logger (nil when called from ApplyMigrations in tests)

New file: internal/database/database_test.go

  • TestApplyMigrations_CreatesSchemaAndTables — verifies all migrations apply and all expected tables exist
  • TestApplyMigrations_Idempotent — verifies running migrations twice produces no errors or duplicates
  • TestBootstrapMigrationsTable_FreshDatabase — verifies bootstrap creates the table and records version 000
  • TestBootstrapMigrationsTable_ExistingTableBackwardsCompat — verifies existing DBs (from old inline-SQL code) get version 000 back-filled without data loss

Conflict note

PR #33 (for issue #28) is also modifying migration code. This PR is based on current main and the conflict will be resolved at merge time.

## Summary Moves the `schema_migrations` table definition from inline Go code into `internal/database/schema/000.sql`, so the migration tracking table schema lives alongside all other schema files. closes #29 ## Changes ### New file: `internal/database/schema/000.sql` - Contains the `CREATE TABLE IF NOT EXISTS schema_migrations` DDL - This is applied as a bootstrap step before the normal migration loop ### Refactored: `internal/database/database.go` - Removed the inline `CREATE TABLE IF NOT EXISTS schema_migrations` SQL from both `runMigrations` and `ApplyMigrations` - Added `bootstrapMigrationsTable()` which: - Checks `sqlite_master` to see if the table already exists - If missing: reads and executes `000.sql` to create it, then records version `000` - If present (backwards compat with existing DBs created by old inline code): back-fills version `000` so the normal loop skips the bootstrap file - Deduplicated: both `Database.runMigrations()` and the exported `ApplyMigrations()` now delegate to a single `applyMigrations()` helper - Added `logInfo`/`logDebug` helpers to handle the optional logger (nil when called from `ApplyMigrations` in tests) ### New file: `internal/database/database_test.go` - `TestApplyMigrations_CreatesSchemaAndTables` — verifies all migrations apply and all expected tables exist - `TestApplyMigrations_Idempotent` — verifies running migrations twice produces no errors or duplicates - `TestBootstrapMigrationsTable_FreshDatabase` — verifies bootstrap creates the table and records version 000 - `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` — verifies existing DBs (from old inline-SQL code) get version 000 back-filled without data loss ## Conflict note [PR #33](https://git.eeqj.de/sneak/pixa/pulls/33) (for [issue #28](https://git.eeqj.de/sneak/pixa/issues/28)) is also modifying migration code. This PR is based on current `main` and the conflict will be resolved at merge time.
clawbot added 1 commit 2026-03-17 09:57:22 +01:00
Move schema_migrations table creation from Go code into 000.sql
All checks were successful
check / check (push) Successful in 1m0s
5504495e0c
The schema_migrations table definition now lives in
internal/database/schema/000.sql instead of being hardcoded as an
inline SQL string in database.go. A bootstrap step checks
sqlite_master for the table and applies 000.sql when it is missing.
Existing databases that already have the table (created by older
inline code) get version 000 back-filled so the normal migration
loop skips the file.

Also deduplicates the migration logic: both the Database.runMigrations
method and the exported ApplyMigrations helper now delegate to a single
applyMigrations function.

Adds database_test.go with tests for fresh migration, idempotency,
bootstrap on a fresh DB, and backwards compatibility with legacy DBs.
clawbot added the needs-review label 2026-03-17 10:03:37 +01:00
clawbot reviewed 2026-03-17 10:25:02 +01:00
clawbot left a comment
Author
Collaborator

Review: PR #36 — Move schema_migrations table creation into 000.sql

Closes issue #29.


1. Policy Divergences

Policy Rule Status Notes
External refs pinned by hash No new external dependencies added
.golangci.yml unmodified Not touched
Makefile/Dockerfile/CI unmodified Not touched
Migration dir internal/db/migrations/ ⚠️ Pre-existing Repo uses internal/database/schema/ — established convention since 001.sql. This PR follows existing structure. Not introduced by this PR.
Pre-1.0.0: modify existing migrations Justified There is no existing .sql file containing the schema_migrations DDL — it was inline Go code. The issue explicitly requests creating a 000 file to hold this schema. This is a bootstrap file for the migration infrastructure itself, not a regular data migration. No policy violation.
go.sum integrity No dependency changes
No secrets committed Clean
make check non-destructive Tests use :memory: SQLite

2. Issue Requirements Checklist (#29)

  • "add migration schema table file"internal/database/schema/000.sql created containing CREATE TABLE IF NOT EXISTS schema_migrations DDL
  • "apply it if no migration version table exists"bootstrapMigrationsTable() checks sqlite_master and applies 000.sql when the table is missing
  • "schema goes in schema files, not in code" — Inline SQL removed from both runMigrations() and ApplyMigrations() in database.go

All requirements satisfied.


3. Code Quality Assessment

Correctness:

  • bootstrapMigrationsTable() correctly queries sqlite_master to detect table existence
  • Fresh DB path: applies 000.sql, records version 000 — table must exist before INSERT, and it does because 000.sql just created it
  • Legacy DB path (table created by old inline code): back-fills version 000 without re-applying DDL
  • Normal migration loop then iterates all .sql files; version 000 is already recorded so 000.sql is skipped
  • CREATE TABLE IF NOT EXISTS in 000.sql provides defense-in-depth

Deduplication:

  • runMigrations() and ApplyMigrations() were near-identical (~80 lines each). Now both delegate to a single applyMigrations() helper. Clean refactor, no behavior change.

Nil logger handling:

  • logInfo/logDebug guard against nil logger. Needed because ApplyMigrations() (the testing entry point) passes nil. Correct.

Edge cases:

  • Idempotent: calling bootstrapMigrationsTable twice is safe (checks before inserting)
  • No transaction wrapping in bootstrap — if CREATE TABLE succeeds but version INSERT fails, next run self-heals via the "table exists, version 000 not recorded" path

Security:

  • All SQL queries use parameterized ? placeholders. No injection risk.

Scope creep:

  • Supporting changes (deduplication, log helpers, tests) are all directly necessary for the bootstrap implementation. No unrelated changes.

4. Test Coverage

Test What it covers
TestApplyMigrations_CreatesSchemaAndTables Full migration run on fresh DB — verifies all tables created, versions recorded
TestApplyMigrations_Idempotent Double-apply produces no errors or duplicate rows
TestBootstrapMigrationsTable_FreshDatabase Bootstrap on empty DB creates table and records 000
TestBootstrapMigrationsTable_ExistingTableBackwardsCompat Legacy DB gets 000 back-filled without losing existing data

4 tests covering fresh, idempotent, and backwards-compat paths. Good coverage.


5. Build Result

docker build .PASSED (fmt-check, lint, test, build all green)

(--no-cache attempt hit transient Go module proxy EOF errors unrelated to this PR; cached build with correct layer invalidation confirms all stages pass.)


6. README Consistency

README does not document migration internals. No updates needed.


Verdict: PASS

Clean implementation that correctly moves the schema_migrations DDL from inline Go code into 000.sql, handles backwards compatibility with existing databases, deduplicates the migration logic, and includes thorough tests.

## Review: [PR #36](https://git.eeqj.de/sneak/pixa/pulls/36) — Move schema_migrations table creation into 000.sql Closes [issue #29](https://git.eeqj.de/sneak/pixa/issues/29). --- ### 1. Policy Divergences | Policy Rule | Status | Notes | |---|---|---| | External refs pinned by hash | ✅ | No new external dependencies added | | `.golangci.yml` unmodified | ✅ | Not touched | | Makefile/Dockerfile/CI unmodified | ✅ | Not touched | | Migration dir `internal/db/migrations/` | ⚠️ Pre-existing | Repo uses `internal/database/schema/` — established convention since `001.sql`. This PR follows existing structure. Not introduced by this PR. | | Pre-1.0.0: modify existing migrations | ✅ Justified | There is no existing `.sql` file containing the `schema_migrations` DDL — it was inline Go code. The issue explicitly requests creating a `000` file to hold this schema. This is a bootstrap file for the migration infrastructure itself, not a regular data migration. No policy violation. | | `go.sum` integrity | ✅ | No dependency changes | | No secrets committed | ✅ | Clean | | `make check` non-destructive | ✅ | Tests use `:memory:` SQLite | --- ### 2. Issue Requirements Checklist ([#29](https://git.eeqj.de/sneak/pixa/issues/29)) - [x] **"add migration schema table file"** — `internal/database/schema/000.sql` created containing `CREATE TABLE IF NOT EXISTS schema_migrations` DDL - [x] **"apply it if no migration version table exists"** — `bootstrapMigrationsTable()` checks `sqlite_master` and applies `000.sql` when the table is missing - [x] **"schema goes in schema files, not in code"** — Inline SQL removed from both `runMigrations()` and `ApplyMigrations()` in `database.go` All requirements satisfied. --- ### 3. Code Quality Assessment **Correctness:** - `bootstrapMigrationsTable()` correctly queries `sqlite_master` to detect table existence - Fresh DB path: applies `000.sql`, records version `000` — table must exist before INSERT, and it does because `000.sql` just created it ✅ - Legacy DB path (table created by old inline code): back-fills version `000` without re-applying DDL ✅ - Normal migration loop then iterates all `.sql` files; version `000` is already recorded so `000.sql` is skipped ✅ - `CREATE TABLE IF NOT EXISTS` in `000.sql` provides defense-in-depth **Deduplication:** - `runMigrations()` and `ApplyMigrations()` were near-identical (~80 lines each). Now both delegate to a single `applyMigrations()` helper. Clean refactor, no behavior change. **Nil logger handling:** - `logInfo`/`logDebug` guard against nil logger. Needed because `ApplyMigrations()` (the testing entry point) passes `nil`. Correct. **Edge cases:** - Idempotent: calling `bootstrapMigrationsTable` twice is safe (checks before inserting) - No transaction wrapping in bootstrap — if `CREATE TABLE` succeeds but version INSERT fails, next run self-heals via the "table exists, version 000 not recorded" path **Security:** - All SQL queries use parameterized `?` placeholders. No injection risk. **Scope creep:** - Supporting changes (deduplication, log helpers, tests) are all directly necessary for the bootstrap implementation. No unrelated changes. --- ### 4. Test Coverage | Test | What it covers | |---|---| | `TestApplyMigrations_CreatesSchemaAndTables` | Full migration run on fresh DB — verifies all tables created, versions recorded | | `TestApplyMigrations_Idempotent` | Double-apply produces no errors or duplicate rows | | `TestBootstrapMigrationsTable_FreshDatabase` | Bootstrap on empty DB creates table and records `000` | | `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` | Legacy DB gets `000` back-filled without losing existing data | 4 tests covering fresh, idempotent, and backwards-compat paths. Good coverage. --- ### 5. Build Result `docker build .` — **PASSED** ✅ (fmt-check, lint, test, build all green) (`--no-cache` attempt hit transient Go module proxy EOF errors unrelated to this PR; cached build with correct layer invalidation confirms all stages pass.) --- ### 6. README Consistency README does not document migration internals. No updates needed. --- ### Verdict: **PASS** ✅ Clean implementation that correctly moves the `schema_migrations` DDL from inline Go code into `000.sql`, handles backwards compatibility with existing databases, deduplicates the migration logic, and includes thorough tests.
clawbot added merge-ready and removed needs-review labels 2026-03-17 10:27:17 +01:00
sneak was assigned by clawbot 2026-03-17 10:27:18 +01:00
clawbot force-pushed feature/migrations-table-schema-file from 5504495e0c to 3d92f2625b 2026-03-18 03:24:45 +01:00 Compare
Author
Collaborator

Rebased onto current main after PR #33 was merged.

Conflict resolution: PR #33 consolidated the duplicate applyMigrations functions into a single exported ApplyMigrations(ctx, db, log) with ParseMigrationVersion, collectMigrations, and ensureMigrationsTable helpers. This PR independently did similar deduplication. Resolved by keeping main's structure (exported 3-arg ApplyMigrations, ParseMigrationVersion, collectMigrations) and replacing ensureMigrationsTable with this PR's bootstrapMigrationsTable + 000.sql approach. Refactored bootstrapMigrationsTable into smaller functions (ensureBootstrapVersionRecorded, applyBootstrapMigration) to satisfy the nestif linter. Tests updated to use the 3-arg ApplyMigrations(ctx, db, log) signature.

All checks pass: make fmt, lint, tests, docker build ..

Rebased onto current `main` after [PR #33](https://git.eeqj.de/sneak/pixa/pulls/33) was merged. **Conflict resolution:** PR #33 consolidated the duplicate `applyMigrations` functions into a single exported `ApplyMigrations(ctx, db, log)` with `ParseMigrationVersion`, `collectMigrations`, and `ensureMigrationsTable` helpers. This PR independently did similar deduplication. Resolved by keeping main's structure (exported 3-arg `ApplyMigrations`, `ParseMigrationVersion`, `collectMigrations`) and replacing `ensureMigrationsTable` with this PR's `bootstrapMigrationsTable` + `000.sql` approach. Refactored `bootstrapMigrationsTable` into smaller functions (`ensureBootstrapVersionRecorded`, `applyBootstrapMigration`) to satisfy the `nestif` linter. Tests updated to use the 3-arg `ApplyMigrations(ctx, db, log)` signature. All checks pass: `make fmt`, lint, tests, `docker build .`.
Owner

we are pre 1.0. there is no backfilling or installed base

we are pre 1.0. there is no backfilling or installed base
sneak removed their assignment 2026-03-18 03:44:19 +01:00
clawbot was assigned by sneak 2026-03-18 03:44:19 +01:00
clawbot added needs-rework and removed merge-ready labels 2026-03-18 03:44:45 +01:00
clawbot added 1 commit 2026-03-18 03:49:20 +01:00
Remove backwards compat code: no installed base pre-1.0
All checks were successful
check / check (push) Successful in 1m49s
8b6aa74951
- Simplify bootstrapMigrationsTable to just check table existence and
  apply 000.sql if missing — no legacy DB detection
- Remove ensureBootstrapVersionRecorded (legacy backfill path)
- Remove applyBootstrapMigration (separate helper, now inlined)
- Remove TestBootstrapMigrationsTable_ExistingTableBackwardsCompat
- Simplify 000.sql header comment
Author
Collaborator

Rework: Removed all backwards compatibility code

Per sneak's review — pixa is pre-1.0 with no installed base, so all legacy DB handling was unnecessary complexity.

Changes

internal/database/database.go — simplified bootstrapMigrationsTable to a single function:

  • If schema_migrations table exists → return (nothing to do)
  • If missing → apply 000.sql, record version 000
  • Removed ensureBootstrapVersionRecorded (legacy backfill path)
  • Removed applyBootstrapMigration (separate helper, logic now inlined)

internal/database/database_test.go:

  • Removed TestBootstrapMigrationsTable_ExistingTableBackwardsCompat — no legacy databases to support

internal/database/schema/000.sql:

  • Simplified header comment

Net result: −101 lines. Three functions collapsed into one simple function with no edge cases.

make fmt, lint, tests, and docker build . all pass.

## Rework: Removed all backwards compatibility code Per sneak's review — pixa is pre-1.0 with no installed base, so all legacy DB handling was unnecessary complexity. ### Changes **`internal/database/database.go`** — simplified `bootstrapMigrationsTable` to a single function: - If `schema_migrations` table exists → return (nothing to do) - If missing → apply `000.sql`, record version `000` - **Removed** `ensureBootstrapVersionRecorded` (legacy backfill path) - **Removed** `applyBootstrapMigration` (separate helper, logic now inlined) **`internal/database/database_test.go`:** - **Removed** `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` — no legacy databases to support **`internal/database/schema/000.sql`:** - Simplified header comment **Net result:** −101 lines. Three functions collapsed into one simple function with no edge cases. `make fmt`, lint, tests, and `docker build .` all pass.
clawbot added needs-review and removed needs-rework labels 2026-03-18 03:50:04 +01:00
clawbot reviewed 2026-03-18 03:54:08 +01:00
clawbot left a comment
Author
Collaborator

Review: PR #36 — Move schema_migrations table creation into 000.sql (post-rework)

Closes issue #29.


1. Policy Divergences

Policy Rule Status Notes
External refs pinned by hash No new external dependencies added
.golangci.yml unmodified Not in diff
Makefile/Dockerfile/CI unmodified Not in diff
Migration dir internal/db/migrations/ ⚠️ Pre-existing Repo uses internal/database/schema/ — established convention predating this PR. Not introduced here.
go.sum integrity No dependency changes
No secrets committed Clean
make check non-destructive Tests use :memory: SQLite

No policy violations introduced by this PR.


2. Requirements Checklist (#29)

  • "add migration schema table file"internal/database/schema/000.sql created with CREATE TABLE IF NOT EXISTS schema_migrations DDL
  • "apply it if no migration version table exists"bootstrapMigrationsTable() checks sqlite_master; applies 000.sql only when table is missing
  • "schema goes in schema files, not in code" — Inline CREATE TABLE SQL removed from database.go; schema now lives in 000.sql
  • sneak's rework: "we are pre 1.0. there is no backfilling or installed base" — All backwards-compat code removed: no ensureBootstrapVersionRecorded, no applyBootstrapMigration, no legacy backfill path. TestBootstrapMigrationsTable_ExistingTableBackwardsCompat deleted. Bootstrap logic is now: table exists → return; table missing → apply 000.sql → record version 000. Clean and simple.

All requirements satisfied.


3. Code Quality

Correctness:

  • bootstrapMigrationsTable queries sqlite_master to detect table — standard SQLite pattern
  • Fresh DB: applies 000.sql, records version 000 — table must exist for INSERT, and it does because 000.sql just created it
  • Normal migration loop then iterates all .sql files; version 000 already recorded so 000.sql is skipped
  • CREATE TABLE IF NOT EXISTS in 000.sql provides defense-in-depth

Edge cases:

  • Idempotent: bootstrapMigrationsTable called twice is safe (table exists check short-circuits)
  • Partial failure self-heals: if CREATE TABLE succeeds but version INSERT fails, next run sees table exists → returns → migration loop finds 000.sql unrecorded → applies it again (IF NOT EXISTS = no-op) → records version. No data loss.

Security:

  • All SQL queries use parameterized ? placeholders. No injection risk.

Scope:

  • Changes are tightly scoped. Only touches migration bootstrapping and its tests. No unrelated modifications.

4. Test Coverage

Test What it covers
TestApplyMigrations_CreatesSchemaAndTables Full migration run on fresh DB — verifies all tables created, versions 000 and 001 recorded
TestApplyMigrations_Idempotent Double-apply produces no errors or duplicate rows
TestBootstrapMigrationsTable_FreshDatabase Bootstrap alone on empty DB — table created, version 000 recorded
TestParseMigrationVersion (pre-existing) Filename parsing — unchanged, continues to pass

3 tests covering fresh, idempotent, and bootstrap-only paths. Backwards-compat test correctly removed per rework.


5. Cheating Check

Only 3 files in diff: database.go, database_test.go, 000.sql. No modifications to .golangci.yml, Makefile, Dockerfile, .gitea/workflows/, or any test config.


6. Build Result

docker build .PASSED

All stages green: make fmt-check, make lint, make test (all tests pass), go build.


7. README Consistency

README does not document migration internals. No updates needed.


Verdict: PASS

Clean, minimal implementation that correctly moves the schema_migrations DDL from inline Go code into 000.sql. Backwards-compat code fully removed per sneak's rework instruction. Tests are thorough. Build is green.

## Review: [PR #36](https://git.eeqj.de/sneak/pixa/pulls/36) — Move schema_migrations table creation into 000.sql (post-rework) Closes [issue #29](https://git.eeqj.de/sneak/pixa/issues/29). --- ### 1. Policy Divergences | Policy Rule | Status | Notes | |---|---|---| | External refs pinned by hash | ✅ | No new external dependencies added | | `.golangci.yml` unmodified | ✅ | Not in diff | | Makefile/Dockerfile/CI unmodified | ✅ | Not in diff | | Migration dir `internal/db/migrations/` | ⚠️ Pre-existing | Repo uses `internal/database/schema/` — established convention predating this PR. Not introduced here. | | `go.sum` integrity | ✅ | No dependency changes | | No secrets committed | ✅ | Clean | | `make check` non-destructive | ✅ | Tests use `:memory:` SQLite | No policy violations introduced by this PR. --- ### 2. Requirements Checklist ([#29](https://git.eeqj.de/sneak/pixa/issues/29)) - [x] **"add migration schema table file"** — `internal/database/schema/000.sql` created with `CREATE TABLE IF NOT EXISTS schema_migrations` DDL - [x] **"apply it if no migration version table exists"** — `bootstrapMigrationsTable()` checks `sqlite_master`; applies `000.sql` only when table is missing - [x] **"schema goes in schema files, not in code"** — Inline `CREATE TABLE` SQL removed from `database.go`; schema now lives in `000.sql` - [x] **sneak's rework: "we are pre 1.0. there is no backfilling or installed base"** — All backwards-compat code removed: no `ensureBootstrapVersionRecorded`, no `applyBootstrapMigration`, no legacy backfill path. `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` deleted. Bootstrap logic is now: table exists → return; table missing → apply `000.sql` → record version `000`. Clean and simple. All requirements satisfied. --- ### 3. Code Quality **Correctness:** - `bootstrapMigrationsTable` queries `sqlite_master` to detect table — standard SQLite pattern ✅ - Fresh DB: applies `000.sql`, records version `000` — table must exist for INSERT, and it does because `000.sql` just created it ✅ - Normal migration loop then iterates all `.sql` files; version `000` already recorded so `000.sql` is skipped ✅ - `CREATE TABLE IF NOT EXISTS` in `000.sql` provides defense-in-depth ✅ **Edge cases:** - Idempotent: `bootstrapMigrationsTable` called twice is safe (table exists check short-circuits) - Partial failure self-heals: if `CREATE TABLE` succeeds but version INSERT fails, next run sees table exists → returns → migration loop finds `000.sql` unrecorded → applies it again (`IF NOT EXISTS` = no-op) → records version. No data loss. **Security:** - All SQL queries use parameterized `?` placeholders. No injection risk. **Scope:** - Changes are tightly scoped. Only touches migration bootstrapping and its tests. No unrelated modifications. --- ### 4. Test Coverage | Test | What it covers | |---|---| | `TestApplyMigrations_CreatesSchemaAndTables` | Full migration run on fresh DB — verifies all tables created, versions `000` and `001` recorded | | `TestApplyMigrations_Idempotent` | Double-apply produces no errors or duplicate rows | | `TestBootstrapMigrationsTable_FreshDatabase` | Bootstrap alone on empty DB — table created, version `000` recorded | | `TestParseMigrationVersion` (pre-existing) | Filename parsing — unchanged, continues to pass | 3 tests covering fresh, idempotent, and bootstrap-only paths. Backwards-compat test correctly removed per rework. --- ### 5. Cheating Check Only 3 files in diff: `database.go`, `database_test.go`, `000.sql`. No modifications to `.golangci.yml`, `Makefile`, `Dockerfile`, `.gitea/workflows/`, or any test config. ✅ --- ### 6. Build Result `docker build .` — **PASSED** ✅ All stages green: `make fmt-check`, `make lint`, `make test` (all tests pass), `go build`. --- ### 7. README Consistency README does not document migration internals. No updates needed. ✅ --- ### Verdict: **PASS** ✅ Clean, minimal implementation that correctly moves the `schema_migrations` DDL from inline Go code into `000.sql`. Backwards-compat code fully removed per sneak's rework instruction. Tests are thorough. Build is green.
clawbot added merge-ready and removed needs-review labels 2026-03-18 03:54:46 +01:00
clawbot removed their assignment 2026-03-18 03:54:46 +01:00
sneak was assigned by clawbot 2026-03-18 03:54:46 +01:00
Owner

why would you do an insert? just put the bootstrap migration row into the schema file.

why would you do an insert? just put the bootstrap migration row into the schema file.
sneak removed their assignment 2026-03-18 04:19:11 +01:00
clawbot was assigned by sneak 2026-03-18 04:19:12 +01:00
clawbot added needs-rework and removed merge-ready labels 2026-03-18 04:19:51 +01:00
clawbot added 1 commit 2026-03-18 04:22:55 +01:00
Move bootstrap migration INSERT into 000.sql
All checks were successful
check / check (push) Successful in 1m41s
0c8de65be8
Per review: the SQL file should be self-contained. 000.sql now
includes both the CREATE TABLE and the INSERT OR IGNORE for recording
its own version. Removed the separate INSERT from Go code in
bootstrapMigrationsTable().
Author
Collaborator

Rework: Moved bootstrap INSERT into 000.sql

Per sneak's review — the SQL file should be self-contained.

Changes

internal/database/schema/000.sql — added INSERT OR IGNORE INTO schema_migrations (version) VALUES ('000'); after the CREATE TABLE. The file now handles both creating the table and recording its own version.

internal/database/database.go — removed the separate INSERT INTO schema_migrations from bootstrapMigrationsTable(). The function now just: checks if table exists → if not, executes 000.sql → done. No Go-side INSERT.

Net result: −6 lines. 000.sql is fully self-contained.

make fmt, lint, tests, and docker build . all pass.

## Rework: Moved bootstrap INSERT into 000.sql Per sneak's review — the SQL file should be self-contained. ### Changes **`internal/database/schema/000.sql`** — added `INSERT OR IGNORE INTO schema_migrations (version) VALUES ('000');` after the `CREATE TABLE`. The file now handles both creating the table and recording its own version. **`internal/database/database.go`** — removed the separate `INSERT INTO schema_migrations` from `bootstrapMigrationsTable()`. The function now just: checks if table exists → if not, executes `000.sql` → done. No Go-side INSERT. **Net result:** −6 lines. `000.sql` is fully self-contained. `make fmt`, lint, tests, and `docker build .` all pass.
clawbot added needs-review and removed needs-rework labels 2026-03-18 04:23:38 +01:00
Author
Collaborator

Review: PR #36 — Move schema_migrations table creation into 000.sql (post-rework v3)

Closes issue #29.


1. Policy Compliance

Policy Rule Status Evidence
External refs pinned by hash No new external dependencies
.golangci.yml unmodified Not in diff
Makefile/Dockerfile/CI unmodified Not in diff
go.sum integrity No dependency changes
No secrets committed Clean
make check non-destructive Tests use :memory: SQLite
Migration dir internal/db/migrations/ ⚠️ Pre-existing Repo uses internal/database/schema/ — established convention. Not introduced by this PR.

No policy violations.


2. Requirements (#29)

  • "add migration schema table file"internal/database/schema/000.sql created with CREATE TABLE IF NOT EXISTS schema_migrations DDL
  • "apply it if no migration version table exists"bootstrapMigrationsTable() checks sqlite_master; applies 000.sql only when table is missing
  • "schema goes in schema files, not in code" — Inline CREATE TABLE SQL removed from database.go

3. Sneak's Feedback Verification

  • "we are pre 1.0. there is no backfilling or installed base" — All backwards-compat code removed. No ensureBootstrapVersionRecorded, no applyBootstrapMigration, no legacy backfill. TestBootstrapMigrationsTable_ExistingTableBackwardsCompat deleted.
  • "why would you do an insert? just put the bootstrap migration row into the schema file"000.sql now contains both CREATE TABLE IF NOT EXISTS AND INSERT OR IGNORE INTO schema_migrations (version) VALUES ('000'). Go code in bootstrapMigrationsTable does zero INSERTs — it reads 000.sql and executes it, nothing more.

Both rework instructions fully addressed.


4. Code Correctness

000.sql:

  • CREATE TABLE IF NOT EXISTS + INSERT OR IGNORE — both idempotent. Self-contained.

bootstrapMigrationsTable:

  • Checks sqlite_master for table existence → if present, returns immediately → if absent, reads and executes 000.sql. No Go-side INSERT.

Migration loop interaction:

  • collectMigrations returns all .sql files including 000.sql
  • Loop checks if version 000 is already recorded (it is — inserted by 000.sql during bootstrap) → skips it
  • No double-INSERT risk: the SQL file's INSERT OR IGNORE already recorded 000, so the loop's SELECT COUNT(*) finds it and skips

Idempotency:

  • Calling bootstrapMigrationsTable twice: second call sees table exists → returns immediately
  • Calling ApplyMigrations twice: all versions already recorded → all skipped

5. Test Coverage

Test Covers
TestApplyMigrations_CreatesSchemaAndTables Full migration on fresh DB — verifies versions 000 and 001 recorded, all tables created
TestApplyMigrations_Idempotent Double-apply: no errors, no duplicate rows for version 000
TestBootstrapMigrationsTable_FreshDatabase Bootstrap alone: table created, version 000 recorded

3 targeted tests covering fresh, idempotent, and bootstrap-only paths. Backwards-compat test correctly removed per rework.


6. Cheating Check

Only 3 files in diff: database.go, database_test.go, 000.sql. No modifications to .golangci.yml, Makefile, Dockerfile, .gitea/workflows/, or any test configuration.


7. Build Result

docker build --no-cache .PASSED

All stages green: make fmt-check, make lint, make test (all tests pass), go build.


Verdict: PASS

Clean, minimal implementation. 000.sql is fully self-contained with both the DDL and its own version row. Go code does zero INSERTs for the bootstrap. Backwards-compat code fully removed. All of sneak's rework feedback addressed. Build is green.

## Review: [PR #36](https://git.eeqj.de/sneak/pixa/pulls/36) — Move schema_migrations table creation into 000.sql (post-rework v3) Closes [issue #29](https://git.eeqj.de/sneak/pixa/issues/29). --- ### 1. Policy Compliance | Policy Rule | Status | Evidence | |---|---|---| | External refs pinned by hash | ✅ | No new external dependencies | | `.golangci.yml` unmodified | ✅ | Not in diff | | Makefile/Dockerfile/CI unmodified | ✅ | Not in diff | | `go.sum` integrity | ✅ | No dependency changes | | No secrets committed | ✅ | Clean | | `make check` non-destructive | ✅ | Tests use `:memory:` SQLite | | Migration dir `internal/db/migrations/` | ⚠️ Pre-existing | Repo uses `internal/database/schema/` — established convention. Not introduced by this PR. | No policy violations. --- ### 2. Requirements ([#29](https://git.eeqj.de/sneak/pixa/issues/29)) - [x] **"add migration schema table file"** — `internal/database/schema/000.sql` created with `CREATE TABLE IF NOT EXISTS schema_migrations` DDL - [x] **"apply it if no migration version table exists"** — `bootstrapMigrationsTable()` checks `sqlite_master`; applies `000.sql` only when table is missing - [x] **"schema goes in schema files, not in code"** — Inline `CREATE TABLE` SQL removed from `database.go` --- ### 3. Sneak's Feedback Verification - [x] **"we are pre 1.0. there is no backfilling or installed base"** — All backwards-compat code removed. No `ensureBootstrapVersionRecorded`, no `applyBootstrapMigration`, no legacy backfill. `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` deleted. - [x] **"why would you do an insert? just put the bootstrap migration row into the schema file"** — `000.sql` now contains both `CREATE TABLE IF NOT EXISTS` AND `INSERT OR IGNORE INTO schema_migrations (version) VALUES ('000')`. Go code in `bootstrapMigrationsTable` does **zero** INSERTs — it reads `000.sql` and executes it, nothing more. Both rework instructions fully addressed. --- ### 4. Code Correctness **`000.sql`:** - `CREATE TABLE IF NOT EXISTS` + `INSERT OR IGNORE` — both idempotent. Self-contained. ✅ **`bootstrapMigrationsTable`:** - Checks `sqlite_master` for table existence → if present, returns immediately → if absent, reads and executes `000.sql`. No Go-side INSERT. ✅ **Migration loop interaction:** - `collectMigrations` returns all `.sql` files including `000.sql` - Loop checks if version `000` is already recorded (it is — inserted by `000.sql` during bootstrap) → skips it - No double-INSERT risk: the SQL file's `INSERT OR IGNORE` already recorded `000`, so the loop's `SELECT COUNT(*)` finds it and skips ✅ **Idempotency:** - Calling `bootstrapMigrationsTable` twice: second call sees table exists → returns immediately ✅ - Calling `ApplyMigrations` twice: all versions already recorded → all skipped ✅ --- ### 5. Test Coverage | Test | Covers | |---|---| | `TestApplyMigrations_CreatesSchemaAndTables` | Full migration on fresh DB — verifies versions `000` and `001` recorded, all tables created | | `TestApplyMigrations_Idempotent` | Double-apply: no errors, no duplicate rows for version `000` | | `TestBootstrapMigrationsTable_FreshDatabase` | Bootstrap alone: table created, version `000` recorded | 3 targeted tests covering fresh, idempotent, and bootstrap-only paths. Backwards-compat test correctly removed per rework. ✅ --- ### 6. Cheating Check Only 3 files in diff: `database.go`, `database_test.go`, `000.sql`. No modifications to `.golangci.yml`, `Makefile`, `Dockerfile`, `.gitea/workflows/`, or any test configuration. ✅ --- ### 7. Build Result `docker build --no-cache .` — **PASSED** ✅ All stages green: `make fmt-check`, `make lint`, `make test` (all tests pass), `go build`. --- ### Verdict: **PASS** ✅ Clean, minimal implementation. `000.sql` is fully self-contained with both the DDL and its own version row. Go code does zero INSERTs for the bootstrap. Backwards-compat code fully removed. All of sneak's rework feedback addressed. Build is green.
clawbot added merge-ready and removed needs-review labels 2026-03-18 04:28:46 +01:00
clawbot removed their assignment 2026-03-18 04:28:47 +01:00
sneak was assigned by clawbot 2026-03-18 04:28:47 +01:00
Owner

schema versions should be an int not text

schema versions should be an int not text
sneak removed their assignment 2026-03-20 07:04:05 +01:00
clawbot was assigned by sneak 2026-03-20 07:04:06 +01:00
sneak added needs-rework and removed merge-ready labels 2026-03-20 07:04:16 +01:00
clawbot force-pushed feature/migrations-table-schema-file from 0c8de65be8 to 49398c1f0f 2026-03-20 07:08:12 +01:00 Compare
Author
Collaborator

Rework: Schema versions as INTEGER

Per sneak's review — schema versions should be int, not text.

Changes

internal/database/schema/000.sql:

  • version TEXT PRIMARY KEYversion INTEGER PRIMARY KEY
  • VALUES ('000')VALUES (0)

internal/database/database.go:

  • bootstrapVersion const: "000"0 (int)
  • ParseMigrationVersion(): return type changed from (string, error) to (int, error) — parses the numeric filename prefix to an integer via strconv.Atoi
  • All version values flowing through ApplyMigrations are now int — SQL parameterized queries and slog handle int natively

internal/database/database_test.go:

  • TestParseMigrationVersion: want field changed from string to int, expected values updated (e.g. "001"1, "042"42)
  • TestApplyMigrations_CreatesSchemaAndTables: scans versions as int, compares against 0 and 1
  • TestApplyMigrations_Idempotent: query uses version = 0 instead of version = '000'
  • TestBootstrapMigrationsTable_FreshDatabase: query uses version = 0 instead of version = '000'

No other files touched. make fmt, lint, tests, and docker build . all pass.

## Rework: Schema versions as INTEGER Per sneak's review — schema versions should be int, not text. ### Changes **`internal/database/schema/000.sql`:** - `version TEXT PRIMARY KEY` → `version INTEGER PRIMARY KEY` - `VALUES ('000')` → `VALUES (0)` **`internal/database/database.go`:** - `bootstrapVersion` const: `"000"` → `0` (int) - `ParseMigrationVersion()`: return type changed from `(string, error)` to `(int, error)` — parses the numeric filename prefix to an integer via `strconv.Atoi` - All version values flowing through `ApplyMigrations` are now `int` — SQL parameterized queries and slog handle int natively **`internal/database/database_test.go`:** - `TestParseMigrationVersion`: `want` field changed from `string` to `int`, expected values updated (e.g. `"001"` → `1`, `"042"` → `42`) - `TestApplyMigrations_CreatesSchemaAndTables`: scans versions as `int`, compares against `0` and `1` - `TestApplyMigrations_Idempotent`: query uses `version = 0` instead of `version = '000'` - `TestBootstrapMigrationsTable_FreshDatabase`: query uses `version = 0` instead of `version = '000'` **No other files touched.** `make fmt`, lint, tests, and `docker build .` all pass.
clawbot added needs-review and removed needs-rework labels 2026-03-20 07:08:50 +01:00
Author
Collaborator

Review: PR #36 — Move schema_migrations table creation into 000.sql (post-rework v4)

Closes issue #29.


1. Policy Compliance

Policy Rule Status Evidence
External refs pinned by hash No new external dependencies
.golangci.yml unmodified Not in diff
Makefile/Dockerfile/CI unmodified Not in diff
go.sum integrity No dependency changes
No secrets committed Clean
make check non-destructive Tests use :memory: SQLite
Migration dir internal/db/migrations/ ⚠️ Pre-existing Repo uses internal/database/schema/ — established convention. Not introduced by this PR.

No policy violations.


2. Requirements (#29)

  • "add migration schema table file"internal/database/schema/000.sql created with CREATE TABLE IF NOT EXISTS schema_migrations DDL
  • "apply it if no migration version table exists"bootstrapMigrationsTable() checks sqlite_master; applies 000.sql only when table is missing
  • "schema goes in schema files, not in code" — Inline CREATE TABLE SQL removed from database.go

3. Sneak's Feedback Verification (All 4 Rework Cycles)

  • "we are pre 1.0. there is no backfilling or installed base" — All backwards-compat code removed. No ensureBootstrapVersionRecorded, no applyBootstrapMigration, no legacy backfill. TestBootstrapMigrationsTable_ExistingTableBackwardsCompat deleted.
  • "just put the bootstrap migration row into the schema file"000.sql contains both CREATE TABLE IF NOT EXISTS AND INSERT OR IGNORE INTO schema_migrations (version) VALUES (0). Go code does zero INSERTs for bootstrap.
  • "schema versions should be an int not text" — Verified throughout:
    • 000.sql: version INTEGER PRIMARY KEY
    • 000.sql: VALUES (0) (integer literal, not string)
    • bootstrapVersion const: 0 (int)
    • ParseMigrationVersion() returns (int, error)
    • strconv.Atoi converts filename prefix to int
    • All SQL queries use int version parameter via ? placeholder
    • All test expectations use int values (0, 1, 42) not strings
    • Format verbs changed from %q/%s to %d in test error messages

All rework instructions fully addressed.


4. Code Correctness

000.sql:

  • CREATE TABLE IF NOT EXISTS + INSERT OR IGNORE — both idempotent, self-contained. version INTEGER PRIMARY KEY.

bootstrapMigrationsTable:

  • Queries sqlite_master → table missing → reads + executes 000.sql → done. Table present → returns immediately. No Go-side INSERT. Clean, minimal.

ParseMigrationVersion:

  • Validates numeric prefix, then strconv.Atoi converts to int. Returns 0 on all error paths (idiomatic Go).

Migration loop interaction:

  • collectMigrations returns all .sql files including 000.sql
  • Bootstrap always runs first → version 0 already recorded → loop skips 000.sql → no double-INSERT risk
  • All version comparisons and INSERTs use int consistently

Idempotency:

  • bootstrapMigrationsTable twice: second call sees table → returns
  • ApplyMigrations twice: all versions recorded → all skipped

5. Test Coverage

Test Covers
TestParseMigrationVersion Filename parsing returns int — "001"1, "042"42, "00001"1. Error cases preserved.
TestApplyMigrations_CreatesSchemaAndTables Full migration on fresh DB — versions scanned as int, verifies 0 and 1 recorded, all 6 application tables verified
TestApplyMigrations_Idempotent Double-apply: no errors, exactly 1 row for version 0 (queried as int)
TestBootstrapMigrationsTable_FreshDatabase Bootstrap alone: table created, version 0 recorded (queried as int)

All tests use int types for version comparisons and format verbs. Backwards-compat test correctly removed per earlier rework.


6. Cheating Check

Only 3 files in diff: database.go, database_test.go, 000.sql. No modifications to .golangci.yml, Makefile, Dockerfile, .gitea/workflows/, or any test configuration. Test helper openTestDB is a new addition (DRY refactor) — not a policy-controlled file.


7. Build Result

docker build --no-cache .PASSED

All stages green: make fmt-check, make lint, make test (all tests pass), go build.


Verdict: PASS

Clean implementation. version INTEGER PRIMARY KEY throughout — SQL schema, Go const, ParseMigrationVersion return type, all queries, all tests. 000.sql is fully self-contained with DDL + version row. No backwards-compat code. No Go-side INSERTs for bootstrap. All four rounds of sneak's feedback addressed. Build is green.

## Review: [PR #36](https://git.eeqj.de/sneak/pixa/pulls/36) — Move schema_migrations table creation into 000.sql (post-rework v4) Closes [issue #29](https://git.eeqj.de/sneak/pixa/issues/29). --- ### 1. Policy Compliance | Policy Rule | Status | Evidence | |---|---|---| | External refs pinned by hash | ✅ | No new external dependencies | | `.golangci.yml` unmodified | ✅ | Not in diff | | Makefile/Dockerfile/CI unmodified | ✅ | Not in diff | | `go.sum` integrity | ✅ | No dependency changes | | No secrets committed | ✅ | Clean | | `make check` non-destructive | ✅ | Tests use `:memory:` SQLite | | Migration dir `internal/db/migrations/` | ⚠️ Pre-existing | Repo uses `internal/database/schema/` — established convention. Not introduced by this PR. | No policy violations. --- ### 2. Requirements ([#29](https://git.eeqj.de/sneak/pixa/issues/29)) - [x] **"add migration schema table file"** — `internal/database/schema/000.sql` created with `CREATE TABLE IF NOT EXISTS schema_migrations` DDL - [x] **"apply it if no migration version table exists"** — `bootstrapMigrationsTable()` checks `sqlite_master`; applies `000.sql` only when table is missing - [x] **"schema goes in schema files, not in code"** — Inline `CREATE TABLE` SQL removed from `database.go` --- ### 3. Sneak's Feedback Verification (All 4 Rework Cycles) - [x] **"we are pre 1.0. there is no backfilling or installed base"** — All backwards-compat code removed. No `ensureBootstrapVersionRecorded`, no `applyBootstrapMigration`, no legacy backfill. `TestBootstrapMigrationsTable_ExistingTableBackwardsCompat` deleted. - [x] **"just put the bootstrap migration row into the schema file"** — `000.sql` contains both `CREATE TABLE IF NOT EXISTS` AND `INSERT OR IGNORE INTO schema_migrations (version) VALUES (0)`. Go code does zero INSERTs for bootstrap. - [x] **"schema versions should be an int not text"** — Verified throughout: - `000.sql`: `version INTEGER PRIMARY KEY` ✅ - `000.sql`: `VALUES (0)` (integer literal, not string) ✅ - `bootstrapVersion` const: `0` (int) ✅ - `ParseMigrationVersion()` returns `(int, error)` ✅ - `strconv.Atoi` converts filename prefix to int ✅ - All SQL queries use `int` version parameter via `?` placeholder ✅ - All test expectations use `int` values (`0`, `1`, `42`) not strings ✅ - Format verbs changed from `%q`/`%s` to `%d` in test error messages ✅ All rework instructions fully addressed. --- ### 4. Code Correctness **`000.sql`:** - `CREATE TABLE IF NOT EXISTS` + `INSERT OR IGNORE` — both idempotent, self-contained. `version INTEGER PRIMARY KEY`. ✅ **`bootstrapMigrationsTable`:** - Queries `sqlite_master` → table missing → reads + executes `000.sql` → done. Table present → returns immediately. No Go-side INSERT. Clean, minimal. ✅ **`ParseMigrationVersion`:** - Validates numeric prefix, then `strconv.Atoi` converts to int. Returns `0` on all error paths (idiomatic Go). ✅ **Migration loop interaction:** - `collectMigrations` returns all `.sql` files including `000.sql` - Bootstrap always runs first → version `0` already recorded → loop skips `000.sql` → no double-INSERT risk ✅ - All version comparisons and INSERTs use `int` consistently ✅ **Idempotency:** - `bootstrapMigrationsTable` twice: second call sees table → returns ✅ - `ApplyMigrations` twice: all versions recorded → all skipped ✅ --- ### 5. Test Coverage | Test | Covers | |---|---| | `TestParseMigrationVersion` | Filename parsing returns int — `"001"` → `1`, `"042"` → `42`, `"00001"` → `1`. Error cases preserved. | | `TestApplyMigrations_CreatesSchemaAndTables` | Full migration on fresh DB — versions scanned as `int`, verifies `0` and `1` recorded, all 6 application tables verified | | `TestApplyMigrations_Idempotent` | Double-apply: no errors, exactly 1 row for version `0` (queried as int) | | `TestBootstrapMigrationsTable_FreshDatabase` | Bootstrap alone: table created, version `0` recorded (queried as int) | All tests use `int` types for version comparisons and format verbs. Backwards-compat test correctly removed per earlier rework. ✅ --- ### 6. Cheating Check Only 3 files in diff: `database.go`, `database_test.go`, `000.sql`. No modifications to `.golangci.yml`, `Makefile`, `Dockerfile`, `.gitea/workflows/`, or any test configuration. Test helper `openTestDB` is a new addition (DRY refactor) — not a policy-controlled file. ✅ --- ### 7. Build Result `docker build --no-cache .` — **PASSED** ✅ All stages green: `make fmt-check`, `make lint`, `make test` (all tests pass), `go build`. --- ### Verdict: **PASS** ✅ Clean implementation. `version INTEGER PRIMARY KEY` throughout — SQL schema, Go const, `ParseMigrationVersion` return type, all queries, all tests. `000.sql` is fully self-contained with DDL + version row. No backwards-compat code. No Go-side INSERTs for bootstrap. All four rounds of sneak's feedback addressed. Build is green.
clawbot added merge-ready and removed needs-review labels 2026-03-20 07:13:35 +01:00
clawbot removed their assignment 2026-03-20 07:13:35 +01:00
sneak was assigned by clawbot 2026-03-20 07:13:35 +01:00
sneak added 1 commit 2026-03-20 23:58:10 +01:00
Merge branch 'main' into feature/migrations-table-schema-file
All checks were successful
check / check (push) Successful in 1m0s
862226b910
Some checks are pending
check / check (push) Successful in 1m0s
Check / check (pull_request)
Required
Some required checks are missing.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feature/migrations-table-schema-file:feature/migrations-table-schema-file
git checkout feature/migrations-table-schema-file
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#36