orez 0.4.3 → 0.4.5
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/pg-proxy-do-backend.d.ts +5 -1
- package/dist/pg-proxy-do-backend.d.ts.map +1 -1
- package/dist/pg-proxy-do-backend.js +84 -19
- package/dist/pg-proxy-do-backend.js.map +1 -1
- package/dist/replication/change-tracker.d.ts +9 -0
- package/dist/replication/change-tracker.d.ts.map +1 -1
- package/dist/replication/change-tracker.js +15 -0
- package/dist/replication/change-tracker.js.map +1 -1
- package/dist/replication/handler.d.ts.map +1 -1
- package/dist/replication/handler.js +15 -12
- package/dist/replication/handler.js.map +1 -1
- package/dist/worker/shims/sqlite.d.ts +2 -0
- package/dist/worker/shims/sqlite.d.ts.map +1 -1
- package/dist/worker/shims/sqlite.js +108 -15
- package/dist/worker/shims/sqlite.js.map +1 -1
- package/package.json +2 -2
|
@@ -16,6 +16,7 @@ export declare class DoBackend {
|
|
|
16
16
|
private rewriteCache;
|
|
17
17
|
private preparedStatements;
|
|
18
18
|
private portals;
|
|
19
|
+
private publicationTableInfoCache;
|
|
19
20
|
private readyPromise;
|
|
20
21
|
private inTransaction;
|
|
21
22
|
private txID;
|
|
@@ -98,6 +99,8 @@ export declare class DoBackend {
|
|
|
98
99
|
private dropTransactionSnapshots;
|
|
99
100
|
private restoreTransactionDataSnapshots;
|
|
100
101
|
private doRawBatch;
|
|
102
|
+
/** run read statements in one /batch round-trip and return per-statement results. */
|
|
103
|
+
private doBatchResults;
|
|
101
104
|
private shouldSkipStatement;
|
|
102
105
|
private executeRewrittenStatement;
|
|
103
106
|
private executeRewrittenStatements;
|
|
@@ -109,11 +112,12 @@ export declare class DoBackend {
|
|
|
109
112
|
private zeroInternalTableRefForSqliteTable;
|
|
110
113
|
private generatedIndexName;
|
|
111
114
|
private uniqueIndexName;
|
|
112
|
-
private
|
|
115
|
+
private sqliteIndexColumnsFromRows;
|
|
113
116
|
private tableIndexInfos;
|
|
114
117
|
private publicationContainsTable;
|
|
115
118
|
private publicationsForTable;
|
|
116
119
|
private publicationTableInfos;
|
|
120
|
+
private loadPublicationTableInfos;
|
|
117
121
|
private projectCatalogRow;
|
|
118
122
|
private pgTablesResult;
|
|
119
123
|
private informationSchemaColumnsResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -473,6 +473,18 @@ function expressionOid(value) {
|
|
|
473
473
|
return oid;
|
|
474
474
|
}
|
|
475
475
|
}
|
|
476
|
+
// json access operators `->` and `#>` return a json/jsonb VALUE in postgres
|
|
477
|
+
// (vs `->>`/`#>>` which return text). sqlite's `->` returns the json text
|
|
478
|
+
// representation (e.g. `"begin"` with quotes), so the column must carry a
|
|
479
|
+
// json oid for the driver to JSON.parse it back into a value — otherwise
|
|
480
|
+
// zero-cache's changeLog catchup reads `change->'tag'` as the literal
|
|
481
|
+
// string `"begin"` and its `case "begin"` switch never matches, mis-tagging
|
|
482
|
+
// every begin/commit as a `data` change and poisoning the change stream.
|
|
483
|
+
if (node.A_Expr?.kind === 'AEXPR_OP') {
|
|
484
|
+
const op = operatorName(node.A_Expr);
|
|
485
|
+
if (op === '->' || op === '#>')
|
|
486
|
+
return PG_TYPE_JSON;
|
|
487
|
+
}
|
|
476
488
|
return undefined;
|
|
477
489
|
}
|
|
478
490
|
function selectResultColumnMetadata(sql) {
|
|
@@ -4546,6 +4558,13 @@ export class DoBackend {
|
|
|
4546
4558
|
rewriteCache;
|
|
4547
4559
|
preparedStatements = new Map();
|
|
4548
4560
|
portals = new Map();
|
|
4561
|
+
// catalog-query answers (pg_tables, information_schema, published-schema)
|
|
4562
|
+
// introspect every sqlite table via PRAGMAs. on a remote DO each PRAGMA is a
|
|
4563
|
+
// round-trip, and zero-cache fires several catalog queries per pg session —
|
|
4564
|
+
// uncached this serialized ~200 round-trips per query and starved /sync
|
|
4565
|
+
// connects past the client's connect budget. cache per instance, invalidated
|
|
4566
|
+
// on DDL / metadata / publication changes and on rollback.
|
|
4567
|
+
publicationTableInfoCache = null;
|
|
4549
4568
|
readyPromise = null;
|
|
4550
4569
|
// Transaction state. The Durable Object refuses raw SQL BEGIN/COMMIT/SAVEPOINT
|
|
4551
4570
|
// (Cloudflare requires ctx.storage.transaction()), so PG-style multi-call
|
|
@@ -4805,6 +4824,7 @@ export class DoBackend {
|
|
|
4805
4824
|
}
|
|
4806
4825
|
// Cached rewrites may reference metadata that the rollback just invalidated.
|
|
4807
4826
|
this.rewriteCache.clear();
|
|
4827
|
+
this.publicationTableInfoCache = null;
|
|
4808
4828
|
}
|
|
4809
4829
|
clearTransactionState() {
|
|
4810
4830
|
this.inTransaction = false;
|
|
@@ -5048,6 +5068,7 @@ export class DoBackend {
|
|
|
5048
5068
|
}
|
|
5049
5069
|
}
|
|
5050
5070
|
if (changed) {
|
|
5071
|
+
this.publicationTableInfoCache = null;
|
|
5051
5072
|
// inside an explicit tx we batch the persist to commit time. chat's
|
|
5052
5073
|
// migrations open one tx and run dozens of DDL statements; persisting
|
|
5053
5074
|
// after every one was the hot path.
|
|
@@ -5710,6 +5731,24 @@ export class DoBackend {
|
|
|
5710
5731
|
'Content-Type': 'application/json',
|
|
5711
5732
|
});
|
|
5712
5733
|
}
|
|
5734
|
+
/** run read statements in one /batch round-trip and return per-statement results. */
|
|
5735
|
+
async doBatchResults(statements) {
|
|
5736
|
+
if (statements.length === 0)
|
|
5737
|
+
return [];
|
|
5738
|
+
const resp = await this.httpClient.post(this.url('/batch'), JSON.stringify({ statements }), { 'Content-Type': 'application/json' });
|
|
5739
|
+
const parsed = JSON.parse(resp);
|
|
5740
|
+
const results = Array.isArray(parsed.results) ? parsed.results : [];
|
|
5741
|
+
return statements.map((_, index) => {
|
|
5742
|
+
const result = results[index] ?? {};
|
|
5743
|
+
const rows = (result.rows ?? []);
|
|
5744
|
+
const columns = Array.isArray(result.columns) && result.columns.length > 0
|
|
5745
|
+
? result.columns.map(String)
|
|
5746
|
+
: rows.length > 0
|
|
5747
|
+
? Object.keys(rows[0])
|
|
5748
|
+
: [];
|
|
5749
|
+
return { rows, columns, affectedRows: result.affectedRows };
|
|
5750
|
+
});
|
|
5751
|
+
}
|
|
5713
5752
|
async shouldSkipStatement(statement) {
|
|
5714
5753
|
if (statement.skipIfColumnExists &&
|
|
5715
5754
|
(await this.columnExists(statement.skipIfColumnExists.table, statement.skipIfColumnExists.column))) {
|
|
@@ -5730,6 +5769,8 @@ export class DoBackend {
|
|
|
5730
5769
|
return { rows: [], columns: [] };
|
|
5731
5770
|
if (await this.shouldSkipStatement(statement))
|
|
5732
5771
|
return { rows: [], columns: [] };
|
|
5772
|
+
if (statement.isDDL)
|
|
5773
|
+
this.publicationTableInfoCache = null;
|
|
5733
5774
|
await this.snapshotTransactionWrite(statement);
|
|
5734
5775
|
const tracking = this.trackingForStatement(statement);
|
|
5735
5776
|
const exec = await this.materializePublishedSchemaFunctions(tracking?.returningSQL ?? statement.sql, statement);
|
|
@@ -5761,6 +5802,8 @@ export class DoBackend {
|
|
|
5761
5802
|
: statement;
|
|
5762
5803
|
if (!item.sql.trim())
|
|
5763
5804
|
continue;
|
|
5805
|
+
if (item.isDDL)
|
|
5806
|
+
this.publicationTableInfoCache = null;
|
|
5764
5807
|
if (item.skipIfColumnExists || item.skipIfColumnMissing || item.skipIfTableEmpty) {
|
|
5765
5808
|
await flush();
|
|
5766
5809
|
if (item.skipIfColumnExists &&
|
|
@@ -5874,9 +5917,8 @@ export class DoBackend {
|
|
|
5874
5917
|
usedNames.add(unique);
|
|
5875
5918
|
return unique;
|
|
5876
5919
|
}
|
|
5877
|
-
|
|
5878
|
-
const
|
|
5879
|
-
const rows = result.rows
|
|
5920
|
+
sqliteIndexColumnsFromRows(xinfoRows) {
|
|
5921
|
+
const rows = xinfoRows
|
|
5880
5922
|
.map((row) => ({
|
|
5881
5923
|
seqno: Number(row.seqno ?? 0),
|
|
5882
5924
|
cid: Number(row.cid ?? -1),
|
|
@@ -5891,7 +5933,7 @@ export class DoBackend {
|
|
|
5891
5933
|
columns[row.name] = row.desc === 1 ? 'DESC' : 'ASC';
|
|
5892
5934
|
return columns;
|
|
5893
5935
|
}
|
|
5894
|
-
|
|
5936
|
+
tableIndexInfos(table, columns, primaryKey, indexListRows, indexColumnsByName) {
|
|
5895
5937
|
const usedNames = new Set();
|
|
5896
5938
|
const seenSignatures = new Set();
|
|
5897
5939
|
const indexes = [];
|
|
@@ -5926,8 +5968,7 @@ export class DoBackend {
|
|
|
5926
5968
|
continue;
|
|
5927
5969
|
addIndex(this.generatedIndexName(table, [column.name], 'key'), { [column.name]: 'ASC' }, true, false);
|
|
5928
5970
|
}
|
|
5929
|
-
const
|
|
5930
|
-
const rawIndexes = result.rows
|
|
5971
|
+
const rawIndexes = indexListRows
|
|
5931
5972
|
.map((row) => ({
|
|
5932
5973
|
seq: Number(row.seq ?? 0),
|
|
5933
5974
|
name: String(row.name ?? ''),
|
|
@@ -5940,7 +5981,7 @@ export class DoBackend {
|
|
|
5940
5981
|
for (const raw of rawIndexes) {
|
|
5941
5982
|
if (raw.partial)
|
|
5942
5983
|
continue;
|
|
5943
|
-
const indexColumns =
|
|
5984
|
+
const indexColumns = indexColumnsByName.get(raw.name) ?? {};
|
|
5944
5985
|
const names = Object.keys(indexColumns);
|
|
5945
5986
|
if (raw.origin === 'pk' && primaryKey.length > 0)
|
|
5946
5987
|
continue;
|
|
@@ -5965,15 +6006,44 @@ export class DoBackend {
|
|
|
5965
6006
|
});
|
|
5966
6007
|
}
|
|
5967
6008
|
async publicationTableInfos(publications) {
|
|
5968
|
-
|
|
6009
|
+
if (!this.publicationTableInfoCache) {
|
|
6010
|
+
this.publicationTableInfoCache = await this.loadPublicationTableInfos();
|
|
6011
|
+
}
|
|
5969
6012
|
const requested = publications?.filter((name) => this.publications.has(name)) ?? [];
|
|
6013
|
+
return this.publicationTableInfoCache.filter((info) => {
|
|
6014
|
+
if (requested.length > 0) {
|
|
6015
|
+
return requested.some((publicationName) => this.publicationContainsTable(this.publications.get(publicationName), info));
|
|
6016
|
+
}
|
|
6017
|
+
return !publications?.length;
|
|
6018
|
+
});
|
|
6019
|
+
}
|
|
6020
|
+
async loadPublicationTableInfos() {
|
|
6021
|
+
const allTables = (await this.listSqliteTables()).filter((table) => !isSystemSqliteTable(table.name));
|
|
6022
|
+
// batch table_info + index_list for every table into ONE round-trip, then
|
|
6023
|
+
// every index_xinfo into a second — per-PRAGMA round-trips to the SQL DO
|
|
6024
|
+
// made each full scan cost seconds and starve concurrent sessions.
|
|
6025
|
+
const pragmaResults = await this.doBatchResults(allTables.flatMap((table) => [
|
|
6026
|
+
`PRAGMA table_info(${quoteIdentifier(table.name)})`,
|
|
6027
|
+
`PRAGMA index_list(${quoteIdentifier(table.name)})`,
|
|
6028
|
+
]));
|
|
6029
|
+
const indexNames = [];
|
|
6030
|
+
for (let i = 0; i < allTables.length; i++) {
|
|
6031
|
+
for (const row of pragmaResults[i * 2 + 1]?.rows ?? []) {
|
|
6032
|
+
const name = String(row.name ?? '');
|
|
6033
|
+
if (name && !Number(row.partial ?? 0))
|
|
6034
|
+
indexNames.push(name);
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
const xinfoResults = await this.doBatchResults(indexNames.map((name) => `PRAGMA index_xinfo(${quoteIdentifier(name)})`));
|
|
6038
|
+
const indexColumnsByName = new Map();
|
|
6039
|
+
for (let i = 0; i < indexNames.length; i++) {
|
|
6040
|
+
indexColumnsByName.set(indexNames[i], this.sqliteIndexColumnsFromRows(xinfoResults[i]?.rows ?? []));
|
|
6041
|
+
}
|
|
5970
6042
|
const infos = [];
|
|
5971
|
-
for (
|
|
5972
|
-
|
|
5973
|
-
continue;
|
|
6043
|
+
for (let i = 0; i < allTables.length; i++) {
|
|
6044
|
+
const table = allTables[i];
|
|
5974
6045
|
const ref = this.tableRefForSqliteTable(table.name);
|
|
5975
|
-
const
|
|
5976
|
-
const columns = result.rows.map((row) => ({
|
|
6046
|
+
const columns = (pragmaResults[i * 2]?.rows ?? []).map((row) => ({
|
|
5977
6047
|
cid: Number(row.cid ?? 0),
|
|
5978
6048
|
name: String(row.name ?? ''),
|
|
5979
6049
|
type: String(row.type ?? ''),
|
|
@@ -6001,12 +6071,7 @@ export class DoBackend {
|
|
|
6001
6071
|
.map((column) => column.name),
|
|
6002
6072
|
indexes: [],
|
|
6003
6073
|
};
|
|
6004
|
-
info.indexes =
|
|
6005
|
-
if (requested.length > 0 &&
|
|
6006
|
-
!requested.some((publicationName) => this.publicationContainsTable(this.publications.get(publicationName), info)))
|
|
6007
|
-
continue;
|
|
6008
|
-
if (requested.length === 0 && publications?.length)
|
|
6009
|
-
continue;
|
|
6074
|
+
info.indexes = this.tableIndexInfos(ref, columns, info.primaryKey, pragmaResults[i * 2 + 1]?.rows ?? [], indexColumnsByName);
|
|
6010
6075
|
infos.push(info);
|
|
6011
6076
|
}
|
|
6012
6077
|
return infos;
|