server: add SQLAlchemy + Alembic dependencies and skeleton#321
Open
nissessenap wants to merge 1 commit intomozilla-ai:mainfrom
Open
server: add SQLAlchemy + Alembic dependencies and skeleton#321nissessenap wants to merge 1 commit intomozilla-ai:mainfrom
nissessenap wants to merge 1 commit intomozilla-ai:mainfrom
Conversation
Part of mozilla-ai#257 (Phase 1, step 1) — per RFC mozilla-ai#275 and issue mozilla-ai#304. Land the dependency + Alembic skeleton so follow-up children (baseline migration, async Store protocol, SqliteStore, CQ_DATABASE_URL factory) have something to build on. Passive infrastructure only: no migrations are defined, no runtime code imports SQLAlchemy or Alembic, and app.py/store.py/tables.py are untouched. - server/backend/pyproject.toml: add sqlalchemy>=2.0.49,<2.1 and alembic>=1.18.4,<2 to runtime dependencies; uv.lock regenerated. - server/backend/src/cq_server/db_url.py: resolve_database_url() helper centralising the CQ_DATABASE_URL -> CQ_DB_PATH -> default precedence. No runtime callers yet; mozilla-ai#309 will wire it into the store factory. - server/backend/alembic.ini + alembic/env.py + script.py.mako + versions/.gitkeep: minimal skeleton. env.py sets render_as_batch=True in both online and offline modes so future migrations run cleanly on SQLite; target_metadata is None until mozilla-ai#305 adds the baseline. - server/backend/README.md: short note explaining the wiring and the URL precedence; full env-var docs land with mozilla-ai#309. - tests/test_db_url.py: three TDD cases (explicit URL wins, CQ_DB_PATH wraps as sqlite:///, default). Acceptance: - alembic current runs cleanly against an existing dev SQLite DB (exits 0, no revision printed — no migrations defined yet). - Full server test suite green (193 passed). - make lint-server-backend clean. - No change in server runtime behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #304. Part of the #257 epic (Phase 1, step 1) — passive
infrastructure only; no migrations, no runtime code imports either
library,
app.py/store.py/tables.pyuntouched.What's in
server/backend/pyproject.toml:sqlalchemy>=2.0.49,<2.1andalembic>=1.18.4,<2added to runtime deps.server/backend/uv.lock: regenerated. Diff vsmainis only the 5net-new packages (alembic, mako, sqlalchemy, greenlet, markupsafe);
no pre-existing entry changed.
server/backend/src/cq_server/db_url.py:resolve_database_url()helper centralising the precedence
CQ_DATABASE_URL→CQ_DB_PATH(wrapped assqlite:///…) → default/data/cq.db.No runtime callers yet; Wire
CQ_DATABASE_URLand store factory #309 will wire it into the store factory.server/backend/alembic.ini+alembic/env.py+alembic/script.py.mako+ emptyversions/: minimal skeleton.env.pysetsrender_as_batch=Truein both online and offlinemodes so future migrations run cleanly on SQLite;
target_metadata=Noneuntil Baseline Alembic migration + stamp-on-startup logic #305 adds the baseline.server/backend/README.md: short note explaining the wiring isstaged-but-unused and documenting the URL precedence.
tests/test_db_url.py: four TDD cases covering explicit URL wins,CQ_DB_PATHwrapping, the/data/cq.dbdefault, and empty-stringCQ_DATABASE_URLfalling through toCQ_DB_PATH(containerorchestrators sometimes pass empty env vars).
What's intentionally out
Deferred to the next Phase 1 children per #257's dep graph:
Storeprotocol → Define asyncStoreprotocol #306.SqliteStorevia the protocol → ImplementSqliteStoreagainstStoreprotocol via Core helpers #308.CQ_DATABASE_URLwiring + store factory → WireCQ_DATABASE_URLand store factory #309._ensure_*DDL → Remove ad-hoc_ensure_*DDL now that Alembic owns the schema #310.CQ_DATABASE_URLin deployment / configuration docs #319.Known follow-up
alembic/env.pyroutes the resolved URL throughconfig.set_main_option("sqlalchemy.url", …), which internally usesConfigParser—%characters are treated as interpolation tokens.Harmless today (SQLite paths only), but a Postgres URL containing a
URL-encoded password (
p%40ss) would blow up. An in-line commentflags this for #309 to resolve — either by escaping at the boundary
or, cleaner, by dropping the
ConfigParserround-trip and passingthe URL straight to
context.configure(url=…)/create_engine(…).Test plan
cd server/backend && CQ_DB_PATH=/tmp/cq.db uv run alembic currentexits 0 with no revision printed (acceptance criterion from Add SQLAlchemy + Alembic dependencies and Alembic skeleton #304).
uv run pytest→ 194 passed.uv run pre-commit run --all-filesclean.alembic checkfails with the expected "no MetaData" message —correct, since
target_metadata=Noneuntil Baseline Alembic migration + stamp-on-startup logic #305.app.pystill calls_ensure_schema()and opens raw sqlite3 connections exactly as onmain.🤖 Generated with Claude Code