0%

Create, Import, and Evolve a Schema · practice

Refuse a Version That Disagrees with Its Shape

A version number is only one piece of evidence. A file may claim version 1 while already containing members.email, or claim version 2 while missing a table. Running a migration on either file could make the damage worse.

Complete prepare_database(database_path) in catalog_setup.py. The caller passes the exact path. Your opens that path, reads PRAGMA user_version, reads user table names, and reads ordered columns with the three fixed PRAGMA table_info(...) statements in the starter.

Decide the whole action before changing anything:

  • Version 0 with no user tables is blank, so create version 2.

  • Version 0 with any user table is unknown. Raise ValueError("Database has tables but no schema version.").

  • Exact version 1 shape migrates once.

  • Exact version 2 shape is already ready and stays untouched.

  • Any other marker raises ValueError("Schema version N is not supported.").

  • Version 1 or 2 with different tables or ordered columns raises ValueError("Schema version N does not match the expected tables and columns.").

Here is the same decision compressed into four safe routes. In every route, the version and the actual shape are checked together:

Checking both version and schema shape leads to create version 2 for a blank database, migrate an exact version 1 database, reuse an exact version 2 database, or refuse an unsupported or mismatched database without changing it.

Run uses four temporary paths and calls the same function as prepare_database(missing_path), prepare_database(version_one_path), prepare_database(version_two_path), and prepare_database(mismatched_path):

== guard schema compatibility ==
missing database -> version 2
exact version 1 -> version 2; M-17 email NULL
exact version 2 -> unchanged; M-18 email alex@example.com
mismatched version 1 -> Error: Schema version 1 does not match the expected tables and columns.

An extra table also counts as disagreement. Ordered columns matter because changing their order can reveal a different schema even when the names form the same set.

Close every connection this path-owning function opens, including on refusal. Do not rebuild a current database or migrate before its version 1 shape has passed the complete check. Refusal should be boring: the marker, columns, and rows remain exactly as they were.

That predictable refusal gives the caller a precise recovery choice instead of a partly modified file.

Task

Complete prepare_database(database_path) in catalog_setup.py.

Implement the exact blank, unversioned-table, version 1, version 2, unsupported-version, and marker/shape disagreement decisions described above. Inspect all three tables and their ordered columns before migrating. Close the connection in finally, and never change a refused database.