Phase 1: introduce SQLModel models alongside Prisma, with parity guard - #28366
Phase 1: introduce SQLModel models alongside Prisma, with parity guard#28366mateo-berri wants to merge 1 commit into
Conversation
Foundation for the multi-phase migration of the proxy persistence layer
from Prisma (prisma-client-py==0.11.0) to SQLModel/SQLAlchemy. This change
is non-functional at runtime: nothing imports the new package from the
existing proxy code paths.
Adds:
* litellm/proxy/db/sqlmodel/schema_parser.py
Pure-Python parser for the subset of Prisma DSL used by schema.prisma.
* litellm/proxy/db/sqlmodel/_generate.py
Code generator that emits SQLModel class definitions from a parsed
schema. Produces Black-formatted output. Run manually after schema
changes:
uv run python -m litellm.proxy.db.sqlmodel._generate \
--schema schema.prisma \
--out litellm/proxy/db/sqlmodel/models.py
* litellm/proxy/db/sqlmodel/models.py
SQLModel classes for all 64 Prisma models, hand-editable. Composite
primary keys, @@unique, @@index (incl. map: '...' renames), @@Map,
String[] arrays, BigInt, Json/JSONB, @updatedat, @default(uuid()/now()),
and reserved Python attribute names (metadata -> metadata_) are all
preserved structurally.
* tests/test_litellm/proxy/db/sqlmodel_orm/{test_schema_parser,test_parity}.py
20 tests covering the parser unit cases, structural parity between
every Prisma model and its SQLModel class (columns, nullability, type
category, ARRAY-ness, primary keys, uniques, indexes), and a strict
guard that the committed models.py is byte-identical to a fresh
generator run.
* litellm/proxy/db/sqlmodel/README.md
Phase 1 plan and the explicit out-of-scope items reserved for later
phases (session abstraction, raw-SQL hotspot port, per-table call site
migration, replacement of PrismaWrapper / RoutingPrismaWrapper /
exception classifier, Alembic migrations, Prisma teardown).
Dependencies:
* Adds 'sqlmodel>=0.0.22,<1.0' to the extra_proxy optional group. This
pulls in SQLAlchemy as a transitive dep. Existing Prisma deps are
unchanged.
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
|
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
🚅 Hi, thanks for the PR! I'm Agent Shin, the automated triage bot for this repository. What's this and why am I getting it? I read the description against our contribution rubric. Here's how it lined up: What you got right:
What's still missing:
If the description isn't updated in the next 24 hours, I'll auto-close this PR. That's not us saying we don't care about the change; we want the open-PR list to mirror what a maintainer can act on right now, so contributors don't get lost in a backlog. A closed PR is a soft "park this for later," not a rejection. Take your time; everything below still works after the close. During the grace period: just update the PR description with the missing pieces. No need to ping me; I'll re-check on the next sweep and skip the auto-close if it now passes. See what counts as QA proof for the full rubric (a linked issue alone isn't enough; it covers context, not proof). If the PR does get auto-closed in 24 hours, you still have easy recovery paths:
Internal BerriAI contributors: this rubric doesn't apply to you; ping a maintainer. (I'm an LLM, so I'm not infallible. If you think I got this wrong, ping a maintainer; they'll override me.) |
Relevant issues
First PR in a multi-phase migration of the proxy persistence layer from Prisma (
prisma-client-py==0.11.0) to SQLModel/SQLAlchemy.Why phased
Scoping the full migration showed:
prisma_client.db.<model>call sites across ~147 production filesquery_raw/execute_rawcalls across ~37 filesschema.prismacopies, 123 bundled SQL migrationsPrismaWrapper(RDS IAM token rotation),RoutingPrismaWrapper(read-replica split),PrismaDBExceptionHandler(~10 distinct error classifications)prisma generate, plus CI workflows, helm charts, and a separately-publishedlitellm-proxy-extraspackage bundling the migrationsA big-bang cutover would be unreviewable and unsafe. Each phase below lands as its own PR.
What this PR ships (Phase 1)
Foundation only — no runtime behaviour changes. Nothing in the existing proxy imports the new package; it sits alongside Prisma and is guarded against drift.
litellm/proxy/db/sqlmodel/schema_parser.pyschema.prisma.litellm/proxy/db/sqlmodel/_generate.pylitellm/proxy/db/sqlmodel/models.pylitellm/proxy/db/sqlmodel/README.mdtests/test_litellm/proxy/db/sqlmodel_orm/test_schema_parser.pytests/test_litellm/proxy/db/sqlmodel_orm/test_parity.pypyproject.toml/uv.locksqlmodel>=0.0.22,<1.0toextra_proxy.Tricky cases the generator handles
@@id([a, b])) →PrimaryKeyConstraint@@unique([...])) →UniqueConstraint@@index([...], map: "...")) →Index("custom_name", ...)<table>_<col>_..._idx)@@map("foo_table")→__tablename__ = "foo_table"@map("created_at")→sa_column_kwargs={'name': 'created_at'}String[]→ARRAY(Text())(Postgres-specific, matching Prisma)Json→JSONBwith both Pythondefault_factoryandserver_default=text("'{}'::jsonb")so omitted-column INSERTs match@updatedAt→sa_column_kwargs={'onupdate': lambda: datetime.utcnow()}@default(uuid())/@default(cuid())→default_factory=lambda: str(uuid.uuid4())metadata,registryclash with SQLAlchemy Declarative) → Python attribute renamed tometadata_while the on-disk column name remainsmetadataParity test coverage
The 9 parity tests fail CI if
models.pyandschema.prismadrift in any of:BigInt→ BigInteger-class, never Integer)String[]↔ARRAY(...))models.pyand a fresh generator run (catches any drift the structural checks miss)Manually verified
from litellm.proxy.db.sqlmodel.models import ALL_MODELSreturns 64 classes)schema.prisma(verified by mutation) is correctly flagged bytest_columns_match_for_every_tableWhat is explicitly not in this PR
These belong to subsequent phases — see
litellm/proxy/db/sqlmodel/README.mdfor the full plan:prisma_clienttoday andAsyncSessiontomorrow.PrismaWrapper/RoutingPrismaWrapper/PrismaDBExceptionHandlerequivalents.pyproject.toml, removeprisma generatefrom 7 Dockerfiles, retirelitellm-proxy-extras, retire the 3schema.prismacopies and theircheck-schema-sync/sync-schemaworkflows.Linear ticket
n/a — agent-driven scoping work.
Pre-Submission checklist
tests/test_litellm/proxy/db/sqlmodel_orm/(20 tests covering both the parser and Prisma↔SQLModel parity).uv run pytest tests/test_litellm/proxy/db/sqlmodel_orm/— 20/20 passing.uv run ruff check litellm/proxy/db/sqlmodel/— clean.uv run black --check litellm/proxy/db/sqlmodel/ tests/test_litellm/proxy/db/sqlmodel_orm/— clean.Slack Thread