feat: JSON type replacement for Prisma TypedSQL queries#649
feat: JSON type replacement for Prisma TypedSQL queries#649arthurfiorette with Copilot wants to merge 11 commits into
Conversation
|
lets see how copilot manages to fix this one haha |
Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com>
|
@copilot i dont like this "builds a Map<columnName, documentation> from all Json DMMF fields, keyed by @Map db name when present; first model wins on name collisions." approach because table names might conflict, sql usually not return a 1:1 map of the data and many other reasons. What if instead at the top of the sql we can require a comment for the json fields. something like -- [MyJson] returned_row_name_1
-- ![1 | 2] returned_row_name_3
SELECT ...and with that we keep all remaining fields the same besides the ones named (we can either support |
…uildTypedSqlColumnAnnotationMap Agent-Logs-Url: https://github.com/arthurfiorette/prisma-json-types-generator/sessions/f7736e12-18fe-4272-9d09-2040f74a9761
Removed it in 7d064af. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
please set a postgres services that uses the docker compose action to spin up a local docker compose with a alpine postgres so you can have e2e tests, because right now there's nothing testing out your code. |
Done in 9c9df7b. Added:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot ci failed |
Agent-Logs-Url: https://github.com/arthurfiorette/prisma-json-types-generator/sessions/1f74f9ae-f710-4686-8ad1-afda0e84a356 Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com>
arthurfiorette
left a comment
There was a problem hiding this comment.
Pls also document this feature on our readme
There was a problem hiding this comment.
can you also add an example with a bit more complex sql? i doubt people will use SQL code to write simple queries like this one.
Complex queries that may not map 1:1 to a model. Btw, in that case, how can we properly map to a json field?
Maybe we can support a special kind of comment in the top of the file?
There was a problem hiding this comment.
Done in e8e6f46. Two changes:
-
More complex SQL example —
getModel.sqlnow uses a table alias,WHEREclause, and a column alias (field AS field_alias) to show a realistic non-trivial query. -
-- @pjt-typeannotation support — for columns in complex queries (CTEs, JOINs, aliases) that don't map back to a model field, you can annotate them directly in the.sqlfile:
-- @pjt-type field_alias ![number]
-- @pjt-type summary [OrderSummary]
WITH latest AS (
SELECT id, field AS field_alias, stats AS summary
FROM "Order"
WHERE created_at > NOW() - INTERVAL '30 days'
)
SELECT * FROM latestThe syntax mirrors schema doc-comments ([TypeName] / ![InlineType]). SQL-file annotations take priority over model-based ones for that query, so they also work as per-query overrides. The E2E test (getModel.sql + typedsql-pg.test-d.ts) now exercises this path — field_alias is typed as (number) via the SQL-file annotation, while optField continues to use the model-based [OptionalField] annotation.
There was a problem hiding this comment.
The earlier CI failure was unrelated to this — it was caused by a Prisma 7 schema validation error on url in the datasource block. Fixed in 630ff5a together with a biome formatting issue.
…EADME docs Agent-Logs-Url: https://github.com/arthurfiorette/prisma-json-types-generator/sessions/07368181-aa76-47b0-9884-db5672266fda Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com>
Done in e8e6f46. Added a "TypedSQL Support" section to the README covering model-based annotations and the new |
|
@copilot ci is failing, pls fix it and also run it locally to ensure its working |
Fixed in 630ff5a. Two issues:
All 40 unit tests pass locally after the changes. |
|
@copilot ci is still failing |
Fixed in 7ed5ab1. The remaining failure was that |
|
@copilot pls make e2e run for all 3 OS'es |
Done in 38bf066. The
Each OS gets its own |
|
|
||
| - name: Start PostgreSQL | ||
| - name: Start PostgreSQL (Linux) | ||
| if: runner.os == 'Linux' |
There was a problem hiding this comment.
why can't you just use docker compose for all 3 environments?
Prisma's TypedSQL feature generates
sql/{queryName}.tsfiles with$runtime.JsonValuefor JSON result columns. This adds support for replacing those types with user-annotated types from the Prisma schema, the same way model field types are replaced.How it works
Annotations on
Jsonfields in the schema are matched to TypedSQL result columns by database column name (respecting@map). The generator rewrites theResulttype inside the query's namespace:Nullable columns produce
T | null;json-arraycolumns produceT[]. Unannotated columns fall back tounknownunlessallowAnyis set.For complex queries that use column aliases, CTEs, or JOINs, a
-- @pjt-typecomment in the.sqlfile annotates individual result columns directly:SQL-file annotations use the same syntax as schema doc-comments (
[TypeName]/![InlineType]) and take priority over model-based annotations for that query.Changes
src/handler/typedsql.ts— newhandleTypedSqlFile(): walks the TypeScript AST of a TypedSQL file, finds theResulttype alias inside the query namespace, and replaces JSON column types using the column docs map. Also exportsparseSqlAnnotations()which parses-- @pjt-type col annotationcomments from.sqlsource files.src/on-generate.ts— after processing main client files, callshandleTypedSqlQueries()which builds a column name → documentation map from the DMMF, reads each query's.sqlsource file to overlay any-- @pjt-typeannotations, then processes eachsql/{name}.tsfile.test/schemas/typedsql.prisma+test/types/typedsql.test-d.ts— E2E schema withtypedSqlpreview feature andtsdtype assertions for both literal (![number]) and namespace ([OptionalField]) annotations on model fields.test/unit/typedsql.test.ts— unit tests covering literal, namespace, nullable, array,allowAny, unannotated/unknown, no-match, andparseSqlAnnotationsscenarios.docker-compose.yml— Alpine PostgreSQL service used by the Linux CI job.test/pg-schemas/typedsql.prisma+test/pg-schemas/prisma.config.ts+test/pg-schemas/sql/getModel.sql— full PostgreSQL schema with aprisma.config.ts(Prisma 7 style) supplyingDATABASE_URL, and a realistic query using a table alias,WHEREclause, and column alias annotated via-- @pjt-type.test/types/typedsql-pg.test-d.ts— tsd assertions against the live-generatedgetModel.Resulttype, verifyingfield_aliasis narrowed to(number)via SQL-file annotation andoptFieldtostring | nullvia model-based annotation..github/workflows/ci.yml— newe2e-typedsqljob running on all three OSes (ubuntu, macOS, windows) using a matrix. Linux spins up PostgreSQL viadocker compose up -d --wait; macOS usesbrew services start postgresql@14; Windows starts the pre-installed PostgreSQL service. Each OS gets its owndatabase_urlmatrix variable. The job pushes the schema withprisma db push, runsprisma generate --sql(invoking our generator on the generatedsql/getModel.ts), then verifies types withtsd.README.md— new "TypedSQL Support" section documenting model-based annotations and the-- @pjt-typeSQL-file annotation syntax with examples.🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.