Skip to content

Commit 9e5e315

Browse files
wmaddenclaude
andcommitted
fix(supabase): make bootstrap shim take a Client; rewrite jargon comment (PR#746)
Two review comments: 1) bootstrapSupabaseShim now takes 'client: Client' instead of 'connectionString: string'. The shim no longer owns the client lifecycle — callers pass their own (already-connected) client so it can be reused across other test setup steps (or bound to a transaction). Both consumers (classification.e2e + skeleton.integration) wrap with the test-utils 'withClient' helper. 2) Rewrote the 'synth strategy (zero ops)' comment in check-integrity.ts in plain English: 'When a space ships no migrations, the planner emits no DDL for it — the database is treated as already at the declared state.' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Will Madden <madden@prisma.io>
1 parent 86fa2b0 commit 9e5e315

4 files changed

Lines changed: 72 additions & 59 deletions

File tree

examples/supabase/test/skeleton.integration.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ describe('supabase walking skeleton — external-contract migrate/verify + publi
8585
// Without this, `db verify` would fail with `declaredMissing` for every
8686
// `auth.*` / `storage.*` table — the verifier's `external` policy
8787
// confirms declared tables actually exist.
88-
await bootstrapSupabaseShim(connectionString);
88+
await withClient(connectionString, async (client) => {
89+
await bootstrapSupabaseShim(client);
90+
});
8991

9092
// Step 2 — Materialise the supabase extension space on disk.
9193
//

packages/1-framework/3-tooling/migration/src/aggregate/check-integrity.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,11 @@ export function computeIntegrityViolations(
9191
// For non-app spaces: a missing head.json is always an authoring error
9292
// (headRefMissing). The graph-reachability check (headRefNotInGraph) only
9393
// applies when the space actually has a migration graph — an extension that
94-
// ships no packages (e.g. all-external auth/storage spaces) has an empty
95-
// graph by design, and requiring the head hash to appear in that empty graph
96-
// would always fail. The planner handles empty-graph spaces via synth
97-
// strategy (zero ops).
94+
// ships no packages (e.g. all-external auth/storage spaces) has nothing to
95+
// reach the head ref through, and requiring the head hash to appear in an
96+
// empty graph would always fail. When a space ships no migrations, the
97+
// planner emits no DDL for it — the database is treated as already at the
98+
// declared state.
9899
if (!isApp && headRefProblem === null) {
99100
if (member.headRef === null) {
100101
violations.push({ kind: 'headRefMissing', spaceId });

packages/3-extensions/supabase/test/classification.e2e.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ import { emitContractSpaceArtefacts } from '@prisma-next/migration-tools/spaces'
3535
import { buildSqlNamespace, SqlStorage } from '@prisma-next/sql-contract/types';
3636
import postgres from '@prisma-next/target-postgres/control';
3737
import { PostgresContractSerializer } from '@prisma-next/target-postgres/runtime';
38-
import { applicationDomainOf, createDevDatabase, timeouts } from '@prisma-next/test-utils';
38+
import {
39+
applicationDomainOf,
40+
createDevDatabase,
41+
timeouts,
42+
withClient,
43+
} from '@prisma-next/test-utils';
3944
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
4045
import supabasePack from '../src/exports/pack';
4146
import { bootstrapSupabaseShim } from './supabase-bootstrap';
@@ -104,7 +109,9 @@ describe('supabase external-schema classification (db init + db verify)', () =>
104109
// The verifier's `external` policy confirms declared tables exist.
105110
// Without this seed, `db verify` would fail with `declaredMissing`
106111
// for every auth.*/storage.* table.
107-
await bootstrapSupabaseShim(connectionString);
112+
await withClient(connectionString, async (client) => {
113+
await bootstrapSupabaseShim(client);
114+
});
108115

109116
// 2. Materialise the supabase extension contract space on disk.
110117
//

packages/3-extensions/supabase/test/supabase-bootstrap.ts

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,28 @@
1616
* `service_role`) and the `auth.uid()`, `auth.jwt()`, `auth.role()` functions.
1717
* - `cross-contract-refs` constituent seeds `auth.users` rows for FK tests.
1818
*
19+
* The caller owns the client lifecycle — pass any already-connected `pg.Client`
20+
* (e.g. one the test is sharing across setup steps, or one bound to a
21+
* transaction for isolation). Convenience wrapper for tests that don't already
22+
* have one:
23+
*
1924
* @example
2025
* ```ts
21-
* import { createDevDatabase } from '@prisma-next/test-utils';
26+
* import { withClient } from '@prisma-next/test-utils';
2227
* import { bootstrapSupabaseShim } from '@prisma-next/extension-supabase/test/utils';
2328
*
24-
* const db = await createDevDatabase();
25-
* await bootstrapSupabaseShim(db.connectionString);
29+
* await withClient(connectionString, async (client) => {
30+
* await bootstrapSupabaseShim(client);
31+
* });
2632
* ```
2733
*/
28-
import { Client } from 'pg';
34+
import type { Client } from 'pg';
2935

3036
/**
31-
* Seeds the database with the external Supabase schemas and tables.
37+
* Seeds the database with the external Supabase schemas and tables. The
38+
* caller passes an already-connected `pg.Client` — this function does not
39+
* open or close connections, so the same client can be reused across the
40+
* test's other setup steps.
3241
*
3342
* Creates two schemas (`auth`, `storage`) and four tables whose columns
3443
* exactly match the `@prisma-next/extension-supabase` contract:
@@ -41,55 +50,49 @@ import { Client } from 'pg';
4150
* Does NOT create Postgres roles or `auth.*` functions — those are added by
4251
* the `postgres-rls` constituent.
4352
*/
44-
export async function bootstrapSupabaseShim(connectionString: string): Promise<void> {
45-
const client = new Client({ connectionString });
46-
await client.connect();
47-
try {
48-
await client.query('CREATE SCHEMA IF NOT EXISTS auth');
49-
await client.query('CREATE SCHEMA IF NOT EXISTS storage');
53+
export async function bootstrapSupabaseShim(client: Client): Promise<void> {
54+
await client.query('CREATE SCHEMA IF NOT EXISTS auth');
55+
await client.query('CREATE SCHEMA IF NOT EXISTS storage');
5056

51-
await client.query(`
52-
CREATE TABLE IF NOT EXISTS auth.users (
53-
id uuid NOT NULL,
54-
email text NOT NULL,
55-
created_at timestamptz NOT NULL,
56-
updated_at timestamptz NOT NULL,
57-
PRIMARY KEY (id)
58-
)
59-
`);
57+
await client.query(`
58+
CREATE TABLE IF NOT EXISTS auth.users (
59+
id uuid NOT NULL,
60+
email text NOT NULL,
61+
created_at timestamptz NOT NULL,
62+
updated_at timestamptz NOT NULL,
63+
PRIMARY KEY (id)
64+
)
65+
`);
6066

61-
await client.query(`
62-
CREATE TABLE IF NOT EXISTS auth.identities (
63-
id uuid NOT NULL,
64-
user_id uuid NOT NULL,
65-
provider text NOT NULL,
66-
created_at timestamptz NOT NULL,
67-
updated_at timestamptz NOT NULL,
68-
PRIMARY KEY (id)
69-
)
70-
`);
67+
await client.query(`
68+
CREATE TABLE IF NOT EXISTS auth.identities (
69+
id uuid NOT NULL,
70+
user_id uuid NOT NULL,
71+
provider text NOT NULL,
72+
created_at timestamptz NOT NULL,
73+
updated_at timestamptz NOT NULL,
74+
PRIMARY KEY (id)
75+
)
76+
`);
7177

72-
await client.query(`
73-
CREATE TABLE IF NOT EXISTS storage.buckets (
74-
id text NOT NULL,
75-
name text NOT NULL,
76-
created_at timestamptz NOT NULL,
77-
updated_at timestamptz NOT NULL,
78-
PRIMARY KEY (id)
79-
)
80-
`);
78+
await client.query(`
79+
CREATE TABLE IF NOT EXISTS storage.buckets (
80+
id text NOT NULL,
81+
name text NOT NULL,
82+
created_at timestamptz NOT NULL,
83+
updated_at timestamptz NOT NULL,
84+
PRIMARY KEY (id)
85+
)
86+
`);
8187

82-
await client.query(`
83-
CREATE TABLE IF NOT EXISTS storage.objects (
84-
id uuid NOT NULL,
85-
bucket_id text NOT NULL,
86-
name text NOT NULL,
87-
created_at timestamptz NOT NULL,
88-
updated_at timestamptz NOT NULL,
89-
PRIMARY KEY (id)
90-
)
91-
`);
92-
} finally {
93-
await client.end();
94-
}
88+
await client.query(`
89+
CREATE TABLE IF NOT EXISTS storage.objects (
90+
id uuid NOT NULL,
91+
bucket_id text NOT NULL,
92+
name text NOT NULL,
93+
created_at timestamptz NOT NULL,
94+
updated_at timestamptz NOT NULL,
95+
PRIMARY KEY (id)
96+
)
97+
`);
9598
}

0 commit comments

Comments
 (0)