Migration filenames now follow the pattern <version>_<description>.sql (e.g. 001_initial_schema.sql). The version stored in schema_migrations is the numeric prefix only, not the full filename stem.
Changes
ParseMigrationVersion() — new exported function that extracts the numeric prefix from migration filenames. Validates that the prefix is purely numeric and rejects malformed filenames (empty prefix, non-numeric characters, leading underscore).
Renamed 001.sql → 001_initial_schema.sql — migration files can now have descriptive names while the tracked version remains 001. This is safe pre-1.0.0 (no installed base).
Deduplicated migration logic — runMigrations() and ApplyMigrations() now share a single applyMigrations() implementation, plus extracted collectMigrations() and ensureMigrationsTable() helpers.
Unit tests — TestParseMigrationVersion covers valid patterns (version-only, with description, multi-digit, multiple underscores) and error cases (empty, leading underscore, non-numeric, mixed alphanumeric). TestApplyMigrations and TestApplyMigrationsIdempotent verify end-to-end migration application against an in-memory SQLite database.
Closes #28
Migration filenames now follow the pattern `<version>_<description>.sql` (e.g. `001_initial_schema.sql`). The version stored in `schema_migrations` is the numeric prefix only, not the full filename stem.
## Changes
- **`ParseMigrationVersion()`** — new exported function that extracts the numeric prefix from migration filenames. Validates that the prefix is purely numeric and rejects malformed filenames (empty prefix, non-numeric characters, leading underscore).
- **Renamed `001.sql` → `001_initial_schema.sql`** — migration files can now have descriptive names while the tracked version remains `001`. This is safe pre-1.0.0 (no installed base).
- **Deduplicated migration logic** — `runMigrations()` and `ApplyMigrations()` now share a single `applyMigrations()` implementation, plus extracted `collectMigrations()` and `ensureMigrationsTable()` helpers.
- **Unit tests** — `TestParseMigrationVersion` covers valid patterns (version-only, with description, multi-digit, multiple underscores) and error cases (empty, leading underscore, non-numeric, mixed alphanumeric). `TestApplyMigrations` and `TestApplyMigrationsIdempotent` verify end-to-end migration application against an in-memory SQLite database.
Migration filenames now follow the pattern <version>_<description>.sql
(e.g. 001_initial_schema.sql). The version stored in schema_migrations
is the numeric prefix only, not the full filename stem.
Changes:
- Add ParseMigrationVersion() to extract numeric prefix from filenames
- Validate version is purely numeric, reject malformed filenames
- Rename 001.sql to 001_initial_schema.sql for clarity
- Deduplicate runMigrations/ApplyMigrations via shared applyMigrations()
- Add comprehensive unit tests for version parsing and migration apply
Closes#28
Remove the unexported applyMigrations() and the runMigrations() method.
ApplyMigrations() is now the single implementation, accepting context
and an optional logger. connect() calls it directly.
All callers updated to pass context.Background() and nil logger.
The unexported applyMigrations() function and the runMigrations() method have been removed. There is now a single ApplyMigrations(ctx context.Context, db *sql.DB, log *slog.Logger) that serves both the production path (called from connect() with context and logger) and the test path (called with context.Background() and nil logger).
Changes:
Removed unexported applyMigrations(ctx, db, log) standalone function
Removed runMigrations(ctx) method on Database
Expanded exported ApplyMigrations signature to accept context.Context and optional *slog.Logger
connect() now calls ApplyMigrations(ctx, s.db, s.log) directly
Updated all test callers across database, imgcache, and handlers packages
All tests pass, docker build . succeeds.
## Rework: consolidated duplicate applyMigrations
The unexported `applyMigrations()` function and the `runMigrations()` method have been removed. There is now a single `ApplyMigrations(ctx context.Context, db *sql.DB, log *slog.Logger)` that serves both the production path (called from `connect()` with context and logger) and the test path (called with `context.Background()` and `nil` logger).
**Changes:**
- Removed unexported `applyMigrations(ctx, db, log)` standalone function
- Removed `runMigrations(ctx)` method on `Database`
- Expanded exported `ApplyMigrations` signature to accept `context.Context` and optional `*slog.Logger`
- `connect()` now calls `ApplyMigrations(ctx, s.db, s.log)` directly
- Updated all test callers across `database`, `imgcache`, and `handlers` packages
All tests pass, `docker build .` succeeds.
Parse version out of migration filename — ParseMigrationVersion() extracts the numeric prefix from <version>_<description>.sql filenames. Validates purely numeric prefix, rejects empty prefix, leading underscore, non-numeric characters.
Migration files use descriptive names — 001.sql renamed to 001_initial_schema.sql; tracked version remains 001.
Consolidate duplicate applyMigrations (sneak's comment) — single exported ApplyMigrations(ctx, db, log) replaces both the unexported standalone function and the runMigrations method. All callers updated.
Unit tests — TestParseMigrationVersion (9 cases: valid patterns + error cases), TestApplyMigrations (end-to-end against in-memory SQLite), TestApplyMigrationsIdempotent (double-apply correctness).
Code Quality
Clean decomposition: collectMigrations(), ensureMigrationsTable(), ApplyMigrations() are well-separated concerns
Optional *slog.Logger parameter with nil-safe checks — clean API for both production and test paths
Error messages include filename context for debuggability
Rebased onto main — already up to date, build confirmed.
Verdict: PASS
## Review: [PR #33](https://git.eeqj.de/sneak/pixa/pulls/33) — feat: parse version prefix from migration filenames
### Policy Compliance
No policy violations found. Specifically:
- No modifications to `.golangci.yml`, Makefile, Dockerfile, or CI config
- No weakened assertions or test shortcuts
- New exported function has unit tests
- `go fmt` passes, linter passes (0 issues)
- External references unchanged; no new unpinned dependencies
- Migration files remain in `internal/database/schema/` (pre-existing path; not changed by this PR)
### Requirements Checklist ([Issue #28](https://git.eeqj.de/sneak/pixa/issues/28))
- [x] **Parse version out of migration filename** — `ParseMigrationVersion()` extracts the numeric prefix from `<version>_<description>.sql` filenames. Validates purely numeric prefix, rejects empty prefix, leading underscore, non-numeric characters.
- [x] **Migration files use descriptive names** — `001.sql` renamed to `001_initial_schema.sql`; tracked version remains `001`.
- [x] **Consolidate duplicate applyMigrations** (sneak's comment) — single exported `ApplyMigrations(ctx, db, log)` replaces both the unexported standalone function and the `runMigrations` method. All callers updated.
- [x] **Unit tests** — `TestParseMigrationVersion` (9 cases: valid patterns + error cases), `TestApplyMigrations` (end-to-end against in-memory SQLite), `TestApplyMigrationsIdempotent` (double-apply correctness).
### Code Quality
- Clean decomposition: `collectMigrations()`, `ensureMigrationsTable()`, `ApplyMigrations()` are well-separated concerns
- Optional `*slog.Logger` parameter with nil-safe checks — clean API for both production and test paths
- Error messages include filename context for debuggability
- Edge cases handled: empty filename, leading underscore, mixed alphanumeric, no-underscore filenames
- All existing test callers (`handlers_test.go`, `stats_test.go`, `testutil_test.go`) updated to new signature
### Build Result
`docker build .` **PASSES** — fmt-check ✅, lint (0 issues) ✅, all tests pass ✅, binary builds ✅
Rebased onto `main` — already up to date, build confirmed.
### Verdict: **PASS**
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #28
Migration filenames now follow the pattern
<version>_<description>.sql(e.g.001_initial_schema.sql). The version stored inschema_migrationsis the numeric prefix only, not the full filename stem.Changes
ParseMigrationVersion()— new exported function that extracts the numeric prefix from migration filenames. Validates that the prefix is purely numeric and rejects malformed filenames (empty prefix, non-numeric characters, leading underscore).001.sql→001_initial_schema.sql— migration files can now have descriptive names while the tracked version remains001. This is safe pre-1.0.0 (no installed base).runMigrations()andApplyMigrations()now share a singleapplyMigrations()implementation, plus extractedcollectMigrations()andensureMigrationsTable()helpers.TestParseMigrationVersioncovers valid patterns (version-only, with description, multi-digit, multiple underscores) and error cases (empty, leading underscore, non-numeric, mixed alphanumeric).TestApplyMigrationsandTestApplyMigrationsIdempotentverify end-to-end migration application against an in-memory SQLite database.why are there two applyMigrations
Rework: consolidated duplicate applyMigrations
The unexported
applyMigrations()function and therunMigrations()method have been removed. There is now a singleApplyMigrations(ctx context.Context, db *sql.DB, log *slog.Logger)that serves both the production path (called fromconnect()with context and logger) and the test path (called withcontext.Background()andnillogger).Changes:
applyMigrations(ctx, db, log)standalone functionrunMigrations(ctx)method onDatabaseApplyMigrationssignature to acceptcontext.Contextand optional*slog.Loggerconnect()now callsApplyMigrations(ctx, s.db, s.log)directlydatabase,imgcache, andhandlerspackagesAll tests pass,
docker build .succeeds.Review: PR #33 — feat: parse version prefix from migration filenames
Policy Compliance
No policy violations found. Specifically:
.golangci.yml, Makefile, Dockerfile, or CI configgo fmtpasses, linter passes (0 issues)internal/database/schema/(pre-existing path; not changed by this PR)Requirements Checklist (Issue #28)
ParseMigrationVersion()extracts the numeric prefix from<version>_<description>.sqlfilenames. Validates purely numeric prefix, rejects empty prefix, leading underscore, non-numeric characters.001.sqlrenamed to001_initial_schema.sql; tracked version remains001.ApplyMigrations(ctx, db, log)replaces both the unexported standalone function and therunMigrationsmethod. All callers updated.TestParseMigrationVersion(9 cases: valid patterns + error cases),TestApplyMigrations(end-to-end against in-memory SQLite),TestApplyMigrationsIdempotent(double-apply correctness).Code Quality
collectMigrations(),ensureMigrationsTable(),ApplyMigrations()are well-separated concerns*slog.Loggerparameter with nil-safe checks — clean API for both production and test pathshandlers_test.go,stats_test.go,testutil_test.go) updated to new signatureBuild Result
docker build .PASSES — fmt-check ✅, lint (0 issues) ✅, all tests pass ✅, binary builds ✅Rebased onto
main— already up to date, build confirmed.Verdict: PASS