@supabase/pg-delta 1.0.0-alpha.25 → 1.0.0-alpha.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/cli/commands/catalog-export.js +22 -1
  2. package/dist/core/catalog.filter.d.ts +17 -0
  3. package/dist/core/catalog.filter.js +75 -0
  4. package/dist/core/catalog.model.js +9 -1
  5. package/dist/core/expand-replace-dependencies.js +1 -7
  6. package/dist/core/integrations/supabase.js +102 -11
  7. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.d.ts +4 -0
  8. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +28 -2
  9. package/dist/core/objects/foreign-data-wrapper/server/server.model.d.ts +4 -0
  10. package/dist/core/objects/foreign-data-wrapper/server/server.model.js +18 -1
  11. package/dist/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.d.ts +4 -0
  12. package/dist/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.js +18 -1
  13. package/dist/core/objects/table/table.diff.js +53 -30
  14. package/dist/core/plan/hierarchy.js +4 -4
  15. package/dist/core/postgres-config.d.ts +7 -0
  16. package/dist/core/postgres-config.js +19 -5
  17. package/dist/core/sort/debug-visualization.js +1 -1
  18. package/dist/core/sort/topological-sort.js +2 -2
  19. package/package.json +34 -33
  20. package/src/cli/commands/catalog-export.ts +26 -1
  21. package/src/core/catalog.filter.ts +96 -0
  22. package/src/core/catalog.model.ts +10 -1
  23. package/src/core/catalog.snapshot.test.ts +1 -0
  24. package/src/core/expand-replace-dependencies.test.ts +12 -0
  25. package/src/core/expand-replace-dependencies.ts +1 -12
  26. package/src/core/integrations/supabase.test.ts +335 -0
  27. package/src/core/integrations/supabase.ts +102 -11
  28. package/src/core/objects/aggregate/changes/aggregate.base.ts +1 -1
  29. package/src/core/objects/collation/changes/collation.base.ts +1 -1
  30. package/src/core/objects/domain/changes/domain.base.ts +1 -1
  31. package/src/core/objects/extension/changes/extension.base.ts +1 -1
  32. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +1 -1
  33. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +1 -1
  34. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +28 -2
  35. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +1 -1
  36. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +18 -1
  37. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +1 -1
  38. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +18 -1
  39. package/src/core/objects/index/changes/index.base.ts +1 -1
  40. package/src/core/objects/language/changes/language.base.ts +1 -1
  41. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +1 -1
  42. package/src/core/objects/procedure/changes/procedure.base.ts +1 -1
  43. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +1 -1
  44. package/src/core/objects/role/changes/role.base.ts +1 -1
  45. package/src/core/objects/schema/changes/schema.base.ts +1 -1
  46. package/src/core/objects/sequence/changes/sequence.base.ts +1 -1
  47. package/src/core/objects/table/changes/table.base.ts +1 -1
  48. package/src/core/objects/table/changes/table.comment.ts +2 -8
  49. package/src/core/objects/table/table.diff.test.ts +198 -5
  50. package/src/core/objects/table/table.diff.ts +63 -34
  51. package/src/core/objects/trigger/changes/trigger.alter.ts +1 -4
  52. package/src/core/objects/trigger/changes/trigger.base.ts +1 -1
  53. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +1 -1
  54. package/src/core/objects/type/enum/changes/enum.base.ts +1 -1
  55. package/src/core/objects/type/range/changes/range.base.ts +1 -1
  56. package/src/core/objects/view/changes/view.base.ts +1 -1
  57. package/src/core/plan/hierarchy.ts +4 -4
  58. package/src/core/postgres-config.test.ts +39 -1
  59. package/src/core/postgres-config.ts +32 -16
  60. package/src/core/sort/debug-visualization.ts +1 -1
  61. package/src/core/sort/sort-changes.test.ts +1 -0
  62. package/src/core/sort/topological-sort.ts +2 -2
@@ -8,7 +8,7 @@ abstract class BaseRangeChange extends BaseChange {
8
8
  | "comment"
9
9
  | "privilege"
10
10
  | "security_label";
11
- readonly objectType: "range" = "range";
11
+ readonly objectType = "range" as const;
12
12
  }
13
13
 
14
14
  export abstract class CreateRangeChange extends BaseRangeChange {
@@ -8,7 +8,7 @@ abstract class BaseViewChange extends BaseChange {
8
8
  | "comment"
9
9
  | "privilege"
10
10
  | "security_label";
11
- readonly objectType: "view" = "view";
11
+ readonly objectType = "view" as const;
12
12
  }
13
13
 
14
14
  export abstract class CreateViewChange extends BaseViewChange {
@@ -322,7 +322,7 @@ function addClusterChange(cluster: ClusterGroup, change: Change): void {
322
322
  break;
323
323
  default: {
324
324
  const _exhaustive: never = objectType;
325
- throw new Error(`Unhandled object type: ${_exhaustive}`);
325
+ throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
326
326
  }
327
327
  }
328
328
  }
@@ -366,7 +366,7 @@ function addChildChange(schema: SchemaGroup, change: Change): void {
366
366
  break;
367
367
  default: {
368
368
  const _exhaustive: never = parentType;
369
- throw new Error(`Unhandled parent type: ${_exhaustive}`);
369
+ throw new Error(`Unhandled parent type: ${JSON.stringify(_exhaustive)}`);
370
370
  }
371
371
  }
372
372
 
@@ -416,7 +416,7 @@ function addChildChange(schema: SchemaGroup, change: Change): void {
416
416
  break;
417
417
  default: {
418
418
  const _exhaustive: never = objectType;
419
- throw new Error(`Unhandled object type: ${_exhaustive}`);
419
+ throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
420
420
  }
421
421
  }
422
422
  }
@@ -568,7 +568,7 @@ function addSchemaLevelChange(
568
568
  break;
569
569
  default: {
570
570
  const _exhaustive: never = objectType;
571
- throw new Error(`Unhandled object type: ${_exhaustive}`);
571
+ throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
572
572
  }
573
573
  }
574
574
  }
@@ -1,6 +1,7 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, spyOn, test } from "bun:test";
2
2
  import {
3
3
  connectWithRetry,
4
+ connectWithTimeout,
4
5
  isRetryableConnectError,
5
6
  poolConfigFromUrl,
6
7
  } from "./postgres-config.ts";
@@ -241,6 +242,43 @@ describe("connectWithRetry", () => {
241
242
  });
242
243
  });
243
244
 
245
+ describe("connectWithTimeout", () => {
246
+ test("clears the timer when connect resolves before it fires", async () => {
247
+ const clearSpy = spyOn(globalThis, "clearTimeout");
248
+ try {
249
+ const sentinel = { client: true };
250
+ const result = await connectWithTimeout(
251
+ () => Promise.resolve(sentinel),
252
+ 60_000,
253
+ "source",
254
+ );
255
+ expect(result).toBe(sentinel);
256
+ expect(clearSpy).toHaveBeenCalled();
257
+ } finally {
258
+ clearSpy.mockRestore();
259
+ }
260
+ });
261
+
262
+ test("rejects with a timeout error when connect is too slow", async () => {
263
+ await expect(
264
+ connectWithTimeout(() => new Promise<never>(() => {}), 5, "target"),
265
+ ).rejects.toThrow(/timed out after 5ms/);
266
+ });
267
+
268
+ test("clears the timer even when connect rejects", async () => {
269
+ const clearSpy = spyOn(globalThis, "clearTimeout");
270
+ try {
271
+ const boom = new Error("connect ECONNREFUSED");
272
+ await expect(
273
+ connectWithTimeout(() => Promise.reject(boom), 60_000, "target"),
274
+ ).rejects.toBe(boom);
275
+ expect(clearSpy).toHaveBeenCalled();
276
+ } finally {
277
+ clearSpy.mockRestore();
278
+ }
279
+ });
280
+ });
281
+
244
282
  describe("poolConfigFromUrl", () => {
245
283
  describe("non-IPv6 URLs pass through as connectionString", () => {
246
284
  test("DNS hostname", () => {
@@ -209,6 +209,37 @@ export async function connectWithRetry<T>(opts: {
209
209
  throw lastError;
210
210
  }
211
211
 
212
+ /**
213
+ * Race `connect()` against a `timeoutMs` rejection and clear the timer when
214
+ * either side wins. If the timer is left running after a fast connect, the
215
+ * pending `setTimeout` keeps the event loop alive and the process hangs for
216
+ * the rest of `timeoutMs`.
217
+ */
218
+ export function connectWithTimeout<T>(
219
+ connect: () => Promise<T>,
220
+ timeoutMs: number,
221
+ label: "source" | "target",
222
+ ): Promise<T> {
223
+ let timer: ReturnType<typeof setTimeout>;
224
+ return Promise.race([
225
+ connect(),
226
+ new Promise<never>((_, reject) => {
227
+ timer = setTimeout(
228
+ () =>
229
+ reject(
230
+ new Error(
231
+ `Connection to ${label} database timed out after ${timeoutMs}ms. ` +
232
+ `The server may require SSL, use an invalid certificate, or be unreachable.`,
233
+ ),
234
+ ),
235
+ timeoutMs,
236
+ );
237
+ }),
238
+ ]).finally(() => {
239
+ clearTimeout(timer);
240
+ });
241
+ }
242
+
212
243
  /**
213
244
  * Options for creating a Pool with event listeners.
214
245
  */
@@ -412,22 +443,7 @@ export async function createManagedPool(
412
443
  const timeoutMs = DEFAULT_CONNECT_TIMEOUT_MS;
413
444
  try {
414
445
  const client = await connectWithRetry({
415
- connect: () =>
416
- Promise.race([
417
- pool.connect(),
418
- new Promise<never>((_, reject) =>
419
- setTimeout(
420
- () =>
421
- reject(
422
- new Error(
423
- `Connection to ${label} database timed out after ${timeoutMs}ms. ` +
424
- `The server may require SSL, use an invalid certificate, or be unreachable.`,
425
- ),
426
- ),
427
- timeoutMs,
428
- ),
429
- ),
430
- ]),
446
+ connect: () => connectWithTimeout(() => pool.connect(), timeoutMs, label),
431
447
  });
432
448
  client.release();
433
449
  } catch (err) {
@@ -233,7 +233,7 @@ export function printDebugGraph(
233
233
  "\n==== Mermaid (cycle detected) ====\n%s\n==== end ====",
234
234
  mermaidDiagram,
235
235
  );
236
- } catch (_error) {
236
+ } catch {
237
237
  // ignore debug printing errors
238
238
  }
239
239
  }
@@ -144,6 +144,7 @@ function table(
144
144
 
145
145
  async function catalogWithDepends(depends: PgDepend[]) {
146
146
  const base = await createEmptyCatalog(170000, "postgres");
147
+ // oxlint-disable-next-line typescript/no-misused-spread
147
148
  return new Catalog({ ...base, depends });
148
149
  }
149
150
 
@@ -14,7 +14,7 @@ export function performStableTopologicalSort(
14
14
  { length: nodeCount },
15
15
  () => new Set<number>(),
16
16
  );
17
- const inDegreeCounts = new Array<number>(nodeCount).fill(0);
17
+ const inDegreeCounts: number[] = Array.from({ length: nodeCount }, () => 0);
18
18
 
19
19
  for (const [sourceIndex, targetIndex] of edges) {
20
20
  if (!adjacencyList[sourceIndex].has(targetIndex)) {
@@ -73,7 +73,7 @@ export function findCycle(
73
73
  }
74
74
 
75
75
  // 0 = unvisited, 1 = visiting, 2 = completed
76
- const visitState = new Array<number>(nodeCount).fill(0);
76
+ const visitState: number[] = Array.from({ length: nodeCount }, () => 0);
77
77
  const pathStack: number[] = [];
78
78
  let cycleNodeIndexes: number[] | null = null;
79
79