CodeRigor

LESSON

Reconcile the actual migrated application

Compare every canonical row by identity and fields, then challenge real PostgreSQL migrations and writes.

Counts and totals can match while individual records are wrong. The capstone compares canonical rows by identity, including owner relationship, title, boolean state, exact cents and timestamp. It reports missing, unexpected and changed IDs in stable order.

Then run the real adapters. Python creates and queries SQLite; Go uses maintained pgx to migrate/import/query PostgreSQL; psql independently checks the final row count. The output distinguishes full-row reconciliation from additional migration, constraint, transaction and lifetime evidence.

Reconcile the actual migrated application
start / 3
Compare every canonical row by identity and fields, then challenge real PostgreSQL migrations and writes.
Reconcile the actual migrated application
Compare every canonical row by identity and fields, then challenge real PostgreSQL migrations and writes.

The source SQLite database is built from fixtures/source.sql in the new owned directory, then read back into typed JSON. Go validates and inserts those actual rows in a transaction. ReadNotes scans typed PostgreSQL results, normalizes UTC formatting and compares the complete records.

After reconciliation, the lab verifies quoted names, a rejected injection-shaped value, generated identity, foreign keys, cents checks, atomic writes, checksum drift, failed-DDL rollback and query cancellation. A canceled query is followed by a successful pool ping. These observations concern the supplied local application, not production readiness.

Go
package main
import ("fmt";"reflect")
func main(){
a:=map[int]int{7:29,42:71};b:=map[int]int{7:71,42:29};fmt.Println(len(a)==len(b),a[7]+a[42]==b[7]+b[42],reflect.DeepEqual(a,b))
}

A full-row comparator distinguishes identity mismatch from field mismatch. Duplicate IDs are invalid input, not an instruction to silently keep the last row. Target rows must already be canonical; otherwise the comparison would hide a target-side normalization defect.

The download includes complete source, versioned SQL, public contract tests, deterministic fixtures, starter and cleanup instructions. Its server is local-only, freshly owned and stopped before removal. The hosted tasks remain pure standard-library Go, preserving the playground’s offline boundary.

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";"sort")
func main(){
ids:=[]int{42,7,1};sort.Ints(ids);fmt.Println(ids)
}

Run go mod download, go test ./... and python3 -B lab.py in the extracted lab. Inspect the complete JSON report, actual target types, full-row reconciliation and psql assertion. The launcher stops and removes only its owned fixture cluster; it never reuses a server or touches learner progress.

Read the known limits: the fixture uses whole-second timestamps, bounded imported IDs/cents and a small local application role. Future production work needs its own authentication, backup, deployment, migration and operating plan.

Download the complete PostgreSQL migration lab: Go/pgx application, isolated PostgreSQL launcher, actual SQLite fixtures, starter, tests and run/cleanup instructions.

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.