Build a queue schema version table for local migrations

Direct answer

A queue database can survive many versions of the code that opens it, so the database needs its own version marker. A one-row schema_version table makes the migration’s assumed starting point queryable. The migration reads version 1, adds the new attempts column, and only then records version 2. That ordering allows a reviewer to see what structural change corresponds to a number.

The second call is the edge case worth testing. Re-running the migration against version 2 raises instead of silently attempting the same ALTER TABLE. That protects against an upgrader guessing its way through an unknown state. The error names both the expected and observed version, which is usually more actionable than a generic SQL failure.

This fixture is in memory and omits transaction wrapping across several migration statements, backup strategy, downgrade support, and concurrent application startup. For a real file, put the migration and version update in the transaction shape appropriate to the supported SQLite operations, and test interruption at each migration boundary.

Complete example

import sqlite3


def migrate_to_two(connection: sqlite3.Connection) -> None:
    version = connection.execute("SELECT version FROM schema_version").fetchone()[0]
    if version != 1:
        raise ValueError(f"expected version 1, got {version}")
    connection.execute("ALTER TABLE jobs ADD COLUMN attempts INTEGER NOT NULL DEFAULT 0")
    connection.execute("UPDATE schema_version SET version = 2")


connection = sqlite3.connect(":memory:")
connection.execute("CREATE TABLE schema_version (version INTEGER NOT NULL)")
connection.execute("CREATE TABLE jobs (id INTEGER PRIMARY KEY)")
connection.execute("INSERT INTO schema_version VALUES (1)")
migrate_to_two(connection)
assert connection.execute("SELECT version FROM schema_version").fetchone()[0] == 2
try:
    migrate_to_two(connection)
except ValueError as error:
    assert str(error) == "expected version 1, got 2"
else:
    raise AssertionError("migration accepted an unexpected version")
print("schema_version=2 repeat=blocked")

Expected stdout:

schema_version=2 repeat=blocked

Sources

- sqlite3 — DB-API 2.0 interface for SQLite

- SQLite transaction documentation

Prepared with AI assistance. The example uses synthetic data; its stated limits apply.

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic