CodeRigor

LESSON

Plan versioned checksum-checked migrations

Accept an exact applied migration prefix and reject drift, gaps or unknown future history.

A versioned migration is a controlled database change with an identity and exact source bytes. A history row says which version was applied and which checksum was reviewed. Editing an already applied file creates drift rather than a new migration.

The native task plans an exact prefix. The real adapter uses a transaction and an advisory transaction lock before reading history, then applies pending SQL and records checksums together. The supplied catalog has two reviewed versions, followed by a deliberately failing third proposal used to prove rollback.

Plan versioned checksum-checked migrations
start / 3
Accept an exact applied migration prefix and reject drift, gaps or unknown future history.
Plan versioned checksum-checked migrations
Accept an exact applied migration prefix and reject drift, gaps or unknown future history.

PendingMigrations checks order and exact checksums, then copies only the unapplied suffix. Returning an aliased slice would let a caller mutate the reviewed catalog accidentally. Even a trailing newline changes the checksum because the bytes differ.

The database adapter takes its advisory transaction lock before reading migration history. A failed migration’s DDL and history update roll back together. This small runner is deliberately local and bounded; it is not a full replacement for an established migration tool in a larger application.

Go
package main
import ("fmt";"crypto/sha256")
func main(){
a:=sha256.Sum256([]byte("sql"));b:=sha256.Sum256([]byte("sql\n"));fmt.Println(a==b)
}

A checksum does not prove that SQL is safe or correct. It binds an applied version to reviewed bytes. The owner still reviews the migration and its data effects. A new legitimate change belongs in a new version, not an edited historical file.

The failing third proposal creates a table and then divides by zero. The actual lab verifies the table is absent afterward and history still has two versions. Reapplying the unchanged two-version catalog performs no new work.

Review source, target and evidence
start / 3
A successful migration includes typed values, actual database behavior and explicit cleanup.
Review source, target and evidence
A successful migration includes typed values, actual database behavior and explicit cleanup.
Go
package main
import ("fmt")
func main(){
catalog:=[]int{1,2};applied:=1;pending:=append([]int{},catalog[applied:]...);pending[0]=99;fmt.Println(catalog,pending)
}

Implement exact history-prefix planning and reject edited history. Next use parameters and a transaction around related application writes.

Actual local SQLite + PostgreSQL 18.6

The records survive the database boundary.

This snapshot came from the owned local lab. Choose an imported identity to inspect its actual source and canonical target. Reconciliation covers all fields, before a separate successful application write brings the final note count to four.

  1. 1 · Schemaowners · notes · events
  2. 2 · Indexowner lookup
  3. Reapplyzero pending versions
  4. Bad version 3DDL/history rolled back

SQLite source · ID 1

JSON
{
  "id": 1,
  "owner_id": 1,
  "title": " first note ",
  "done": 0,
  "cents": 29,
  "created_at": "2024-01-01T01:00:00+01:00"
}

PostgreSQL canonical row

JSON
{
  "id": 1,
  "owner_id": 1,
  "title": "first note",
  "done": false,
  "cents": 29,
  "created_at": "2024-01-01T00:00:00Z"
}
done → booleancents → bigintcreated_at → timestamp with time zone

3 source rows · 3 target rows · no missing, unexpected or changed identities

Inspect the separate database checks
Quoted owner name
2 matching rows with a bound parameter
Injection-shaped name
0 matches · value remains data
Next generated identity
43 after imported maximum 42
Failed note/event transaction
Partial note write rolled back
Foreign key and cents constraints
Actual invalid inserts rejected
Canceled query
Cancellation observed; pool usable afterward
Application role
Nonsuperuser · pool maximum two connections
Owned cleanup
Cluster stop confirmed; fixture directory removed
Download the application, migrations, real database launcher and tests →

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Optional database overview. The authored lessons and real local lab teach the exact schema, migration and application-lifetime boundaries used here.