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.
@@ -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 sqliteIndexColumns;
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":"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"}
1
+ {"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"AAizHA,wBAAsB,+BAA+B,CACnD,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC,CAiCpD;AAwkCD,qBAAa,SAAS;IACpB,KAAK,UAAQ;IACb,MAAM,UAAQ;IACd,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,oBAAoB,CAAa;IACzC,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,kBAAkB,CAAuC;IACjE,OAAO,CAAC,OAAO,CAAiC;IAOhD,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,YAAY,CAA6B;IAQjD,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,UAAU,CAA2C;IAC7D,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,iBAAiB,CAAI;IAM7B,OAAO,CAAC,yBAAyB,CAAQ;IAGzC,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,iBAAiB,CAAQ;gBAG/B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAmB,EAC3B,SAAS,SAAY,EACrB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;KAAE;IAajC,IAAI,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;IAED,OAAO,CAAC,WAAW;YAWL,IAAI;YAUJ,0BAA0B;YAqB1B,mBAAmB;IAIjC,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,mBAAmB;YAyBb,mBAAmB;YA8BnB,+BAA+B;YA8B/B,sBAAsB;IAgC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,kCAAkC;IAsB1C,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,gBAAgB;YAMV,gBAAgB;YAOhB,iBAAiB;YAejB,mBAAmB;YAiBnB,wBAAwB;YAQxB,0BAA0B;IAQlC,eAAe,CACnB,OAAO,EAAE,UAAU,EACnB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,OAAO,CAAC,UAAU,CAAC;IAqBtB,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,2BAA2B;YAKrB,mBAAmB;YAoCnB,iBAAiB;YAgGjB,sBAAsB;IA+BpC,OAAO,CAAC,yBAAyB;IAgCjC,OAAO,CAAC,sBAAsB;IAkC9B,gBAAgB,IAAI,MAAM,EAAE;IAI5B,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,wBAAwB;YAYlB,sBAAsB;YAQtB,mCAAmC;IAkBjD,OAAO,CAAC,WAAW;IAuFnB,OAAO,CAAC,UAAU;YAWJ,aAAa;IA8H3B,OAAO,CAAC,UAAU;YAIJ,cAAc;IAuB5B,OAAO,CAAC,WAAW;IAgBb,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YA4BzB,wBAAwB;IAqBhC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,GAAG,EAAE,GACb,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC;IAkFzB,OAAO,CAAC,GAAG;IAQX,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,qBAAqB;YAkCf,MAAM;YAIN,YAAY;IA6C1B,OAAO,CAAC,uBAAuB;YAKjB,eAAe;YAQf,2BAA2B;YAkB3B,wBAAwB;YAkBxB,+BAA+B;YAc/B,wBAAwB;YAOxB,wBAAwB;YAQxB,+BAA+B;YA2B/B,UAAU;IAQxB,qFAAqF;YACvE,cAAc;YAsBd,mBAAmB;YA4BnB,yBAAyB;YAmBzB,0BAA0B;YAU1B,WAAW;YA2EX,YAAY;YAKZ,YAAY;YAOZ,gBAAgB;IAY9B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,kCAAkC;IA0B1C,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,0BAA0B;IAmBlC,OAAO,CAAC,eAAe;IAsFvB,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,oBAAoB;YAUd,qBAAqB;YAiBrB,yBAAyB;IA8EvC,OAAO,CAAC,iBAAiB;YAcX,cAAc;YAiBd,8BAA8B;YAmD9B,iCAAiC;YAwEjC,yBAAyB;IA0DvC,OAAO,CAAC,oBAAoB;YAyCd,qBAAqB;YAiBrB,sBAAsB;YAatB,qBAAqB;IAoBnC,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,UAAU;IA+ClB,OAAO,CAAC,YAAY;IAqGpB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,cAAc;IA2GtB,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,aAAa;IAqCrB,OAAO,CAAC,eAAe;IA8CvB,OAAO,CAAC,4BAA4B,CAAoB;IAExD,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,uBAAuB;IAuB/B,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,4BAA4B;IAoDpC,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,oBAAoB;YA0Bd,cAAc;IAoB5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,mBAAmB;YAOb,oBAAoB;YAgBpB,kBAAkB;YAIlB,mBAAmB;CAkBlC"}
@@ -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
- async sqliteIndexColumns(indexName) {
5878
- const result = await this.doExecResult(`PRAGMA index_xinfo(${quoteIdentifier(indexName)})`);
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
- async tableIndexInfos(table, columns, primaryKey) {
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 result = await this.doExecResult(`PRAGMA index_list(${quoteIdentifier(table.table)})`);
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 = await this.sqliteIndexColumns(raw.name);
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
- const allTables = await this.listSqliteTables();
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 (const table of allTables) {
5972
- if (isSystemSqliteTable(table.name))
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 result = await this.doExecResult(`PRAGMA table_info(${quoteIdentifier(table.name)})`);
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 = await this.tableIndexInfos(ref, columns, info.primaryKey);
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;