- Collect: replace WalkDir with ReadDir to avoid subdirectory recursion
and the risk of duplicate filenames silently overwriting each other
- shmigrate: check scanner.Err() after reading migrations log
- shmigrate: shell-quote all paths in generated scripts to prevent
shell injection via migration filenames
- shmigrate: wrap errors with ErrQueryApplied sentinel for consistency
with DB backends
- mustInit: remove stale err check that could never fire
- mustInit: fix swapped error messages (read vs create)
parseAndFixupBatches treated every line as a migration name, but the
new log format uses id\tname (tab-separated). This caused fixupMigration
to look for non-existent files like '05aba66a\t2026-06-03-003000_team-create.up.sql'.
Align with shmigrate.Applied() which already handles both formats.
Replace directives pointing to local paths prevent `go install` from
working. Use published module versions (sqlmigrate v1.0.2, shmigrate
v1.0.2) so users can install with:
go install github.com/therootcompany/golib/cmd/sql-migrate/v2@latest
- Use full flag names in command defaults (--no-align, --tuples-only, etc.)
- Add sqlite/sqlite3/lite alias for SQLite
- Add sqlcmd/mssql/sqlserver alias for SQL Server (go-sqlcmd, TDS 8.0)
- Add SQL Server help text with SQLCMD env vars and TLS docs
- Add sqlite and sqlcmd SELECT expressions for id+name migration log
Migration{ID, Name} is the identity type returned by Up/Down/Latest/Drop.
Script{Migration, Up, Down} holds collected SQL content from Collect().
Migrator interface now takes SQL as a separate parameter:
ExecUp(ctx, Migration, sql string)
ExecDown(ctx, Migration, sql string)
This separates identity from content — callers that track what ran
don't need to carry around SQL strings they'll never use.
Updates shmigrate to match (ignores the sql parameter, references
files on disk instead).
- logMigrationsSelect() returns DB-specific SELECT for id+name output,
matching psql explicitly and erroring on unrecognized --sql-command
- logMigrationsQueryNote const for the comment header
- maybeUpgradeLogQuery() auto-upgrades old _migrations.sql on first run,
replacing only the matching SELECT line
- Add UPGRADING help section pointing to sync subcommand
Passing 0 to Up() or Down() is an easy mistake — it silently means
"all" which could be destructive. Now n=0 returns ErrInvalidN.
Convention: n > 0 for a specific count, n < 0 (typically -1) for all.
Factor the inline migration logic from cmd/sql-migrate into reusable
packages: database/sqlmigrate (core types, matching, file collection)
and database/sqlmigrate/shmigrate (shell script generation backend).
No behavior changes — the CLI produces identical output. The shmigrate
package implements the sqlmigrate.Migrator interface so other backends
(pgmigrate, mymigrate, etc.) can follow the same pattern.
Document how to use PGOPTIONS="-c search_path=..." for multi-tenant
PostgreSQL migrations. Each schema gets its own _migrations table,
so tenants are migrated independently.
An explicit 0 argument should error, not silently run all pending (up)
or get handled as a special case (down). Change the guard from < 0 to
< 1 in both subcommands so '0' is treated as invalid input.
An explicit 0 argument to 'up' should error (like 'down 0' already
does), not silently run all pending migrations. Change the guard
from < 0 to < 1 to match 'down' behavior.
The psql command constant uses -A -t (--no-align --tuples-only) but
the help text and code comments only showed --no-align. Without
--tuples-only, psql prints column headers into migrations.log,
corrupting it.