Skip to content

fix: parity gaps from 80 production projects (4.0.2) - #15

Merged
RiyaSharma03 merged 1 commit into
mainfrom
fix/parity-80-projects
Oct 7, 2026
Merged

RiyaSharma03 merged 1 commit into
mainfrom
fix/parity-80-projects

Conversation

@RiyaSharma03

Copy link
Copy Markdown
Collaborator

Ran 80 production RapidNative projects (four seeded random sets of 20, the last one unseen while fixing) through rapidnative-website's migration validator on PGlite and on pg-mem, through the real tools: db_migration_new per migration, db_seed, db_tables/db_describe, lints, generated types, RLS row counts as anon / demo user / stranger, and must-reject / must-accept probes. All 80 now match PGlite (0 differences). Every fix has a minimal repro in corpus-parity.spec.ts.

Wrong results (silent)

  • An aggregate in a select-list subquery aggregated the outer query: select id, (select count(*) from c where c.p = p.id) from p returned one row with id: null. Already in 4.0.0. hasAggreg no longer descends into subqueries.
  • agg(x ORDER BY y) ignored the ORDER BY (jsonb_agg, string_agg, array_agg, ...). Rows are now fed in order per group; the ORDER BY comparator is shared with order-by.ts.
  • json_agg / jsonb_agg dropped NULL inputs; postgres keeps them as json null.

Valid SQL that was rejected

  • f(unnest(arr)) calls f per element (the result is set-returning): lower(unnest(_emails)) resolved lower(text[]) to the range overload.
  • RETURNS SETOF <scalar> SQL functions.
  • A set-returning call as a subquery's first FROM item reads the outer row: (select … from jsonb_array_elements(outer.col)) (built against the empty selection so the ref resolves as correlated; FunctionCallTable evaluates non-constant args per outer row).
  • UPDATE t alias / DELETE FROM t alias: the alias names the table, in the statement and its subqueries. RLS still applies.
  • plpgsql: fields of a FOR rec IN <query> record in SQL statements inside the loop (update … set x = rec.col), nested loops included; string literals are left alone.
  • json -> key / ->> with a column, variable or expression key (needs @tinbase/pgsql-ast-parser 12.2.1, json -> / ->> with a non-literal key (12.2.1) sanketsahu/pgsql-ast-parser#2).

Drift

  • ALTER COLUMN … TYPE and RENAME COLUMN kept the column but moved it to the end (generated types listed it last).
  • INSERT … VALUES checks each row against the target columns first, so a seed row with one value too many reports "INSERT has more expressions than target columns", as postgres does.

Checks

  • bun test: 1345 pass, 0 fail (locally against parser 12.2.1)
  • rapidnative-website npm run test:db-tools on this build: 116/116
  • CI will fail until @tinbase/[email protected] is published; then regenerate bun.lockb.

Version 4.0.2.

🤖 Generated with Claude Code

Wrong results: an aggregate in a select-list subquery aggregated the outer
query; agg(x ORDER BY y) ignored the ORDER BY; json_agg dropped NULLs.

Rejected valid SQL: f(unnest(arr)) (lower(unnest(emails)) hit the range
overload); RETURNS SETOF <scalar>; outer refs in a subquery FROM call
(from jsonb_array_elements(outer.col)); UPDATE/DELETE table aliases;
plpgsql FOR-loop record fields in embedded SQL; json -> <non-literal>.

Drift: ALTER COLUMN TYPE / RENAME moved the column to the end; INSERT
VALUES row-length errors now match postgres' wording.

Needs @tinbase/pgsql-ast-parser 12.2.1.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@RiyaSharma03
RiyaSharma03 merged commit 835c076 into main Oct 7, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant