prisma-pglite-bridge 1.1.0 → 1.2.0
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/index.cjs +90 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -5
- package/dist/index.d.mts +12 -5
- package/dist/index.mjs +90 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
package/dist/index.cjs
CHANGED
|
@@ -183,6 +183,7 @@ const rewriteRowDescriptionInPlace = (buf) => {
|
|
|
183
183
|
*/
|
|
184
184
|
var BackendMessageFramer = class {
|
|
185
185
|
suppressIntermediateReadyForQuery;
|
|
186
|
+
rewriteSystemCatalogCharOids;
|
|
186
187
|
onChunk;
|
|
187
188
|
onErrorResponse;
|
|
188
189
|
onReadyForQuery;
|
|
@@ -198,6 +199,7 @@ var BackendMessageFramer = class {
|
|
|
198
199
|
rowDescOffset = 0;
|
|
199
200
|
constructor(options) {
|
|
200
201
|
this.suppressIntermediateReadyForQuery = options.suppressIntermediateReadyForQuery ?? false;
|
|
202
|
+
this.rewriteSystemCatalogCharOids = options.rewriteSystemCatalogCharOids ?? true;
|
|
201
203
|
this.onChunk = options.onChunk;
|
|
202
204
|
this.onErrorResponse = options.onErrorResponse;
|
|
203
205
|
this.onReadyForQuery = options.onReadyForQuery;
|
|
@@ -231,7 +233,7 @@ var BackendMessageFramer = class {
|
|
|
231
233
|
if (msgType === 69) this.onErrorResponse?.();
|
|
232
234
|
if (msgType === 90 && messageLength === 5) {
|
|
233
235
|
flushPassthrough(offset);
|
|
234
|
-
|
|
236
|
+
this.dropStaleHeldReadyForQuery();
|
|
235
237
|
/* c8 ignore next — messageLength === 5 for RFQ; payload is 1 byte */
|
|
236
238
|
const status = chunk[offset + 5] ?? 0;
|
|
237
239
|
this.heldRfq[0] = msgType;
|
|
@@ -246,16 +248,12 @@ var BackendMessageFramer = class {
|
|
|
246
248
|
this.emitReadyForQuery();
|
|
247
249
|
this.rfqBytesRead = 0;
|
|
248
250
|
}
|
|
249
|
-
} else if (msgType === 84
|
|
251
|
+
} else if (msgType === 84 && this.rewriteSystemCatalogCharOids && rowDescriptionNeedsRewrite(chunk, offset, offset + totalLen)) {
|
|
250
252
|
flushPassthrough(offset);
|
|
251
|
-
|
|
253
|
+
this.dropStaleHeldReadyForQuery();
|
|
252
254
|
this.emitRewrittenRowDescription(Buffer.from(chunk.subarray(offset, offset + totalLen)));
|
|
253
255
|
} else {
|
|
254
|
-
|
|
255
|
-
if (passthroughStart < 0) passthroughStart = offset;
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
if (this.suppressIntermediateReadyForQuery && this.rfqBytesRead === 6) this.dropHeldReadyForQuery();
|
|
256
|
+
this.dropStaleHeldReadyForQuery();
|
|
259
257
|
if (passthroughStart < 0) passthroughStart = offset;
|
|
260
258
|
}
|
|
261
259
|
offset += totalLen;
|
|
@@ -263,7 +261,7 @@ var BackendMessageFramer = class {
|
|
|
263
261
|
}
|
|
264
262
|
}
|
|
265
263
|
flushPassthrough(offset);
|
|
266
|
-
|
|
264
|
+
this.dropStaleHeldReadyForQuery();
|
|
267
265
|
/* c8 ignore next — offset < chunk.length guaranteed by outer while */
|
|
268
266
|
this.messageType = chunk[offset] ?? 0;
|
|
269
267
|
this.headerBytesRead = 0;
|
|
@@ -297,7 +295,7 @@ var BackendMessageFramer = class {
|
|
|
297
295
|
if (this.messageType === 69) this.onErrorResponse?.();
|
|
298
296
|
if (this.isReadyForQueryFrame()) continue;
|
|
299
297
|
this.dropHeldReadyForQuery();
|
|
300
|
-
if (this.messageType === 84) {
|
|
298
|
+
if (this.messageType === 84 && this.rewriteSystemCatalogCharOids) {
|
|
301
299
|
this.rowDescBuffer = Buffer.alloc(5 + this.payloadBytesRemaining);
|
|
302
300
|
this.rowDescBuffer[0] = 84;
|
|
303
301
|
this.rowDescBuffer.set(this.headerScratch, 1);
|
|
@@ -347,14 +345,6 @@ var BackendMessageFramer = class {
|
|
|
347
345
|
this.rfqBytesRead = 0;
|
|
348
346
|
}
|
|
349
347
|
}
|
|
350
|
-
reset() {
|
|
351
|
-
this.messageType = void 0;
|
|
352
|
-
this.headerBytesRead = 0;
|
|
353
|
-
this.payloadBytesRemaining = 0;
|
|
354
|
-
this.rfqBytesRead = 0;
|
|
355
|
-
this.rowDescBuffer = void 0;
|
|
356
|
-
this.rowDescOffset = 0;
|
|
357
|
-
}
|
|
358
348
|
isReadyForQueryFrame() {
|
|
359
349
|
return this.messageType === 90 && this.payloadBytesRemaining === 1;
|
|
360
350
|
}
|
|
@@ -371,6 +361,11 @@ var BackendMessageFramer = class {
|
|
|
371
361
|
dropHeldReadyForQuery() {
|
|
372
362
|
this.rfqBytesRead = 0;
|
|
373
363
|
}
|
|
364
|
+
/** Drop a complete held RFQ once a following frame proves it was an
|
|
365
|
+
* intermediate one. No-op unless suppressing and a full RFQ is buffered. */
|
|
366
|
+
dropStaleHeldReadyForQuery() {
|
|
367
|
+
if (this.suppressIntermediateReadyForQuery && this.rfqBytesRead === 6) this.dropHeldReadyForQuery();
|
|
368
|
+
}
|
|
374
369
|
emitPrefix() {
|
|
375
370
|
const prefix = new Uint8Array(5);
|
|
376
371
|
/* c8 ignore next — messageType always set when emitPrefix is called */
|
|
@@ -575,6 +570,7 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
575
570
|
bridgeId;
|
|
576
571
|
telemetry;
|
|
577
572
|
syncToFs;
|
|
573
|
+
rewriteSystemCatalogCharOids;
|
|
578
574
|
timeout;
|
|
579
575
|
duplexId;
|
|
580
576
|
/** Incoming bytes framed directly from a queued chunk buffer */
|
|
@@ -617,6 +613,7 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
617
613
|
this.telemetry = options.telemetry;
|
|
618
614
|
this.timeout = options.timeout;
|
|
619
615
|
this.syncToFs = options.syncToFs ?? true;
|
|
616
|
+
this.rewriteSystemCatalogCharOids = options.rewriteSystemCatalogCharOids ?? true;
|
|
620
617
|
this.duplexId = Symbol("duplex");
|
|
621
618
|
this.onClose = new Promise((resolve) => this.once("close", () => resolve()));
|
|
622
619
|
}
|
|
@@ -722,9 +719,7 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
722
719
|
/* c8 ignore next — len === undefined unreachable once length ≥ 4 */
|
|
723
720
|
if (len === void 0 || this.input.length < len) return;
|
|
724
721
|
const message = this.input.consume(len);
|
|
725
|
-
|
|
726
|
-
if (session) await session;
|
|
727
|
-
await this.runUnderRunExclusive(async () => {
|
|
722
|
+
await this.runUntimed(async () => {
|
|
728
723
|
await this.streamProtocol(message, {
|
|
729
724
|
detectErrors: false,
|
|
730
725
|
suppressIntermediateRfq: false
|
|
@@ -758,6 +753,13 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
758
753
|
}
|
|
759
754
|
});
|
|
760
755
|
}
|
|
756
|
+
/** Acquire the session, then run `op` under runExclusive without timing —
|
|
757
|
+
* the untimed path shared by startup and the no-telemetry query branch. */
|
|
758
|
+
async runUntimed(op) {
|
|
759
|
+
const session = this.acquireSession();
|
|
760
|
+
if (session) await session;
|
|
761
|
+
await this.runUnderRunExclusive(op);
|
|
762
|
+
}
|
|
761
763
|
/**
|
|
762
764
|
* Frames and processes regular wire protocol messages.
|
|
763
765
|
*
|
|
@@ -866,9 +868,7 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
866
868
|
const wantTiming = wantTelemetry || publishQuery || publishLockWait;
|
|
867
869
|
const detectErrors = wantTelemetry || publishQuery;
|
|
868
870
|
if (!wantTiming) {
|
|
869
|
-
|
|
870
|
-
if (session) await session;
|
|
871
|
-
await this.runUnderRunExclusive(async () => {
|
|
871
|
+
await this.runUntimed(async () => {
|
|
872
872
|
await op(false);
|
|
873
873
|
});
|
|
874
874
|
return;
|
|
@@ -915,6 +915,7 @@ var PGliteDuplex = class extends node_stream.Duplex {
|
|
|
915
915
|
let errSeen = false;
|
|
916
916
|
const framer = new BackendMessageFramer({
|
|
917
917
|
suppressIntermediateReadyForQuery: suppressIntermediateRfq,
|
|
918
|
+
rewriteSystemCatalogCharOids: this.rewriteSystemCatalogCharOids,
|
|
918
919
|
onChunk: (chunk) => {
|
|
919
920
|
/* c8 ignore next — race-only: tornDown becomes true mid-stream */
|
|
920
921
|
if (!this.tornDown && chunk.length > 0) this.push(chunk);
|
|
@@ -1119,17 +1120,12 @@ var SessionLock = class {
|
|
|
1119
1120
|
this.waitQueue = remaining;
|
|
1120
1121
|
return cancelled;
|
|
1121
1122
|
}
|
|
1122
|
-
/**
|
|
1123
|
-
* Grant ownership to the next waiter, if any.
|
|
1124
|
-
*
|
|
1125
|
-
* @returns `true` if a waiter was unblocked; `false` if the queue was empty.
|
|
1126
|
-
*/
|
|
1123
|
+
/** Grant ownership to the next waiter, if any. */
|
|
1127
1124
|
drainWaitQueue() {
|
|
1128
1125
|
const next = this.waitQueue.shift();
|
|
1129
|
-
if (!next) return
|
|
1126
|
+
if (!next) return;
|
|
1130
1127
|
this.owner = next.id;
|
|
1131
1128
|
next.resolve();
|
|
1132
|
-
return true;
|
|
1133
1129
|
}
|
|
1134
1130
|
};
|
|
1135
1131
|
//#endregion
|
|
@@ -1348,16 +1344,7 @@ var PgBridgePool = class extends pg.default.Pool {
|
|
|
1348
1344
|
return super.end().then(cleanup);
|
|
1349
1345
|
}
|
|
1350
1346
|
};
|
|
1351
|
-
|
|
1352
|
-
//#region src/telemetry/bridge-stats.ts
|
|
1353
|
-
/**
|
|
1354
|
-
* Maximum number of recent query durations retained for percentile
|
|
1355
|
-
* computation. Beyond this window, `recentP50QueryMs`, `recentP95QueryMs`,
|
|
1356
|
-
* and `recentMaxQueryMs` reflect only the most recent N queries — lifetime
|
|
1357
|
-
* counters (`queryCount`, `totalQueryMs`, `avgQueryMs`) remain complete.
|
|
1358
|
-
*/
|
|
1359
|
-
const QUERY_DURATION_WINDOW_SIZE = 1e4;
|
|
1360
|
-
const QUERY_DURATION_TRIM_THRESHOLD = QUERY_DURATION_WINDOW_SIZE * 2;
|
|
1347
|
+
const QUERY_DURATION_TRIM_THRESHOLD = 1e4 * 2;
|
|
1361
1348
|
const DB_SIZE_QUERY_TIMEOUT_MS = 5e3;
|
|
1362
1349
|
/**
|
|
1363
1350
|
* `process.resourceUsage().maxRSS` returns kilobytes on every platform
|
|
@@ -1402,7 +1389,7 @@ var BridgeStats = class {
|
|
|
1402
1389
|
this.queryCount += 1;
|
|
1403
1390
|
this.totalQueryMs += durationMs;
|
|
1404
1391
|
this.queryDurations.push(durationMs);
|
|
1405
|
-
if (this.queryDurations.length > QUERY_DURATION_TRIM_THRESHOLD) this.queryDurations = this.queryDurations.slice(-
|
|
1392
|
+
if (this.queryDurations.length > QUERY_DURATION_TRIM_THRESHOLD) this.queryDurations = this.queryDurations.slice(-1e4);
|
|
1406
1393
|
if (!succeeded) this.failedQueryCount += 1;
|
|
1407
1394
|
}
|
|
1408
1395
|
recordLockWait(durationMs) {
|
|
@@ -1478,15 +1465,18 @@ var BridgeStats = class {
|
|
|
1478
1465
|
}
|
|
1479
1466
|
};
|
|
1480
1467
|
//#endregion
|
|
1468
|
+
//#region src/utils/quote-ident.ts
|
|
1469
|
+
/** JS equivalent of PostgreSQL's `quote_ident()`; matches its escaping rules. */
|
|
1470
|
+
const quoteIdent = (identifier) => `"${identifier.replace(/"/g, "\"\"")}"`;
|
|
1471
|
+
//#endregion
|
|
1481
1472
|
//#region src/pglite-bridge/snapshot-manager.ts
|
|
1482
1473
|
const SNAPSHOT_SCHEMA = "_pglite_snapshot";
|
|
1483
|
-
const
|
|
1484
|
-
AND schemaname != '${SNAPSHOT_SCHEMA}'
|
|
1474
|
+
const SYSTEM_SCHEMA_EXCLUSION = `schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
1475
|
+
AND schemaname != '${SNAPSHOT_SCHEMA}'`;
|
|
1476
|
+
const USER_TABLES_WHERE = `${SYSTEM_SCHEMA_EXCLUSION}
|
|
1485
1477
|
AND tablename NOT LIKE '_prisma%'`;
|
|
1486
1478
|
const escapeLiteral = (s) => `'${s.replace(/'/g, "''")}'`;
|
|
1487
|
-
|
|
1488
|
-
const quoteIdent$1 = (identifier) => `"${identifier.replace(/"/g, "\"\"")}"`;
|
|
1489
|
-
const SNAPSHOT_SCHEMA_IDENT = quoteIdent$1(SNAPSHOT_SCHEMA);
|
|
1479
|
+
const SNAPSHOT_SCHEMA_IDENT = quoteIdent(SNAPSHOT_SCHEMA);
|
|
1490
1480
|
const SNAPSHOT_SCHEMA_LITERAL = escapeLiteral(SNAPSHOT_SCHEMA);
|
|
1491
1481
|
/**
|
|
1492
1482
|
* Snapshot helpers backing `PGliteBridge`'s `snapshotDb` / `resetDb` /
|
|
@@ -1507,32 +1497,30 @@ var SnapshotManager = class {
|
|
|
1507
1497
|
* the `_pglite_snapshot` schema. Replaces any previous snapshot.
|
|
1508
1498
|
*/
|
|
1509
1499
|
async snapshotDb() {
|
|
1510
|
-
|
|
1511
|
-
await pglite.exec(`DROP SCHEMA IF EXISTS ${SNAPSHOT_SCHEMA_IDENT} CASCADE`);
|
|
1500
|
+
await this.#pglite.exec(`DROP SCHEMA IF EXISTS ${SNAPSHOT_SCHEMA_IDENT} CASCADE`);
|
|
1512
1501
|
try {
|
|
1513
|
-
await pglite.exec("BEGIN");
|
|
1514
|
-
await pglite.exec(`CREATE SCHEMA ${SNAPSHOT_SCHEMA_IDENT}`);
|
|
1515
|
-
const { rows: tables } = await pglite.query(`SELECT schemaname, tablename,
|
|
1502
|
+
await this.#pglite.exec("BEGIN");
|
|
1503
|
+
await this.#pglite.exec(`CREATE SCHEMA ${SNAPSHOT_SCHEMA_IDENT}`);
|
|
1504
|
+
const { rows: tables } = await this.#pglite.query(`SELECT schemaname, tablename,
|
|
1516
1505
|
quote_ident(schemaname) || '.' || quote_ident(tablename) AS qualified
|
|
1517
1506
|
FROM pg_tables
|
|
1518
1507
|
WHERE ${USER_TABLES_WHERE}`);
|
|
1519
|
-
await pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.__tables (snap_name text, source_schema text, source_table text)`);
|
|
1508
|
+
await this.#pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.__tables (snap_name text, source_schema text, source_table text)`);
|
|
1520
1509
|
for (const [i, { schemaname, tablename, qualified }] of tables.entries()) {
|
|
1521
1510
|
const snapName = `_snap_${i}`;
|
|
1522
|
-
await pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.${quoteIdent
|
|
1523
|
-
await pglite.exec(`INSERT INTO ${SNAPSHOT_SCHEMA_IDENT}.__tables VALUES (${escapeLiteral(snapName)}, ${escapeLiteral(schemaname)}, ${escapeLiteral(tablename)})`);
|
|
1511
|
+
await this.#pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.${quoteIdent(snapName)} AS SELECT * FROM ${qualified}`);
|
|
1512
|
+
await this.#pglite.exec(`INSERT INTO ${SNAPSHOT_SCHEMA_IDENT}.__tables VALUES (${escapeLiteral(snapName)}, ${escapeLiteral(schemaname)}, ${escapeLiteral(tablename)})`);
|
|
1524
1513
|
}
|
|
1525
|
-
const { rows: seqs } = await pglite.query(`SELECT quote_literal(quote_ident(schemaname) || '.' || quote_ident(sequencename)) AS name, last_value::text AS value
|
|
1514
|
+
const { rows: seqs } = await this.#pglite.query(`SELECT quote_literal(quote_ident(schemaname) || '.' || quote_ident(sequencename)) AS name, last_value::text AS value
|
|
1526
1515
|
FROM pg_sequences
|
|
1527
|
-
WHERE
|
|
1528
|
-
AND schemaname != '${SNAPSHOT_SCHEMA}'
|
|
1516
|
+
WHERE ${SYSTEM_SCHEMA_EXCLUSION}
|
|
1529
1517
|
AND last_value IS NOT NULL`);
|
|
1530
|
-
await pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.__sequences (name text, value bigint)`);
|
|
1531
|
-
for (const { name, value } of seqs) await pglite.exec(`INSERT INTO ${SNAPSHOT_SCHEMA_IDENT}.__sequences VALUES (${name}, ${value})`);
|
|
1532
|
-
await pglite.exec("COMMIT");
|
|
1518
|
+
await this.#pglite.exec(`CREATE TABLE ${SNAPSHOT_SCHEMA_IDENT}.__sequences (name text, value bigint)`);
|
|
1519
|
+
for (const { name, value } of seqs) await this.#pglite.exec(`INSERT INTO ${SNAPSHOT_SCHEMA_IDENT}.__sequences VALUES (${name}, ${value})`);
|
|
1520
|
+
await this.#pglite.exec("COMMIT");
|
|
1533
1521
|
} catch (err) {
|
|
1534
|
-
await pglite.exec("ROLLBACK");
|
|
1535
|
-
await pglite.exec(`DROP SCHEMA IF EXISTS ${SNAPSHOT_SCHEMA_IDENT} CASCADE`);
|
|
1522
|
+
await this.#pglite.exec("ROLLBACK");
|
|
1523
|
+
await this.#pglite.exec(`DROP SCHEMA IF EXISTS ${SNAPSHOT_SCHEMA_IDENT} CASCADE`);
|
|
1536
1524
|
throw err;
|
|
1537
1525
|
}
|
|
1538
1526
|
this.#hasSnapshot = true;
|
|
@@ -1547,26 +1535,25 @@ var SnapshotManager = class {
|
|
|
1547
1535
|
* sequence values afterwards; otherwise just truncate and `DISCARD ALL`.
|
|
1548
1536
|
*/
|
|
1549
1537
|
async resetDb() {
|
|
1550
|
-
const pglite = this.#pglite;
|
|
1551
1538
|
if (this.#hasSnapshot) await this.#snapshotSchemaExists();
|
|
1552
1539
|
const tables = await this.#getTables();
|
|
1553
1540
|
if (tables) await this.#withReplicationRoleReplica(async () => {
|
|
1554
|
-
await pglite.exec(`TRUNCATE TABLE ${tables} RESTART IDENTITY CASCADE`);
|
|
1541
|
+
await this.#pglite.exec(`TRUNCATE TABLE ${tables} RESTART IDENTITY CASCADE`);
|
|
1555
1542
|
if (!this.#hasSnapshot) return;
|
|
1556
|
-
const { rows: snapshotTables } = await pglite.query(`SELECT quote_ident(snap_name) AS snap_name_ident,
|
|
1543
|
+
const { rows: snapshotTables } = await this.#pglite.query(`SELECT quote_ident(snap_name) AS snap_name_ident,
|
|
1557
1544
|
quote_ident(source_schema) || '.' || quote_ident(source_table) AS qualified
|
|
1558
1545
|
FROM ${SNAPSHOT_SCHEMA_IDENT}.__tables`);
|
|
1559
|
-
for (const { snap_name_ident, qualified } of snapshotTables) await pglite.exec(`INSERT INTO ${qualified} SELECT * FROM ${SNAPSHOT_SCHEMA_IDENT}.${snap_name_ident}`);
|
|
1560
|
-
const { rows: seqs } = await pglite.query(`SELECT quote_literal(name) AS name, value::text AS value FROM ${SNAPSHOT_SCHEMA_IDENT}.__sequences`);
|
|
1561
|
-
for (const { name, value } of seqs) await pglite.exec(`SELECT setval(${name}, ${value})`);
|
|
1546
|
+
for (const { snap_name_ident, qualified } of snapshotTables) await this.#pglite.exec(`INSERT INTO ${qualified} SELECT * FROM ${SNAPSHOT_SCHEMA_IDENT}.${snap_name_ident}`);
|
|
1547
|
+
const { rows: seqs } = await this.#pglite.query(`SELECT quote_literal(name) AS name, value::text AS value FROM ${SNAPSHOT_SCHEMA_IDENT}.__sequences`);
|
|
1548
|
+
for (const { name, value } of seqs) await this.#pglite.exec(`SELECT setval(${name}, ${value})`);
|
|
1562
1549
|
});
|
|
1563
|
-
await pglite.exec("DISCARD ALL");
|
|
1550
|
+
await this.#pglite.exec("DISCARD ALL");
|
|
1564
1551
|
}
|
|
1565
1552
|
async #getTables() {
|
|
1566
1553
|
const { rows } = await this.#pglite.query(`SELECT quote_ident(schemaname) || '.' || quote_ident(tablename) AS qualified
|
|
1567
1554
|
FROM pg_tables
|
|
1568
1555
|
WHERE ${USER_TABLES_WHERE}`);
|
|
1569
|
-
return rows.
|
|
1556
|
+
return rows.map((row) => row.qualified).join(", ");
|
|
1570
1557
|
}
|
|
1571
1558
|
/**
|
|
1572
1559
|
* Self-heal: someone (e.g. `resetSchema`) may drop `_pglite_snapshot`
|
|
@@ -1865,7 +1852,8 @@ var PGliteServer = class {
|
|
|
1865
1852
|
socket.duplex = new PGliteDuplex(this.pglite, {
|
|
1866
1853
|
sessionLock: this.#sessionLock,
|
|
1867
1854
|
timeout: this.#options.timeout,
|
|
1868
|
-
syncToFs: resolveSyncToFs(this.pglite, this.#options.syncToFs)
|
|
1855
|
+
syncToFs: resolveSyncToFs(this.pglite, this.#options.syncToFs),
|
|
1856
|
+
rewriteSystemCatalogCharOids: false
|
|
1869
1857
|
});
|
|
1870
1858
|
socket.duplex.on("error", () => socket.destroy());
|
|
1871
1859
|
socket.once("close", () => {
|
|
@@ -1911,16 +1899,43 @@ var PGliteServer = class {
|
|
|
1911
1899
|
}
|
|
1912
1900
|
};
|
|
1913
1901
|
//#endregion
|
|
1902
|
+
//#region src/schema/pg18-not-null.ts
|
|
1903
|
+
const ENGINE_DENYLIST = "contype NOT IN ('p', 'u', 'f')";
|
|
1904
|
+
const PATCHED_DENYLIST = "contype NOT IN ('p', 'u', 'f', 'n')";
|
|
1905
|
+
const rewritePg18ConstraintsSql = (sql) => {
|
|
1906
|
+
if (!sql.includes("pg_constraint") || !sql.includes(ENGINE_DENYLIST)) return sql;
|
|
1907
|
+
return sql.replace(ENGINE_DENYLIST, PATCHED_DENYLIST);
|
|
1908
|
+
};
|
|
1909
|
+
/**
|
|
1910
|
+
* Proxies (rather than spreads) so class-based adapters keep working: every
|
|
1911
|
+
* untouched member is delegated with `this` bound to the original instance,
|
|
1912
|
+
* and members added in future @prisma/driver-adapter-utils versions pass
|
|
1913
|
+
* through without changes here.
|
|
1914
|
+
*/
|
|
1915
|
+
const wrapAdapter = (adapter) => new Proxy(adapter, { get(target, prop) {
|
|
1916
|
+
if (prop === "queryRaw") return (query) => target.queryRaw({
|
|
1917
|
+
...query,
|
|
1918
|
+
sql: rewritePg18ConstraintsSql(query.sql)
|
|
1919
|
+
});
|
|
1920
|
+
const value = Reflect.get(target, prop);
|
|
1921
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1922
|
+
} });
|
|
1923
|
+
const wrapFactoryForPg18 = (factory) => new Proxy(factory, { get(target, prop) {
|
|
1924
|
+
if (prop === "connect") return async () => wrapAdapter(await target.connect());
|
|
1925
|
+
if (prop === "connectToShadowDb") return async () => wrapAdapter(await target.connectToShadowDb());
|
|
1926
|
+
const value = Reflect.get(target, prop);
|
|
1927
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1928
|
+
} });
|
|
1929
|
+
//#endregion
|
|
1914
1930
|
//#region src/schema/index.ts
|
|
1915
1931
|
const bindAdapter = async (adapter) => {
|
|
1916
1932
|
const { bindMigrationAwareSqlAdapterFactory } = await import("@prisma/driver-adapter-utils");
|
|
1917
|
-
return bindMigrationAwareSqlAdapterFactory(adapter);
|
|
1933
|
+
return bindMigrationAwareSqlAdapterFactory(wrapFactoryForPg18(adapter));
|
|
1918
1934
|
};
|
|
1919
1935
|
const emptyFilter = () => ({
|
|
1920
1936
|
externalTables: [],
|
|
1921
1937
|
externalEnums: []
|
|
1922
1938
|
});
|
|
1923
|
-
const quoteIdent = (name) => `"${name.replace(/"/g, "\"\"")}"`;
|
|
1924
1939
|
/**
|
|
1925
1940
|
* Drop every non-system schema (and recreate `public`). Issued as raw SQL
|
|
1926
1941
|
* through the adapter rather than `engine.reset(...)` because the engine only
|
|
@@ -2100,7 +2115,7 @@ const hasMigrations = async (pglite) => {
|
|
|
2100
2115
|
const { rows } = await pglite.query(`SELECT to_regclass('public._prisma_migrations') IS NOT NULL AS exists`);
|
|
2101
2116
|
if (!rows[0]?.exists) return false;
|
|
2102
2117
|
const { rows: applied } = await pglite.query(`SELECT count(*)::int AS count FROM _prisma_migrations WHERE finished_at IS NOT NULL`);
|
|
2103
|
-
return applied[0]
|
|
2118
|
+
return (applied[0]?.count ?? 0) > 0;
|
|
2104
2119
|
};
|
|
2105
2120
|
/**
|
|
2106
2121
|
* Returns `true` when the `public` schema contains at least one user table.
|