Skip to content

refactor(postgrest-typegen): render the view definition rewrites from a table - #179

Merged
spydon merged 1 commit into
mainfrom
lukasklingsbo/postgrest-typegen-node-tree-rewrites
Sep 15, 2026
Merged

spydon merged 1 commit into
mainfrom
lukasklingsbo/postgrest-typegen-node-tree-rewrites

Conversation

@spydon

@spydon spydon commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Summary

VIEWS_KEY_DEPENDENCIES_SQL converts a view's pg_node_tree definition into JSON with a hand-written pyramid of nineteen nested replace calls, one regexp_replace in the middle, and the arguments aligned by hand. It came verbatim from PostgREST via postgres-meta and is hard to read or modify safely.

This keeps the exact same rewrites, in the same order, but moves them into an ordered table (NODE_TREE_TO_JSON_REWRITES) with PostgREST's reasoning as per-step comments, and renders the nested calls with a small helper. The generated SQL applies the identical sequence of rewrites, so the query's behaviour is unchanged; only the SQL text layout differs.

Verification

  • bun run test passes with Docker (133 tests), including the view to table, table to view and view to view relationship expansions in introspect.test.ts, which exercise this query end to end.
  • The inline SQL snapshot in sql.test.ts was regenerated; the diff is only the transform_json block.
  • check-types, format-and-lint and knip pass.

Context

Surfaced while porting the introspection to Dart in supabase/supabase-flutter#1837, which mirrors this SQL byte for byte and will pick the new layout up on its next version bump.

… a table

The pg_node_tree to JSON conversion in VIEWS_KEY_DEPENDENCIES_SQL was a
hand-written pyramid of nineteen nested replace calls with the arguments
aligned by hand. The rewrites now live in an ordered table and a small
renderer emits the nested calls, so a step can be read, added or reordered
without counting parentheses. The rendered SQL is semantically unchanged
and the view relationship integration tests cover it.
@spydon
spydon requested a review from a team as a code owner September 14, 2026 15:32
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 717dfde9-0845-402a-9492-2c916613b2ec


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@spydon
spydon merged commit 6be1bff into main Sep 15, 2026
6 of 7 checks passed
@spydon
spydon deleted the lukasklingsbo/postgrest-typegen-node-tree-rewrites branch September 15, 2026 08:55
spydon added a commit that referenced this pull request Sep 15, 2026
…om the introspection (#180)

Stacked on #179.

## Summary

The introspection SQL builders were ported from postgres-meta's managers
together with every option those managers accept: `limit`, `offset`,
`idsFilter`, `nameFilter`, `tableIdentifierFilter`,
`viewIdentifierFilter`, `columnNameFilter`, `tableIdFilter`, the `args`
filter of the functions query and the
`includeTableTypes`/`includeArrayTypes` flags of the types query.
`introspect()` sets exactly one of them, the schema filter. The builders
are not exported from the package and nothing else in the repository
passes the other options, so they were unreachable code that still had
to be read around.

- Every builder now takes `SchemaFilterProps`, a required `schemaFilter`
and nothing else. `TYPES_SQL` becomes a constant since it had no
variable part left.
- The `args` block of `FUNCTIONS_SQL`, a nested ternary interpolating a
`string[]` through `Array#toString`, goes away together with the
file-wide lint suppression it needed.
- The rendered SQL loses all but one conditional filter line per
builder, and with it most of the blank lines with trailing whitespace.
- `introspect()` no longer re-filters the `schemas` rows in JavaScript.
The query already applies the same include and exclude filter; the only
case where the two differed was a schema listed in both lists, which the
JavaScript filter dropped from `schemas` while every other collection
still contained it.
- `introspect()` passes the filter it already built to
`listRelationships` instead of having it rebuilt from the options.
- The cartesian product in `expandViewRelationships` is a `flatMap`
instead of the gist-linked `map`/`reduce` pair.

## Verification

- `bun run test` with Docker: 133 pass, including the introspection
integration tests and the view relationship expansions.
- SQL snapshots in `sql.test.ts` regenerated; the diff is the removed
blank lines, the constant `TYPES_SQL`, and the schemas query's
unconditional `pg_` exclusion.
- `check-types`, `format-and-lint` and `knip` pass.

Generated output is unchanged for every option combination
`introspect()` can produce, so the byte-parity constraint with
postgres-meta holds.
spydon added a commit that referenced this pull request Sep 15, 2026
…#181)

Stacked on #180 (which is stacked on #179).

## Summary

`sortGeneratorMetadata`, the TypeScript generator's merge sorts and the
Swift generator's sorts all used `String.prototype.localeCompare`
without a locale, so the canonical order of generated output depended on
the default locale of the machine running the generator.

Reproduction with Node 26:

```
LANG=en_US.UTF-8 node -e '...["b","ä","a","z"].sort((a,b)=>a.localeCompare(b))'   # ["a","ä","b","z"]
LANG=sv_SE.UTF-8 node -e '...'                                                      # ["a","b","z","ä"]
```

Bun currently ignores the host locale and always resolves `en-US`, so
the CLI binary is not affected today, but postgres-meta and any Node
consumer are, and nothing pins the behaviour.

All 24 comparisons now go through a single `Intl.Collator("en")` in
`src/collation.ts`. English has no tailoring over the ICU root
collation, so this is exactly the order the English CI runners and the
postgres-meta parity fixtures already produce; only machines with
another default locale change, and they now agree with CI.

## Verification

- New test in `sort.test.ts` asserting `["a", "ä", "b", "z"]` regardless
of host locale.
- `bun run test` with Docker: 134 pass. No snapshot or parity fixture
changed, which is the point.
- `check-types`, `format-and-lint` and `knip` pass.
spydon added a commit to supabase/supabase-flutter that referenced this pull request Sep 15, 2026
…CLI (#1837)

## Summary

`supabase_typegen` could only read a `GeneratorMetadata` document on
stdin and relied on `supabase gen types --lang dart` to produce it,
which has not shipped (supabase/cli#6230 was closed and
supabase/cli#6404 carries no Dart path). This adds a Dart port of the
introspection of
[`@supabase/postgrest-typegen`](https://github.com/supabase/sdk/tree/main/packages/postgrest-typegen),
pinned to `postgrest-typegen-v0.2.2`, so the tool can produce the
document itself. The database connection is delegated to the Supabase
CLI:

```sh
dart run supabase_typegen --local
dart run supabase_typegen --linked
dart run supabase_typegen --project-ref <ref>
dart run supabase_typegen --db-url 'postgresql://…'
dart run supabase_typegen --local --dump-metadata
```

Stdin stays the default when no target is given, so the eventual CLI
integration is untouched. Everything new lives under
`lib/src/introspection/`, `lib/introspection.dart`,
`test/introspection/`, the tool scripts and the drift workflow, and the
README states that it will be removed once the CLI ships Dart support.

## How it connects

The eleven introspection queries are folded into one `SELECT` with a
`json_agg` sub-select per collection and run through a single `supabase
db query --output json --file <statement>` call. The CLI resolves and
authenticates the connection: `--local` uses the running stack,
`--linked` and `--project-ref` go through the Management API with the
`supabase login` credentials and need no database password, and
`--db-url` is passed straight through. The package has no database
driver; `postgres` is only a dev dependency for seeding the parity
database.

Failures produce actionable messages: the CLI missing from `PATH` (with
the install link), not logged in (`supabase login` or
`SUPABASE_ACCESS_TOKEN`), no linked project (`supabase link` or
`--project-ref`), and everything else surfaces the CLI's own message
with its colour codes and progress line stripped, which already covers
"run `supabase start`" and network restriction hints. Passing more than
one target is a usage error.

## What is ported

- The eleven SQL builders, one file each, taking the schema filter
alone, matching the trimmed builders of supabase/sdk#180. The view
definition rewrites render from a table, matching supabase/sdk#179. The
`pg-format` literal escaping is included for the schema filter.
- The view relationship expansion (cartesian product over view key
dependencies).
- The ordering pass, with a stable merge sort because the TypeScript
sort relies on `Array.prototype.sort` being stable for composite primary
keys and tied relationships.
- `localeCompare` semantics: the ICU root collation for printable ASCII
(punctuation, digits, then letters with case as the last tiebreaker,
lower case first), verified against Bun and Node. Non-ASCII code units
sort after ASCII by code unit, which only affects collection order for
accented names.

Following 0.2.2 also brings in the changes since 0.2.0:
`is_insert_enabled` and `is_update_enabled` on views, trigger and rule
backed view columns marked updatable, and virtual generated columns
counted as generated. The fixture and goldens are regenerated
accordingly; the join view with an `INSTEAD OF INSERT` trigger now gets
a `BookSubmissionsInsert` type, and the two tests asserting the old
behaviour were updated.

## Verification

- Parity test (`test/introspection/parity_test.dart`): seeds a fresh
`postgres:15` with `test/fixtures/seed.sql` when the database is empty,
introspects it through the CLI unfiltered and restricted to `public`,
and asserts the document holds the same records as
`test/fixtures/generator_metadata.json`, collection by collection.
Records are compared as maps, so key order is irrelevant; record order
within a collection is checked since the document is sorted. It also
runs the binary and checks `--dump-metadata` yields the fixture records
and `--output -` reproduces `test/goldens/supabase_schema.dart`. The
test skips unless `SUPABASE_TYPEGEN_PARITY_DATABASE_URL` is set;
`test.yml` starts the container and installs the CLI for the
`supabase_typegen` matrix entry.
- Drift guard (`tool/check_introspection_drift.ts`): fetches the
TypeScript builders of the pinned supabase/sdk revision from GitHub,
renders every query for three filter scenarios, and compares byte for
byte with `dart run tool/dump_introspection_sql.dart`. The new
`typegen-drift.yml` runs it on PRs touching the package and weekly
against supabase/sdk `main` with `--latest`, so an upstream SQL change
surfaces as a failing scheduled run. Bumping the pin is: run the script
with `--ref`, port the printed diff, regenerate the fixture with
`tool/regenerate_fixture.ts --source <sdk checkout>`, update
`postgrestTypegenRevision`.
- Unit tests for the literal escaping, the schema filter and builder
conditionals, the relationship expansion (ported from upstream), the
sort and collation, the document assembly against a fake query runner,
and the CLI runner against a fake `supabase` script (flags, JSON
parsing, not installed, not logged in).
- Manually ran `--local` against the running local stack and the error
paths (not logged in, not linked, CLI missing from `PATH`, local stack
down, conflicting flags).

## Notes

- The direct modes require a Supabase CLI with `db query` (2.116 or
newer). `--db-url` against a server without TLS needs `sslmode=disable`
in the connection string, as the CLI requires TLS otherwise.
- `oven-sh/setup-bun` is a new third-party action, pinned by SHA like
the others in this repo.

Closes SDK-1834.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added database introspection through local, linked, project-reference,
or database URL connections.
  * Added `--dump-metadata` to output raw generator metadata.
* Added flexible output options for writing generated code to a file or
standard output.
* Improved support for view relationships and insertable views,
including generated insert types.

* **Documentation**
* Updated usage guidance for connection modes, authentication, TLS
settings, and output options.

* **Bug Fixes**
* Improved metadata ordering and relationship handling for more
consistent generated output.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

2 participants