@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.
- package/dist/cli/commands/catalog-export.js +22 -1
- package/dist/core/catalog.filter.d.ts +17 -0
- package/dist/core/catalog.filter.js +75 -0
- package/dist/core/catalog.model.js +9 -1
- package/dist/core/expand-replace-dependencies.js +1 -7
- package/dist/core/integrations/supabase.js +102 -11
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.d.ts +4 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +28 -2
- package/dist/core/objects/foreign-data-wrapper/server/server.model.d.ts +4 -0
- package/dist/core/objects/foreign-data-wrapper/server/server.model.js +18 -1
- package/dist/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.d.ts +4 -0
- package/dist/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.js +18 -1
- package/dist/core/objects/table/table.diff.js +53 -30
- package/dist/core/plan/hierarchy.js +4 -4
- package/dist/core/postgres-config.d.ts +7 -0
- package/dist/core/postgres-config.js +19 -5
- package/dist/core/sort/debug-visualization.js +1 -1
- package/dist/core/sort/topological-sort.js +2 -2
- package/package.json +34 -33
- package/src/cli/commands/catalog-export.ts +26 -1
- package/src/core/catalog.filter.ts +96 -0
- package/src/core/catalog.model.ts +10 -1
- package/src/core/catalog.snapshot.test.ts +1 -0
- package/src/core/expand-replace-dependencies.test.ts +12 -0
- package/src/core/expand-replace-dependencies.ts +1 -12
- package/src/core/integrations/supabase.test.ts +335 -0
- package/src/core/integrations/supabase.ts +102 -11
- package/src/core/objects/aggregate/changes/aggregate.base.ts +1 -1
- package/src/core/objects/collation/changes/collation.base.ts +1 -1
- package/src/core/objects/domain/changes/domain.base.ts +1 -1
- package/src/core/objects/extension/changes/extension.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +28 -2
- package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/server/server.model.ts +18 -1
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +18 -1
- package/src/core/objects/index/changes/index.base.ts +1 -1
- package/src/core/objects/language/changes/language.base.ts +1 -1
- package/src/core/objects/materialized-view/changes/materialized-view.base.ts +1 -1
- package/src/core/objects/procedure/changes/procedure.base.ts +1 -1
- package/src/core/objects/rls-policy/changes/rls-policy.base.ts +1 -1
- package/src/core/objects/role/changes/role.base.ts +1 -1
- package/src/core/objects/schema/changes/schema.base.ts +1 -1
- package/src/core/objects/sequence/changes/sequence.base.ts +1 -1
- package/src/core/objects/table/changes/table.base.ts +1 -1
- package/src/core/objects/table/changes/table.comment.ts +2 -8
- package/src/core/objects/table/table.diff.test.ts +198 -5
- package/src/core/objects/table/table.diff.ts +63 -34
- package/src/core/objects/trigger/changes/trigger.alter.ts +1 -4
- package/src/core/objects/trigger/changes/trigger.base.ts +1 -1
- package/src/core/objects/type/composite-type/changes/composite-type.base.ts +1 -1
- package/src/core/objects/type/enum/changes/enum.base.ts +1 -1
- package/src/core/objects/type/range/changes/range.base.ts +1 -1
- package/src/core/objects/view/changes/view.base.ts +1 -1
- package/src/core/plan/hierarchy.ts +4 -4
- package/src/core/postgres-config.test.ts +39 -1
- package/src/core/postgres-config.ts +32 -16
- package/src/core/sort/debug-visualization.ts +1 -1
- package/src/core/sort/sort-changes.test.ts +1 -0
- 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
|
|
11
|
+
readonly objectType = "range" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateRangeChange extends BaseRangeChange {
|
|
@@ -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) {
|
|
@@ -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 =
|
|
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 =
|
|
76
|
+
const visitState: number[] = Array.from({ length: nodeCount }, () => 0);
|
|
77
77
|
const pathStack: number[] = [];
|
|
78
78
|
let cycleNodeIndexes: number[] | null = null;
|
|
79
79
|
|