@rocicorp/zero 1.3.0-canary.0 → 1.3.0-canary.2

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 (258) hide show
  1. package/out/analyze-query/src/bin-analyze.js +7 -7
  2. package/out/analyze-query/src/bin-transform.js +3 -3
  3. package/out/ast-to-zql/src/bin.js +2 -2
  4. package/out/shared/src/logging.d.ts.map +1 -1
  5. package/out/shared/src/logging.js +1 -1
  6. package/out/shared/src/logging.js.map +1 -1
  7. package/out/shared/src/options.d.ts.map +1 -1
  8. package/out/shared/src/options.js +1 -1
  9. package/out/shared/src/options.js.map +1 -1
  10. package/out/zero/package.js +90 -88
  11. package/out/zero/package.js.map +1 -1
  12. package/out/zero/src/zero-cache-dev.js +1 -1
  13. package/out/zero/src/zero-cache-dev.js.map +1 -1
  14. package/out/zero/src/zero-out.js +1 -1
  15. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  16. package/out/zero-cache/src/auth/auth.js.map +1 -1
  17. package/out/zero-cache/src/auth/load-permissions.js +2 -2
  18. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  19. package/out/zero-cache/src/auth/write-authorizer.js +5 -14
  20. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  21. package/out/zero-cache/src/config/network.d.ts +1 -1
  22. package/out/zero-cache/src/config/network.d.ts.map +1 -1
  23. package/out/zero-cache/src/config/network.js +1 -1
  24. package/out/zero-cache/src/config/network.js.map +1 -1
  25. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  26. package/out/zero-cache/src/config/normalize.js.map +1 -1
  27. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  28. package/out/zero-cache/src/config/zero-config.js +6 -3
  29. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  30. package/out/zero-cache/src/custom/fetch.d.ts +1 -1
  31. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  32. package/out/zero-cache/src/custom/fetch.js +0 -1
  33. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  34. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  35. package/out/zero-cache/src/db/lite-tables.js +3 -3
  36. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  37. package/out/zero-cache/src/observability/events.d.ts.map +1 -1
  38. package/out/zero-cache/src/observability/events.js +1 -1
  39. package/out/zero-cache/src/observability/events.js.map +1 -1
  40. package/out/zero-cache/src/scripts/decommission.js +1 -1
  41. package/out/zero-cache/src/scripts/deploy-permissions.js +2 -2
  42. package/out/zero-cache/src/scripts/permissions.js +1 -1
  43. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  44. package/out/zero-cache/src/server/anonymous-otel-start.js +2 -2
  45. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  46. package/out/zero-cache/src/server/change-streamer.d.ts +1 -1
  47. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  48. package/out/zero-cache/src/server/change-streamer.js +19 -8
  49. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  50. package/out/zero-cache/src/server/logging.js +1 -1
  51. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  52. package/out/zero-cache/src/server/main.js +22 -22
  53. package/out/zero-cache/src/server/main.js.map +1 -1
  54. package/out/zero-cache/src/server/mutator.js +1 -1
  55. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  56. package/out/zero-cache/src/server/reaper.js +3 -3
  57. package/out/zero-cache/src/server/reaper.js.map +1 -1
  58. package/out/zero-cache/src/server/replicator.js +2 -2
  59. package/out/zero-cache/src/server/replicator.js.map +1 -1
  60. package/out/zero-cache/src/server/runner/run-worker.js +1 -1
  61. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  62. package/out/zero-cache/src/server/syncer.js +7 -7
  63. package/out/zero-cache/src/server/syncer.js.map +1 -1
  64. package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
  65. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +1 -1
  66. package/out/zero-cache/src/services/change-source/common/replica-schema.js +1 -1
  67. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  68. package/out/zero-cache/src/services/change-source/pg/change-source.js +2 -2
  69. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  70. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +3 -3
  71. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  72. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
  73. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -1
  74. package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
  75. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
  76. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +1 -1
  77. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -1
  78. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  79. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +1 -1
  80. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  81. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +2 -1
  82. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  83. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +8 -5
  84. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  85. package/out/zero-cache/src/services/change-streamer/replica-monitor.js +2 -2
  86. package/out/zero-cache/src/services/change-streamer/storer.d.ts +14 -1
  87. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  88. package/out/zero-cache/src/services/change-streamer/storer.js +61 -2
  89. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  90. package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
  91. package/out/zero-cache/src/services/heapz.js +1 -1
  92. package/out/zero-cache/src/services/heapz.js.map +1 -1
  93. package/out/zero-cache/src/services/life-cycle.d.ts +2 -1
  94. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  95. package/out/zero-cache/src/services/life-cycle.js +9 -6
  96. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  97. package/out/zero-cache/src/services/litestream/commands.d.ts +15 -4
  98. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  99. package/out/zero-cache/src/services/litestream/commands.js +31 -31
  100. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  101. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  102. package/out/zero-cache/src/services/mutagen/pusher.d.ts +28 -28
  103. package/out/zero-cache/src/services/replicator/change-processor.js +2 -2
  104. package/out/zero-cache/src/services/replicator/incremental-sync.js +1 -1
  105. package/out/zero-cache/src/services/replicator/schema/replication-state.js +1 -1
  106. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  107. package/out/zero-cache/src/services/replicator/write-worker.js +2 -2
  108. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  109. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  110. package/out/zero-cache/src/services/run-ast.js +2 -2
  111. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  112. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  113. package/out/zero-cache/src/services/statz.js +2 -2
  114. package/out/zero-cache/src/services/statz.js.map +1 -1
  115. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +1 -1
  116. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +2 -2
  117. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  119. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +1 -1
  120. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
  121. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -16
  122. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  123. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +29 -37
  124. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  125. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  126. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +2 -2
  127. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  128. package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -2
  129. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  130. package/out/zero-cache/src/services/view-syncer/view-syncer.js +6 -6
  131. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  132. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  133. package/out/zero-cache/src/types/profiler.js.map +1 -1
  134. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  135. package/out/zero-cache/src/types/row-key.js.map +1 -1
  136. package/out/zero-cache/src/types/streams.d.ts +1 -1
  137. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  138. package/out/zero-cache/src/types/streams.js.map +1 -1
  139. package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
  140. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  141. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  142. package/out/zero-cache/src/workers/connection.d.ts +1 -1
  143. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  144. package/out/zero-cache/src/workers/connection.js.map +1 -1
  145. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  146. package/out/zero-cache/src/workers/syncer.d.ts +1 -1
  147. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  148. package/out/zero-cache/src/workers/syncer.js +2 -2
  149. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  150. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  151. package/out/zero-client/src/client/crud-impl.js +4 -13
  152. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  153. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  154. package/out/zero-client/src/client/ivm-branch.js +4 -13
  155. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  156. package/out/zero-client/src/client/options.d.ts +0 -4
  157. package/out/zero-client/src/client/options.d.ts.map +1 -1
  158. package/out/zero-client/src/client/options.js.map +1 -1
  159. package/out/zero-client/src/client/version.js +1 -1
  160. package/out/zero-protocol/src/error.d.ts.map +1 -1
  161. package/out/zero-protocol/src/error.js +1 -1
  162. package/out/zero-protocol/src/error.js.map +1 -1
  163. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  164. package/out/zero-solid/src/solid-view.js +13 -13
  165. package/out/zero-solid/src/solid-view.js.map +1 -1
  166. package/out/zql/src/builder/builder.d.ts.map +1 -1
  167. package/out/zql/src/builder/builder.js.map +1 -1
  168. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  169. package/out/zql/src/ivm/array-view.js +26 -1
  170. package/out/zql/src/ivm/array-view.js.map +1 -1
  171. package/out/zql/src/ivm/change-index-enum.d.ts +9 -0
  172. package/out/zql/src/ivm/change-index-enum.d.ts.map +1 -0
  173. package/out/zql/src/ivm/change-index.d.ts +5 -0
  174. package/out/zql/src/ivm/change-index.d.ts.map +1 -0
  175. package/out/zql/src/ivm/change-type-enum.d.ts +9 -0
  176. package/out/zql/src/ivm/change-type-enum.d.ts.map +1 -0
  177. package/out/zql/src/ivm/change-type.d.ts +5 -0
  178. package/out/zql/src/ivm/change-type.d.ts.map +1 -0
  179. package/out/zql/src/ivm/change.d.ts +20 -22
  180. package/out/zql/src/ivm/change.d.ts.map +1 -1
  181. package/out/zql/src/ivm/change.js +33 -0
  182. package/out/zql/src/ivm/change.js.map +1 -0
  183. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  184. package/out/zql/src/ivm/exists.js +27 -38
  185. package/out/zql/src/ivm/exists.js.map +1 -1
  186. package/out/zql/src/ivm/fan-in.d.ts +3 -2
  187. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  188. package/out/zql/src/ivm/fan-in.js.map +1 -1
  189. package/out/zql/src/ivm/fan-out.d.ts +1 -1
  190. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  191. package/out/zql/src/ivm/fan-out.js +1 -1
  192. package/out/zql/src/ivm/fan-out.js.map +1 -1
  193. package/out/zql/src/ivm/filter-operators.d.ts +3 -3
  194. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  195. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  196. package/out/zql/src/ivm/filter-push.d.ts.map +1 -1
  197. package/out/zql/src/ivm/filter-push.js +7 -7
  198. package/out/zql/src/ivm/filter-push.js.map +1 -1
  199. package/out/zql/src/ivm/filter.d.ts +1 -1
  200. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  201. package/out/zql/src/ivm/filter.js.map +1 -1
  202. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  203. package/out/zql/src/ivm/flipped-join.js +49 -58
  204. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  205. package/out/zql/src/ivm/join-utils.d.ts +2 -6
  206. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  207. package/out/zql/src/ivm/join-utils.js +25 -25
  208. package/out/zql/src/ivm/join-utils.js.map +1 -1
  209. package/out/zql/src/ivm/join.d.ts.map +1 -1
  210. package/out/zql/src/ivm/join.js +32 -51
  211. package/out/zql/src/ivm/join.js.map +1 -1
  212. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  213. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  214. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +5 -10
  215. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  216. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  217. package/out/zql/src/ivm/memory-source.js +51 -59
  218. package/out/zql/src/ivm/memory-source.js.map +1 -1
  219. package/out/zql/src/ivm/push-accumulated.d.ts +3 -2
  220. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  221. package/out/zql/src/ivm/push-accumulated.js +98 -122
  222. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  223. package/out/zql/src/ivm/skip.d.ts +1 -1
  224. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  225. package/out/zql/src/ivm/skip.js +2 -2
  226. package/out/zql/src/ivm/skip.js.map +1 -1
  227. package/out/zql/src/ivm/source-change-index-enum.d.ts +7 -0
  228. package/out/zql/src/ivm/source-change-index-enum.d.ts.map +1 -0
  229. package/out/zql/src/ivm/source-change-index.d.ts +5 -0
  230. package/out/zql/src/ivm/source-change-index.d.ts.map +1 -0
  231. package/out/zql/src/ivm/source.d.ts +11 -13
  232. package/out/zql/src/ivm/source.d.ts.map +1 -1
  233. package/out/zql/src/ivm/source.js +26 -0
  234. package/out/zql/src/ivm/source.js.map +1 -0
  235. package/out/zql/src/ivm/take.d.ts.map +1 -1
  236. package/out/zql/src/ivm/take.js +27 -50
  237. package/out/zql/src/ivm/take.js.map +1 -1
  238. package/out/zql/src/ivm/union-fan-in.d.ts +2 -1
  239. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  240. package/out/zql/src/ivm/union-fan-in.js +3 -3
  241. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  242. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  243. package/out/zql/src/ivm/union-fan-out.js +1 -1
  244. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  245. package/out/zql/src/planner/planner-debug.d.ts +2 -2
  246. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  247. package/out/zql/src/planner/planner-debug.js.map +1 -1
  248. package/out/zql/src/planner/planner-graph.d.ts +1 -1
  249. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  250. package/out/zql/src/planner/planner-graph.js.map +1 -1
  251. package/out/zqlite/src/internal/sql-inline.d.ts.map +1 -1
  252. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  253. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  254. package/out/zqlite/src/query-builder.js.map +1 -1
  255. package/out/zqlite/src/table-source.d.ts.map +1 -1
  256. package/out/zqlite/src/table-source.js +11 -11
  257. package/out/zqlite/src/table-source.js.map +1 -1
  258. package/package.json +94 -92
@@ -2,6 +2,7 @@ import { assert, unreachable } from "../../../shared/src/asserts.js";
2
2
  import { binarySearch } from "../../../shared/src/binary-search.js";
3
3
  import { emptyArray } from "../../../shared/src/sentinels.js";
4
4
  import { throwOutput } from "./operator.js";
5
+ import { makeAddChange, makeChildChange, makeEditChange, makeRemoveChange } from "./change.js";
5
6
  import { constraintsAreCompatible } from "./constraint.js";
6
7
  import { buildJoinConstraint, generateWithOverlayNoYield, isJoinMatch, rowEqualsForCompoundKey } from "./join-utils.js";
7
8
  //#region ../zql/src/ivm/flipped-join.ts
@@ -22,6 +23,7 @@ var FlippedJoin = class {
22
23
  #schema;
23
24
  #output = throwOutput;
24
25
  #inprogressChildChange;
26
+ #inprogressChildChangePosition;
25
27
  constructor({ parent, child, parentKey, childKey, relationshipName, hidden, system }) {
26
28
  assert(parent !== child, "Parent and child must be different operators");
27
29
  assert(parentKey.length === childKey.length, "The parentKey and childKey keys must have same length");
@@ -74,8 +76,8 @@ var FlippedJoin = class {
74
76
  }
75
77
  childNodes.push(node);
76
78
  }
77
- if (this.#inprogressChildChange?.change.type === "remove") {
78
- const removedNode = this.#inprogressChildChange.change.node;
79
+ if (this.#inprogressChildChange?.[0] === 1) {
80
+ const removedNode = this.#inprogressChildChange[1];
79
81
  const compare = this.#child.getSchema().compareRows;
80
82
  const insertPos = binarySearch(childNodes.length, (i) => compare(removedNode.row, childNodes[i].row));
81
83
  childNodes.splice(insertPos, 0, removedNode);
@@ -138,11 +140,11 @@ var FlippedJoin = class {
138
140
  nextParentNodes[minParentNodeChildIndex] = result.done ? null : result.value;
139
141
  }
140
142
  let overlaidRelatedChildNodes = relatedChildNodes;
141
- if (this.#inprogressChildChange && this.#inprogressChildChange.position && isJoinMatch(this.#inprogressChildChange.change.node.row, this.#childKey, minParentNode.row, this.#parentKey)) {
142
- const hasInprogressChildChangeBeenPushedForMinParentNode = this.#parent.getSchema().compareRows(minParentNode.row, this.#inprogressChildChange.position) <= 0;
143
- if (this.#inprogressChildChange.change.type === "remove") {
144
- if (hasInprogressChildChangeBeenPushedForMinParentNode) overlaidRelatedChildNodes = relatedChildNodes.filter((n) => n !== this.#inprogressChildChange?.change.node);
145
- } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) overlaidRelatedChildNodes = [...generateWithOverlayNoYield(relatedChildNodes, this.#inprogressChildChange.change, this.#child.getSchema())];
143
+ if (this.#inprogressChildChange && this.#inprogressChildChangePosition && isJoinMatch(this.#inprogressChildChange[1].row, this.#childKey, minParentNode.row, this.#parentKey)) {
144
+ const hasInprogressChildChangeBeenPushedForMinParentNode = this.#parent.getSchema().compareRows(minParentNode.row, this.#inprogressChildChangePosition) <= 0;
145
+ if (this.#inprogressChildChange[0] === 1) {
146
+ if (hasInprogressChildChangeBeenPushedForMinParentNode) overlaidRelatedChildNodes = relatedChildNodes.filter((n) => n !== this.#inprogressChildChange?.[1]);
147
+ } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) overlaidRelatedChildNodes = [...generateWithOverlayNoYield(relatedChildNodes, this.#inprogressChildChange, this.#child.getSchema())];
146
148
  }
147
149
  if (overlaidRelatedChildNodes.length > 0) yield {
148
150
  ...minParentNode,
@@ -165,37 +167,33 @@ var FlippedJoin = class {
165
167
  }
166
168
  }
167
169
  *#pushChild(change) {
168
- switch (change.type) {
169
- case "add":
170
- case "remove":
170
+ switch (change[0]) {
171
+ case 0:
172
+ case 1:
171
173
  yield* this.#pushChildChange(change);
172
174
  break;
173
- case "edit":
174
- assert(rowEqualsForCompoundKey(change.oldNode.row, change.node.row, this.#childKey), `Child edit must not change relationship.`);
175
+ case 2:
176
+ assert(rowEqualsForCompoundKey(change[2].row, change[1].row, this.#childKey), `Child edit must not change relationship.`);
175
177
  yield* this.#pushChildChange(change, true);
176
178
  break;
177
- case "child":
179
+ case 3:
178
180
  yield* this.#pushChildChange(change, true);
179
181
  break;
180
182
  }
181
183
  }
182
184
  *#pushChildChange(change, exists) {
183
- this.#inprogressChildChange = {
184
- change,
185
- position: void 0
186
- };
185
+ this.#inprogressChildChange = change;
186
+ this.#inprogressChildChangePosition = void 0;
187
187
  try {
188
- const constraint = buildJoinConstraint(change.node.row, this.#childKey, this.#parentKey);
188
+ const constraint = buildJoinConstraint(change[1].row, this.#childKey, this.#parentKey);
189
189
  const parentNodeStream = constraint ? this.#parent.fetch({ constraint }) : [];
190
190
  for (const parentNode of parentNodeStream) {
191
191
  if (parentNode === "yield") {
192
192
  yield "yield";
193
193
  continue;
194
194
  }
195
- this.#inprogressChildChange = {
196
- change,
197
- position: parentNode.row
198
- };
195
+ this.#inprogressChildChange = change;
196
+ this.#inprogressChildChangePosition = parentNode.row;
199
197
  const childNodeStream = () => {
200
198
  const constraint = buildJoinConstraint(parentNode.row, this.#parentKey, this.#childKey);
201
199
  return constraint ? this.#child.fetch({ constraint }) : [];
@@ -205,35 +203,31 @@ var FlippedJoin = class {
205
203
  yield "yield";
206
204
  continue;
207
205
  }
208
- if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
206
+ if (this.#child.getSchema().compareRows(childNode.row, change[1].row) !== 0) {
209
207
  exists = true;
210
208
  break;
211
209
  }
212
210
  }
213
- if (exists) yield* this.#output.push({
214
- type: "child",
215
- node: {
216
- ...parentNode,
217
- relationships: {
218
- ...parentNode.relationships,
219
- [this.#relationshipName]: childNodeStream
220
- }
221
- },
222
- child: {
223
- relationshipName: this.#relationshipName,
224
- change
211
+ if (exists) yield* this.#output.push(makeChildChange({
212
+ ...parentNode,
213
+ relationships: {
214
+ ...parentNode.relationships,
215
+ [this.#relationshipName]: childNodeStream
225
216
  }
226
- }, this);
227
- else yield* this.#output.push({
228
- ...change,
229
- node: {
217
+ }, {
218
+ relationshipName: this.#relationshipName,
219
+ change
220
+ }), this);
221
+ else {
222
+ const newNode = {
230
223
  ...parentNode,
231
224
  relationships: {
232
225
  ...parentNode.relationships,
233
- [this.#relationshipName]: () => [change.node]
226
+ [this.#relationshipName]: () => [change[1]]
234
227
  }
235
- }
236
- }, this);
228
+ };
229
+ yield* this.#output.push(change[0] === 0 ? makeAddChange(newNode) : makeRemoveChange(newNode), this);
230
+ }
237
231
  }
238
232
  } finally {
239
233
  this.#inprogressChildChange = void 0;
@@ -252,7 +246,7 @@ var FlippedJoin = class {
252
246
  }
253
247
  });
254
248
  let hasRelatedChild = false;
255
- for (const node of childNodeStream(change.node)()) if (node === "yield") {
249
+ for (const node of childNodeStream(change[1])()) if (node === "yield") {
256
250
  yield "yield";
257
251
  continue;
258
252
  } else {
@@ -260,22 +254,19 @@ var FlippedJoin = class {
260
254
  break;
261
255
  }
262
256
  if (!hasRelatedChild) return;
263
- switch (change.type) {
264
- case "add":
265
- case "remove":
266
- case "child":
267
- yield* this.#output.push({
268
- ...change,
269
- node: flip(change.node)
270
- }, this);
257
+ switch (change[0]) {
258
+ case 0:
259
+ yield* this.#output.push(makeAddChange(flip(change[1])), this);
260
+ break;
261
+ case 1:
262
+ yield* this.#output.push(makeRemoveChange(flip(change[1])), this);
263
+ break;
264
+ case 3:
265
+ yield* this.#output.push(makeChildChange(flip(change[1]), change[2]), this);
271
266
  break;
272
- case "edit":
273
- assert(rowEqualsForCompoundKey(change.oldNode.row, change.node.row, this.#parentKey), `Parent edit must not change relationship.`);
274
- yield* this.#output.push({
275
- type: "edit",
276
- oldNode: flip(change.oldNode),
277
- node: flip(change.node)
278
- }, this);
267
+ case 2:
268
+ assert(rowEqualsForCompoundKey(change[2].row, change[1].row, this.#parentKey), `Parent edit must not change relationship.`);
269
+ yield* this.#output.push(makeEditChange(flip(change[1]), flip(change[2])), this);
279
270
  break;
280
271
  default: unreachable(change);
281
272
  }
@@ -1 +1 @@
1
- {"version":3,"file":"flipped-join.js","names":["#parent","#child","#parentKey","#childKey","#relationshipName","#schema","#pushParent","#pushChild","#output","#inprogressChildChange","#pushChildChange"],"sources":["../../../../../zql/src/ivm/flipped-join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {binarySearch} from '../../../shared/src/binary-search.ts';\nimport {emptyArray} from '../../../shared/src/sentinels.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Value} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {constraintsAreCompatible} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n buildJoinConstraint,\n generateWithOverlayNoYield,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n // The nth key in childKey corresponds to the nth key in parentKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * An *inner* join which fetches nodes from its child input first and then\n * fetches their related nodes from its parent input. Output nodes are the\n * nodes from parent input (in parent input order), which have at least one\n * related child. These output nodes have a new relationship added to them,\n * which has the name `relationshipName`. The value of the relationship is a\n * stream of related nodes from the child input (in child input order).\n */\nexport class FlippedJoin implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: JoinChangeOverlay | undefined;\n\n constructor({\n parent,\n child,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#child.destroy();\n this.#parent.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n // TODO: When parentKey is the parent's primary key (or more\n // generally when the parent cardinality is expected to be small) a different\n // algorithm should be used: For each child node, fetch all parent nodes\n // eagerly and then sort using quicksort.\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n // Translate constraints for the parent on parts of the join key to\n // constraints for the child.\n const childConstraint: Record<string, Value> = {};\n let hasChildConstraint = false;\n if (req.constraint) {\n for (const [key, value] of Object.entries(req.constraint)) {\n const index = this.#parentKey.indexOf(key);\n if (index !== -1) {\n hasChildConstraint = true;\n childConstraint[this.#childKey[index]] = value;\n }\n }\n }\n\n const childNodes: Node[] = [];\n for (const node of this.#child.fetch(\n hasChildConstraint ? {constraint: childConstraint} : {},\n )) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n childNodes.push(node);\n }\n\n // FlippedJoin's split-push change overlay logic is largely\n // the same as Join's with the exception of remove. For remove,\n // the change is undone here, and then re-applied to parents with order\n // less than or equal to change.position below. This is necessary\n // because if the removed node was the last related child, the\n // related parents with position greater than change.position\n // (which should not yet have the node removed), would not even\n // be fetched here, and would be absent from the output all together.\n if (this.#inprogressChildChange?.change.type === 'remove') {\n const removedNode = this.#inprogressChildChange.change.node;\n const compare = this.#child.getSchema().compareRows;\n const insertPos = binarySearch(childNodes.length, i =>\n compare(removedNode.row, childNodes[i].row),\n );\n childNodes.splice(insertPos, 0, removedNode);\n }\n const parentIterators: Iterator<Node | 'yield'>[] = [];\n let threw = false;\n try {\n for (const childNode of childNodes) {\n // TODO: consider adding the ability to pass a set of\n // ids to fetch, and have them applied to sqlite using IN.\n const constraintFromChild = buildJoinConstraint(\n childNode.row,\n this.#childKey,\n this.#parentKey,\n );\n if (\n !constraintFromChild ||\n (req.constraint &&\n !constraintsAreCompatible(constraintFromChild, req.constraint))\n ) {\n parentIterators.push(emptyArray[Symbol.iterator]());\n } else {\n const stream = this.#parent.fetch({\n ...req,\n constraint: {\n ...req.constraint,\n ...constraintFromChild,\n },\n });\n const iterator = stream[Symbol.iterator]();\n parentIterators.push(iterator);\n }\n }\n const nextParentNodes: (Node | null)[] = [];\n for (let i = 0; i < parentIterators.length; i++) {\n const iter = parentIterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[i] = result.done ? null : (result.value as Node);\n }\n\n while (true) {\n let minParentNode = null;\n let minParentNodeChildIndexes: number[] = [];\n for (let i = 0; i < nextParentNodes.length; i++) {\n const parentNode = nextParentNodes[i];\n if (parentNode === null) {\n continue;\n }\n if (minParentNode === null) {\n minParentNode = parentNode;\n minParentNodeChildIndexes.push(i);\n } else {\n const compareResult =\n this.#schema.compareRows(parentNode.row, minParentNode.row) *\n (req.reverse ? -1 : 1);\n if (compareResult === 0) {\n minParentNodeChildIndexes.push(i);\n } else if (compareResult < 0) {\n minParentNode = parentNode;\n minParentNodeChildIndexes = [i];\n }\n }\n }\n if (minParentNode === null) {\n return;\n }\n const relatedChildNodes: Node[] = [];\n for (const minParentNodeChildIndex of minParentNodeChildIndexes) {\n relatedChildNodes.push(childNodes[minParentNodeChildIndex]);\n const iter = parentIterators[minParentNodeChildIndex];\n let result = iter.next();\n // yield yields when advancing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[minParentNodeChildIndex] = result.done\n ? null\n : (result.value as Node);\n }\n let overlaidRelatedChildNodes = relatedChildNodes;\n if (\n this.#inprogressChildChange &&\n this.#inprogressChildChange.position &&\n isJoinMatch(\n this.#inprogressChildChange.change.node.row,\n this.#childKey,\n minParentNode.row,\n this.#parentKey,\n )\n ) {\n const hasInprogressChildChangeBeenPushedForMinParentNode =\n this.#parent\n .getSchema()\n .compareRows(\n minParentNode.row,\n this.#inprogressChildChange.position,\n ) <= 0;\n if (this.#inprogressChildChange.change.type === 'remove') {\n if (hasInprogressChildChangeBeenPushedForMinParentNode) {\n // Remove form relatedChildNodes since the removed child\n // was inserted into childNodes above.\n overlaidRelatedChildNodes = relatedChildNodes.filter(\n n => n !== this.#inprogressChildChange?.change.node,\n );\n }\n } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {\n overlaidRelatedChildNodes = [\n ...generateWithOverlayNoYield(\n relatedChildNodes,\n this.#inprogressChildChange.change,\n this.#child.getSchema(),\n ),\n ];\n }\n }\n\n // yield node if after the overlay it still has relationship nodes\n if (overlaidRelatedChildNodes.length > 0) {\n yield {\n ...minParentNode,\n relationships: {\n ...minParentNode.relationships,\n [this.#relationshipName]: () => overlaidRelatedChildNodes,\n },\n };\n }\n }\n } catch (e) {\n threw = true;\n for (const iter of parentIterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of parentIterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n }\n\n *#pushChild(change: Change): Stream<'yield'> {\n switch (change.type) {\n case 'add':\n case 'remove':\n yield* this.#pushChildChange(change);\n break;\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#childKey,\n ),\n `Child edit must not change relationship.`,\n );\n yield* this.#pushChildChange(change, true);\n break;\n }\n case 'child':\n yield* this.#pushChildChange(change, true);\n break;\n }\n }\n\n *#pushChildChange(change: Change, exists?: boolean): Stream<'yield'> {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const constraint = buildJoinConstraint(\n change.node.row,\n this.#childKey,\n this.#parentKey,\n );\n const parentNodeStream = constraint\n ? this.#parent.fetch({constraint})\n : [];\n for (const parentNode of parentNodeStream) {\n if (parentNode === 'yield') {\n yield 'yield';\n continue;\n }\n this.#inprogressChildChange = {\n change,\n position: parentNode.row,\n };\n const childNodeStream = () => {\n const constraint = buildJoinConstraint(\n parentNode.row,\n this.#parentKey,\n this.#childKey,\n );\n return constraint ? this.#child.fetch({constraint}) : [];\n };\n if (!exists) {\n for (const childNode of childNodeStream()) {\n if (childNode === 'yield') {\n yield 'yield';\n continue;\n }\n if (\n this.#child\n .getSchema()\n .compareRows(childNode.row, change.node.row) !== 0\n ) {\n exists = true;\n break;\n }\n }\n }\n if (exists) {\n yield* this.#output.push(\n {\n type: 'child',\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: childNodeStream,\n },\n },\n child: {\n relationshipName: this.#relationshipName,\n change,\n },\n },\n this,\n );\n } else {\n yield* this.#output.push(\n {\n ...change,\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: () => [change.node],\n },\n },\n },\n this,\n );\n }\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n }\n\n *#pushParent(change: Change): Stream<'yield'> {\n const childNodeStream = (node: Node) => () => {\n const constraint = buildJoinConstraint(\n node.row,\n this.#parentKey,\n this.#childKey,\n );\n return constraint ? this.#child.fetch({constraint}) : [];\n };\n\n const flip = (node: Node) => ({\n ...node,\n relationships: {\n ...node.relationships,\n [this.#relationshipName]: childNodeStream(node),\n },\n });\n\n // If no related child don't push as this is an inner join.\n let hasRelatedChild = false;\n for (const node of childNodeStream(change.node)()) {\n if (node === 'yield') {\n yield 'yield';\n continue;\n } else {\n hasRelatedChild = true;\n break;\n }\n }\n if (!hasRelatedChild) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n yield* this.#output.push(\n {\n ...change,\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n yield* this.#output.push(\n {\n type: 'edit',\n oldNode: flip(change.oldNode),\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flipped-join.js","names":["#parent","#child","#parentKey","#childKey","#relationshipName","#schema","#pushParent","#pushChild","#output","#inprogressChildChange","#inprogressChildChangePosition","#pushChildChange"],"sources":["../../../../../zql/src/ivm/flipped-join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {binarySearch} from '../../../shared/src/binary-search.ts';\nimport {emptyArray} from '../../../shared/src/sentinels.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {\n makeAddChange,\n makeChildChange,\n makeEditChange,\n makeRemoveChange,\n type Change,\n} from './change.ts';\nimport {constraintsAreCompatible} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n buildJoinConstraint,\n generateWithOverlayNoYield,\n isJoinMatch,\n rowEqualsForCompoundKey,\n} from './join-utils.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n // The nth key in childKey corresponds to the nth key in parentKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * An *inner* join which fetches nodes from its child input first and then\n * fetches their related nodes from its parent input. Output nodes are the\n * nodes from parent input (in parent input order), which have at least one\n * related child. These output nodes have a new relationship added to them,\n * which has the name `relationshipName`. The value of the relationship is a\n * stream of related nodes from the child input (in child input order).\n */\nexport class FlippedJoin implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: Change | undefined;\n #inprogressChildChangePosition: Row | undefined;\n\n constructor({\n parent,\n child,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#child.destroy();\n this.#parent.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n // TODO: When parentKey is the parent's primary key (or more\n // generally when the parent cardinality is expected to be small) a different\n // algorithm should be used: For each child node, fetch all parent nodes\n // eagerly and then sort using quicksort.\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n // Translate constraints for the parent on parts of the join key to\n // constraints for the child.\n const childConstraint: Record<string, Value> = {};\n let hasChildConstraint = false;\n if (req.constraint) {\n for (const [key, value] of Object.entries(req.constraint)) {\n const index = this.#parentKey.indexOf(key);\n if (index !== -1) {\n hasChildConstraint = true;\n childConstraint[this.#childKey[index]] = value;\n }\n }\n }\n\n const childNodes: Node[] = [];\n for (const node of this.#child.fetch(\n hasChildConstraint ? {constraint: childConstraint} : {},\n )) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n childNodes.push(node);\n }\n\n // FlippedJoin's split-push change overlay logic is largely\n // the same as Join's with the exception of remove. For remove,\n // the change is undone here, and then re-applied to parents with order\n // less than or equal to change.position below. This is necessary\n // because if the removed node was the last related child, the\n // related parents with position greater than change.position\n // (which should not yet have the node removed), would not even\n // be fetched here, and would be absent from the output all together.\n if (this.#inprogressChildChange?.[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n const removedNode = this.#inprogressChildChange[ChangeIndex.NODE];\n const compare = this.#child.getSchema().compareRows;\n const insertPos = binarySearch(childNodes.length, i =>\n compare(removedNode.row, childNodes[i].row),\n );\n childNodes.splice(insertPos, 0, removedNode);\n }\n const parentIterators: Iterator<Node | 'yield'>[] = [];\n let threw = false;\n try {\n for (const childNode of childNodes) {\n // TODO: consider adding the ability to pass a set of\n // ids to fetch, and have them applied to sqlite using IN.\n const constraintFromChild = buildJoinConstraint(\n childNode.row,\n this.#childKey,\n this.#parentKey,\n );\n if (\n !constraintFromChild ||\n (req.constraint &&\n !constraintsAreCompatible(constraintFromChild, req.constraint))\n ) {\n parentIterators.push(emptyArray[Symbol.iterator]());\n } else {\n const stream = this.#parent.fetch({\n ...req,\n constraint: {\n ...req.constraint,\n ...constraintFromChild,\n },\n });\n const iterator = stream[Symbol.iterator]();\n parentIterators.push(iterator);\n }\n }\n const nextParentNodes: (Node | null)[] = [];\n for (let i = 0; i < parentIterators.length; i++) {\n const iter = parentIterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[i] = result.done ? null : (result.value as Node);\n }\n\n while (true) {\n let minParentNode = null;\n let minParentNodeChildIndexes: number[] = [];\n for (let i = 0; i < nextParentNodes.length; i++) {\n const parentNode = nextParentNodes[i];\n if (parentNode === null) {\n continue;\n }\n if (minParentNode === null) {\n minParentNode = parentNode;\n minParentNodeChildIndexes.push(i);\n } else {\n const compareResult =\n this.#schema.compareRows(parentNode.row, minParentNode.row) *\n (req.reverse ? -1 : 1);\n if (compareResult === 0) {\n minParentNodeChildIndexes.push(i);\n } else if (compareResult < 0) {\n minParentNode = parentNode;\n minParentNodeChildIndexes = [i];\n }\n }\n }\n if (minParentNode === null) {\n return;\n }\n const relatedChildNodes: Node[] = [];\n for (const minParentNodeChildIndex of minParentNodeChildIndexes) {\n relatedChildNodes.push(childNodes[minParentNodeChildIndex]);\n const iter = parentIterators[minParentNodeChildIndex];\n let result = iter.next();\n // yield yields when advancing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[minParentNodeChildIndex] = result.done\n ? null\n : (result.value as Node);\n }\n let overlaidRelatedChildNodes = relatedChildNodes;\n if (\n this.#inprogressChildChange &&\n this.#inprogressChildChangePosition &&\n isJoinMatch(\n this.#inprogressChildChange[ChangeIndex.NODE].row,\n this.#childKey,\n minParentNode.row,\n this.#parentKey,\n )\n ) {\n const hasInprogressChildChangeBeenPushedForMinParentNode =\n this.#parent\n .getSchema()\n .compareRows(\n minParentNode.row,\n this.#inprogressChildChangePosition,\n ) <= 0;\n if (\n this.#inprogressChildChange[ChangeIndex.TYPE] === ChangeType.REMOVE\n ) {\n if (hasInprogressChildChangeBeenPushedForMinParentNode) {\n // Remove form relatedChildNodes since the removed child\n // was inserted into childNodes above.\n overlaidRelatedChildNodes = relatedChildNodes.filter(\n n => n !== this.#inprogressChildChange?.[ChangeIndex.NODE],\n );\n }\n } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {\n overlaidRelatedChildNodes = [\n ...generateWithOverlayNoYield(\n relatedChildNodes,\n this.#inprogressChildChange,\n this.#child.getSchema(),\n ),\n ];\n }\n }\n\n // yield node if after the overlay it still has relationship nodes\n if (overlaidRelatedChildNodes.length > 0) {\n yield {\n ...minParentNode,\n relationships: {\n ...minParentNode.relationships,\n [this.#relationshipName]: () => overlaidRelatedChildNodes,\n },\n };\n }\n }\n } catch (e) {\n threw = true;\n for (const iter of parentIterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of parentIterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n }\n\n *#pushChild(change: Change): Stream<'yield'> {\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n case ChangeType.REMOVE:\n yield* this.#pushChildChange(change);\n break;\n case ChangeType.EDIT: {\n assert(\n rowEqualsForCompoundKey(\n change[ChangeIndex.OLD_NODE].row,\n change[ChangeIndex.NODE].row,\n this.#childKey,\n ),\n `Child edit must not change relationship.`,\n );\n yield* this.#pushChildChange(change, true);\n break;\n }\n case ChangeType.CHILD:\n yield* this.#pushChildChange(change, true);\n break;\n }\n }\n\n *#pushChildChange(change: Change, exists?: boolean): Stream<'yield'> {\n this.#inprogressChildChange = change;\n this.#inprogressChildChangePosition = undefined;\n try {\n const constraint = buildJoinConstraint(\n change[ChangeIndex.NODE].row,\n this.#childKey,\n this.#parentKey,\n );\n const parentNodeStream = constraint\n ? this.#parent.fetch({constraint})\n : [];\n for (const parentNode of parentNodeStream) {\n if (parentNode === 'yield') {\n yield 'yield';\n continue;\n }\n this.#inprogressChildChange = change;\n this.#inprogressChildChangePosition = parentNode.row;\n const childNodeStream = () => {\n const constraint = buildJoinConstraint(\n parentNode.row,\n this.#parentKey,\n this.#childKey,\n );\n return constraint ? this.#child.fetch({constraint}) : [];\n };\n if (!exists) {\n for (const childNode of childNodeStream()) {\n if (childNode === 'yield') {\n yield 'yield';\n continue;\n }\n if (\n this.#child\n .getSchema()\n .compareRows(childNode.row, change[ChangeIndex.NODE].row) !== 0\n ) {\n exists = true;\n break;\n }\n }\n }\n if (exists) {\n yield* this.#output.push(\n makeChildChange(\n {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: childNodeStream,\n },\n },\n {\n relationshipName: this.#relationshipName,\n change,\n },\n ),\n this,\n );\n } else {\n const newNode = {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: () => [change[ChangeIndex.NODE]],\n },\n };\n yield* this.#output.push(\n change[ChangeIndex.TYPE] === ChangeType.ADD\n ? makeAddChange(newNode)\n : makeRemoveChange(newNode),\n this,\n );\n }\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n }\n\n *#pushParent(change: Change): Stream<'yield'> {\n const childNodeStream = (node: Node) => () => {\n const constraint = buildJoinConstraint(\n node.row,\n this.#parentKey,\n this.#childKey,\n );\n return constraint ? this.#child.fetch({constraint}) : [];\n };\n\n const flip = (node: Node) => ({\n ...node,\n relationships: {\n ...node.relationships,\n [this.#relationshipName]: childNodeStream(node),\n },\n });\n\n // If no related child don't push as this is an inner join.\n let hasRelatedChild = false;\n for (const node of childNodeStream(change[ChangeIndex.NODE])()) {\n if (node === 'yield') {\n yield 'yield';\n continue;\n } else {\n hasRelatedChild = true;\n break;\n }\n }\n if (!hasRelatedChild) {\n return;\n }\n\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n yield* this.#output.push(\n makeAddChange(flip(change[ChangeIndex.NODE])),\n this,\n );\n break;\n case ChangeType.REMOVE:\n yield* this.#output.push(\n makeRemoveChange(flip(change[ChangeIndex.NODE])),\n this,\n );\n break;\n case ChangeType.CHILD: {\n yield* this.#output.push(\n makeChildChange(\n flip(change[ChangeIndex.NODE]),\n change[ChangeIndex.CHILD_DATA],\n ),\n this,\n );\n break;\n }\n case ChangeType.EDIT: {\n assert(\n rowEqualsForCompoundKey(\n change[ChangeIndex.OLD_NODE].row,\n change[ChangeIndex.NODE].row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n yield* this.#output.push(\n makeEditChange(\n flip(change[ChangeIndex.NODE]),\n flip(change[ChangeIndex.OLD_NODE]),\n ),\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmDA,IAAa,cAAb,MAA0C;CACxC;CACA;CACA;CACA;CACA;CACA;CAEA,UAAkB;CAElB;CACA;CAEA,YAAY,EACV,QACA,OACA,WACA,UACA,kBACA,QACA,UACO;AACP,SAAO,WAAW,OAAO,+CAA+C;AACxE,SACE,UAAU,WAAW,SAAS,QAC9B,wDACD;AACD,QAAA,SAAe;AACf,QAAA,QAAc;AACd,QAAA,YAAkB;AAClB,QAAA,WAAiB;AACjB,QAAA,mBAAyB;EAEzB,MAAM,eAAe,OAAO,WAAW;EACvC,MAAM,cAAc,MAAM,WAAW;AACrC,QAAA,SAAe;GACb,GAAG;GACH,eAAe;IACb,GAAG,aAAa;KACf,mBAAmB;KAClB,GAAG;KACH,UAAU;KACV;KACD;IACF;GACF;AAED,SAAO,UAAU,EACf,OAAO,WAAmB,MAAA,WAAiB,OAAO,EACnD,CAAC;AACF,QAAM,UAAU,EACd,OAAO,WAAmB,MAAA,UAAgB,OAAO,EAClD,CAAC;;CAGJ,UAAgB;AACd,QAAA,MAAY,SAAS;AACrB,QAAA,OAAa,SAAS;;CAGxB,UAAU,QAAsB;AAC9B,QAAA,SAAe;;CAGjB,YAA0B;AACxB,SAAO,MAAA;;CAOT,CAAC,MAAM,KAA2C;EAGhD,MAAM,kBAAyC,EAAE;EACjD,IAAI,qBAAqB;AACzB,MAAI,IAAI,WACN,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,WAAW,EAAE;GACzD,MAAM,QAAQ,MAAA,UAAgB,QAAQ,IAAI;AAC1C,OAAI,UAAU,IAAI;AAChB,yBAAqB;AACrB,oBAAgB,MAAA,SAAe,UAAU;;;EAK/C,MAAM,aAAqB,EAAE;AAC7B,OAAK,MAAM,QAAQ,MAAA,MAAY,MAC7B,qBAAqB,EAAC,YAAY,iBAAgB,GAAG,EAAE,CACxD,EAAE;AACD,OAAI,SAAS,SAAS;AACpB,UAAM;AACN;;AAEF,cAAW,KAAK,KAAK;;AAWvB,MAAI,MAAA,wBAA8B,OAAsB,GAAmB;GACzE,MAAM,cAAc,MAAA,sBAA4B;GAChD,MAAM,UAAU,MAAA,MAAY,WAAW,CAAC;GACxC,MAAM,YAAY,aAAa,WAAW,SAAQ,MAChD,QAAQ,YAAY,KAAK,WAAW,GAAG,IAAI,CAC5C;AACD,cAAW,OAAO,WAAW,GAAG,YAAY;;EAE9C,MAAM,kBAA8C,EAAE;EACtD,IAAI,QAAQ;AACZ,MAAI;AACF,QAAK,MAAM,aAAa,YAAY;IAGlC,MAAM,sBAAsB,oBAC1B,UAAU,KACV,MAAA,UACA,MAAA,UACD;AACD,QACE,CAAC,uBACA,IAAI,cACH,CAAC,yBAAyB,qBAAqB,IAAI,WAAW,CAEhE,iBAAgB,KAAK,WAAW,OAAO,WAAW,CAAC;SAC9C;KAQL,MAAM,WAPS,MAAA,OAAa,MAAM;MAChC,GAAG;MACH,YAAY;OACV,GAAG,IAAI;OACP,GAAG;OACJ;MACF,CAAC,CACsB,OAAO,WAAW;AAC1C,qBAAgB,KAAK,SAAS;;;GAGlC,MAAM,kBAAmC,EAAE;AAC3C,QAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;IAC/C,MAAM,OAAO,gBAAgB;IAC7B,IAAI,SAAS,KAAK,MAAM;AAExB,WAAO,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS;AAC/C,WAAM,OAAO;AACb,cAAS,KAAK,MAAM;;AAEtB,oBAAgB,KAAK,OAAO,OAAO,OAAQ,OAAO;;AAGpD,UAAO,MAAM;IACX,IAAI,gBAAgB;IACpB,IAAI,4BAAsC,EAAE;AAC5C,SAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;KAC/C,MAAM,aAAa,gBAAgB;AACnC,SAAI,eAAe,KACjB;AAEF,SAAI,kBAAkB,MAAM;AAC1B,sBAAgB;AAChB,gCAA0B,KAAK,EAAE;YAC5B;MACL,MAAM,gBACJ,MAAA,OAAa,YAAY,WAAW,KAAK,cAAc,IAAI,IAC1D,IAAI,UAAU,KAAK;AACtB,UAAI,kBAAkB,EACpB,2BAA0B,KAAK,EAAE;eACxB,gBAAgB,GAAG;AAC5B,uBAAgB;AAChB,mCAA4B,CAAC,EAAE;;;;AAIrC,QAAI,kBAAkB,KACpB;IAEF,MAAM,oBAA4B,EAAE;AACpC,SAAK,MAAM,2BAA2B,2BAA2B;AAC/D,uBAAkB,KAAK,WAAW,yBAAyB;KAC3D,MAAM,OAAO,gBAAgB;KAC7B,IAAI,SAAS,KAAK,MAAM;AAExB,YAAO,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS;AAC/C,YAAM,OAAO;AACb,eAAS,KAAK,MAAM;;AAEtB,qBAAgB,2BAA2B,OAAO,OAC9C,OACC,OAAO;;IAEd,IAAI,4BAA4B;AAChC,QACE,MAAA,yBACA,MAAA,iCACA,YACE,MAAA,sBAA4B,GAAkB,KAC9C,MAAA,UACA,cAAc,KACd,MAAA,UACD,EACD;KACA,MAAM,qDACJ,MAAA,OACG,WAAW,CACX,YACC,cAAc,KACd,MAAA,8BACD,IAAI;AACT,SACE,MAAA,sBAA4B,OAAsB;UAE9C,mDAGF,6BAA4B,kBAAkB,QAC5C,MAAK,MAAM,MAAA,wBAA8B,GAC1C;gBAEM,CAAC,mDACV,6BAA4B,CAC1B,GAAG,2BACD,mBACA,MAAA,uBACA,MAAA,MAAY,WAAW,CACxB,CACF;;AAKL,QAAI,0BAA0B,SAAS,EACrC,OAAM;KACJ,GAAG;KACH,eAAe;MACb,GAAG,cAAc;OAChB,MAAA,yBAA+B;MACjC;KACF;;WAGE,GAAG;AACV,WAAQ;AACR,QAAK,MAAM,QAAQ,gBACjB,KAAI;AACF,SAAK,QAAQ,EAAE;YACR,eAAe;AAK1B,SAAM;YACE;AACR,OAAI,CAAC,MACH,MAAK,MAAM,QAAQ,gBACjB,KAAI;AACF,SAAK,UAAU;YACR,eAAe;;;CAShC,EAAA,UAAY,QAAiC;AAC3C,UAAQ,OAAO,IAAf;GACE,KAAK;GACL,KAAK;AACH,WAAO,MAAA,gBAAsB,OAAO;AACpC;GACF,KAAK;AACH,WACE,wBACE,OAAO,GAAsB,KAC7B,OAAO,GAAkB,KACzB,MAAA,SACD,EACD,2CACD;AACD,WAAO,MAAA,gBAAsB,QAAQ,KAAK;AAC1C;GAEF,KAAK;AACH,WAAO,MAAA,gBAAsB,QAAQ,KAAK;AAC1C;;;CAIN,EAAA,gBAAkB,QAAgB,QAAmC;AACnE,QAAA,wBAA8B;AAC9B,QAAA,gCAAsC,KAAA;AACtC,MAAI;GACF,MAAM,aAAa,oBACjB,OAAO,GAAkB,KACzB,MAAA,UACA,MAAA,UACD;GACD,MAAM,mBAAmB,aACrB,MAAA,OAAa,MAAM,EAAC,YAAW,CAAC,GAChC,EAAE;AACN,QAAK,MAAM,cAAc,kBAAkB;AACzC,QAAI,eAAe,SAAS;AAC1B,WAAM;AACN;;AAEF,UAAA,wBAA8B;AAC9B,UAAA,gCAAsC,WAAW;IACjD,MAAM,wBAAwB;KAC5B,MAAM,aAAa,oBACjB,WAAW,KACX,MAAA,WACA,MAAA,SACD;AACD,YAAO,aAAa,MAAA,MAAY,MAAM,EAAC,YAAW,CAAC,GAAG,EAAE;;AAE1D,QAAI,CAAC,OACH,MAAK,MAAM,aAAa,iBAAiB,EAAE;AACzC,SAAI,cAAc,SAAS;AACzB,YAAM;AACN;;AAEF,SACE,MAAA,MACG,WAAW,CACX,YAAY,UAAU,KAAK,OAAO,GAAkB,IAAI,KAAK,GAChE;AACA,eAAS;AACT;;;AAIN,QAAI,OACF,QAAO,MAAA,OAAa,KAClB,gBACE;KACE,GAAG;KACH,eAAe;MACb,GAAG,WAAW;OACb,MAAA,mBAAyB;MAC3B;KACF,EACD;KACE,kBAAkB,MAAA;KAClB;KACD,CACF,EACD,KACD;SACI;KACL,MAAM,UAAU;MACd,GAAG;MACH,eAAe;OACb,GAAG,WAAW;QACb,MAAA,yBAA+B,CAAC,OAAO,GAAkB;OAC3D;MACF;AACD,YAAO,MAAA,OAAa,KAClB,OAAO,OAAsB,IACzB,cAAc,QAAQ,GACtB,iBAAiB,QAAQ,EAC7B,KACD;;;YAGG;AACR,SAAA,wBAA8B,KAAA;;;CAIlC,EAAA,WAAa,QAAiC;EAC5C,MAAM,mBAAmB,eAAqB;GAC5C,MAAM,aAAa,oBACjB,KAAK,KACL,MAAA,WACA,MAAA,SACD;AACD,UAAO,aAAa,MAAA,MAAY,MAAM,EAAC,YAAW,CAAC,GAAG,EAAE;;EAG1D,MAAM,QAAQ,UAAgB;GAC5B,GAAG;GACH,eAAe;IACb,GAAG,KAAK;KACP,MAAA,mBAAyB,gBAAgB,KAAK;IAChD;GACF;EAGD,IAAI,kBAAkB;AACtB,OAAK,MAAM,QAAQ,gBAAgB,OAAO,GAAkB,EAAE,CAC5D,KAAI,SAAS,SAAS;AACpB,SAAM;AACN;SACK;AACL,qBAAkB;AAClB;;AAGJ,MAAI,CAAC,gBACH;AAGF,UAAQ,OAAO,IAAf;GACE,KAAK;AACH,WAAO,MAAA,OAAa,KAClB,cAAc,KAAK,OAAO,GAAkB,CAAC,EAC7C,KACD;AACD;GACF,KAAK;AACH,WAAO,MAAA,OAAa,KAClB,iBAAiB,KAAK,OAAO,GAAkB,CAAC,EAChD,KACD;AACD;GACF,KAAK;AACH,WAAO,MAAA,OAAa,KAClB,gBACE,KAAK,OAAO,GAAkB,EAC9B,OAAO,GACR,EACD,KACD;AACD;GAEF,KAAK;AACH,WACE,wBACE,OAAO,GAAsB,KAC7B,OAAO,GAAkB,KACzB,MAAA,UACD,EACD,4CACD;AACD,WAAO,MAAA,OAAa,KAClB,eACE,KAAK,OAAO,GAAkB,EAC9B,KAAK,OAAO,GAAsB,CACnC,EACD,KACD;AACD;GAEF,QACE,aAAY,OAAO"}
@@ -1,13 +1,9 @@
1
+ import type { CompoundKey } from '../../../zero-protocol/src/ast.ts';
1
2
  import type { Row, Value } from '../../../zero-protocol/src/data.ts';
2
3
  import type { Change } from './change.ts';
4
+ import { type Node } from './data.ts';
3
5
  import type { SourceSchema } from './schema.ts';
4
6
  import type { Stream } from './stream.ts';
5
- import { type Node } from './data.ts';
6
- import type { CompoundKey } from '../../../zero-protocol/src/ast.ts';
7
- export type JoinChangeOverlay = {
8
- change: Change;
9
- position: Row | undefined;
10
- };
11
7
  export declare function generateWithOverlayNoYield(stream: Stream<Node>, overlay: Change, schema: SourceSchema): Stream<Node>;
12
8
  export declare function generateWithOverlay(stream: Stream<Node | 'yield'>, overlay: Change, schema: SourceSchema): Stream<Node | 'yield'>;
13
9
  export declare function generateWithOverlayNoYieldUnordered(stream: Stream<Node>, overlay: Change, schema: SourceSchema): Stream<Node>;
@@ -1 +1 @@
1
- {"version":3,"file":"join-utils.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAA6B,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAEhE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mCAAmC,CAAC;AAEnE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,GAAG,SAAS,CAAC;CAC3B,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,CAAC,CAEd;AAED,wBAAiB,mBAAmB,CAClC,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CA6FxB;AAED,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,CAAC,CAEd;AAED,wBAAiB,4BAA4B,CAC3C,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAmDxB;AAED,wBAAgB,uBAAuB,CACrC,CAAC,EAAE,GAAG,EACN,CAAC,EAAE,GAAG,EACN,GAAG,EAAE,WAAW,GACf,OAAO,CAOT;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,GAAG,EACX,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,WAAW,WAQtB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,WAAW,EACtB,SAAS,EAAE,WAAW,GACrB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,SAAS,CAUnC"}
1
+ {"version":3,"file":"join-utils.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AAGnE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAA6B,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,CAAC,CAEd;AAED,wBAAiB,mBAAmB,CAClC,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAqGxB;AAED,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,CAAC,CAEd;AAED,wBAAiB,4BAA4B,CAC3C,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAkExB;AAED,wBAAgB,uBAAuB,CACrC,CAAC,EAAE,GAAG,EACN,CAAC,EAAE,GAAG,EACN,GAAG,EAAE,WAAW,GACf,OAAO,CAOT;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,GAAG,EACX,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,WAAW,WAQtB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,WAAW,EACtB,SAAS,EAAE,WAAW,GACrB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,SAAS,CAUnC"}
@@ -14,39 +14,39 @@ function* generateWithOverlay(stream, overlay, schema) {
14
14
  continue;
15
15
  }
16
16
  let yieldNode = true;
17
- if (!applied) switch (overlay.type) {
18
- case "add":
19
- if (schema.compareRows(overlay.node.row, node.row) === 0) {
17
+ if (!applied) switch (overlay[0]) {
18
+ case 0:
19
+ if (schema.compareRows(overlay[1].row, node.row) === 0) {
20
20
  applied = true;
21
21
  yieldNode = false;
22
22
  }
23
23
  break;
24
- case "remove":
25
- if (schema.compareRows(overlay.node.row, node.row) < 0) {
24
+ case 1:
25
+ if (schema.compareRows(overlay[1].row, node.row) < 0) {
26
26
  applied = true;
27
- yield overlay.node;
27
+ yield overlay[1];
28
28
  }
29
29
  break;
30
- case "edit":
31
- if (!editOldApplied && schema.compareRows(overlay.oldNode.row, node.row) < 0) {
30
+ case 2:
31
+ if (!editOldApplied && schema.compareRows(overlay[2].row, node.row) < 0) {
32
32
  editOldApplied = true;
33
33
  if (editNewApplied) applied = true;
34
- yield overlay.oldNode;
34
+ yield overlay[2];
35
35
  }
36
- if (!editNewApplied && schema.compareRows(overlay.node.row, node.row) === 0) {
36
+ if (!editNewApplied && schema.compareRows(overlay[1].row, node.row) === 0) {
37
37
  editNewApplied = true;
38
38
  if (editOldApplied) applied = true;
39
39
  yieldNode = false;
40
40
  }
41
41
  break;
42
- case "child":
43
- if (schema.compareRows(overlay.node.row, node.row) === 0) {
42
+ case 3:
43
+ if (schema.compareRows(overlay[1].row, node.row) === 0) {
44
44
  applied = true;
45
45
  yield {
46
46
  row: node.row,
47
47
  relationships: {
48
48
  ...node.relationships,
49
- [overlay.child.relationshipName]: () => generateWithOverlay(node.relationships[overlay.child.relationshipName](), overlay.child.change, schema.relationships[overlay.child.relationshipName])
49
+ [overlay[2].relationshipName]: () => generateWithOverlay(node.relationships[overlay[2].relationshipName](), overlay[2].change, schema.relationships[overlay[2].relationshipName])
50
50
  }
51
51
  };
52
52
  yieldNode = false;
@@ -56,21 +56,21 @@ function* generateWithOverlay(stream, overlay, schema) {
56
56
  if (yieldNode) yield node;
57
57
  }
58
58
  if (!applied) {
59
- if (overlay.type === "remove") {
59
+ if (overlay[0] === 1) {
60
60
  applied = true;
61
- yield overlay.node;
62
- } else if (overlay.type === "edit") {
61
+ yield overlay[1];
62
+ } else if (overlay[0] === 2) {
63
63
  assert(editNewApplied, "edit overlay: new node must be applied before old node");
64
64
  editOldApplied = true;
65
65
  applied = true;
66
- yield overlay.oldNode;
66
+ yield overlay[2];
67
67
  }
68
68
  }
69
69
  assert(applied, "overlayGenerator: overlay was never applied to any fetched node");
70
70
  }
71
71
  function* generateWithOverlayUnordered(stream, overlay, schema) {
72
- if (overlay.type === "remove") yield overlay.node;
73
- else if (overlay.type === "edit") yield overlay.oldNode;
72
+ if (overlay[0] === 1) yield overlay[1];
73
+ else if (overlay[0] === 2) yield overlay[2];
74
74
  let suppressed = false;
75
75
  for (const node of stream) {
76
76
  if (node === "yield") {
@@ -78,20 +78,20 @@ function* generateWithOverlayUnordered(stream, overlay, schema) {
78
78
  continue;
79
79
  }
80
80
  if (!suppressed) {
81
- if (overlay.type === "add" || overlay.type === "edit") {
82
- if (rowEqualsForCompoundKey(overlay.node.row, node.row, schema.primaryKey)) {
81
+ if (overlay[0] === 0 || overlay[0] === 2) {
82
+ if (rowEqualsForCompoundKey(overlay[1].row, node.row, schema.primaryKey)) {
83
83
  suppressed = true;
84
84
  continue;
85
85
  }
86
86
  }
87
- if (overlay.type === "child") {
88
- if (rowEqualsForCompoundKey(overlay.node.row, node.row, schema.primaryKey)) {
87
+ if (overlay[0] === 3) {
88
+ if (rowEqualsForCompoundKey(overlay[1].row, node.row, schema.primaryKey)) {
89
89
  suppressed = true;
90
90
  yield {
91
91
  row: node.row,
92
92
  relationships: {
93
93
  ...node.relationships,
94
- [overlay.child.relationshipName]: () => generateWithOverlay(node.relationships[overlay.child.relationshipName](), overlay.child.change, schema.relationships[overlay.child.relationshipName])
94
+ [overlay[2].relationshipName]: () => generateWithOverlay(node.relationships[overlay[2].relationshipName](), overlay[2].change, schema.relationships[overlay[2].relationshipName])
95
95
  }
96
96
  };
97
97
  continue;
@@ -100,7 +100,7 @@ function* generateWithOverlayUnordered(stream, overlay, schema) {
100
100
  }
101
101
  yield node;
102
102
  }
103
- assert(suppressed || overlay.type === "remove", "overlayGenerator: overlay was never applied to any fetched node");
103
+ assert(suppressed || overlay[0] === 1, "overlayGenerator: overlay was never applied to any fetched node");
104
104
  }
105
105
  function rowEqualsForCompoundKey(a, b, key) {
106
106
  for (let i = 0; i < key.length; i++) if (compareValues(a[key[i]], b[key[i]]) !== 0) return false;
@@ -1 +1 @@
1
- {"version":3,"file":"join-utils.js","names":[],"sources":["../../../../../zql/src/ivm/join-utils.ts"],"sourcesContent":["import type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\nimport {compareValues, valuesEqual, type Node} from './data.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\n\nexport type JoinChangeOverlay = {\n change: Change;\n position: Row | undefined;\n};\n\nexport function generateWithOverlayNoYield(\n stream: Stream<Node>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node> {\n return generateWithOverlay(stream, overlay, schema) as Stream<Node>;\n}\n\nexport function* generateWithOverlay(\n stream: Stream<Node | 'yield'>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node | 'yield'> {\n let applied = false;\n let editOldApplied = false;\n let editNewApplied = false;\n for (const node of stream) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n let yieldNode = true;\n if (!applied) {\n switch (overlay.type) {\n case 'add': {\n if (schema.compareRows(overlay.node.row, node.row) === 0) {\n applied = true;\n yieldNode = false;\n }\n break;\n }\n case 'remove': {\n if (schema.compareRows(overlay.node.row, node.row) < 0) {\n applied = true;\n yield overlay.node;\n }\n break;\n }\n case 'edit': {\n if (\n !editOldApplied &&\n schema.compareRows(overlay.oldNode.row, node.row) < 0\n ) {\n editOldApplied = true;\n if (editNewApplied) {\n applied = true;\n }\n yield overlay.oldNode;\n }\n if (\n !editNewApplied &&\n schema.compareRows(overlay.node.row, node.row) === 0\n ) {\n editNewApplied = true;\n if (editOldApplied) {\n applied = true;\n }\n yieldNode = false;\n }\n break;\n }\n case 'child': {\n if (schema.compareRows(overlay.node.row, node.row) === 0) {\n applied = true;\n yield {\n row: node.row,\n relationships: {\n ...node.relationships,\n [overlay.child.relationshipName]: () =>\n generateWithOverlay(\n node.relationships[overlay.child.relationshipName](),\n overlay.child.change,\n schema.relationships[overlay.child.relationshipName],\n ),\n },\n };\n yieldNode = false;\n }\n break;\n }\n }\n }\n if (yieldNode) {\n yield node;\n }\n }\n if (!applied) {\n if (overlay.type === 'remove') {\n applied = true;\n yield overlay.node;\n } else if (overlay.type === 'edit') {\n assert(\n editNewApplied,\n 'edit overlay: new node must be applied before old node',\n );\n editOldApplied = true;\n applied = true;\n yield overlay.oldNode;\n }\n }\n\n assert(\n applied,\n 'overlayGenerator: overlay was never applied to any fetched node',\n );\n}\n\nexport function generateWithOverlayNoYieldUnordered(\n stream: Stream<Node>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node> {\n return generateWithOverlayUnordered(stream, overlay, schema) as Stream<Node>;\n}\n\nexport function* generateWithOverlayUnordered(\n stream: Stream<Node | 'yield'>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node | 'yield'> {\n // Eager inject\n if (overlay.type === 'remove') {\n yield overlay.node;\n } else if (overlay.type === 'edit') {\n yield overlay.oldNode;\n }\n\n // Stream with inline suppress\n let suppressed = false;\n for (const node of stream) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (!suppressed) {\n if (overlay.type === 'add' || overlay.type === 'edit') {\n if (\n rowEqualsForCompoundKey(overlay.node.row, node.row, schema.primaryKey)\n ) {\n suppressed = true;\n continue;\n }\n }\n if (overlay.type === 'child') {\n if (\n rowEqualsForCompoundKey(overlay.node.row, node.row, schema.primaryKey)\n ) {\n suppressed = true;\n yield {\n row: node.row,\n relationships: {\n ...node.relationships,\n [overlay.child.relationshipName]: () =>\n generateWithOverlay(\n node.relationships[overlay.child.relationshipName](),\n overlay.child.change,\n schema.relationships[overlay.child.relationshipName],\n ),\n },\n };\n continue;\n }\n }\n }\n yield node;\n }\n assert(\n suppressed || overlay.type === 'remove',\n 'overlayGenerator: overlay was never applied to any fetched node',\n );\n}\n\nexport function rowEqualsForCompoundKey(\n a: Row,\n b: Row,\n key: CompoundKey,\n): boolean {\n for (let i = 0; i < key.length; i++) {\n if (compareValues(a[key[i]], b[key[i]]) !== 0) {\n return false;\n }\n }\n return true;\n}\n\nexport function isJoinMatch(\n parent: Row,\n parentKey: CompoundKey,\n child: Row,\n childKey: CompoundKey,\n) {\n for (let i = 0; i < parentKey.length; i++) {\n if (!valuesEqual(parent[parentKey[i]], child[childKey[i]])) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Builds a constraint object by mapping values from `sourceRow` using `sourceKey`\n * to keys specified by `targetKey`. Returns `undefined` if any source value is `null`,\n * since null foreign keys cannot match any rows.\n */\nexport function buildJoinConstraint(\n sourceRow: Row,\n sourceKey: CompoundKey,\n targetKey: CompoundKey,\n): Record<string, Value> | undefined {\n const constraint: Record<string, Value> = {};\n for (let i = 0; i < targetKey.length; i++) {\n const value = sourceRow[sourceKey[i]];\n if (value === null) {\n return undefined;\n }\n constraint[targetKey[i]] = value;\n }\n return constraint;\n}\n"],"mappings":";;;AAaA,SAAgB,2BACd,QACA,SACA,QACc;AACd,QAAO,oBAAoB,QAAQ,SAAS,OAAO;;AAGrD,UAAiB,oBACf,QACA,SACA,QACwB;CACxB,IAAI,UAAU;CACd,IAAI,iBAAiB;CACrB,IAAI,iBAAiB;AACrB,MAAK,MAAM,QAAQ,QAAQ;AACzB,MAAI,SAAS,SAAS;AACpB,SAAM;AACN;;EAEF,IAAI,YAAY;AAChB,MAAI,CAAC,QACH,SAAQ,QAAQ,MAAhB;GACE,KAAK;AACH,QAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,GAAG;AACxD,eAAU;AACV,iBAAY;;AAEd;GAEF,KAAK;AACH,QAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,IAAI,GAAG,GAAG;AACtD,eAAU;AACV,WAAM,QAAQ;;AAEhB;GAEF,KAAK;AACH,QACE,CAAC,kBACD,OAAO,YAAY,QAAQ,QAAQ,KAAK,KAAK,IAAI,GAAG,GACpD;AACA,sBAAiB;AACjB,SAAI,eACF,WAAU;AAEZ,WAAM,QAAQ;;AAEhB,QACE,CAAC,kBACD,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,GACnD;AACA,sBAAiB;AACjB,SAAI,eACF,WAAU;AAEZ,iBAAY;;AAEd;GAEF,KAAK;AACH,QAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,GAAG;AACxD,eAAU;AACV,WAAM;MACJ,KAAK,KAAK;MACV,eAAe;OACb,GAAG,KAAK;QACP,QAAQ,MAAM,yBACb,oBACE,KAAK,cAAc,QAAQ,MAAM,mBAAmB,EACpD,QAAQ,MAAM,QACd,OAAO,cAAc,QAAQ,MAAM,kBACpC;OACJ;MACF;AACD,iBAAY;;AAEd;;AAIN,MAAI,UACF,OAAM;;AAGV,KAAI,CAAC;MACC,QAAQ,SAAS,UAAU;AAC7B,aAAU;AACV,SAAM,QAAQ;aACL,QAAQ,SAAS,QAAQ;AAClC,UACE,gBACA,yDACD;AACD,oBAAiB;AACjB,aAAU;AACV,SAAM,QAAQ;;;AAIlB,QACE,SACA,kEACD;;AAWH,UAAiB,6BACf,QACA,SACA,QACwB;AAExB,KAAI,QAAQ,SAAS,SACnB,OAAM,QAAQ;UACL,QAAQ,SAAS,OAC1B,OAAM,QAAQ;CAIhB,IAAI,aAAa;AACjB,MAAK,MAAM,QAAQ,QAAQ;AACzB,MAAI,SAAS,SAAS;AACpB,SAAM;AACN;;AAEF,MAAI,CAAC,YAAY;AACf,OAAI,QAAQ,SAAS,SAAS,QAAQ,SAAS;QAE3C,wBAAwB,QAAQ,KAAK,KAAK,KAAK,KAAK,OAAO,WAAW,EACtE;AACA,kBAAa;AACb;;;AAGJ,OAAI,QAAQ,SAAS;QAEjB,wBAAwB,QAAQ,KAAK,KAAK,KAAK,KAAK,OAAO,WAAW,EACtE;AACA,kBAAa;AACb,WAAM;MACJ,KAAK,KAAK;MACV,eAAe;OACb,GAAG,KAAK;QACP,QAAQ,MAAM,yBACb,oBACE,KAAK,cAAc,QAAQ,MAAM,mBAAmB,EACpD,QAAQ,MAAM,QACd,OAAO,cAAc,QAAQ,MAAM,kBACpC;OACJ;MACF;AACD;;;;AAIN,QAAM;;AAER,QACE,cAAc,QAAQ,SAAS,UAC/B,kEACD;;AAGH,SAAgB,wBACd,GACA,GACA,KACS;AACT,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAC9B,KAAI,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAC1C,QAAO;AAGX,QAAO;;AAGT,SAAgB,YACd,QACA,WACA,OACA,UACA;AACA,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IACpC,KAAI,CAAC,YAAY,OAAO,UAAU,KAAK,MAAM,SAAS,IAAI,CACxD,QAAO;AAGX,QAAO;;;;;;;AAQT,SAAgB,oBACd,WACA,WACA,WACmC;CACnC,MAAM,aAAoC,EAAE;AAC5C,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;EACzC,MAAM,QAAQ,UAAU,UAAU;AAClC,MAAI,UAAU,KACZ;AAEF,aAAW,UAAU,MAAM;;AAE7B,QAAO"}
1
+ {"version":3,"file":"join-utils.js","names":[],"sources":["../../../../../zql/src/ivm/join-utils.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport type {Change} from './change.ts';\nimport {compareValues, valuesEqual, type Node} from './data.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\n\nexport function generateWithOverlayNoYield(\n stream: Stream<Node>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node> {\n return generateWithOverlay(stream, overlay, schema) as Stream<Node>;\n}\n\nexport function* generateWithOverlay(\n stream: Stream<Node | 'yield'>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node | 'yield'> {\n let applied = false;\n let editOldApplied = false;\n let editNewApplied = false;\n for (const node of stream) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n let yieldNode = true;\n if (!applied) {\n switch (overlay[ChangeIndex.TYPE]) {\n case ChangeType.ADD: {\n if (\n schema.compareRows(overlay[ChangeIndex.NODE].row, node.row) === 0\n ) {\n applied = true;\n yieldNode = false;\n }\n break;\n }\n case ChangeType.REMOVE: {\n if (schema.compareRows(overlay[ChangeIndex.NODE].row, node.row) < 0) {\n applied = true;\n yield overlay[ChangeIndex.NODE];\n }\n break;\n }\n case ChangeType.EDIT: {\n if (\n !editOldApplied &&\n schema.compareRows(overlay[ChangeIndex.OLD_NODE].row, node.row) < 0\n ) {\n editOldApplied = true;\n if (editNewApplied) {\n applied = true;\n }\n yield overlay[ChangeIndex.OLD_NODE];\n }\n if (\n !editNewApplied &&\n schema.compareRows(overlay[ChangeIndex.NODE].row, node.row) === 0\n ) {\n editNewApplied = true;\n if (editOldApplied) {\n applied = true;\n }\n yieldNode = false;\n }\n break;\n }\n case ChangeType.CHILD: {\n if (\n schema.compareRows(overlay[ChangeIndex.NODE].row, node.row) === 0\n ) {\n applied = true;\n yield {\n row: node.row,\n relationships: {\n ...node.relationships,\n [overlay[ChangeIndex.CHILD_DATA].relationshipName]: () =>\n generateWithOverlay(\n node.relationships[\n overlay[ChangeIndex.CHILD_DATA].relationshipName\n ](),\n overlay[ChangeIndex.CHILD_DATA].change,\n schema.relationships[\n overlay[ChangeIndex.CHILD_DATA].relationshipName\n ],\n ),\n },\n };\n yieldNode = false;\n }\n break;\n }\n }\n }\n if (yieldNode) {\n yield node;\n }\n }\n if (!applied) {\n if (overlay[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n applied = true;\n yield overlay[ChangeIndex.NODE];\n } else if (overlay[ChangeIndex.TYPE] === ChangeType.EDIT) {\n assert(\n editNewApplied,\n 'edit overlay: new node must be applied before old node',\n );\n editOldApplied = true;\n applied = true;\n yield overlay[ChangeIndex.OLD_NODE];\n }\n }\n\n assert(\n applied,\n 'overlayGenerator: overlay was never applied to any fetched node',\n );\n}\n\nexport function generateWithOverlayNoYieldUnordered(\n stream: Stream<Node>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node> {\n return generateWithOverlayUnordered(stream, overlay, schema) as Stream<Node>;\n}\n\nexport function* generateWithOverlayUnordered(\n stream: Stream<Node | 'yield'>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node | 'yield'> {\n // Eager inject\n if (overlay[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n yield overlay[ChangeIndex.NODE];\n } else if (overlay[ChangeIndex.TYPE] === ChangeType.EDIT) {\n yield overlay[ChangeIndex.OLD_NODE];\n }\n\n // Stream with inline suppress\n let suppressed = false;\n for (const node of stream) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (!suppressed) {\n if (\n overlay[ChangeIndex.TYPE] === ChangeType.ADD ||\n overlay[ChangeIndex.TYPE] === ChangeType.EDIT\n ) {\n if (\n rowEqualsForCompoundKey(\n overlay[ChangeIndex.NODE].row,\n node.row,\n schema.primaryKey,\n )\n ) {\n suppressed = true;\n continue;\n }\n }\n if (overlay[ChangeIndex.TYPE] === ChangeType.CHILD) {\n if (\n rowEqualsForCompoundKey(\n overlay[ChangeIndex.NODE].row,\n node.row,\n schema.primaryKey,\n )\n ) {\n suppressed = true;\n yield {\n row: node.row,\n relationships: {\n ...node.relationships,\n [overlay[ChangeIndex.CHILD_DATA].relationshipName]: () =>\n generateWithOverlay(\n node.relationships[\n overlay[ChangeIndex.CHILD_DATA].relationshipName\n ](),\n overlay[ChangeIndex.CHILD_DATA].change,\n schema.relationships[\n overlay[ChangeIndex.CHILD_DATA].relationshipName\n ],\n ),\n },\n };\n continue;\n }\n }\n }\n yield node;\n }\n assert(\n suppressed || overlay[ChangeIndex.TYPE] === ChangeType.REMOVE,\n 'overlayGenerator: overlay was never applied to any fetched node',\n );\n}\n\nexport function rowEqualsForCompoundKey(\n a: Row,\n b: Row,\n key: CompoundKey,\n): boolean {\n for (let i = 0; i < key.length; i++) {\n if (compareValues(a[key[i]], b[key[i]]) !== 0) {\n return false;\n }\n }\n return true;\n}\n\nexport function isJoinMatch(\n parent: Row,\n parentKey: CompoundKey,\n child: Row,\n childKey: CompoundKey,\n) {\n for (let i = 0; i < parentKey.length; i++) {\n if (!valuesEqual(parent[parentKey[i]], child[childKey[i]])) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Builds a constraint object by mapping values from `sourceRow` using `sourceKey`\n * to keys specified by `targetKey`. Returns `undefined` if any source value is `null`,\n * since null foreign keys cannot match any rows.\n */\nexport function buildJoinConstraint(\n sourceRow: Row,\n sourceKey: CompoundKey,\n targetKey: CompoundKey,\n): Record<string, Value> | undefined {\n const constraint: Record<string, Value> = {};\n for (let i = 0; i < targetKey.length; i++) {\n const value = sourceRow[sourceKey[i]];\n if (value === null) {\n return undefined;\n }\n constraint[targetKey[i]] = value;\n }\n return constraint;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAG3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AASpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,IAAK,YAAW,KAAK;;gBAYpB,EACV,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAkCP,OAAO,IAAI,IAAI;IAKf,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;CAkMlD"}
1
+ {"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAW3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAQpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,IAAK,YAAW,KAAK;;gBAapB,EACV,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAkCP,OAAO,IAAI,IAAI;IAKf,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;CAwLlD"}
@@ -1,5 +1,6 @@
1
1
  import { assert, unreachable } from "../../../shared/src/asserts.js";
2
2
  import { throwOutput } from "./operator.js";
3
+ import { makeAddChange, makeChildChange, makeEditChange, makeRemoveChange } from "./change.js";
3
4
  import { buildJoinConstraint, generateWithOverlay, generateWithOverlayUnordered, isJoinMatch, rowEqualsForCompoundKey } from "./join-utils.js";
4
5
  //#region ../zql/src/ivm/join.ts
5
6
  /**
@@ -21,6 +22,7 @@ var Join = class {
21
22
  #schema;
22
23
  #output = throwOutput;
23
24
  #inprogressChildChange;
25
+ #inprogressChildChangePosition;
24
26
  constructor({ parent, child, parentKey, childKey, relationshipName, hidden, system }) {
25
27
  assert(parent !== child, "Parent and child must be different operators");
26
28
  assert(parentKey.length === childKey.length, "The parentKey and childKey keys must have same length");
@@ -65,49 +67,35 @@ var Join = class {
65
67
  }
66
68
  }
67
69
  *#pushParent(change) {
68
- switch (change.type) {
69
- case "add":
70
- yield* this.#output.push({
71
- type: "add",
72
- node: this.#processParentNode(change.node.row, change.node.relationships)
73
- }, this);
70
+ switch (change[0]) {
71
+ case 0:
72
+ yield* this.#output.push(makeAddChange(this.#processParentNode(change[1].row, change[1].relationships)), this);
74
73
  break;
75
- case "remove":
76
- yield* this.#output.push({
77
- type: "remove",
78
- node: this.#processParentNode(change.node.row, change.node.relationships)
79
- }, this);
74
+ case 1:
75
+ yield* this.#output.push(makeRemoveChange(this.#processParentNode(change[1].row, change[1].relationships)), this);
80
76
  break;
81
- case "child":
82
- yield* this.#output.push({
83
- type: "child",
84
- node: this.#processParentNode(change.node.row, change.node.relationships),
85
- child: change.child
86
- }, this);
77
+ case 3:
78
+ yield* this.#output.push(makeChildChange(this.#processParentNode(change[1].row, change[1].relationships), change[2]), this);
87
79
  break;
88
- case "edit":
89
- assert(rowEqualsForCompoundKey(change.oldNode.row, change.node.row, this.#parentKey), `Parent edit must not change relationship.`);
90
- yield* this.#output.push({
91
- type: "edit",
92
- oldNode: this.#processParentNode(change.oldNode.row, change.oldNode.relationships),
93
- node: this.#processParentNode(change.node.row, change.node.relationships)
94
- }, this);
80
+ case 2:
81
+ assert(rowEqualsForCompoundKey(change[2].row, change[1].row, this.#parentKey), `Parent edit must not change relationship.`);
82
+ yield* this.#output.push(makeEditChange(this.#processParentNode(change[1].row, change[1].relationships), this.#processParentNode(change[2].row, change[2].relationships)), this);
95
83
  break;
96
84
  default: unreachable(change);
97
85
  }
98
86
  }
99
87
  *#pushChild(change) {
100
- switch (change.type) {
101
- case "add":
102
- case "remove":
103
- yield* this.#pushChildChange(change.node.row, change);
88
+ switch (change[0]) {
89
+ case 0:
90
+ case 1:
91
+ yield* this.#pushChildChange(change[1].row, change);
104
92
  break;
105
- case "child":
106
- yield* this.#pushChildChange(change.node.row, change);
93
+ case 3:
94
+ yield* this.#pushChildChange(change[1].row, change);
107
95
  break;
108
- case "edit": {
109
- const childRow = change.node.row;
110
- const oldChildRow = change.oldNode.row;
96
+ case 2: {
97
+ const childRow = change[1].row;
98
+ const oldChildRow = change[2].row;
111
99
  assert(rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey), "Child edit must not change relationship.");
112
100
  yield* this.#pushChildChange(childRow, change);
113
101
  break;
@@ -116,27 +104,20 @@ var Join = class {
116
104
  }
117
105
  }
118
106
  *#pushChildChange(childRow, change) {
119
- this.#inprogressChildChange = {
120
- change,
121
- position: void 0
122
- };
107
+ this.#inprogressChildChange = change;
108
+ this.#inprogressChildChangePosition = void 0;
123
109
  try {
124
110
  const constraint = buildJoinConstraint(childRow, this.#childKey, this.#parentKey);
125
- const parentNodes = constraint ? this.#parent.fetch({ constraint }) : [];
126
- for (const parentNode of parentNodes) {
111
+ if (constraint) for (const parentNode of this.#parent.fetch({ constraint })) {
127
112
  if (parentNode === "yield") {
128
113
  yield parentNode;
129
114
  continue;
130
115
  }
131
- this.#inprogressChildChange.position = parentNode.row;
132
- const childChange = {
133
- type: "child",
134
- node: this.#processParentNode(parentNode.row, parentNode.relationships),
135
- child: {
136
- relationshipName: this.#relationshipName,
137
- change
138
- }
139
- };
116
+ this.#inprogressChildChangePosition = parentNode.row;
117
+ const childChange = makeChildChange(this.#processParentNode(parentNode.row, parentNode.relationships), {
118
+ relationshipName: this.#relationshipName,
119
+ change
120
+ });
140
121
  yield* this.#output.push(childChange, this);
141
122
  }
142
123
  } finally {
@@ -147,10 +128,10 @@ var Join = class {
147
128
  const childStream = () => {
148
129
  const constraint = buildJoinConstraint(parentNodeRow, this.#parentKey, this.#childKey);
149
130
  const stream = constraint ? this.#child.fetch({ constraint }) : [];
150
- if (this.#inprogressChildChange && isJoinMatch(parentNodeRow, this.#parentKey, this.#inprogressChildChange.change.node.row, this.#childKey) && this.#inprogressChildChange.position && this.#schema.compareRows(parentNodeRow, this.#inprogressChildChange.position) > 0) {
131
+ if (this.#inprogressChildChange && isJoinMatch(parentNodeRow, this.#parentKey, this.#inprogressChildChange[1].row, this.#childKey) && this.#inprogressChildChangePosition && this.#schema.compareRows(parentNodeRow, this.#inprogressChildChangePosition) > 0) {
151
132
  const childSchema = this.#child.getSchema();
152
- if (childSchema.sort === void 0) return generateWithOverlayUnordered(stream, this.#inprogressChildChange.change, childSchema);
153
- return generateWithOverlay(stream, this.#inprogressChildChange.change, childSchema);
133
+ if (childSchema.sort === void 0) return generateWithOverlayUnordered(stream, this.#inprogressChildChange, childSchema);
134
+ return generateWithOverlay(stream, this.#inprogressChildChange, childSchema);
154
135
  }
155
136
  return stream;
156
137
  };