@rocicorp/zero 0.26.1-canary.8 → 0.26.1

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 (75) hide show
  1. package/out/analyze-query/src/bin-analyze.js +3 -0
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  4. package/out/analyze-query/src/run-ast.js +11 -2
  5. package/out/analyze-query/src/run-ast.js.map +1 -1
  6. package/out/zero/package.json.js +1 -1
  7. package/out/zero-cache/src/config/zero-config.d.ts +4 -0
  8. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  9. package/out/zero-cache/src/config/zero-config.js +17 -0
  10. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  11. package/out/zero-cache/src/db/lite-tables.d.ts +2 -1
  12. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  13. package/out/zero-cache/src/db/lite-tables.js +7 -3
  14. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  15. package/out/zero-cache/src/db/specs.d.ts +8 -2
  16. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  17. package/out/zero-cache/src/db/specs.js.map +1 -1
  18. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  19. package/out/zero-cache/src/db/transaction-pool.js +17 -11
  20. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  21. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  22. package/out/zero-cache/src/server/change-streamer.js +3 -1
  23. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  24. package/out/zero-cache/src/services/analyze.js +1 -0
  25. package/out/zero-cache/src/services/analyze.js.map +1 -1
  26. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +2 -0
  27. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  28. package/out/zero-cache/src/services/change-source/common/replica-schema.js +56 -3
  29. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  30. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  31. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +15 -11
  32. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  33. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  34. package/out/zero-cache/src/services/change-source/pg/change-source.js +61 -0
  35. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  36. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +100 -0
  37. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -0
  38. package/out/zero-cache/src/services/change-streamer/broadcast.js +171 -0
  39. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -0
  40. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
  41. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  42. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +14 -7
  43. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  44. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +17 -1
  45. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  46. package/out/zero-cache/src/services/change-streamer/forwarder.js +52 -4
  47. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  48. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +18 -0
  49. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  50. package/out/zero-cache/src/services/change-streamer/subscriber.js +68 -12
  51. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  52. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  53. package/out/zero-cache/src/services/replicator/change-processor.js +10 -13
  54. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  55. package/out/zero-cache/src/services/replicator/schema/table-metadata.d.ts +28 -7
  56. package/out/zero-cache/src/services/replicator/schema/table-metadata.d.ts.map +1 -1
  57. package/out/zero-cache/src/services/replicator/schema/table-metadata.js +55 -24
  58. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  59. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  60. package/out/zero-cache/src/services/run-ast.js +4 -2
  61. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  62. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +3 -2
  63. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  64. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +27 -12
  65. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  66. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +3 -3
  67. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  68. package/out/zero-cache/src/services/view-syncer/snapshotter.js +4 -0
  69. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  70. package/out/zero-cache/src/types/subscription.d.ts +3 -1
  71. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  72. package/out/zero-cache/src/types/subscription.js +21 -9
  73. package/out/zero-cache/src/types/subscription.js.map +1 -1
  74. package/out/zero-client/src/client/version.js +1 -1
  75. package/package.json +2 -1
@@ -1,53 +1,84 @@
1
+ import { liteTableName } from "../../../types/names.js";
1
2
  const CREATE_TABLE_METADATA_TABLE = (
2
3
  /*sql*/
3
4
  `
4
5
  CREATE TABLE "_zero.tableMetadata" (
5
- "schema" TEXT NOT NULL,
6
- "table" TEXT NOT NULL,
7
- "metadata" TEXT NOT NULL,
6
+ "schema" TEXT NOT NULL,
7
+ "table" TEXT NOT NULL,
8
+ "minRowVersion" TEXT NOT NULL DEFAULT "00",
9
+ "upstreamMetadata" TEXT,
10
+ "metadata" TEXT, -- deprecated
8
11
  PRIMARY KEY ("schema", "table")
9
12
  );
10
13
  `
11
14
  );
12
15
  class TableMetadataTracker {
13
- #set;
16
+ #db;
17
+ // All statements are lazily created.
18
+ #setUpstreamMetadata;
19
+ #setMinRowVersion;
20
+ #getMinRowVersions;
14
21
  #rename;
15
22
  #drop;
16
23
  constructor(db) {
17
- this.#set = db.prepare(
24
+ this.#db = db;
25
+ }
26
+ setUpstreamMetadata({ schema, name }, metadata) {
27
+ (this.#setUpstreamMetadata ??= this.#db.prepare(
18
28
  /*sql*/
19
29
  `
20
- INSERT OR REPLACE INTO "_zero.tableMetadata"
21
- ("schema", "table", "metadata") VALUES (?, ?, ?);
30
+ INSERT INTO "_zero.tableMetadata" ("schema", "table", "upstreamMetadata")
31
+ VALUES (@schema, @name, @metadata)
32
+ ON CONFLICT ("schema", "table")
33
+ DO UPDATE SET "upstreamMetadata" = @metadata
22
34
  `
23
- );
24
- this.#rename = db.prepare(
35
+ )).run({
36
+ schema,
37
+ name,
38
+ metadata: JSON.stringify(metadata)
39
+ });
40
+ }
41
+ setMinRowVersion({ schema, name }, version) {
42
+ (this.#setMinRowVersion ??= this.#db.prepare(
25
43
  /*sql*/
26
44
  `
27
- UPDATE "_zero.tableMetadata" SET "schema" = ?, "table" = ?
28
- WHERE "schema" = ? AND "table" = ?
45
+ INSERT INTO "_zero.tableMetadata" ("schema", "table", "minRowVersion")
46
+ VALUES (@schema, @name, @version)
47
+ ON CONFLICT ("schema", "table")
48
+ DO UPDATE SET "minRowVersion" = @version;
29
49
  `
30
- );
31
- this.#drop = db.prepare(
50
+ )).run({ schema, name, version });
51
+ }
52
+ getMinRowVersions() {
53
+ const results = (this.#getMinRowVersions ??= this.#db.prepare(
32
54
  /*sql*/
33
55
  `
34
- DELETE FROM "_zero.tableMetadata" WHERE "schema" = ? AND "table" = ?
56
+ SELECT "schema", "table" as "name", "minRowVersion" FROM "_zero.tableMetadata"
35
57
  `
58
+ )).all();
59
+ return new Map(
60
+ results.map(({ schema, name, minRowVersion }) => [
61
+ liteTableName({ schema, name }),
62
+ minRowVersion
63
+ ])
36
64
  );
37
65
  }
38
- set({ schema, name }, metadata) {
39
- this.#set.run(schema, name, JSON.stringify(metadata));
40
- }
41
66
  rename(oldTable, newTable) {
42
- this.#rename.run(
43
- newTable.schema,
44
- newTable.name,
45
- oldTable.schema,
46
- oldTable.name
47
- );
67
+ (this.#rename ??= this.#db.prepare(
68
+ /*sql*/
69
+ `
70
+ UPDATE "_zero.tableMetadata" SET "schema" = ?, "table" = ?
71
+ WHERE "schema" = ? AND "table" = ?
72
+ `
73
+ )).run(newTable.schema, newTable.name, oldTable.schema, oldTable.name);
48
74
  }
49
75
  drop({ schema, name }) {
50
- this.#drop.run(schema, name);
76
+ (this.#drop ??= this.#db.prepare(
77
+ /*sql*/
78
+ `
79
+ DELETE FROM "_zero.tableMetadata" WHERE "schema" = ? AND "table" = ?
80
+ `
81
+ )).run(schema, name);
51
82
  }
52
83
  }
53
84
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"table-metadata.js","sources":["../../../../../../../zero-cache/src/services/replicator/schema/table-metadata.ts"],"sourcesContent":["import type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport type {\n Identifier,\n TableMetadata,\n} from '../../change-source/protocol/current.ts';\n\n/**\n * Replica-level analog of tableMetadata in change-streamer/schema.\n * Per the requirement of the backfill protocol, backfill metadata\n * must be tracked outside of the change source (otherwise the change\n * source would have to be able to compute the state of the metadata at\n * arbitrary points in the past).\n *\n * This tracking is done:\n * 1. at the Change DB level, by the change-streamer\n * 2. at the replica level, in order to support the eventual configuration\n * of ephemeral Change DBs (on SQLite) that are initialized from data\n * in the replica.\n */\nexport const CREATE_TABLE_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.tableMetadata\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"metadata\" TEXT NOT NULL,\n PRIMARY KEY (\"schema\", \"table\")\n );\n`;\n\nexport class TableMetadataTracker {\n readonly #set: Statement;\n readonly #rename: Statement;\n readonly #drop: Statement;\n\n constructor(db: Database) {\n this.#set = db.prepare(/*sql*/ `\n INSERT OR REPLACE INTO \"_zero.tableMetadata\"\n (\"schema\", \"table\", \"metadata\") VALUES (?, ?, ?);\n `);\n this.#rename = db.prepare(/*sql*/ `\n UPDATE \"_zero.tableMetadata\" SET \"schema\" = ?, \"table\" = ?\n WHERE \"schema\" = ? AND \"table\" = ?\n `);\n this.#drop = db.prepare(/*sql*/ `\n DELETE FROM \"_zero.tableMetadata\" WHERE \"schema\" = ? AND \"table\" = ?\n `);\n }\n\n set({schema, name}: Identifier, metadata: TableMetadata) {\n this.#set.run(schema, name, JSON.stringify(metadata));\n }\n\n rename(oldTable: Identifier, newTable: Identifier) {\n this.#rename.run(\n newTable.schema,\n newTable.name,\n oldTable.schema,\n oldTable.name,\n );\n }\n\n drop({schema, name}: Identifier) {\n this.#drop.run(schema, name);\n }\n}\n"],"names":[],"mappings":"AAmBO,MAAM;AAAA;AAAA,EAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS5C,MAAM,qBAAqB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,IAAc;AACxB,SAAK,OAAO,GAAG;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA;AAAA,IAAA;AAI/B,SAAK,UAAU,GAAG;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA;AAAA,IAAA;AAIlC,SAAK,QAAQ,GAAG;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA,IAAA;AAAA,EAGlC;AAAA,EAEA,IAAI,EAAC,QAAQ,KAAA,GAAmB,UAAyB;AACvD,SAAK,KAAK,IAAI,QAAQ,MAAM,KAAK,UAAU,QAAQ,CAAC;AAAA,EACtD;AAAA,EAEA,OAAO,UAAsB,UAAsB;AACjD,SAAK,QAAQ;AAAA,MACX,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,IAAA;AAAA,EAEb;AAAA,EAEA,KAAK,EAAC,QAAQ,QAAmB;AAC/B,SAAK,MAAM,IAAI,QAAQ,IAAI;AAAA,EAC7B;AACF;"}
1
+ {"version":3,"file":"table-metadata.js","sources":["../../../../../../../zero-cache/src/services/replicator/schema/table-metadata.ts"],"sourcesContent":["import type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport {liteTableName} from '../../../types/names.ts';\nimport type {\n Identifier,\n TableMetadata,\n} from '../../change-source/protocol/current.ts';\n\n/**\n * Table-level controls for handling replicated data.\n *\n * ### Columns\n *\n * `minRowVersion`: the minimum `_0_version` value to apply to\n * all rows in the table. This overrides any per-row\n * `_0_version` value that is smaller (i.e. earlier).\n * The `minRowVersion` column is used to force a re-download\n * of all rows after a table-wide schema change (by giving\n * each row a version that's newer than what's in any CVR).\n * The naive, brute-force method of updating all of the rows\n * requires re-writing the entire table into the WAL as one\n * SQLite operation, which is too costly from both latency\n * and storage space.\n *\n * `upstreamMetadata`: the replica-level analog of tableMetadata in\n * change-streamer/schema. Per the requirement of the backfill\n * protocol, backfill metadata must be tracked outside of the\n * change source (otherwise the change source would have to be\n * able to compute the state of the metadata at arbitrary points\n * in the past).\n *\n * `metadata`: the previous name of the `upstreamMetadata` column,\n * kept for backwards compatibility.\n *\n * This tracking is done:\n * 1. at the Change DB level, by the change-streamer\n * 2. at the replica level, in order to support the eventual configuration\n * of ephemeral Change DBs (on SQLite) that are initialized from data\n * in the replica.\n */\nexport const CREATE_TABLE_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.tableMetadata\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"minRowVersion\" TEXT NOT NULL DEFAULT \"00\",\n \"upstreamMetadata\" TEXT,\n \"metadata\" TEXT, -- deprecated\n PRIMARY KEY (\"schema\", \"table\")\n );\n`;\n\nexport class TableMetadataTracker {\n readonly #db: Database;\n\n // All statements are lazily created.\n #setUpstreamMetadata: Statement | undefined;\n #setMinRowVersion: Statement | undefined;\n #getMinRowVersions: Statement | undefined;\n #rename: Statement | undefined;\n #drop: Statement | undefined;\n\n constructor(db: Database) {\n this.#db = db;\n }\n\n setUpstreamMetadata({schema, name}: Identifier, metadata: TableMetadata) {\n (this.#setUpstreamMetadata ??= this.#db.prepare(/*sql*/ `\n INSERT INTO \"_zero.tableMetadata\" (\"schema\", \"table\", \"upstreamMetadata\") \n VALUES (@schema, @name, @metadata)\n ON CONFLICT (\"schema\", \"table\")\n DO UPDATE SET \"upstreamMetadata\" = @metadata\n `)).run({\n schema,\n name,\n metadata: JSON.stringify(metadata),\n });\n }\n\n setMinRowVersion({schema, name}: Identifier, version: string) {\n (this.#setMinRowVersion ??= this.#db.prepare(/*sql*/ `\n INSERT INTO \"_zero.tableMetadata\" (\"schema\", \"table\", \"minRowVersion\") \n VALUES (@schema, @name, @version)\n ON CONFLICT (\"schema\", \"table\")\n DO UPDATE SET \"minRowVersion\" = @version;\n `)).run({schema, name, version});\n }\n\n getMinRowVersions(): Map<string, string> {\n const results = (this.#getMinRowVersions ??= this.#db.prepare(/*sql*/ `\n SELECT \"schema\", \"table\" as \"name\", \"minRowVersion\" FROM \"_zero.tableMetadata\"\n `)).all<{schema: string; name: string; minRowVersion: string}>();\n return new Map(\n results.map(({schema, name, minRowVersion}) => [\n liteTableName({schema, name}),\n minRowVersion,\n ]),\n );\n }\n\n rename(oldTable: Identifier, newTable: Identifier) {\n (this.#rename ??= this.#db.prepare(/*sql*/ `\n UPDATE \"_zero.tableMetadata\" SET \"schema\" = ?, \"table\" = ?\n WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(newTable.schema, newTable.name, oldTable.schema, oldTable.name);\n }\n\n drop({schema, name}: Identifier) {\n (this.#drop ??= this.#db.prepare(/*sql*/ `\n DELETE FROM \"_zero.tableMetadata\" WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(schema, name);\n }\n}\n"],"names":[],"mappings":";AAuCO,MAAM;AAAA;AAAA,EAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW5C,MAAM,qBAAqB;AAAA,EACvB;AAAA;AAAA,EAGT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,IAAc;AACxB,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,oBAAoB,EAAC,QAAQ,KAAA,GAAmB,UAAyB;AACvE,KAAC,KAAK,yBAAyB,KAAK,IAAI;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,GAKpD,IAAI;AAAA,MACN;AAAA,MACA;AAAA,MACA,UAAU,KAAK,UAAU,QAAQ;AAAA,IAAA,CAClC;AAAA,EACH;AAAA,EAEA,iBAAiB,EAAC,QAAQ,KAAA,GAAmB,SAAiB;AAC5D,KAAC,KAAK,sBAAsB,KAAK,IAAI;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,GAKjD,IAAI,EAAC,QAAQ,MAAM,SAAQ;AAAA,EACjC;AAAA,EAEA,oBAAyC;AACvC,UAAM,WAAW,KAAK,uBAAuB,KAAK,IAAI;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA,IAAA,GAElE,IAAA;AACJ,WAAO,IAAI;AAAA,MACT,QAAQ,IAAI,CAAC,EAAC,QAAQ,MAAM,oBAAmB;AAAA,QAC7C,cAAc,EAAC,QAAQ,MAAK;AAAA,QAC5B;AAAA,MAAA,CACD;AAAA,IAAA;AAAA,EAEL;AAAA,EAEA,OAAO,UAAsB,UAAsB;AACjD,KAAC,KAAK,YAAY,KAAK,IAAI;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA;AAAA,IAAA,GAGvC,IAAI,SAAS,QAAQ,SAAS,MAAM,SAAS,QAAQ,SAAS,IAAI;AAAA,EACxE;AAAA,EAEA,KAAK,EAAC,QAAQ,QAAmB;AAC/B,KAAC,KAAK,UAAU,KAAK,IAAI;AAAA;AAAA,MAAgB;AAAA;AAAA;AAAA,IAAA,GAErC,IAAI,QAAQ,IAAI;AAAA,EACtB;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-ast.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/run-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAQjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oDAAoD,CAAC;AAC3F,OAAO,KAAK,EAAC,GAAG,EAAe,MAAM,mCAAmC,CAAC;AAEzE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6CAA6C,CAAC;AAG9E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kDAAkD,CAAC;AACxF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gDAAgD,CAAC;AACxF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2CAA2C,CAAC;AAC5E,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAExD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,gBAAgB,CAAC;AAGnD,MAAM,MAAM,aAAa,GAAG;IAC1B,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,oBAAoB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9C,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAsB,MAAM,CAC1B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAwI7B"}
1
+ {"version":3,"file":"run-ast.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/run-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAQjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oDAAoD,CAAC;AAC3F,OAAO,KAAK,EAAC,GAAG,EAAe,MAAM,mCAAmC,CAAC;AAEzE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6CAA6C,CAAC;AAG9E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kDAAkD,CAAC;AACxF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gDAAgD,CAAC;AACxF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2CAA2C,CAAC;AAC5E,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAExD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAG7C,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,gBAAgB,CAAC;AAGnD,MAAM,MAAM,aAAa,GAAG;IAC1B,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,oBAAoB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9C,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAsB,MAAM,CAC1B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAyI7B"}
@@ -9,9 +9,10 @@ import { buildPipeline } from "../../../zql/src/builder/builder.js";
9
9
  import { skipYields } from "../../../zql/src/ivm/operator.js";
10
10
  import { resolveSimpleScalarSubqueries } from "../../../zqlite/src/resolve-scalar-subqueries.js";
11
11
  import { transformAndHashQuery } from "../auth/read-authorizer.js";
12
+ import { computeZqlSpecs } from "../db/lite-tables.js";
12
13
  import { hydrate } from "./view-syncer/pipeline-driver.js";
13
14
  async function runAst(lc, clientSchema, ast, isTransformed, options, yieldProcess) {
14
- const { permissions, host } = options;
15
+ const { permissions, host, db } = options;
15
16
  const result = {
16
17
  warnings: [],
17
18
  syncedRows: void 0,
@@ -70,7 +71,8 @@ async function runAst(lc, clientSchema, ast, isTransformed, options, yieldProces
70
71
  for (const rowChange of hydrate(
71
72
  pipeline,
72
73
  hashOfAST(resolvedAst),
73
- clientSchema
74
+ clientSchema,
75
+ computeZqlSpecs(lc, db, { includeBackfillingColumns: false })
74
76
  )) {
75
77
  if (rowChange === "yield") {
76
78
  await yieldProcess();
@@ -1 +1 @@
1
- {"version":3,"file":"run-ast.js","sources":["../../../../../zero-cache/src/services/run-ast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n// @circular-dep-ignore\nimport {astToZQL} from '../../../ast-to-zql/src/ast-to-zql.ts';\n// @circular-dep-ignore\nimport {formatOutput} from '../../../ast-to-zql/src/format.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST, LiteralValue} from '../../../zero-protocol/src/ast.ts';\nimport {mapAST} from '../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport {hashOfAST} from '../../../zero-protocol/src/query-hash.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {NameMapper} from '../../../zero-schema/src/name-mapper.ts';\nimport {\n buildPipeline,\n type BuilderDelegate,\n} from '../../../zql/src/builder/builder.ts';\nimport type {Node} from '../../../zql/src/ivm/data.ts';\nimport {skipYields} from '../../../zql/src/ivm/operator.ts';\nimport type {ConnectionCostModel} from '../../../zql/src/planner/planner-connection.ts';\nimport type {PlanDebugger} from '../../../zql/src/planner/planner-debug.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {resolveSimpleScalarSubqueries} from '../../../zqlite/src/resolve-scalar-subqueries.ts';\nimport type {JWTAuth} from '../auth/auth.ts';\nimport {transformAndHashQuery} from '../auth/read-authorizer.ts';\nimport type {LiteAndZqlSpec} from '../db/specs.ts';\nimport {hydrate} from './view-syncer/pipeline-driver.ts';\n\nexport type RunAstOptions = {\n applyPermissions?: boolean | undefined;\n auth?: JWTAuth | undefined;\n clientToServerMapper?: NameMapper | undefined;\n costModel?: ConnectionCostModel | undefined;\n db: Database;\n host: BuilderDelegate;\n permissions?: PermissionsConfig | undefined;\n planDebugger?: PlanDebugger | undefined;\n syncedRows?: boolean | undefined;\n tableSpecs: Map<string, LiteAndZqlSpec>;\n vendedRows?: boolean | undefined;\n};\n\nexport async function runAst(\n lc: LogContext,\n clientSchema: ClientSchema,\n ast: AST,\n isTransformed: boolean,\n options: RunAstOptions,\n yieldProcess: () => Promise<void>,\n): Promise<AnalyzeQueryResult> {\n const {clientToServerMapper, permissions, host} = options;\n const result: AnalyzeQueryResult = {\n warnings: [],\n syncedRows: undefined,\n syncedRowCount: 0,\n start: 0,\n end: 0,\n elapsed: 0,\n afterPermissions: undefined,\n readRows: undefined,\n readRowCountsByQuery: {},\n readRowCount: undefined,\n };\n\n if (!isTransformed) {\n // map the AST to server names if not already transformed\n ast = mapAST(ast, must(clientToServerMapper));\n }\n if (options.applyPermissions) {\n const auth = options.auth;\n if (!auth) {\n result.warnings.push(\n 'No auth data provided. Permission rules will compare to `NULL` wherever an auth data field is referenced.',\n );\n }\n ast = transformAndHashQuery(\n lc,\n 'clientGroupIDForAnalyze',\n ast,\n must(permissions),\n auth,\n false,\n ).transformedAst;\n result.afterPermissions = await formatOutput(ast.table + astToZQL(ast));\n }\n\n // Resolve scalar subqueries (e.g. whereExists with {scalar: true}) to\n // literal equality conditions so that SQLite can use indexes effectively.\n // Without this, correlated subqueries get stripped from SQL filters and\n // queries on large tables fall back to full table scans.\n const executor = (\n subqueryAST: AST,\n childField: string,\n ): LiteralValue | null | undefined => {\n const input = buildPipeline(subqueryAST, host, 'scalar-subquery');\n // Consume the full stream rather than using first() to avoid\n // triggering early return on Take's #initialFetch assertion.\n // The subquery AST already has limit: 1, so at most one row is produced.\n let node: Node | undefined;\n for (const n of skipYields(input.fetch({}))) {\n node ??= n;\n }\n input.destroy();\n return node ? ((node.row[childField] as LiteralValue) ?? null) : undefined;\n };\n\n const {ast: resolvedAst} = resolveSimpleScalarSubqueries(\n ast,\n options.tableSpecs,\n executor,\n );\n\n const pipeline = buildPipeline(\n resolvedAst,\n host,\n 'query-id',\n options.costModel,\n lc,\n options.planDebugger,\n );\n\n const start = performance.now();\n\n let syncedRowCount = 0;\n const rowsByTable: Record<string, Row[]> = {};\n const seenByTable: Set<string> = new Set();\n for (const rowChange of hydrate(\n pipeline,\n hashOfAST(resolvedAst),\n clientSchema,\n )) {\n if (rowChange === 'yield') {\n await yieldProcess();\n continue;\n }\n assert(rowChange.type === 'add', 'Hydration only handles add row changes');\n\n // yield to other tasks to avoid blocking for too long\n if (syncedRowCount % 10 === 0) {\n await Promise.resolve();\n }\n if (syncedRowCount % 100 === 0) {\n await sleep(1);\n }\n\n let rows: Row[] = rowsByTable[rowChange.table];\n const s = rowChange.table + '.' + JSON.stringify(rowChange.row);\n if (seenByTable.has(s)) {\n continue; // skip duplicates\n }\n syncedRowCount++;\n seenByTable.add(s);\n if (options.syncedRows) {\n if (!rows) {\n rows = [];\n rowsByTable[rowChange.table] = rows;\n }\n rows.push(rowChange.row);\n }\n }\n\n const end = performance.now();\n if (options.syncedRows) {\n result.syncedRows = rowsByTable;\n }\n result.start = start;\n result.end = end;\n result.elapsed = end - start;\n\n // Always include the count of synced and vended rows.\n result.syncedRowCount = syncedRowCount;\n result.readRowCountsByQuery = host.debug?.getVendedRowCounts() ?? {};\n let readRowCount = 0;\n for (const c of Object.values(result.readRowCountsByQuery)) {\n for (const v of Object.values(c)) {\n readRowCount += v;\n }\n }\n result.readRowCount = readRowCount;\n result.dbScansByQuery = host.debug?.getNVisitCounts() ?? {};\n\n if (options.vendedRows) {\n result.readRows = host.debug?.getVendedRows();\n }\n return result;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-ast.js","sources":["../../../../../zero-cache/src/services/run-ast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n// @circular-dep-ignore\nimport {astToZQL} from '../../../ast-to-zql/src/ast-to-zql.ts';\n// @circular-dep-ignore\nimport {formatOutput} from '../../../ast-to-zql/src/format.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST, LiteralValue} from '../../../zero-protocol/src/ast.ts';\nimport {mapAST} from '../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport {hashOfAST} from '../../../zero-protocol/src/query-hash.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {NameMapper} from '../../../zero-schema/src/name-mapper.ts';\nimport {\n buildPipeline,\n type BuilderDelegate,\n} from '../../../zql/src/builder/builder.ts';\nimport type {Node} from '../../../zql/src/ivm/data.ts';\nimport {skipYields} from '../../../zql/src/ivm/operator.ts';\nimport type {ConnectionCostModel} from '../../../zql/src/planner/planner-connection.ts';\nimport type {PlanDebugger} from '../../../zql/src/planner/planner-debug.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {resolveSimpleScalarSubqueries} from '../../../zqlite/src/resolve-scalar-subqueries.ts';\nimport type {JWTAuth} from '../auth/auth.ts';\nimport {transformAndHashQuery} from '../auth/read-authorizer.ts';\nimport {computeZqlSpecs} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec} from '../db/specs.ts';\nimport {hydrate} from './view-syncer/pipeline-driver.ts';\n\nexport type RunAstOptions = {\n applyPermissions?: boolean | undefined;\n auth?: JWTAuth | undefined;\n clientToServerMapper?: NameMapper | undefined;\n costModel?: ConnectionCostModel | undefined;\n db: Database;\n host: BuilderDelegate;\n permissions?: PermissionsConfig | undefined;\n planDebugger?: PlanDebugger | undefined;\n syncedRows?: boolean | undefined;\n tableSpecs: Map<string, LiteAndZqlSpec>;\n vendedRows?: boolean | undefined;\n};\n\nexport async function runAst(\n lc: LogContext,\n clientSchema: ClientSchema,\n ast: AST,\n isTransformed: boolean,\n options: RunAstOptions,\n yieldProcess: () => Promise<void>,\n): Promise<AnalyzeQueryResult> {\n const {clientToServerMapper, permissions, host, db} = options;\n const result: AnalyzeQueryResult = {\n warnings: [],\n syncedRows: undefined,\n syncedRowCount: 0,\n start: 0,\n end: 0,\n elapsed: 0,\n afterPermissions: undefined,\n readRows: undefined,\n readRowCountsByQuery: {},\n readRowCount: undefined,\n };\n\n if (!isTransformed) {\n // map the AST to server names if not already transformed\n ast = mapAST(ast, must(clientToServerMapper));\n }\n if (options.applyPermissions) {\n const auth = options.auth;\n if (!auth) {\n result.warnings.push(\n 'No auth data provided. Permission rules will compare to `NULL` wherever an auth data field is referenced.',\n );\n }\n ast = transformAndHashQuery(\n lc,\n 'clientGroupIDForAnalyze',\n ast,\n must(permissions),\n auth,\n false,\n ).transformedAst;\n result.afterPermissions = await formatOutput(ast.table + astToZQL(ast));\n }\n\n // Resolve scalar subqueries (e.g. whereExists with {scalar: true}) to\n // literal equality conditions so that SQLite can use indexes effectively.\n // Without this, correlated subqueries get stripped from SQL filters and\n // queries on large tables fall back to full table scans.\n const executor = (\n subqueryAST: AST,\n childField: string,\n ): LiteralValue | null | undefined => {\n const input = buildPipeline(subqueryAST, host, 'scalar-subquery');\n // Consume the full stream rather than using first() to avoid\n // triggering early return on Take's #initialFetch assertion.\n // The subquery AST already has limit: 1, so at most one row is produced.\n let node: Node | undefined;\n for (const n of skipYields(input.fetch({}))) {\n node ??= n;\n }\n input.destroy();\n return node ? ((node.row[childField] as LiteralValue) ?? null) : undefined;\n };\n\n const {ast: resolvedAst} = resolveSimpleScalarSubqueries(\n ast,\n options.tableSpecs,\n executor,\n );\n\n const pipeline = buildPipeline(\n resolvedAst,\n host,\n 'query-id',\n options.costModel,\n lc,\n options.planDebugger,\n );\n\n const start = performance.now();\n\n let syncedRowCount = 0;\n const rowsByTable: Record<string, Row[]> = {};\n const seenByTable: Set<string> = new Set();\n for (const rowChange of hydrate(\n pipeline,\n hashOfAST(resolvedAst),\n clientSchema,\n computeZqlSpecs(lc, db, {includeBackfillingColumns: false}),\n )) {\n if (rowChange === 'yield') {\n await yieldProcess();\n continue;\n }\n assert(rowChange.type === 'add', 'Hydration only handles add row changes');\n\n // yield to other tasks to avoid blocking for too long\n if (syncedRowCount % 10 === 0) {\n await Promise.resolve();\n }\n if (syncedRowCount % 100 === 0) {\n await sleep(1);\n }\n\n let rows: Row[] = rowsByTable[rowChange.table];\n const s = rowChange.table + '.' + JSON.stringify(rowChange.row);\n if (seenByTable.has(s)) {\n continue; // skip duplicates\n }\n syncedRowCount++;\n seenByTable.add(s);\n if (options.syncedRows) {\n if (!rows) {\n rows = [];\n rowsByTable[rowChange.table] = rows;\n }\n rows.push(rowChange.row);\n }\n }\n\n const end = performance.now();\n if (options.syncedRows) {\n result.syncedRows = rowsByTable;\n }\n result.start = start;\n result.end = end;\n result.elapsed = end - start;\n\n // Always include the count of synced and vended rows.\n result.syncedRowCount = syncedRowCount;\n result.readRowCountsByQuery = host.debug?.getVendedRowCounts() ?? {};\n let readRowCount = 0;\n for (const c of Object.values(result.readRowCountsByQuery)) {\n for (const v of Object.values(c)) {\n readRowCount += v;\n }\n }\n result.readRowCount = readRowCount;\n result.dbScansByQuery = host.debug?.getNVisitCounts() ?? {};\n\n if (options.vendedRows) {\n result.readRows = host.debug?.getVendedRows();\n }\n return result;\n}\n"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { type Input } from '../../../../zql/src/ivm/operator.ts';
7
7
  import type { ClientGroupStorage } from '../../../../zqlite/src/database-storage.ts';
8
8
  import { type LoadedPermissions } from '../../auth/load-permissions.ts';
9
9
  import type { LogConfig, ZeroConfig } from '../../config/zero-config.ts';
10
+ import type { LiteAndZqlSpec } from '../../db/specs.ts';
10
11
  import type { InspectorDelegate } from '../../server/inspector-delegate.ts';
11
12
  import { type RowKey } from '../../types/row-key.ts';
12
13
  import { type ShardID } from '../../types/shards.ts';
@@ -134,7 +135,7 @@ export declare class PipelineDriver {
134
135
  * function for reuse by bin-analyze so that bin-analyze's hydration logic
135
136
  * is as close as possible to zero-cache's real hydration logic.
136
137
  */
137
- export declare function hydrate(input: Input, hash: string, clientSchema: ClientSchema): Iterable<RowChange | 'yield'>;
138
- export declare function hydrateInternal(input: Input, hash: string, primaryKeys: Map<string, PrimaryKey>): Iterable<RowChange | 'yield'>;
138
+ export declare function hydrate(input: Input, hash: string, clientSchema: ClientSchema, tableSpecs: Map<string, LiteAndZqlSpec>): Iterable<RowChange | 'yield'>;
139
+ export declare function hydrateInternal(input: Input, hash: string, primaryKeys: Map<string, PrimaryKey>, tableSpecs: Map<string, LiteAndZqlSpec>): Iterable<RowChange | 'yield'>;
139
140
  export {};
140
141
  //# sourceMappingURL=pipeline-driver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-driver.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline-driver.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ import { upstreamSchema } from "../../types/shards.js";
17
17
  import { getSubscriptionState } from "../replicator/schema/replication-state.js";
18
18
  import { checkClientSchema } from "./client-schema.js";
19
19
  import { ResetPipelinesSignal } from "./snapshotter.js";
20
+ import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/constants.js";
20
21
  const MIN_ADVANCEMENT_TIME_LIMIT_MS = 50;
21
22
  class PipelineDriver {
22
23
  #tables = /* @__PURE__ */ new Map();
@@ -303,7 +304,12 @@ class PipelineDriver {
303
304
  return [];
304
305
  }
305
306
  });
306
- yield* hydrateInternal(input, queryID, must(this.#primaryKeys));
307
+ yield* hydrateInternal(
308
+ input,
309
+ queryID,
310
+ must(this.#primaryKeys),
311
+ this.#tableSpecs
312
+ );
307
313
  for (const { table, row } of companionRows) {
308
314
  const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);
309
315
  yield {
@@ -591,7 +597,7 @@ class PipelineDriver {
591
597
  }
592
598
  #startAccumulating() {
593
599
  assert(this.#streamer === null, "Streamer already started");
594
- this.#streamer = new Streamer(must(this.#primaryKeys));
600
+ this.#streamer = new Streamer(must(this.#primaryKeys), this.#tableSpecs);
595
601
  }
596
602
  #stopAccumulating() {
597
603
  const streamer = this.#streamer;
@@ -602,8 +608,10 @@ class PipelineDriver {
602
608
  }
603
609
  class Streamer {
604
610
  #primaryKeys;
605
- constructor(primaryKeys) {
611
+ #tableSpecs;
612
+ constructor(primaryKeys, tableSpecs) {
606
613
  this.#primaryKeys = primaryKeys;
614
+ this.#tableSpecs = tableSpecs;
607
615
  }
608
616
  #changes = [];
609
617
  accumulate(queryID, schema, changes) {
@@ -652,6 +660,7 @@ class Streamer {
652
660
  *#streamNodes(queryID, schema, op, nodes) {
653
661
  const { tableName: table, system } = schema;
654
662
  const primaryKey = must(this.#primaryKeys.get(table));
663
+ const spec = must(this.#tableSpecs.get(table)).tableSpec;
655
664
  if (system === "permissions") {
656
665
  return;
657
666
  }
@@ -660,8 +669,15 @@ class Streamer {
660
669
  yield node;
661
670
  continue;
662
671
  }
663
- const { relationships, row } = node;
672
+ const { relationships } = node;
673
+ let { row } = node;
664
674
  const rowKey = getRowKey(primaryKey, row);
675
+ if (op !== "remove") {
676
+ const rowVersion = row[ZERO_VERSION_COLUMN_NAME];
677
+ if (typeof rowVersion === "string" && rowVersion < (spec.minRowVersion ?? "00")) {
678
+ row = { ...row, [ZERO_VERSION_COLUMN_NAME]: spec.minRowVersion };
679
+ }
680
+ }
665
681
  yield {
666
682
  type: op,
667
683
  queryID,
@@ -688,18 +704,17 @@ function* toAdds(nodes) {
688
704
  function getRowKey(cols, row) {
689
705
  return Object.fromEntries(cols.map((col) => [col, must(row[col])]));
690
706
  }
691
- function* hydrate(input, hash, clientSchema) {
707
+ function* hydrate(input, hash, clientSchema, tableSpecs) {
692
708
  const res = input.fetch({});
693
- const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(
694
- hash,
695
- input.getSchema(),
696
- toAdds(res)
697
- );
709
+ const streamer = new Streamer(
710
+ buildPrimaryKeys(clientSchema),
711
+ tableSpecs
712
+ ).accumulate(hash, input.getSchema(), toAdds(res));
698
713
  yield* streamer.stream();
699
714
  }
700
- function* hydrateInternal(input, hash, primaryKeys) {
715
+ function* hydrateInternal(input, hash, primaryKeys, tableSpecs) {
701
716
  const res = input.fetch({});
702
- const streamer = new Streamer(primaryKeys).accumulate(
717
+ const streamer = new Streamer(primaryKeys, tableSpecs).accumulate(
703
718
  hash,
704
719
  input.getSchema(),
705
720
  toAdds(res)
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST, LiteralValue} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport {\n skipYields,\n type Input,\n type Storage,\n} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {\n resolveSimpleScalarSubqueries,\n type CompanionSubquery,\n} from '../../../../zqlite/src/resolve-scalar-subqueries.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig, ZeroConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {getSubscriptionState} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype CompanionPipeline = {\n readonly input: Input;\n readonly childField: string;\n readonly resolvedValue: LiteralValue | null | undefined;\n};\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly transformedAst: AST;\n readonly transformationHash: string;\n readonly companions: readonly CompanionPipeline[];\n};\n\ntype QueryInfo = {\n readonly transformedAst: AST;\n readonly transformationHash: string;\n};\n\ntype AdvanceContext = {\n readonly timer: Timer;\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n pos: number;\n};\n\ntype HydrateContext = {\n readonly timer: Timer;\n};\n\nexport type Timer = {\n elapsedLap: () => number;\n totalElapsed: () => number;\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 50;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // Query id to pipeline\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #config: ZeroConfig | undefined;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #allTableNames = new Set<string>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n readonly #yieldThresholdMs: () => number;\n #streamer: Streamer | null = null;\n #hydrateContext: HydrateContext | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n yieldThresholdMs: () => number,\n enablePlanner?: boolean | undefined,\n config?: ZeroConfig | undefined,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#config = config;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n this.#yieldThresholdMs = yieldThresholdMs;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const pipeline of this.#pipelines.values()) {\n pipeline.input.destroy();\n for (const companion of pipeline.companions) {\n companion.input.destroy();\n }\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#allTableNames.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(\n this.#lc,\n db.db,\n {includeBackfillingColumns: false},\n this.#tableSpecs,\n fullTables,\n );\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n this.#allTableNames.clear();\n for (const table of fullTables.keys()) {\n this.#allTableNames.add(table);\n }\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n this.#config,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return Map from query ID to PipelineInfo for all added queries. */\n queries(): ReadonlyMap<string, QueryInfo> {\n return this.#pipelines;\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n #resolveScalarSubqueries(ast: AST): {\n ast: AST;\n companionRows: {table: string; row: Row}[];\n companions: CompanionSubquery[];\n companionInputs: Input[];\n } {\n const companionRows: {table: string; row: Row}[] = [];\n const companionInputs: Input[] = [];\n\n const executor = (\n subqueryAST: AST,\n childField: string,\n ): LiteralValue | null | undefined => {\n const input = buildPipeline(\n subqueryAST,\n {\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput): Input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n 'scalar-subquery',\n );\n // Consume the full stream rather than using first() to avoid\n // triggering early return on Take's #initialFetch assertion.\n // The subquery AST already has limit: 1, so at most one row is produced.\n let node: Node | undefined;\n for (const n of skipYields(input.fetch({}))) {\n node ??= n;\n }\n if (!node) {\n // Keep the companion alive even with no results — it will\n // detect a future insert that creates the row.\n companionInputs.push(input);\n return undefined;\n }\n companionRows.push({table: subqueryAST.table, row: node.row as Row});\n companionInputs.push(input);\n return (node.row[childField] as LiteralValue) ?? null;\n };\n\n const {ast: resolved, companions} = resolveSimpleScalarSubqueries(\n ast,\n this.#tableSpecs,\n executor,\n );\n return {ast: resolved, companionRows, companions, companionInputs};\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with the same queryID is already added, the existing pipeline\n * will be removed and destroyed before adding the new pipeline.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: Timer,\n ): Iterable<RowChange | 'yield'> {\n assert(\n this.initialized(),\n 'Pipeline driver must be initialized before adding queries',\n );\n this.removeQuery(queryID);\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n assert(\n this.#advanceContext === null,\n 'Cannot hydrate while advance is in progress',\n );\n this.#hydrateContext = {\n timer,\n };\n try {\n const {\n ast: resolvedQuery,\n companionRows,\n companions: companionMeta,\n companionInputs,\n } = this.#resolveScalarSubqueries(query);\n\n const input = buildPipeline(\n resolvedQuery,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n queryID,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n streamer.accumulate(queryID, schema, [change]);\n return [];\n },\n });\n\n yield* hydrateInternal(input, queryID, must(this.#primaryKeys));\n\n for (const {table, row} of companionRows) {\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n yield {\n type: 'add',\n queryID,\n table,\n rowKey: getRowKey(primaryKey, row),\n row,\n } as RowChange;\n }\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('queryID', queryID)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Set up live companion pipelines for reactive scalar subquery monitoring.\n const liveCompanions: CompanionPipeline[] = [];\n for (let i = 0; i < companionMeta.length; i++) {\n const meta = companionMeta[i];\n const companionInput = companionInputs[i];\n const companionSchema = companionInput.getSchema();\n const {childField, resolvedValue} = meta;\n companionInput.setOutput({\n push: (change: Change) => {\n let newValue: LiteralValue | null | undefined;\n switch (change.type) {\n case 'add':\n case 'edit':\n newValue =\n (change.node.row[childField] as LiteralValue) ?? null;\n break;\n case 'remove':\n newValue = undefined;\n break;\n case 'child':\n return [];\n }\n if (!scalarValuesEqual(newValue, resolvedValue)) {\n throw new ResetPipelinesSignal(\n `Scalar subquery value changed for ${meta.ast.table}: ` +\n `${String(resolvedValue)} -> ${String(newValue)}`,\n );\n }\n const streamer = this.#streamer;\n assert(\n streamer,\n 'must #startAccumulating() before pushing changes',\n );\n streamer.accumulate(queryID, companionSchema, [change]);\n return [];\n },\n });\n liveCompanions.push({input: companionInput, childField, resolvedValue});\n }\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(queryID, {\n input,\n hydrationTimeMs,\n transformedAst: resolvedQuery,\n transformationHash,\n companions: liveCompanions,\n });\n } finally {\n this.#hydrateContext = null;\n }\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(queryID: string) {\n const pipeline = this.#pipelines.get(queryID);\n if (pipeline) {\n this.#pipelines.delete(queryID);\n pipeline.input.destroy();\n for (const companion of pipeline.companions) {\n companion.input.destroy();\n }\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: Timer): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange | 'yield'>;\n } {\n assert(\n this.initialized(),\n 'Pipeline driver must be initialized before advancing',\n );\n const diff = this.#snapshotter.advance(\n this.#tableSpecs,\n this.#allTableNames,\n );\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: Timer,\n numChanges: number,\n ): Iterable<RowChange | 'yield'> {\n assert(\n this.#hydrateContext === null,\n 'Cannot advance while hydration is in progress',\n );\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n // Advance progress is checked each time a row is fetched\n // from a TableSource during push processing, but some pushes\n // don't read any rows. Check progress here before processing\n // the next change.\n if (this.#shouldAdvanceYieldMaybeAbortAdvance()) {\n yield 'yield';\n }\n const start = timer.totalElapsed();\n\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = timer.totalElapsed() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n () => this.#shouldYield(),\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n #shouldYield(): boolean {\n if (this.#hydrateContext) {\n return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs();\n }\n if (this.#advanceContext) {\n return this.#shouldAdvanceYieldMaybeAbortAdvance();\n }\n throw new Error('shouldYield called outside of hydration or advancement');\n }\n\n /**\n * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if\n * it has taken longer than half the total hydration time to make it through\n * half of the advancement, or if processing time exceeds total hydration\n * time. This serves as both a circuit breaker for very large transactions,\n * as well as a bound on the amount of time the previous connection locks\n * the inactive WAL file (as the lock prevents WAL2 from switching to the\n * free WAL when the current one is over the size limit, which can make\n * the WAL grow continuously and compound slowness).\n * This is checked:\n * 1. before starting to process each change in an advancement is processed\n * 2. whenever a row is fetched from a TableSource during push processing\n */\n #shouldAdvanceYieldMaybeAbortAdvance(): boolean {\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = must(this.#advanceContext);\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes ` +\n `after ${elapsed} ms. Advancement time limited based on total ` +\n `hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n return advanceTimer.elapsedLap() > this.#yieldThresholdMs();\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(\n source: TableSource,\n change: SourceChange,\n ): Iterable<RowChange | 'yield'> {\n this.#startAccumulating();\n try {\n for (const val of source.genPush(change)) {\n if (val === 'yield') {\n yield 'yield';\n }\n for (const changeOrYield of this.#stopAccumulating().stream()) {\n yield changeOrYield;\n }\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null, 'Streamer already started');\n this.#streamer = new Streamer(must(this.#primaryKeys));\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer, 'Streamer not started');\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n\n constructor(primaryKeys: Map<string, PrimaryKey>) {\n this.#primaryKeys = primaryKeys;\n }\n\n readonly #changes: [\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ][] = [];\n\n accumulate(\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): this {\n this.#changes.push([queryID, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange | 'yield'> {\n for (const [queryID, schema, changes] of this.#changes) {\n yield* this.#streamChanges(queryID, schema, changes);\n }\n }\n\n *#streamChanges(\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n if (change === 'yield') {\n yield change;\n continue;\n }\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryID, schema, type, () => [change.node]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryID, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryID, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryID: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const {relationships, row} = node;\n const rowKey = getRowKey(primaryKey, row);\n\n yield {\n type: op,\n queryID,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryID, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node | 'yield'>): Iterable<Change | 'yield'> {\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n\n/**\n * Compares two scalar subquery resolved values for equality.\n * Unlike `valuesEqual` in data.ts (which treats null != null for join\n * semantics), this uses identity semantics: undefined === undefined\n * (no row matched), null === null (row matched but field was NULL).\n */\nfunction scalarValuesEqual(\n a: LiteralValue | null | undefined,\n b: LiteralValue | null | undefined,\n): boolean {\n return a === b;\n}\n"],"names":["input"],"mappings":";;;;;;;;;;;;;;;;;;;AAwHA,MAAM,gCAAgC;AAK/B,MAAM,eAAe;AAAA,EACjB,8BAAc,IAAA;AAAA;AAAA,EAEd,iCAAiB,IAAA;AAAA,EAEjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kCAAkB,IAAA;AAAA,EAClB,qCAAqB,IAAA;AAAA,EACrB;AAAA,EACA;AAAA,EACT,YAA6B;AAAA,EAC7B,kBAAyC;AAAA,EACzC,kBAAyC;AAAA,EACzC,kBAAiC;AAAA,EACjC,eAA+C;AAAA,EAC/C,eAAyC;AAAA,EAEhC,eAAe,qBAAqB,QAAQ,oBAAoB;AAAA,IACvE,aACE;AAAA,IACF,MAAM;AAAA,EAAA,CACP;AAAA,EAEQ,uBAAuB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGO;AAAA,EAET,YACE,IACA,WACA,aACA,SACA,SACA,eACA,mBACA,kBACA,eACA,QACA;AACA,SAAK,MAAM,GAAG,YAAY,iBAAiB,aAAa;AACxD,SAAK,eAAe;AACpB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,aAAa;AAClB,SAAK,UAAU;AACf,SAAK,qBAAqB;AAC1B,SAAK,cAAc,gBAAgB,oBAAI,QAAA,IAAY;AACnD,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,cAA4B;AAC/B,WAAO,CAAC,KAAK,aAAa,YAAA,GAAe,qBAAqB;AAC9D,SAAK,aAAa,KAAA;AAClB,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,aAAa,YAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAA4B;AAChC,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,eAAS,MAAM,QAAA;AACf,iBAAW,aAAa,SAAS,YAAY;AAC3C,kBAAU,MAAM,QAAA;AAAA,MAClB;AAAA,IACF;AACA,SAAK,WAAW,MAAA;AAChB,SAAK,QAAQ,MAAA;AACb,SAAK,eAAe,MAAA;AACpB,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA,EAEA,oBAAoB,cAA4B;AAC9C,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,UAAM,iCAAiB,IAAA;AACvB;AAAA,MACE,KAAK;AAAA,MACL,GAAG;AAAA,MACH,EAAC,2BAA2B,MAAA;AAAA,MAC5B,KAAK;AAAA,MACL;AAAA,IAAA;AAEF;AAAA,MACE,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IAAA;AAEF,SAAK,eAAe,MAAA;AACpB,eAAW,SAAS,WAAW,QAAQ;AACrC,WAAK,eAAe,IAAI,KAAK;AAAA,IAC/B;AACA,UAAM,cAAc,KAAK,gBAAgB,oBAAI,IAAA;AAC7C,SAAK,eAAe;AACpB,gBAAY,MAAA;AACZ,eAAW,CAAC,OAAO,IAAI,KAAK,KAAK,YAAY,WAAW;AACtD,UAAI,MAAM,WAAW,eAAe,KAAK,QAAQ,CAAC,GAAG;AACnD,oBAAY,IAAI,OAAO,KAAK,UAAU,UAAU;AAAA,MAClD;AAAA,IACF;AACA,qBAAiB,cAAc,WAAW;AAC1C,UAAM,EAAC,eAAA,IAAkB,qBAAqB,EAAE;AAChD,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,KAAK,iBAAiB,qBAAqB;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAyB;AACvB,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,WAAO,KAAK,aAAa,QAAA,EAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA+C;AAC7C,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,MAAM;AAAA,MACV,KAAK;AAAA,MACL,KAAK,aAAa,QAAA,EAAU;AAAA,MAC5B,KAAK,SAAS;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,IAAA;AAEP,QAAI,IAAI,SAAS;AACf,WAAK,eAAe,IAAI;AACxB,WAAK,IAAI;AAAA,QACP;AAAA,QACA,KAAK,UAAU,KAAK,YAAY;AAAA,MAAA;AAAA,IAEpC;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAA6B;AAC3B,UAAM,EAAC,IAAI,QAAA,IAAW,KAAK,aAAa,qBAAqB;AAC7D,eAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,YAAM,MAAM,GAAG,EAAE;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gCAAgC,IAAc;AAC5C,QAAI,WAAW,KAAK,aAAa,IAAI,EAAE;AACvC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa;AACpB,YAAM,YAAY,sBAAsB,IAAI,KAAK,WAAW;AAC5D,WAAK,YAAY,IAAI,IAAI,SAAS;AAClC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU;AACR,SAAK,SAAS,QAAA;AACd,SAAK,aAAa,QAAA;AAAA,EACpB;AAAA;AAAA,EAGA,UAA0C;AACxC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,uBAA+B;AAC7B,QAAI,QAAQ;AACZ,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,eAAS,SAAS;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,yBAAyB,KAKvB;AACA,UAAM,gBAA6C,CAAA;AACnD,UAAM,kBAA2B,CAAA;AAEjC,UAAM,WAAW,CACf,aACA,eACoC;AACpC,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,UACE,WAAW,CAAA,SAAQ,KAAK,WAAW,IAAI;AAAA,UACvC,eAAe,MAAM,KAAK,eAAA;AAAA,UAC1B,qBAAqB,CAACA,WAA8BA;AAAAA,UACpD,eAAe,CAAAA,WAASA;AAAAA,UACxB,UAAU;AAAA,UAAC;AAAA,UACX,qBAAqB,CAAAA,WAASA;AAAAA,QAAA;AAAA,QAEhC;AAAA,MAAA;AAKF,UAAI;AACJ,iBAAW,KAAK,WAAW,MAAM,MAAM,CAAA,CAAE,CAAC,GAAG;AAC3C,iBAAS;AAAA,MACX;AACA,UAAI,CAAC,MAAM;AAGT,wBAAgB,KAAK,KAAK;AAC1B,eAAO;AAAA,MACT;AACA,oBAAc,KAAK,EAAC,OAAO,YAAY,OAAO,KAAK,KAAK,KAAW;AACnE,sBAAgB,KAAK,KAAK;AAC1B,aAAQ,KAAK,IAAI,UAAU,KAAsB;AAAA,IACnD;AAEA,UAAM,EAAC,KAAK,UAAU,WAAA,IAAc;AAAA,MAClC;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IAAA;AAEF,WAAO,EAAC,KAAK,UAAU,eAAe,YAAY,gBAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,CAAC,SACC,oBACA,SACA,OACA,OAC+B;AAC/B;AAAA,MACE,KAAK,YAAA;AAAA,MACL;AAAA,IAAA;AAEF,SAAK,YAAY,OAAO;AACxB,UAAM,gBAAgB,kBAAkB,kBACpC,IAAI,UACJ;AAEJ,UAAM,YAAY,KAAK;AAAA,MACrB,KAAK,aAAa,QAAA,EAAU,GAAG;AAAA,IAAA;AAGjC;AAAA,MACE,KAAK,oBAAoB;AAAA,MACzB;AAAA,IAAA;AAEF,SAAK,kBAAkB;AAAA,MACrB;AAAA,IAAA;AAEF,QAAI;AACF,YAAM;AAAA,QACJ,KAAK;AAAA,QACL;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,MAAA,IACE,KAAK,yBAAyB,KAAK;AAEvC,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,iBAAiB;AAAA;AAAA,UACjB,WAAW,CAAA,SAAQ,KAAK,WAAW,IAAI;AAAA,UACvC,eAAe,MAAM,KAAK,eAAA;AAAA,UAC1B,qBAAqB,CAACA,QAAoB,aACxC,IAAI;AAAA,YACFA;AAAAA,YACA;AAAA,YACA,KAAK;AAAA,YACL;AAAA,UAAA;AAAA,UAEJ,eAAe,CAAAA,WAASA;AAAAA,UACxB,UAAU;AAAA,UAAC;AAAA,UACX,qBAAqB,CAAAA,WAASA;AAAAA,QAAA;AAAA,QAEhC;AAAA,QACA;AAAA,MAAA;AAEF,YAAM,SAAS,MAAM,UAAA;AACrB,YAAM,UAAU;AAAA,QACd,MAAM,CAAA,WAAU;AACd,gBAAM,WAAW,KAAK;AACtB,iBAAO,UAAU,kDAAkD;AACnE,mBAAS,WAAW,SAAS,QAAQ,CAAC,MAAM,CAAC;AAC7C,iBAAO,CAAA;AAAA,QACT;AAAA,MAAA,CACD;AAED,aAAO,gBAAgB,OAAO,SAAS,KAAK,KAAK,YAAY,CAAC;AAE9D,iBAAW,EAAC,OAAO,IAAA,KAAQ,eAAe;AACxC,cAAM,aAAa,kBAAkB,KAAK,cAAc,KAAK;AAC7D,cAAM;AAAA,UACJ,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,QAAQ,UAAU,YAAY,GAAG;AAAA,UACjC;AAAA,QAAA;AAAA,MAEJ;AAEA,YAAM,kBAAkB,MAAM,aAAA;AAC9B,UAAI,kBAAkB,sBAAsB;AAC1C,YAAI,kBAAkB,KAAK,WAAW,sBAAsB;AAC1D,cAAI,sBAAsB;AAC1B,gBAAM,KAAK,KAAK,IACb,YAAY,WAAW,OAAO,EAC9B,YAAY,mBAAmB,eAAe;AACjD,qBAAW,aAAa,KAAK,QAAQ,KAAA,GAAQ;AAC3C,kBAAM,UAAU,OAAO;AAAA,cACrB,eAAe,qBAAqB,SAAS,KAAK,CAAA;AAAA,YAAC;AAErD,mCAAuB,QAAQ;AAAA,cAC7B,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,cAC7B;AAAA,YAAA;AAEF,eAAG,OAAO,YAAY,aAAa,OAAO;AAAA,UAC5C;AACA,aAAG,OAAO,0BAA0B,mBAAmB,EAAE;AAAA,QAC3D;AAAA,MACF;AACA,qBAAe,MAAA;AAGf,YAAM,iBAAsC,CAAA;AAC5C,eAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,cAAM,OAAO,cAAc,CAAC;AAC5B,cAAM,iBAAiB,gBAAgB,CAAC;AACxC,cAAM,kBAAkB,eAAe,UAAA;AACvC,cAAM,EAAC,YAAY,cAAA,IAAiB;AACpC,uBAAe,UAAU;AAAA,UACvB,MAAM,CAAC,WAAmB;AACxB,gBAAI;AACJ,oBAAQ,OAAO,MAAA;AAAA,cACb,KAAK;AAAA,cACL,KAAK;AACH,2BACG,OAAO,KAAK,IAAI,UAAU,KAAsB;AACnD;AAAA,cACF,KAAK;AACH,2BAAW;AACX;AAAA,cACF,KAAK;AACH,uBAAO,CAAA;AAAA,YAAC;AAEZ,gBAAI,CAAC,kBAAkB,UAAU,aAAa,GAAG;AAC/C,oBAAM,IAAI;AAAA,gBACR,qCAAqC,KAAK,IAAI,KAAK,KAC9C,OAAO,aAAa,CAAC,OAAO,OAAO,QAAQ,CAAC;AAAA,cAAA;AAAA,YAErD;AACA,kBAAM,WAAW,KAAK;AACtB;AAAA,cACE;AAAA,cACA;AAAA,YAAA;AAEF,qBAAS,WAAW,SAAS,iBAAiB,CAAC,MAAM,CAAC;AACtD,mBAAO,CAAA;AAAA,UACT;AAAA,QAAA,CACD;AACD,uBAAe,KAAK,EAAC,OAAO,gBAAgB,YAAY,eAAc;AAAA,MACxE;AAKA,WAAK,WAAW,IAAI,SAAS;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA,QACA,YAAY;AAAA,MAAA,CACb;AAAA,IACH,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,SAAiB;AAC3B,UAAM,WAAW,KAAK,WAAW,IAAI,OAAO;AAC5C,QAAI,UAAU;AACZ,WAAK,WAAW,OAAO,OAAO;AAC9B,eAAS,MAAM,QAAA;AACf,iBAAW,aAAa,SAAS,YAAY;AAC3C,kBAAU,MAAM,QAAA;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,OAAe,IAA6B;AACjD,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC;AAC3C,WAAO,OAAO,OAAO,EAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,QAAQ,OAIN;AACA;AAAA,MACE,KAAK,YAAA;AAAA,MACL;AAAA,IAAA;AAEF,UAAM,OAAO,KAAK,aAAa;AAAA,MAC7B,KAAK;AAAA,MACL,KAAK;AAAA,IAAA;AAEP,UAAM,EAAC,MAAM,MAAM,QAAA,IAAW;AAC9B,SAAK,IAAI;AAAA,MACP,WAAW,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,IAAA;AAGxD,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,SAAS,KAAK,SAAS,MAAM,OAAO,OAAO;AAAA,IAAA;AAAA,EAE/C;AAAA,EAEA,CAAC,SACC,MACA,OACA,YAC+B;AAC/B;AAAA,MACE,KAAK,oBAAoB;AAAA,MACzB;AAAA,IAAA;AAEF,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,sBAAsB,KAAK,qBAAA;AAAA,MAC3B;AAAA,MACA,KAAK;AAAA,IAAA;AAEP,QAAI;AACF,iBAAW,EAAC,OAAO,YAAY,UAAA,KAAc,MAAM;AAKjD,YAAI,KAAK,wCAAwC;AAC/C,gBAAM;AAAA,QACR;AACA,cAAM,QAAQ,MAAM,aAAA;AAEpB,YAAI;AACJ,YAAI;AACF,gBAAM,cAAc,KAAK,QAAQ,IAAI,KAAK;AAC1C,cAAI,CAAC,aAAa;AAEhB;AAAA,UACF;AACA,gBAAM,aAAa,kBAAkB,KAAK,cAAc,KAAK;AAC7D,cAAI,aAA8B;AAClC,qBAAW,aAAa,YAAY;AAClC,gBACE,aACA;AAAA,cACE,UAAU,YAAY,SAAgB;AAAA,cACtC,UAAU,YAAY,SAAgB;AAAA,YAAA,GAExC;AACA,2BAAa;AAAA,YACf,OAAO;AACL,kBAAI,WAAW;AACb,qBAAK,qBAAqB,IAAI,CAAC;AAAA,cACjC;AACA,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AACA,cAAI,WAAW;AACb,gBAAI,YAAY;AACd,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,QAAQ;AAAA,cAAA,CACT;AAAA,YACH,OAAO;AACL,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AAAA,QACF,UAAA;AACE,eAAK,gBAAgB;AAAA,QACvB;AAEA,cAAM,UAAU,MAAM,aAAA,IAAiB;AACvC,aAAK,aAAa,OAAO,UAAU,KAAM;AAAA,UACvC;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MACH;AAGA,YAAM,EAAC,SAAQ;AACf,iBAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,cAAM,MAAM,KAAK,GAAG,EAAE;AAAA,MACxB;AACA,WAAK,gCAAgC,KAAK,GAAG,EAAE;AAC/C,WAAK,IAAI,QAAQ,eAAe,KAAK,OAAO,EAAE;AAAA,IAChD,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,WAA2B;AACpC,QAAI,SAAS,KAAK,QAAQ,IAAI,SAAS;AACvC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,iBAAiB,KAAK,aAAa,SAAS;AAC9D,UAAM,aAAa,kBAAkB,KAAK,cAAc,SAAS;AAEjE,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,aAAS,IAAI;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,MAAM,KAAK,aAAA;AAAA,IAAa;AAE1B,SAAK,QAAQ,IAAI,WAAW,MAAM;AAClC,SAAK,IAAI,QAAQ,2BAA2B,SAAS,EAAE;AACvD,WAAO;AAAA,EACT;AAAA,EAEA,eAAwB;AACtB,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,gBAAgB,MAAM,WAAA,IAAe,KAAK,kBAAA;AAAA,IACxD;AACA,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,qCAAA;AAAA,IACd;AACA,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,uCAAgD;AAC9C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IAAA,IACE,KAAK,KAAK,eAAe;AAC7B,UAAM,UAAU,aAAa,aAAA;AAC7B,QACE,UAAU,kCACT,UAAU,wBACR,UAAU,uBAAuB,KAAK,OAAO,aAAa,IAC7D;AACA,YAAM,IAAI;AAAA,QACR,mCAAmC,GAAG,OAAO,UAAU,kBAC5C,OAAO,kEACK,oBAAoB;AAAA,MAAA;AAAA,IAE/C;AACA,WAAO,aAAa,eAAe,KAAK,kBAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,iBAA0B;AACxB,WAAO,KAAK,SAAS,cAAA;AAAA,EACvB;AAAA,EAEA,CAAC,MACC,QACA,QAC+B;AAC/B,SAAK,mBAAA;AACL,QAAI;AACF,iBAAW,OAAO,OAAO,QAAQ,MAAM,GAAG;AACxC,YAAI,QAAQ,SAAS;AACnB,gBAAM;AAAA,QACR;AACA,mBAAW,iBAAiB,KAAK,kBAAA,EAAoB,UAAU;AAC7D,gBAAM;AAAA,QACR;AACA,aAAK,mBAAA;AAAA,MACP;AAAA,IACF,UAAA;AACE,UAAI,KAAK,cAAc,MAAM;AAC3B,aAAK,kBAAA;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAEA,qBAAqB;AACnB,WAAO,KAAK,cAAc,MAAM,0BAA0B;AAC1D,SAAK,YAAY,IAAI,SAAS,KAAK,KAAK,YAAY,CAAC;AAAA,EACvD;AAAA,EAEA,oBAA8B;AAC5B,UAAM,WAAW,KAAK;AACtB,WAAO,UAAU,sBAAsB;AACvC,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AACF;AAEA,MAAM,SAAS;AAAA,EACJ;AAAA,EAET,YAAY,aAAsC;AAChD,SAAK,eAAe;AAAA,EACtB;AAAA,EAES,WAIH,CAAA;AAAA,EAEN,WACE,SACA,QACA,SACM;AACN,SAAK,SAAS,KAAK,CAAC,SAAS,QAAQ,OAAO,CAAC;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,CAAC,SAAwC;AACvC,eAAW,CAAC,SAAS,QAAQ,OAAO,KAAK,KAAK,UAAU;AACtD,aAAO,KAAK,eAAe,SAAS,QAAQ,OAAO;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,CAAC,eACC,SACA,QACA,SAC+B;AAG/B,QAAI,OAAO,WAAW,eAAe;AACnC;AAAA,IACF;AAEA,eAAW,UAAU,SAAS;AAC5B,UAAI,WAAW,SAAS;AACtB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,SAAQ;AAEf,cAAQ,MAAA;AAAA,QACN,KAAK;AAAA,QACL,KAAK,UAAU;AACb,iBAAO,KAAK,aAAa,SAAS,QAAQ,MAAM,MAAM,CAAC,OAAO,IAAI,CAAC;AACnE;AAAA,QACF;AAAA,QACA,KAAK,SAAS;AACZ,gBAAM,EAAC,UAAS;AAChB,gBAAM,cAAc;AAAA,YAClB,OAAO,cAAc,MAAM,gBAAgB;AAAA,UAAA;AAG7C,iBAAO,KAAK,eAAe,SAAS,aAAa,CAAC,MAAM,MAAM,CAAC;AAC/D;AAAA,QACF;AAAA,QACA,KAAK;AACH,iBAAO,KAAK,aAAa,SAAS,QAAQ,MAAM,MAAM;AAAA,YACpD,EAAC,KAAK,OAAO,KAAK,KAAK,eAAe,CAAA,EAAC;AAAA,UAAC,CACzC;AACD;AAAA,QACF;AACE,sBAAgB;AAAA,MAAA;AAAA,IAEtB;AAAA,EACF;AAAA,EAEA,CAAC,aACC,SACA,QACA,IACA,OAC+B;AAC/B,UAAM,EAAC,WAAW,OAAO,OAAA,IAAU;AAEnC,UAAM,aAAa,KAAK,KAAK,aAAa,IAAI,KAAK,CAAC;AAIpD,QAAI,WAAW,eAAe;AAC5B;AAAA,IACF;AAEA,eAAW,QAAQ,SAAS;AAC1B,UAAI,SAAS,SAAS;AACpB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,eAAe,IAAA,IAAO;AAC7B,YAAM,SAAS,UAAU,YAAY,GAAG;AAExC,YAAM;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,OAAO,WAAW,SAAY;AAAA,MAAA;AAGrC,iBAAW,CAAC,cAAc,QAAQ,KAAK,OAAO,QAAQ,aAAa,GAAG;AACpE,cAAM,cAAc,KAAK,OAAO,cAAc,YAAY,CAAC;AAC3D,eAAO,KAAK,aAAa,SAAS,aAAa,IAAI,QAAQ;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AACF;AAEA,UAAU,OAAO,OAA6D;AAC5E,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,SAAS;AACpB,YAAM;AACN;AAAA,IACF;AACA,UAAM,EAAC,MAAM,OAAO,KAAA;AAAA,EACtB;AACF;AAEA,SAAS,UAAU,MAAkB,KAAkB;AACrD,SAAO,OAAO,YAAY,KAAK,IAAI,CAAA,QAAO,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE;AAOO,UAAU,QACf,OACA,MACA,cAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,iBAAiB,YAAY,CAAC,EAAE;AAAA,IAC5D;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEO,UAAU,gBACf,OACA,MACA,aAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,WAAW,EAAE;AAAA,IACzC;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEA,SAAS,iBACP,cACA,cAAuC,oBAAI,OAC3C;AACA,aAAW,CAAC,WAAW,EAAC,WAAA,CAAW,KAAK,OAAO,QAAQ,aAAa,MAAM,GAAG;AAC3E,gBAAY,IAAI,WAAW,UAAmC;AAAA,EAChE;AACA,SAAO;AACT;AAEA,SAAS,kBACP,aACA,OACY;AACZ,QAAM,QAAQ,KAAK,aAAa,iCAAiC;AAEjE,SAAO;AAAA,IACL,MAAM,IAAI,KAAK;AAAA,IACf,UAAU,KAAK,oBAAoB,CAAC,GAAG,MAAM,KAAA,CAAM,EAAE,KAAA,CAAM;AAAA,EAAA;AAG/D;AAQA,SAAS,kBACP,GACA,GACS;AACT,SAAO,MAAM;AACf;"}
1
+ {"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST, LiteralValue} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport {\n skipYields,\n type Input,\n type Storage,\n} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {\n resolveSimpleScalarSubqueries,\n type CompanionSubquery,\n} from '../../../../zqlite/src/resolve-scalar-subqueries.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig, ZeroConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {\n getSubscriptionState,\n ZERO_VERSION_COLUMN_NAME,\n} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryID: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype CompanionPipeline = {\n readonly input: Input;\n readonly childField: string;\n readonly resolvedValue: LiteralValue | null | undefined;\n};\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly transformedAst: AST;\n readonly transformationHash: string;\n readonly companions: readonly CompanionPipeline[];\n};\n\ntype QueryInfo = {\n readonly transformedAst: AST;\n readonly transformationHash: string;\n};\n\ntype AdvanceContext = {\n readonly timer: Timer;\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n pos: number;\n};\n\ntype HydrateContext = {\n readonly timer: Timer;\n};\n\nexport type Timer = {\n elapsedLap: () => number;\n totalElapsed: () => number;\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 50;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // Query id to pipeline\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #config: ZeroConfig | undefined;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #allTableNames = new Set<string>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n readonly #yieldThresholdMs: () => number;\n #streamer: Streamer | null = null;\n #hydrateContext: HydrateContext | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n yieldThresholdMs: () => number,\n enablePlanner?: boolean | undefined,\n config?: ZeroConfig | undefined,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#config = config;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n this.#yieldThresholdMs = yieldThresholdMs;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const pipeline of this.#pipelines.values()) {\n pipeline.input.destroy();\n for (const companion of pipeline.companions) {\n companion.input.destroy();\n }\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#allTableNames.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(\n this.#lc,\n db.db,\n {includeBackfillingColumns: false},\n this.#tableSpecs,\n fullTables,\n );\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n this.#allTableNames.clear();\n for (const table of fullTables.keys()) {\n this.#allTableNames.add(table);\n }\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n this.#config,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return Map from query ID to PipelineInfo for all added queries. */\n queries(): ReadonlyMap<string, QueryInfo> {\n return this.#pipelines;\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n #resolveScalarSubqueries(ast: AST): {\n ast: AST;\n companionRows: {table: string; row: Row}[];\n companions: CompanionSubquery[];\n companionInputs: Input[];\n } {\n const companionRows: {table: string; row: Row}[] = [];\n const companionInputs: Input[] = [];\n\n const executor = (\n subqueryAST: AST,\n childField: string,\n ): LiteralValue | null | undefined => {\n const input = buildPipeline(\n subqueryAST,\n {\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput): Input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n 'scalar-subquery',\n );\n // Consume the full stream rather than using first() to avoid\n // triggering early return on Take's #initialFetch assertion.\n // The subquery AST already has limit: 1, so at most one row is produced.\n let node: Node | undefined;\n for (const n of skipYields(input.fetch({}))) {\n node ??= n;\n }\n if (!node) {\n // Keep the companion alive even with no results — it will\n // detect a future insert that creates the row.\n companionInputs.push(input);\n return undefined;\n }\n companionRows.push({table: subqueryAST.table, row: node.row as Row});\n companionInputs.push(input);\n return (node.row[childField] as LiteralValue) ?? null;\n };\n\n const {ast: resolved, companions} = resolveSimpleScalarSubqueries(\n ast,\n this.#tableSpecs,\n executor,\n );\n return {ast: resolved, companionRows, companions, companionInputs};\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with the same queryID is already added, the existing pipeline\n * will be removed and destroyed before adding the new pipeline.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: Timer,\n ): Iterable<RowChange | 'yield'> {\n assert(\n this.initialized(),\n 'Pipeline driver must be initialized before adding queries',\n );\n this.removeQuery(queryID);\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n assert(\n this.#advanceContext === null,\n 'Cannot hydrate while advance is in progress',\n );\n this.#hydrateContext = {\n timer,\n };\n try {\n const {\n ast: resolvedQuery,\n companionRows,\n companions: companionMeta,\n companionInputs,\n } = this.#resolveScalarSubqueries(query);\n\n const input = buildPipeline(\n resolvedQuery,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n queryID,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n streamer.accumulate(queryID, schema, [change]);\n return [];\n },\n });\n\n yield* hydrateInternal(\n input,\n queryID,\n must(this.#primaryKeys),\n this.#tableSpecs,\n );\n\n for (const {table, row} of companionRows) {\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n yield {\n type: 'add',\n queryID,\n table,\n rowKey: getRowKey(primaryKey, row),\n row,\n } as RowChange;\n }\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('queryID', queryID)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Set up live companion pipelines for reactive scalar subquery monitoring.\n const liveCompanions: CompanionPipeline[] = [];\n for (let i = 0; i < companionMeta.length; i++) {\n const meta = companionMeta[i];\n const companionInput = companionInputs[i];\n const companionSchema = companionInput.getSchema();\n const {childField, resolvedValue} = meta;\n companionInput.setOutput({\n push: (change: Change) => {\n let newValue: LiteralValue | null | undefined;\n switch (change.type) {\n case 'add':\n case 'edit':\n newValue =\n (change.node.row[childField] as LiteralValue) ?? null;\n break;\n case 'remove':\n newValue = undefined;\n break;\n case 'child':\n return [];\n }\n if (!scalarValuesEqual(newValue, resolvedValue)) {\n throw new ResetPipelinesSignal(\n `Scalar subquery value changed for ${meta.ast.table}: ` +\n `${String(resolvedValue)} -> ${String(newValue)}`,\n );\n }\n const streamer = this.#streamer;\n assert(\n streamer,\n 'must #startAccumulating() before pushing changes',\n );\n streamer.accumulate(queryID, companionSchema, [change]);\n return [];\n },\n });\n liveCompanions.push({input: companionInput, childField, resolvedValue});\n }\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(queryID, {\n input,\n hydrationTimeMs,\n transformedAst: resolvedQuery,\n transformationHash,\n companions: liveCompanions,\n });\n } finally {\n this.#hydrateContext = null;\n }\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(queryID: string) {\n const pipeline = this.#pipelines.get(queryID);\n if (pipeline) {\n this.#pipelines.delete(queryID);\n pipeline.input.destroy();\n for (const companion of pipeline.companions) {\n companion.input.destroy();\n }\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: Timer): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange | 'yield'>;\n } {\n assert(\n this.initialized(),\n 'Pipeline driver must be initialized before advancing',\n );\n const diff = this.#snapshotter.advance(\n this.#tableSpecs,\n this.#allTableNames,\n );\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: Timer,\n numChanges: number,\n ): Iterable<RowChange | 'yield'> {\n assert(\n this.#hydrateContext === null,\n 'Cannot advance while hydration is in progress',\n );\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n // Advance progress is checked each time a row is fetched\n // from a TableSource during push processing, but some pushes\n // don't read any rows. Check progress here before processing\n // the next change.\n if (this.#shouldAdvanceYieldMaybeAbortAdvance()) {\n yield 'yield';\n }\n const start = timer.totalElapsed();\n\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = timer.totalElapsed() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n () => this.#shouldYield(),\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n #shouldYield(): boolean {\n if (this.#hydrateContext) {\n return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs();\n }\n if (this.#advanceContext) {\n return this.#shouldAdvanceYieldMaybeAbortAdvance();\n }\n throw new Error('shouldYield called outside of hydration or advancement');\n }\n\n /**\n * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if\n * it has taken longer than half the total hydration time to make it through\n * half of the advancement, or if processing time exceeds total hydration\n * time. This serves as both a circuit breaker for very large transactions,\n * as well as a bound on the amount of time the previous connection locks\n * the inactive WAL file (as the lock prevents WAL2 from switching to the\n * free WAL when the current one is over the size limit, which can make\n * the WAL grow continuously and compound slowness).\n * This is checked:\n * 1. before starting to process each change in an advancement is processed\n * 2. whenever a row is fetched from a TableSource during push processing\n */\n #shouldAdvanceYieldMaybeAbortAdvance(): boolean {\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = must(this.#advanceContext);\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes ` +\n `after ${elapsed} ms. Advancement time limited based on total ` +\n `hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n return advanceTimer.elapsedLap() > this.#yieldThresholdMs();\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(\n source: TableSource,\n change: SourceChange,\n ): Iterable<RowChange | 'yield'> {\n this.#startAccumulating();\n try {\n for (const val of source.genPush(change)) {\n if (val === 'yield') {\n yield 'yield';\n }\n for (const changeOrYield of this.#stopAccumulating().stream()) {\n yield changeOrYield;\n }\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null, 'Streamer already started');\n this.#streamer = new Streamer(must(this.#primaryKeys), this.#tableSpecs);\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer, 'Streamer not started');\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n readonly #tableSpecs: Map<string, LiteAndZqlSpec>;\n\n constructor(\n primaryKeys: Map<string, PrimaryKey>,\n tableSpecs: Map<string, LiteAndZqlSpec>,\n ) {\n this.#primaryKeys = primaryKeys;\n this.#tableSpecs = tableSpecs;\n }\n\n readonly #changes: [\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ][] = [];\n\n accumulate(\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): this {\n this.#changes.push([queryID, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange | 'yield'> {\n for (const [queryID, schema, changes] of this.#changes) {\n yield* this.#streamChanges(queryID, schema, changes);\n }\n }\n\n *#streamChanges(\n queryID: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n if (change === 'yield') {\n yield change;\n continue;\n }\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryID, schema, type, () => [change.node]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryID, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryID, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryID: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n const spec = must(this.#tableSpecs.get(table)).tableSpec;\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const {relationships} = node;\n let {row} = node;\n const rowKey = getRowKey(primaryKey, row);\n if (op !== 'remove') {\n const rowVersion = row[ZERO_VERSION_COLUMN_NAME];\n if (\n typeof rowVersion === 'string' &&\n rowVersion < (spec.minRowVersion ?? '00')\n ) {\n row = {...row, [ZERO_VERSION_COLUMN_NAME]: spec.minRowVersion};\n }\n }\n\n yield {\n type: op,\n queryID,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryID, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node | 'yield'>): Iterable<Change | 'yield'> {\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n tableSpecs: Map<string, LiteAndZqlSpec>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(\n buildPrimaryKeys(clientSchema),\n tableSpecs,\n ).accumulate(hash, input.getSchema(), toAdds(res));\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n tableSpecs: Map<string, LiteAndZqlSpec>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys, tableSpecs).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n\n/**\n * Compares two scalar subquery resolved values for equality.\n * Unlike `valuesEqual` in data.ts (which treats null != null for join\n * semantics), this uses identity semantics: undefined === undefined\n * (no row matched), null === null (row matched but field was NULL).\n */\nfunction scalarValuesEqual(\n a: LiteralValue | null | undefined,\n b: LiteralValue | null | undefined,\n): boolean {\n return a === b;\n}\n"],"names":["input"],"mappings":"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"}
@@ -2,7 +2,7 @@ import type { LogContext } from '@rocicorp/logger';
2
2
  import { type JSONValue } from '../../../../shared/src/bigint-json.ts';
3
3
  import type { Row } from '../../../../zero-protocol/src/data.ts';
4
4
  import type { PrimaryKey } from '../../../../zero-types/src/schema.ts';
5
- import type { LiteAndZqlSpec, LiteTableSpecWithKeys } from '../../db/specs.ts';
5
+ import type { LiteAndZqlSpec, LiteTableSpecWithKeysAndVersion } from '../../db/specs.ts';
6
6
  import { StatementRunner } from '../../db/statements.ts';
7
7
  import { type RowKey, type RowValue } from '../../types/row-key.ts';
8
8
  import type { AppID } from '../../types/shards.ts';
@@ -186,8 +186,8 @@ declare class Snapshot {
186
186
  changes: IterableIterator<unknown>;
187
187
  cleanup: () => void;
188
188
  };
189
- getRow(table: LiteTableSpecWithKeys, rowKey: JSONValue): any;
190
- getRows(table: LiteTableSpecWithKeys, keys: PrimaryKey[], row: RowValue): any[];
189
+ getRow(table: LiteTableSpecWithKeysAndVersion, rowKey: JSONValue): any;
190
+ getRows(table: LiteTableSpecWithKeysAndVersion, keys: PrimaryKey[], row: RowValue): any[];
191
191
  resetToHead(): Snapshot;
192
192
  }
193
193
  export declare class InvalidDiffError extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"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"}