feat(python): PostgREST/Supabase query dialect in generated services (parity with TS #36/#56-#60) - #117
Open
cultron wants to merge 1 commit into
Open
feat(python): PostgREST/Supabase query dialect in generated services (parity with TS #36/#56-#60)#117cultron wants to merge 1 commit into
cultron wants to merge 1 commit into
Conversation
Port the @apso/crud PostgREST dialect to the Python (FastAPI+SQLAlchemy) code generator, so generated services accept the same PostgREST URL conventions the TypeScript services now do (parity with TS #36/#56-#60). The generated utils/query.py gains a second parser path alongside the incumbent nestjsx parser: - select=a,b (+ alias:col rename #57, + rel(cols) embeds as eager loads) - col=op.value filters: eq/neq/gt/gte/lt/lte/like/ilike/in/is and not.<op>, with the TS operator mapping and *->% like/ilike wildcards - or=(...) / and=(...) logical groups, nested (#56) - order=col.asc|desc[.nullsfirst|nullslast] - limit / offset Dialect detection mirrors dialect.ts: X-Crud-Dialect header wins (postgrest|nestjsx, else 400); otherwise param-shape (select/order or a bare col=op.value => postgrest; fields/filter/join/sort/s/or/per_page => nestjsx; both families => 400; default nestjsx). The router passes the header + raw query to the parser. Response shaping: the postgrest path returns a BARE JSON array (no {data,count} envelope), even with limit/offset (#58); nestjsx keeps its envelope. An unknown filter/select/order column on the postgrest path is a 400, not a 500 (#60). Deferred (as in TS): cs/cd/ov/fts and range operators (#54) are rejected clearly. Embedded resource filtering (rel.col=op.value) is deferred and rejected: the Python join path uses selectinload (a separate SELECT) and cannot push a predicate into a JOIN ON clause; select embeds still load the relation. nestjsx behavior is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
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.
Ports the
@apso/crudPostgREST/Supabase dialect to the Python (FastAPI + SQLAlchemy) code generator. Generated services now accept the same PostgREST URL conventions the TypeScript services do. The nestjsx dialect is unchanged.What changed (generated output)
utils/query.pygains a second parser path alongside the incumbent nestjsx parser, plus a dialect detector. The router reads theX-Crud-Dialectheader and shapes the response per dialect. The service exposes both retrieval methods.src/lib/templates/python/utils/query.eta— PostgREST parser, dialect detection, postgrest-awareQueryBuildersrc/lib/templates/python/routers/router.eta— header-driven dialect selection + response shapingsrc/lib/templates/python/services/service.eta—get_many_list(bare array) alongsideget_many(envelope)src/lib/templates/python/utils/init.eta— exportstest/lib/generators/python.test.ts— 9 new generator testsOperators / behaviors covered
select=a,bincludingalias:coloutput-key rename (CLI first pivot: new command surface, architecture refactor, tests #57),col::typecast stripping, andrel(cols)embeds (mapped toselectinloadeager loads)col=op.valuefilters:eq / neq / gt / gte / lt / lte / like / ilike / in / isandnot.<op>, with the TS operator mapping and*→%like/ilike wildcards;is.null/is.true/is.false;in.(1,2,3)with quoted-value supportor=(...)/and=(...)logical groups, nestedor(...)/and(...)(Plat 1269 #56)order=col.asc|desc[.nullsfirst|nullslast]limit/offsetDialect detection (mirrors
dialect.ts)X-Crud-Dialectheader wins (postgrest|nestjsx, any other value → 400)select/orderor a barecol=op.value→ postgrest;fields/filter/join/sort/s/or/per_page→ nestjsx;limit/offset/page/cacheneutralResponse shaping
limit/offset, which just window the array) — feat: MCP server + CLI modernization #58{data,count,total,page,pageCount}envelope — unchangedQueryParseError→HTTPException 400), not a 500 — Feature: auto-detect codegen/schema issues from real usage and (opt-in) auto-file GitHub issues #60Deferred
cs / cd / ov / ftsand range operators (Plat 1288 #54, as in TS) — rejected clearly with a parse error rather than silently acceptedrel.col=op.value, incl.!innerparent filtering — primaryKeyType: "uuid" generates a non-generated @PrimaryColumn() → every insert fails with null id #59): the Python join path usesselectinload(a separate SELECT) and cannot push a predicate into a JOIN ON clause, so embedded filters are rejected with a 400.selectembeds still eager-load the relation. Postgrest filters are scoped to root columns.Tests
NODE_OPTIONS='--experimental-vm-modules' jest), including 9 new PostgREST-dialect testsquery.pywas loaded in Python and run against real SQLAlchemy compilation (eq, not/in/is, like/ilike*→%,or=()/nestedand=(),order+ nulls,selectalias projection, unknown-column 400, bare-arraylimit/offsetwindowing, deferred-op rejection, embedded-filter rejection, dialect detection incl. header override + collision) — all green. Generatedquery.py,router.py,service.pyall parse.Do not merge — merging publishes the CLI. Left green for review.
🤖 Generated with Claude Code