@rocicorp/zero 0.25.0-canary.10 → 0.25.0-canary.12

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 (188) hide show
  1. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  2. package/out/analyze-query/src/run-ast.js +3 -7
  3. package/out/analyze-query/src/run-ast.js.map +1 -1
  4. package/out/shared/src/iterables.d.ts +0 -1
  5. package/out/shared/src/iterables.d.ts.map +1 -1
  6. package/out/shared/src/iterables.js +0 -34
  7. package/out/shared/src/iterables.js.map +1 -1
  8. package/out/zero/package.json.js +1 -1
  9. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  10. package/out/zero-cache/src/db/transaction-pool.js +3 -6
  11. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  12. package/out/zero-cache/src/services/analyze.d.ts +1 -1
  13. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  14. package/out/zero-cache/src/services/analyze.js +50 -37
  15. package/out/zero-cache/src/services/analyze.js.map +1 -1
  16. package/out/zero-cache/src/services/run-ast.d.ts +1 -1
  17. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  18. package/out/zero-cache/src/services/run-ast.js +5 -1
  19. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  20. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -4
  21. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  22. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +71 -23
  23. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  24. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -1
  25. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  26. package/out/zero-cache/src/services/view-syncer/view-syncer.js +10 -6
  27. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  28. package/out/zero-client/src/client/bindings.d.ts +2 -3
  29. package/out/zero-client/src/client/bindings.d.ts.map +1 -1
  30. package/out/zero-client/src/client/bindings.js.map +1 -1
  31. package/out/zero-client/src/client/make-mutate-property.d.ts +2 -2
  32. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
  33. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  34. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  35. package/out/zero-client/src/client/options.d.ts +3 -3
  36. package/out/zero-client/src/client/options.d.ts.map +1 -1
  37. package/out/zero-client/src/client/options.js.map +1 -1
  38. package/out/zero-client/src/client/version.js +1 -1
  39. package/out/zero-client/src/client/zero.d.ts +1 -2
  40. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  41. package/out/zero-client/src/client/zero.js +6 -2
  42. package/out/zero-client/src/client/zero.js.map +1 -1
  43. package/out/zero-client/src/mod.d.ts +5 -7
  44. package/out/zero-client/src/mod.d.ts.map +1 -1
  45. package/out/zero-react/src/components/inspector.d.ts +1 -2
  46. package/out/zero-react/src/components/inspector.d.ts.map +1 -1
  47. package/out/zero-react/src/components/inspector.js.map +1 -1
  48. package/out/zero-react/src/components/zero-inspector.d.ts +1 -2
  49. package/out/zero-react/src/components/zero-inspector.d.ts.map +1 -1
  50. package/out/zero-react/src/components/zero-inspector.js.map +1 -1
  51. package/out/zero-react/src/use-query.d.ts +1 -2
  52. package/out/zero-react/src/use-query.d.ts.map +1 -1
  53. package/out/zero-react/src/use-query.js.map +1 -1
  54. package/out/zero-react/src/zero-provider.d.ts +4 -5
  55. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  56. package/out/zero-react/src/zero-provider.js.map +1 -1
  57. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  58. package/out/zero-solid/src/solid-view.js +4 -3
  59. package/out/zero-solid/src/solid-view.js.map +1 -1
  60. package/out/zero-solid/src/use-zero.d.ts +4 -5
  61. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  62. package/out/zero-solid/src/use-zero.js.map +1 -1
  63. package/out/zero-types/src/default-types.d.ts +2 -2
  64. package/out/zero-types/src/default-types.d.ts.map +1 -1
  65. package/out/zql/src/builder/builder.d.ts.map +1 -1
  66. package/out/zql/src/builder/builder.js +0 -1
  67. package/out/zql/src/builder/builder.js.map +1 -1
  68. package/out/zql/src/ivm/array-view.d.ts +1 -1
  69. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  70. package/out/zql/src/ivm/array-view.js +2 -1
  71. package/out/zql/src/ivm/array-view.js.map +1 -1
  72. package/out/zql/src/ivm/data.d.ts +7 -2
  73. package/out/zql/src/ivm/data.d.ts.map +1 -1
  74. package/out/zql/src/ivm/data.js +3 -0
  75. package/out/zql/src/ivm/data.js.map +1 -1
  76. package/out/zql/src/ivm/exists.d.ts +3 -2
  77. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  78. package/out/zql/src/ivm/exists.js +29 -76
  79. package/out/zql/src/ivm/exists.js.map +1 -1
  80. package/out/zql/src/ivm/fan-in.d.ts +2 -0
  81. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  82. package/out/zql/src/ivm/fan-in.js +4 -0
  83. package/out/zql/src/ivm/fan-in.js.map +1 -1
  84. package/out/zql/src/ivm/fan-out.d.ts +2 -0
  85. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  86. package/out/zql/src/ivm/fan-out.js +4 -0
  87. package/out/zql/src/ivm/fan-out.js.map +1 -1
  88. package/out/zql/src/ivm/filter-operators.d.ts +6 -2
  89. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  90. package/out/zql/src/ivm/filter-operators.js +16 -0
  91. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  92. package/out/zql/src/ivm/filter.d.ts +2 -0
  93. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  94. package/out/zql/src/ivm/filter.js +4 -0
  95. package/out/zql/src/ivm/filter.js.map +1 -1
  96. package/out/zql/src/ivm/flipped-join.d.ts +1 -1
  97. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  98. package/out/zql/src/ivm/flipped-join.js +26 -13
  99. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  100. package/out/zql/src/ivm/join-utils.d.ts +2 -1
  101. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  102. package/out/zql/src/ivm/join-utils.js +8 -0
  103. package/out/zql/src/ivm/join-utils.js.map +1 -1
  104. package/out/zql/src/ivm/join.d.ts +1 -1
  105. package/out/zql/src/ivm/join.d.ts.map +1 -1
  106. package/out/zql/src/ivm/join.js +15 -6
  107. package/out/zql/src/ivm/join.js.map +1 -1
  108. package/out/zql/src/ivm/memory-source.d.ts +1 -1
  109. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  110. package/out/zql/src/ivm/memory-source.js +8 -1
  111. package/out/zql/src/ivm/memory-source.js.map +1 -1
  112. package/out/zql/src/ivm/operator.d.ts +9 -1
  113. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  114. package/out/zql/src/ivm/operator.js +8 -0
  115. package/out/zql/src/ivm/operator.js.map +1 -1
  116. package/out/zql/src/ivm/push-accumulated.d.ts +1 -1
  117. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  118. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  119. package/out/zql/src/ivm/skip.d.ts +1 -1
  120. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  121. package/out/zql/src/ivm/skip.js +7 -1
  122. package/out/zql/src/ivm/skip.js.map +1 -1
  123. package/out/zql/src/ivm/take.d.ts +1 -1
  124. package/out/zql/src/ivm/take.d.ts.map +1 -1
  125. package/out/zql/src/ivm/take.js +87 -59
  126. package/out/zql/src/ivm/take.js.map +1 -1
  127. package/out/zql/src/ivm/union-fan-in.d.ts +2 -1
  128. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  129. package/out/zql/src/ivm/union-fan-in.js +67 -5
  130. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  131. package/out/zql/src/ivm/union-fan-out.d.ts +1 -1
  132. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  133. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  134. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  135. package/out/zql/src/ivm/view-apply-change.js +3 -2
  136. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  137. package/out/zql/src/mutate/custom.d.ts +2 -2
  138. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  139. package/out/zql/src/mutate/custom.js.map +1 -1
  140. package/out/zql/src/mutate/mutator-registry.d.ts +33 -15
  141. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  142. package/out/zql/src/mutate/mutator-registry.js +2 -8
  143. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  144. package/out/zql/src/mutate/mutator.d.ts +50 -25
  145. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  146. package/out/zql/src/mutate/mutator.js +2 -3
  147. package/out/zql/src/mutate/mutator.js.map +1 -1
  148. package/out/zql/src/query/abstract-query.d.ts +43 -0
  149. package/out/zql/src/query/abstract-query.d.ts.map +1 -0
  150. package/out/zql/src/query/abstract-query.js +408 -0
  151. package/out/zql/src/query/abstract-query.js.map +1 -0
  152. package/out/zql/src/query/create-builder.d.ts +2 -0
  153. package/out/zql/src/query/create-builder.d.ts.map +1 -1
  154. package/out/zql/src/query/create-builder.js +7 -2
  155. package/out/zql/src/query/create-builder.js.map +1 -1
  156. package/out/zql/src/query/measure-push-operator.d.ts +1 -1
  157. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  158. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  159. package/out/zql/src/query/query-delegate-base.d.ts +7 -1
  160. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  161. package/out/zql/src/query/query-delegate-base.js +132 -2
  162. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  163. package/out/zql/src/query/query-impl.d.ts +5 -39
  164. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  165. package/out/zql/src/query/query-impl.js +3 -521
  166. package/out/zql/src/query/query-impl.js.map +1 -1
  167. package/out/zql/src/query/query-internals.d.ts.map +1 -1
  168. package/out/zql/src/query/query-internals.js +2 -2
  169. package/out/zql/src/query/query-internals.js.map +1 -1
  170. package/out/zql/src/query/query-registry.d.ts +126 -58
  171. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  172. package/out/zql/src/query/query-registry.js +13 -21
  173. package/out/zql/src/query/query-registry.js.map +1 -1
  174. package/out/zql/src/query/query.d.ts +21 -0
  175. package/out/zql/src/query/query.d.ts.map +1 -1
  176. package/out/zql/src/query/runnable-query-impl.d.ts +22 -0
  177. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -0
  178. package/out/zql/src/query/runnable-query-impl.js +60 -0
  179. package/out/zql/src/query/runnable-query-impl.js.map +1 -0
  180. package/out/zql/src/query/static-query.d.ts +1 -1
  181. package/out/zql/src/query/static-query.d.ts.map +1 -1
  182. package/out/zql/src/query/static-query.js +1 -1
  183. package/out/zql/src/query/static-query.js.map +1 -1
  184. package/out/zqlite/src/table-source.d.ts +7 -1
  185. package/out/zqlite/src/table-source.d.ts.map +1 -1
  186. package/out/zqlite/src/table-source.js +34 -14
  187. package/out/zqlite/src/table-source.js.map +1 -1
  188. package/package.json +1 -1
@@ -14,6 +14,8 @@ export declare class FanOut implements FilterOperator {
14
14
  setFilterOutput(output: FilterOutput): void;
15
15
  destroy(): void;
16
16
  getSchema(): import("./schema.ts").SourceSchema;
17
+ beginFilter(): void;
18
+ endFilter(): void;
17
19
  filter(node: Node, cleanup: boolean): boolean;
18
20
  push(change: Change): void;
19
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fan-out.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/fan-out.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,YAAY,EACb,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAM/B,KAAK,EAAE,WAAW;IAK9B,QAAQ,CAAC,KAAK,EAAE,KAAK;IAIrB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAWf,SAAS;IAIT,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAa7C,IAAI,CAAC,MAAM,EAAE,MAAM;CASpB"}
1
+ {"version":3,"file":"fan-out.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/fan-out.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,YAAY,EACb,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAM/B,KAAK,EAAE,WAAW;IAK9B,QAAQ,CAAC,KAAK,EAAE,KAAK;IAIrB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAWf,SAAS;IAIT,WAAW,IAAI,IAAI;IAEnB,SAAS,IAAI,IAAI;IAEjB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAa7C,IAAI,CAAC,MAAM,EAAE,MAAM;CASpB"}
@@ -27,6 +27,10 @@ class FanOut {
27
27
  getSchema() {
28
28
  return this.#input.getSchema();
29
29
  }
30
+ beginFilter() {
31
+ }
32
+ endFilter() {
33
+ }
30
34
  filter(node, cleanup) {
31
35
  let result = false;
32
36
  for (const output of this.#outputs) {
@@ -1 +1 @@
1
- {"version":3,"file":"fan-out.js","sources":["../../../../../zql/src/ivm/fan-out.ts"],"sourcesContent":["import {must} from '../../../shared/src/must.ts';\nimport type {Change} from './change.ts';\nimport type {FanIn} from './fan-in.ts';\nimport type {Node} from './data.ts';\nimport type {\n FilterInput,\n FilterOperator,\n FilterOutput,\n} from './filter-operators.ts';\n\n/**\n * Forks a stream into multiple streams.\n * Is meant to be paired with a `FanIn` operator which will\n * later merge the forks back together.\n */\nexport class FanOut implements FilterOperator {\n readonly #input: FilterInput;\n readonly #outputs: FilterOutput[] = [];\n #fanIn: FanIn | undefined;\n #destroyCount: number = 0;\n\n constructor(input: FilterInput) {\n this.#input = input;\n input.setFilterOutput(this);\n }\n\n setFanIn(fanIn: FanIn) {\n this.#fanIn = fanIn;\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#outputs.push(output);\n }\n\n destroy(): void {\n if (this.#destroyCount < this.#outputs.length) {\n ++this.#destroyCount;\n if (this.#destroyCount === this.#outputs.length) {\n this.#input.destroy();\n }\n } else {\n throw new Error('FanOut already destroyed once for each output');\n }\n }\n\n getSchema() {\n return this.#input.getSchema();\n }\n\n filter(node: Node, cleanup: boolean): boolean {\n let result = false;\n for (const output of this.#outputs) {\n result = output.filter(node, cleanup) || result;\n // Cleanup needs to be forwarded to all outputs, don't short circuit\n // cleanup. For non-cleanup we can short-circuit on first true.\n if (!cleanup && result) {\n return true;\n }\n }\n return result;\n }\n\n push(change: Change) {\n for (const out of this.#outputs) {\n out.push(change, this);\n }\n must(\n this.#fanIn,\n 'fan-out must have a corresponding fan-in set!',\n ).fanOutDonePushingToAllBranches(change.type);\n }\n}\n"],"names":[],"mappings":";AAeO,MAAM,OAAiC;AAAA,EACnC;AAAA,EACA,WAA2B,CAAA;AAAA,EACpC;AAAA,EACA,gBAAwB;AAAA,EAExB,YAAY,OAAoB;AAC9B,SAAK,SAAS;AACd,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,SAAS,OAAc;AACrB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,gBAAgB,QAA4B;AAC1C,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,gBAAgB,KAAK,SAAS,QAAQ;AAC7C,QAAE,KAAK;AACP,UAAI,KAAK,kBAAkB,KAAK,SAAS,QAAQ;AAC/C,aAAK,OAAO,QAAA;AAAA,MACd;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,OAAO,MAAY,SAA2B;AAC5C,QAAI,SAAS;AACb,eAAW,UAAU,KAAK,UAAU;AAClC,eAAS,OAAO,OAAO,MAAM,OAAO,KAAK;AAGzC,UAAI,CAAC,WAAW,QAAQ;AACtB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,QAAgB;AACnB,eAAW,OAAO,KAAK,UAAU;AAC/B,UAAI,KAAK,QAAQ,IAAI;AAAA,IACvB;AACA;AAAA,MACE,KAAK;AAAA,MACL;AAAA,IAAA,EACA,+BAA+B,OAAO,IAAI;AAAA,EAC9C;AACF;"}
1
+ {"version":3,"file":"fan-out.js","sources":["../../../../../zql/src/ivm/fan-out.ts"],"sourcesContent":["import {must} from '../../../shared/src/must.ts';\nimport type {Change} from './change.ts';\nimport type {FanIn} from './fan-in.ts';\nimport type {Node} from './data.ts';\nimport type {\n FilterInput,\n FilterOperator,\n FilterOutput,\n} from './filter-operators.ts';\n\n/**\n * Forks a stream into multiple streams.\n * Is meant to be paired with a `FanIn` operator which will\n * later merge the forks back together.\n */\nexport class FanOut implements FilterOperator {\n readonly #input: FilterInput;\n readonly #outputs: FilterOutput[] = [];\n #fanIn: FanIn | undefined;\n #destroyCount: number = 0;\n\n constructor(input: FilterInput) {\n this.#input = input;\n input.setFilterOutput(this);\n }\n\n setFanIn(fanIn: FanIn) {\n this.#fanIn = fanIn;\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#outputs.push(output);\n }\n\n destroy(): void {\n if (this.#destroyCount < this.#outputs.length) {\n ++this.#destroyCount;\n if (this.#destroyCount === this.#outputs.length) {\n this.#input.destroy();\n }\n } else {\n throw new Error('FanOut already destroyed once for each output');\n }\n }\n\n getSchema() {\n return this.#input.getSchema();\n }\n\n beginFilter(): void {}\n\n endFilter(): void {}\n\n filter(node: Node, cleanup: boolean): boolean {\n let result = false;\n for (const output of this.#outputs) {\n result = output.filter(node, cleanup) || result;\n // Cleanup needs to be forwarded to all outputs, don't short circuit\n // cleanup. For non-cleanup we can short-circuit on first true.\n if (!cleanup && result) {\n return true;\n }\n }\n return result;\n }\n\n push(change: Change) {\n for (const out of this.#outputs) {\n out.push(change, this);\n }\n must(\n this.#fanIn,\n 'fan-out must have a corresponding fan-in set!',\n ).fanOutDonePushingToAllBranches(change.type);\n }\n}\n"],"names":[],"mappings":";AAeO,MAAM,OAAiC;AAAA,EACnC;AAAA,EACA,WAA2B,CAAA;AAAA,EACpC;AAAA,EACA,gBAAwB;AAAA,EAExB,YAAY,OAAoB;AAC9B,SAAK,SAAS;AACd,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,SAAS,OAAc;AACrB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,gBAAgB,QAA4B;AAC1C,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,gBAAgB,KAAK,SAAS,QAAQ;AAC7C,QAAE,KAAK;AACP,UAAI,KAAK,kBAAkB,KAAK,SAAS,QAAQ;AAC/C,aAAK,OAAO,QAAA;AAAA,MACd;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,cAAoB;AAAA,EAAC;AAAA,EAErB,YAAkB;AAAA,EAAC;AAAA,EAEnB,OAAO,MAAY,SAA2B;AAC5C,QAAI,SAAS;AACb,eAAW,UAAU,KAAK,UAAU;AAClC,eAAS,OAAO,OAAO,MAAM,OAAO,KAAK;AAGzC,UAAI,CAAC,WAAW,QAAQ;AACtB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,QAAgB;AACnB,eAAW,OAAO,KAAK,UAAU;AAC/B,UAAI,KAAK,QAAQ,IAAI;AAAA,IACvB;AACA;AAAA,MACE,KAAK;AAAA,MACL;AAAA,IAAA,EACA,+BAA+B,OAAO,IAAI;AAAA,EAC9C;AACF;"}
@@ -27,7 +27,9 @@ export interface FilterInput extends InputBase {
27
27
  setFilterOutput(output: FilterOutput): void;
28
28
  }
29
29
  export interface FilterOutput extends Output {
30
+ beginFilter(): void;
30
31
  filter(node: Node, cleanup: boolean): boolean;
32
+ endFilter(): void;
31
33
  }
32
34
  export interface FilterOperator extends FilterInput, FilterOutput {
33
35
  }
@@ -44,13 +46,15 @@ export declare class FilterStart implements FilterInput, Output {
44
46
  destroy(): void;
45
47
  getSchema(): SourceSchema;
46
48
  push(change: Change): void;
47
- fetch(req: FetchRequest): Stream<Node>;
49
+ fetch(req: FetchRequest): Stream<Node | 'yield'>;
48
50
  cleanup(req: FetchRequest): Stream<Node>;
49
51
  }
50
52
  export declare class FilterEnd implements Input, FilterOutput {
51
53
  #private;
52
54
  constructor(start: FilterStart, input: FilterInput);
53
- fetch(req: FetchRequest): Stream<Node>;
55
+ fetch(req: FetchRequest): Stream<Node | 'yield'>;
56
+ beginFilter(): void;
57
+ endFilter(): void;
54
58
  cleanup(req: FetchRequest): Stream<Node>;
55
59
  filter(_node: Node, _cleanup: boolean): boolean;
56
60
  setOutput(output: Output): void;
@@ -1 +1 @@
1
- {"version":3,"file":"filter-operators.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter-operators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAe,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAClD,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,KAAK,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,+CAA+C;IAC/C,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CAC/C;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW,EAAE,YAAY;CAAG;AAEpE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,YAQ/B,CAAC;AAEF,qBAAa,WAAY,YAAW,WAAW,EAAE,MAAM;;gBAIzC,KAAK,EAAE,KAAK;IAKxB,eAAe,CAAC,MAAM,EAAE,YAAY;IAIpC,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;IAIlB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAQtC,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAS1C;AAED,qBAAa,SAAU,YAAW,KAAK,EAAE,YAAY;;gBAMvC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW;IAMjD,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAMtC,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAMzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO;IAIrC,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;CAGpB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,WAAW,GAClD,KAAK,CAQP"}
1
+ {"version":3,"file":"filter-operators.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter-operators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAe,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAClD,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,KAAK,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,+CAA+C;IAC/C,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAI1C,WAAW,IAAI,IAAI,CAAC;IACpB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IAC9C,SAAS,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW,EAAE,YAAY;CAAG;AAEpE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,YAW/B,CAAC;AAEF,qBAAa,WAAY,YAAW,WAAW,EAAE,MAAM;;gBAIzC,KAAK,EAAE,KAAK;IAKxB,eAAe,CAAC,MAAM,EAAE,YAAY;IAIpC,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;IAIlB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAchD,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAW1C;AAED,qBAAa,SAAU,YAAW,KAAK,EAAE,YAAY;;gBAMvC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW;IAMjD,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAMjD,WAAW;IACX,SAAS;IAER,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAMzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO;IAIrC,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;CAGpB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,WAAW,GAClD,KAAK,CAQP"}
@@ -5,6 +5,10 @@ const throwFilterOutput = {
5
5
  },
6
6
  filter(_node, _cleanup) {
7
7
  throw new Error("Output not set");
8
+ },
9
+ beginFilter() {
10
+ },
11
+ endFilter() {
8
12
  }
9
13
  };
10
14
  class FilterStart {
@@ -27,13 +31,20 @@ class FilterStart {
27
31
  this.#output.push(change, this);
28
32
  }
29
33
  *fetch(req) {
34
+ this.#output.beginFilter();
30
35
  for (const node of this.#input.fetch(req)) {
36
+ if (node === "yield") {
37
+ yield node;
38
+ continue;
39
+ }
31
40
  if (this.#output.filter(node, false)) {
32
41
  yield node;
33
42
  }
34
43
  }
44
+ this.#output.endFilter();
35
45
  }
36
46
  *cleanup(req) {
47
+ this.#output.beginFilter();
37
48
  for (const node of this.#input.cleanup(req)) {
38
49
  if (this.#output.filter(node, true)) {
39
50
  yield node;
@@ -41,6 +52,7 @@ class FilterStart {
41
52
  drainStreams(node);
42
53
  }
43
54
  }
55
+ this.#output.endFilter();
44
56
  }
45
57
  }
46
58
  class FilterEnd {
@@ -57,6 +69,10 @@ class FilterEnd {
57
69
  yield node;
58
70
  }
59
71
  }
72
+ beginFilter() {
73
+ }
74
+ endFilter() {
75
+ }
60
76
  *cleanup(req) {
61
77
  for (const node of this.#start.cleanup(req)) {
62
78
  yield node;
@@ -1 +1 @@
1
- {"version":3,"file":"filter-operators.js","sources":["../../../../../zql/src/ivm/filter-operators.ts"],"sourcesContent":["import type {FetchRequest, Input, InputBase, Output} from './operator.ts';\nimport {drainStreams, type Node} from './data.ts';\nimport type {Change} from './change.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\nimport type {BuilderDelegate} from '../builder/builder.ts';\n\n/**\n * The `where` clause of a ZQL query is implemented using a sub-graph of\n * `FilterOperators`. This sub-graph starts with a `FilterStart` operator,\n * that adapts from the normal `Operator` `Output`, to the\n * `FilterOperator` `FilterInput`, and ends with a `FilterEnd` operator that\n * adapts from a `FilterOperator` `FilterOutput` to a normal `Operator` `Input`.\n * `FilterOperator'`s do not have `fetch` or `cleanup` instead they have a\n * `filter(node: Node, cleanup: boolean): boolean` method.\n * They also have `push` which is just like normal `Operator` push.\n * Not having a `fetch` means these `FilterOperator`'s cannot modify\n * `Node` `row`s or `relationship`s, but they shouldn't, they should just\n * filter.\n *\n * This `FilterOperator` abstraction enables much more efficient processing of\n * `fetch` for `where` clauses containing OR conditions.\n *\n * See https://github.com/rocicorp/mono/pull/4339\n */\n\nexport interface FilterInput extends InputBase {\n /** Tell the input where to send its output. */\n setFilterOutput(output: FilterOutput): void;\n}\n\nexport interface FilterOutput extends Output {\n filter(node: Node, cleanup: boolean): boolean;\n}\n\nexport interface FilterOperator extends FilterInput, FilterOutput {}\n\n/**\n * An implementation of FilterOutput that throws if push or filter is called.\n * It is used as the initial value for for an operator's output before it is\n * set.\n */\nexport const throwFilterOutput: FilterOutput = {\n push(_change: Change): void {\n throw new Error('Output not set');\n },\n\n filter(_node: Node, _cleanup): boolean {\n throw new Error('Output not set');\n },\n};\n\nexport class FilterStart implements FilterInput, Output {\n readonly #input: Input;\n #output: FilterOutput = throwFilterOutput;\n\n constructor(input: Input) {\n this.#input = input;\n input.setOutput(this);\n }\n\n setFilterOutput(output: FilterOutput) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n this.#output.push(change, this);\n }\n\n *fetch(req: FetchRequest): Stream<Node> {\n for (const node of this.#input.fetch(req)) {\n if (this.#output.filter(node, false)) {\n yield node;\n }\n }\n }\n\n *cleanup(req: FetchRequest): Stream<Node> {\n for (const node of this.#input.cleanup(req)) {\n if (this.#output.filter(node, true)) {\n yield node;\n } else {\n drainStreams(node);\n }\n }\n }\n}\n\nexport class FilterEnd implements Input, FilterOutput {\n readonly #start: FilterStart;\n readonly #input: FilterInput;\n\n #output: Output = throwFilterOutput;\n\n constructor(start: FilterStart, input: FilterInput) {\n this.#start = start;\n this.#input = input;\n input.setFilterOutput(this);\n }\n\n *fetch(req: FetchRequest): Stream<Node> {\n for (const node of this.#start.fetch(req)) {\n yield node;\n }\n }\n\n *cleanup(req: FetchRequest): Stream<Node> {\n for (const node of this.#start.cleanup(req)) {\n yield node;\n }\n }\n\n filter(_node: Node, _cleanup: boolean) {\n return true;\n }\n\n setOutput(output: Output) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n this.#output.push(change, this);\n }\n}\n\nexport function buildFilterPipeline(\n input: Input,\n delegate: BuilderDelegate,\n pipeline: (filterInput: FilterInput) => FilterInput,\n): Input {\n const filterStart = new FilterStart(input);\n delegate.addEdge(input, filterStart);\n const middle = pipeline(filterStart);\n delegate.addEdge(filterStart, middle);\n const filterEnd = new FilterEnd(filterStart, middle);\n delegate.addEdge(middle, filterEnd);\n return filterEnd;\n}\n"],"names":[],"mappings":";AA0CO,MAAM,oBAAkC;AAAA,EAC7C,KAAK,SAAuB;AAC1B,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AAAA,EAEA,OAAO,OAAa,UAAmB;AACrC,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACF;AAEO,MAAM,YAA2C;AAAA,EAC7C;AAAA,EACT,UAAwB;AAAA,EAExB,YAAY,OAAc;AACxB,SAAK,SAAS;AACd,UAAM,UAAU,IAAI;AAAA,EACtB;AAAA,EAEA,gBAAgB,QAAsB;AACpC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EAChC;AAAA,EAEA,CAAC,MAAM,KAAiC;AACtC,eAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,UAAI,KAAK,QAAQ,OAAO,MAAM,KAAK,GAAG;AACpC,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,CAAC,QAAQ,KAAiC;AACxC,eAAW,QAAQ,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC3C,UAAI,KAAK,QAAQ,OAAO,MAAM,IAAI,GAAG;AACnC,cAAM;AAAA,MACR,OAAO;AACL,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,UAAyC;AAAA,EAC3C;AAAA,EACA;AAAA,EAET,UAAkB;AAAA,EAElB,YAAY,OAAoB,OAAoB;AAClD,SAAK,SAAS;AACd,SAAK,SAAS;AACd,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,CAAC,MAAM,KAAiC;AACtC,eAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,CAAC,QAAQ,KAAiC;AACxC,eAAW,QAAQ,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC3C,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,OAAO,OAAa,UAAmB;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAAgB;AACxB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EAChC;AACF;AAEO,SAAS,oBACd,OACA,UACA,UACO;AACP,QAAM,cAAc,IAAI,YAAY,KAAK;AACzC,WAAS,QAAQ,OAAO,WAAW;AACnC,QAAM,SAAS,SAAS,WAAW;AACnC,WAAS,QAAQ,aAAa,MAAM;AACpC,QAAM,YAAY,IAAI,UAAU,aAAa,MAAM;AACnD,WAAS,QAAQ,QAAQ,SAAS;AAClC,SAAO;AACT;"}
1
+ {"version":3,"file":"filter-operators.js","sources":["../../../../../zql/src/ivm/filter-operators.ts"],"sourcesContent":["import type {FetchRequest, Input, InputBase, Output} from './operator.ts';\nimport {drainStreams, type Node} from './data.ts';\nimport type {Change} from './change.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\nimport type {BuilderDelegate} from '../builder/builder.ts';\n\n/**\n * The `where` clause of a ZQL query is implemented using a sub-graph of\n * `FilterOperators`. This sub-graph starts with a `FilterStart` operator,\n * that adapts from the normal `Operator` `Output`, to the\n * `FilterOperator` `FilterInput`, and ends with a `FilterEnd` operator that\n * adapts from a `FilterOperator` `FilterOutput` to a normal `Operator` `Input`.\n * `FilterOperator'`s do not have `fetch` or `cleanup` instead they have a\n * `filter(node: Node, cleanup: boolean): boolean` method.\n * They also have `push` which is just like normal `Operator` push.\n * Not having a `fetch` means these `FilterOperator`'s cannot modify\n * `Node` `row`s or `relationship`s, but they shouldn't, they should just\n * filter.\n *\n * This `FilterOperator` abstraction enables much more efficient processing of\n * `fetch` for `where` clauses containing OR conditions.\n *\n * See https://github.com/rocicorp/mono/pull/4339\n */\n\nexport interface FilterInput extends InputBase {\n /** Tell the input where to send its output. */\n setFilterOutput(output: FilterOutput): void;\n}\n\nexport interface FilterOutput extends Output {\n // Lets the operator know that we're in a loop of filtering\n // nodes. E.g., so the operator can cache results for the\n // duration of the loop.\n beginFilter(): void;\n filter(node: Node, cleanup: boolean): boolean;\n endFilter(): void;\n}\n\nexport interface FilterOperator extends FilterInput, FilterOutput {}\n\n/**\n * An implementation of FilterOutput that throws if push or filter is called.\n * It is used as the initial value for for an operator's output before it is\n * set.\n */\nexport const throwFilterOutput: FilterOutput = {\n push(_change: Change): void {\n throw new Error('Output not set');\n },\n\n filter(_node: Node, _cleanup): boolean {\n throw new Error('Output not set');\n },\n\n beginFilter() {},\n endFilter() {},\n};\n\nexport class FilterStart implements FilterInput, Output {\n readonly #input: Input;\n #output: FilterOutput = throwFilterOutput;\n\n constructor(input: Input) {\n this.#input = input;\n input.setOutput(this);\n }\n\n setFilterOutput(output: FilterOutput) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n this.#output.push(change, this);\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n this.#output.beginFilter();\n for (const node of this.#input.fetch(req)) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (this.#output.filter(node, false)) {\n yield node;\n }\n }\n this.#output.endFilter();\n }\n\n *cleanup(req: FetchRequest): Stream<Node> {\n this.#output.beginFilter();\n for (const node of this.#input.cleanup(req)) {\n if (this.#output.filter(node, true)) {\n yield node;\n } else {\n drainStreams(node);\n }\n }\n this.#output.endFilter();\n }\n}\n\nexport class FilterEnd implements Input, FilterOutput {\n readonly #start: FilterStart;\n readonly #input: FilterInput;\n\n #output: Output = throwFilterOutput;\n\n constructor(start: FilterStart, input: FilterInput) {\n this.#start = start;\n this.#input = input;\n input.setFilterOutput(this);\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n for (const node of this.#start.fetch(req)) {\n yield node;\n }\n }\n\n beginFilter() {}\n endFilter() {}\n\n *cleanup(req: FetchRequest): Stream<Node> {\n for (const node of this.#start.cleanup(req)) {\n yield node;\n }\n }\n\n filter(_node: Node, _cleanup: boolean) {\n return true;\n }\n\n setOutput(output: Output) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n this.#output.push(change, this);\n }\n}\n\nexport function buildFilterPipeline(\n input: Input,\n delegate: BuilderDelegate,\n pipeline: (filterInput: FilterInput) => FilterInput,\n): Input {\n const filterStart = new FilterStart(input);\n delegate.addEdge(input, filterStart);\n const middle = pipeline(filterStart);\n delegate.addEdge(filterStart, middle);\n const filterEnd = new FilterEnd(filterStart, middle);\n delegate.addEdge(middle, filterEnd);\n return filterEnd;\n}\n"],"names":[],"mappings":";AA+CO,MAAM,oBAAkC;AAAA,EAC7C,KAAK,SAAuB;AAC1B,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AAAA,EAEA,OAAO,OAAa,UAAmB;AACrC,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AAAA,EAEA,cAAc;AAAA,EAAC;AAAA,EACf,YAAY;AAAA,EAAC;AACf;AAEO,MAAM,YAA2C;AAAA,EAC7C;AAAA,EACT,UAAwB;AAAA,EAExB,YAAY,OAAc;AACxB,SAAK,SAAS;AACd,UAAM,UAAU,IAAI;AAAA,EACtB;AAAA,EAEA,gBAAgB,QAAsB;AACpC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EAChC;AAAA,EAEA,CAAC,MAAM,KAA2C;AAChD,SAAK,QAAQ,YAAA;AACb,eAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,UAAI,SAAS,SAAS;AACpB,cAAM;AACN;AAAA,MACF;AACA,UAAI,KAAK,QAAQ,OAAO,MAAM,KAAK,GAAG;AACpC,cAAM;AAAA,MACR;AAAA,IACF;AACA,SAAK,QAAQ,UAAA;AAAA,EACf;AAAA,EAEA,CAAC,QAAQ,KAAiC;AACxC,SAAK,QAAQ,YAAA;AACb,eAAW,QAAQ,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC3C,UAAI,KAAK,QAAQ,OAAO,MAAM,IAAI,GAAG;AACnC,cAAM;AAAA,MACR,OAAO;AACL,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AACA,SAAK,QAAQ,UAAA;AAAA,EACf;AACF;AAEO,MAAM,UAAyC;AAAA,EAC3C;AAAA,EACA;AAAA,EAET,UAAkB;AAAA,EAElB,YAAY,OAAoB,OAAoB;AAClD,SAAK,SAAS;AACd,SAAK,SAAS;AACd,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,CAAC,MAAM,KAA2C;AAChD,eAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,cAAc;AAAA,EAAC;AAAA,EACf,YAAY;AAAA,EAAC;AAAA,EAEb,CAAC,QAAQ,KAAiC;AACxC,eAAW,QAAQ,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC3C,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,OAAO,OAAa,UAAmB;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAAgB;AACxB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EAChC;AACF;AAEO,SAAS,oBACd,OACA,UACA,UACO;AACP,QAAM,cAAc,IAAI,YAAY,KAAK;AACzC,WAAS,QAAQ,OAAO,WAAW;AACnC,QAAM,SAAS,SAAS,WAAW;AACnC,WAAS,QAAQ,aAAa,MAAM;AACpC,QAAM,YAAY,IAAI,UAAU,aAAa,MAAM;AACnD,WAAS,QAAQ,QAAQ,SAAS;AAClC,SAAO;AACT;"}
@@ -11,6 +11,8 @@ import type { SourceSchema } from './schema.ts';
11
11
  export declare class Filter implements FilterOperator {
12
12
  #private;
13
13
  constructor(input: FilterInput, predicate: (row: Row) => boolean);
14
+ beginFilter(): void;
15
+ endFilter(): void;
14
16
  filter(node: Node, cleanup: boolean): boolean;
15
17
  setFilterOutput(output: FilterOutput): void;
16
18
  destroy(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAM/B,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO;IAMhE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAI7C,eAAe,CAAC,MAAM,EAAE,YAAY;IAIpC,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;CAGpB"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAM/B,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO;IAMhE,WAAW,IAAI,IAAI;IAEnB,SAAS,IAAI,IAAI;IAEjB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAI7C,eAAe,CAAC,MAAM,EAAE,YAAY;IAIpC,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;CAGpB"}
@@ -10,6 +10,10 @@ class Filter {
10
10
  this.#predicate = predicate;
11
11
  input.setFilterOutput(this);
12
12
  }
13
+ beginFilter() {
14
+ }
15
+ endFilter() {
16
+ }
13
17
  filter(node, cleanup) {
14
18
  return this.#predicate(node.row) && this.#output.filter(node, cleanup);
15
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sources":["../../../../../zql/src/ivm/filter.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport {filterPush} from './filter-push.ts';\nimport {type Node} from './data.ts';\nimport type {SourceSchema} from './schema.ts';\n\n/**\n * The Filter operator filters data through a predicate. It is stateless.\n *\n * The predicate must be pure.\n */\nexport class Filter implements FilterOperator {\n readonly #input: FilterInput;\n readonly #predicate: (row: Row) => boolean;\n\n #output: FilterOutput = throwFilterOutput;\n\n constructor(input: FilterInput, predicate: (row: Row) => boolean) {\n this.#input = input;\n this.#predicate = predicate;\n input.setFilterOutput(this);\n }\n\n filter(node: Node, cleanup: boolean): boolean {\n return this.#predicate(node.row) && this.#output.filter(node, cleanup);\n }\n\n setFilterOutput(output: FilterOutput) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n filterPush(change, this.#output, this, this.#predicate);\n }\n}\n"],"names":[],"mappings":";;;AAiBO,MAAM,OAAiC;AAAA,EACnC;AAAA,EACA;AAAA,EAET,UAAwB;AAAA,EAExB,YAAY,OAAoB,WAAkC;AAChE,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,OAAO,MAAY,SAA2B;AAC5C,WAAO,KAAK,WAAW,KAAK,GAAG,KAAK,KAAK,QAAQ,OAAO,MAAM,OAAO;AAAA,EACvE;AAAA,EAEA,gBAAgB,QAAsB;AACpC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,eAAW,QAAQ,KAAK,SAAS,MAAM,KAAK,UAAU;AAAA,EACxD;AACF;"}
1
+ {"version":3,"file":"filter.js","sources":["../../../../../zql/src/ivm/filter.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport {filterPush} from './filter-push.ts';\nimport {type Node} from './data.ts';\nimport type {SourceSchema} from './schema.ts';\n\n/**\n * The Filter operator filters data through a predicate. It is stateless.\n *\n * The predicate must be pure.\n */\nexport class Filter implements FilterOperator {\n readonly #input: FilterInput;\n readonly #predicate: (row: Row) => boolean;\n\n #output: FilterOutput = throwFilterOutput;\n\n constructor(input: FilterInput, predicate: (row: Row) => boolean) {\n this.#input = input;\n this.#predicate = predicate;\n input.setFilterOutput(this);\n }\n\n beginFilter(): void {}\n\n endFilter(): void {}\n\n filter(node: Node, cleanup: boolean): boolean {\n return this.#predicate(node.row) && this.#output.filter(node, cleanup);\n }\n\n setFilterOutput(output: FilterOutput) {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n push(change: Change) {\n filterPush(change, this.#output, this, this.#predicate);\n }\n}\n"],"names":[],"mappings":";;;AAiBO,MAAM,OAAiC;AAAA,EACnC;AAAA,EACA;AAAA,EAET,UAAwB;AAAA,EAExB,YAAY,OAAoB,WAAkC;AAChE,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AAAA,EAEA,cAAoB;AAAA,EAAC;AAAA,EAErB,YAAkB;AAAA,EAAC;AAAA,EAEnB,OAAO,MAAY,SAA2B;AAC5C,WAAO,KAAK,WAAW,KAAK,GAAG,KAAK,KAAK,QAAQ,OAAO,MAAM,OAAO;AAAA,EACvE;AAAA,EAEA,gBAAgB,QAAsB;AACpC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,KAAK,QAAgB;AACnB,eAAW,QAAQ,KAAK,SAAS,MAAM,KAAK,UAAU;AAAA,EACxD;AACF;"}
@@ -26,7 +26,7 @@ export declare class FlippedJoin implements Input {
26
26
  destroy(): void;
27
27
  setOutput(output: Output): void;
28
28
  getSchema(): SourceSchema;
29
- fetch(req: FetchRequest): Stream<Node>;
29
+ fetch(req: FetchRequest): Stream<Node | 'yield'>;
30
30
  cleanup(_req: FetchRequest): Stream<Node>;
31
31
  }
32
32
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"flipped-join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAI3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,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,EAAQ,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAE/C,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,KAAK;;gBAY3B,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;IAQxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAkLtC,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAkK3C"}
1
+ {"version":3,"file":"flipped-join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAI3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAQ,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAE/C,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,KAAK;;gBAY3B,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;IAQxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAmMhD,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAkK3C"}
@@ -2,8 +2,8 @@ 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 { constraintsAreCompatible } from "./constraint.js";
5
- import { isJoinMatch, generateWithOverlay, rowEqualsForCompoundKey } from "./join-utils.js";
6
- import { throwOutput } from "./operator.js";
5
+ import { isJoinMatch, generateWithOverlayNoYield, rowEqualsForCompoundKey } from "./join-utils.js";
6
+ import { throwOutput, skipYields } from "./operator.js";
7
7
  import { first } from "./stream.js";
8
8
  class FlippedJoin {
9
9
  #parent;
@@ -79,11 +79,16 @@ class FlippedJoin {
79
79
  }
80
80
  }
81
81
  }
82
- const childNodes = [
83
- ...this.#child.fetch(
84
- hasChildConstraint ? { constraint: childConstraint } : {}
85
- )
86
- ];
82
+ const childNodes = [];
83
+ for (const node of this.#child.fetch(
84
+ hasChildConstraint ? { constraint: childConstraint } : {}
85
+ )) {
86
+ if (node === "yield") {
87
+ yield node;
88
+ continue;
89
+ }
90
+ childNodes.push(node);
91
+ }
87
92
  if (this.#inprogressChildChange?.change.type === "remove") {
88
93
  const removedNode = this.#inprogressChildChange.change.node;
89
94
  const compare = this.#child.getSchema().compareRows;
@@ -118,7 +123,11 @@ class FlippedJoin {
118
123
  const nextParentNodes = [];
119
124
  for (let i = 0; i < parentIterators.length; i++) {
120
125
  const iter = parentIterators[i];
121
- const result = iter.next();
126
+ let result = iter.next();
127
+ while (!result.done && result.value === "yield") {
128
+ yield result.value;
129
+ result = iter.next();
130
+ }
122
131
  nextParentNodes[i] = result.done ? null : result.value;
123
132
  }
124
133
  while (true) {
@@ -149,7 +158,11 @@ class FlippedJoin {
149
158
  for (const minParentNodeChildIndex of minParentNodeChildIndexes) {
150
159
  relatedChildNodes.push(childNodes[minParentNodeChildIndex]);
151
160
  const iter = parentIterators[minParentNodeChildIndex];
152
- const result = iter.next();
161
+ let result = iter.next();
162
+ while (!result.done && result.value === "yield") {
163
+ yield result.value;
164
+ result = iter.next();
165
+ }
153
166
  nextParentNodes[minParentNodeChildIndex] = result.done ? null : result.value;
154
167
  }
155
168
  let overlaidRelatedChildNodes = relatedChildNodes;
@@ -171,7 +184,7 @@ class FlippedJoin {
171
184
  }
172
185
  } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {
173
186
  overlaidRelatedChildNodes = [
174
- ...generateWithOverlay(
187
+ ...generateWithOverlayNoYield(
175
188
  relatedChildNodes,
176
189
  this.#inprogressChildChange.change,
177
190
  this.#child.getSchema()
@@ -226,7 +239,7 @@ class FlippedJoin {
226
239
  ])
227
240
  )
228
241
  });
229
- for (const parentNode of parentNodeStream) {
242
+ for (const parentNode of skipYields(parentNodeStream)) {
230
243
  this.#inprogressChildChange = {
231
244
  change,
232
245
  position: parentNode.row
@@ -240,7 +253,7 @@ class FlippedJoin {
240
253
  )
241
254
  });
242
255
  if (!exists) {
243
- for (const childNode of childNodeStream()) {
256
+ for (const childNode of skipYields(childNodeStream())) {
244
257
  if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
245
258
  exists = true;
246
259
  break;
@@ -320,7 +333,7 @@ class FlippedJoin {
320
333
  [this.#relationshipName]: childNodeStream(node)
321
334
  }
322
335
  });
323
- if (first(childNodeStream(change.node)()) === void 0) {
336
+ if (first(skipYields(childNodeStream(change.node)())) === void 0) {
324
337
  return;
325
338
  }
326
339
  switch (change.type) {
@@ -1 +1 @@
1
- {"version":3,"file":"flipped-join.js","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 {Writable} from '../../../shared/src/writable.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, type Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlay,\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 {first, 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> {\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 const childNodes = [\n ...this.#child.fetch(\n hasChildConstraint ? {constraint: childConstraint} : {},\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>[] = [];\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: Writable<Constraint> = {};\n for (let i = 0; i < this.#parentKey.length; i++) {\n constraintFromChild[this.#parentKey[i]] =\n childNode.row[this.#childKey[i]];\n }\n if (\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 const result = iter.next();\n nextParentNodes[i] = result.done ? null : result.value;\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 const result = iter.next();\n nextParentNodes[minParentNodeChildIndex] = result.done\n ? null\n : result.value;\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 ...generateWithOverlay(\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 *cleanup(_req: FetchRequest): Stream<Node> {}\n\n #pushChild(change: Change): void {\n const pushChildChange = (exists?: boolean) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const parentNodeStream = this.#parent.fetch({\n constraint: Object.fromEntries(\n this.#parentKey.map((key, i) => [\n key,\n change.node.row[this.#childKey[i]],\n ]),\n ),\n });\n for (const parentNode of parentNodeStream) {\n this.#inprogressChildChange = {\n change,\n position: parentNode.row,\n };\n const childNodeStream = () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [\n key,\n parentNode.row[this.#parentKey[i]],\n ]),\n ),\n });\n if (!exists) {\n for (const childNode of childNodeStream()) {\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 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 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 switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange();\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 pushChildChange(true);\n break;\n }\n case 'child':\n pushChildChange(true);\n break;\n }\n }\n\n #pushParent(change: Change): void {\n const childNodeStream = (node: Node) => () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]]),\n ),\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 if (first(childNodeStream(change.node)()) === undefined) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n 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 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"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"flipped-join.js","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 {Writable} from '../../../shared/src/writable.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, type Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlayNoYield,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, 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: Writable<Constraint> = {};\n for (let i = 0; i < this.#parentKey.length; i++) {\n constraintFromChild[this.#parentKey[i]] =\n childNode.row[this.#childKey[i]];\n }\n if (\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 *cleanup(_req: FetchRequest): Stream<Node> {}\n\n #pushChild(change: Change): void {\n const pushChildChange = (exists?: boolean) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const parentNodeStream = this.#parent.fetch({\n constraint: Object.fromEntries(\n this.#parentKey.map((key, i) => [\n key,\n change.node.row[this.#childKey[i]],\n ]),\n ),\n });\n for (const parentNode of skipYields(parentNodeStream)) {\n this.#inprogressChildChange = {\n change,\n position: parentNode.row,\n };\n const childNodeStream = () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [\n key,\n parentNode.row[this.#parentKey[i]],\n ]),\n ),\n });\n if (!exists) {\n for (const childNode of skipYields(childNodeStream())) {\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 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 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 switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange();\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 pushChildChange(true);\n break;\n }\n case 'child':\n pushChildChange(true);\n break;\n }\n }\n\n #pushParent(change: Change): void {\n const childNodeStream = (node: Node) => () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]]),\n ),\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 if (first(skipYields(childNodeStream(change.node)())) === undefined) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n 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 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"],"names":[],"mappings":"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"}
@@ -8,7 +8,8 @@ export type JoinChangeOverlay = {
8
8
  change: Change;
9
9
  position: Row | undefined;
10
10
  };
11
- export declare function generateWithOverlay(stream: Stream<Node>, overlay: Change, schema: SourceSchema): Stream<Node>;
11
+ export declare function generateWithOverlayNoYield(stream: Stream<Node>, overlay: Change, schema: SourceSchema): Stream<Node>;
12
+ export declare function generateWithOverlay(stream: Stream<Node | 'yield'>, overlay: Change, schema: SourceSchema): Stream<Node | 'yield'>;
12
13
  export declare function rowEqualsForCompoundKey(a: Row, b: Row, key: CompoundKey): boolean;
13
14
  export declare function isJoinMatch(parent: Row, parentKey: CompoundKey, child: Row, childKey: CompoundKey): boolean;
14
15
  //# sourceMappingURL=join-utils.d.ts.map
@@ -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,EAAC,MAAM,oCAAoC,CAAC;AAC5D,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,wBAAiB,mBAAmB,CAClC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,IAAI,CAAC,CAmFd;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"}
1
+ {"version":3,"file":"join-utils.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,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,CAuFxB;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"}
@@ -1,10 +1,17 @@
1
1
  import { compareValues, valuesEqual } from "./data.js";
2
2
  import { assert } from "../../../shared/src/asserts.js";
3
+ function generateWithOverlayNoYield(stream, overlay, schema) {
4
+ return generateWithOverlay(stream, overlay, schema);
5
+ }
3
6
  function* generateWithOverlay(stream, overlay, schema) {
4
7
  let applied = false;
5
8
  let editOldApplied = false;
6
9
  let editNewApplied = false;
7
10
  for (const node of stream) {
11
+ if (node === "yield") {
12
+ yield node;
13
+ continue;
14
+ }
8
15
  let yieldNode = true;
9
16
  if (!applied) {
10
17
  switch (overlay.type) {
@@ -94,6 +101,7 @@ function isJoinMatch(parent, parentKey, child, childKey) {
94
101
  }
95
102
  export {
96
103
  generateWithOverlay,
104
+ generateWithOverlayNoYield,
97
105
  isJoinMatch,
98
106
  rowEqualsForCompoundKey
99
107
  };
@@ -1 +1 @@
1
- {"version":3,"file":"join-utils.js","sources":["../../../../../zql/src/ivm/join-utils.ts"],"sourcesContent":["import type {Row} 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* generateWithOverlay(\n stream: Stream<Node>,\n overlay: Change,\n schema: SourceSchema,\n): Stream<Node> {\n let applied = false;\n let editOldApplied = false;\n let editNewApplied = false;\n for (const node of stream) {\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(editNewApplied);\n editOldApplied = true;\n applied = true;\n yield overlay.oldNode;\n }\n }\n\n assert(applied);\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"],"names":[],"mappings":";;AAaO,UAAU,oBACf,QACA,SACA,QACc;AACd,MAAI,UAAU;AACd,MAAI,iBAAiB;AACrB,MAAI,iBAAiB;AACrB,aAAW,QAAQ,QAAQ;AACzB,QAAI,YAAY;AAChB,QAAI,CAAC,SAAS;AACZ,cAAQ,QAAQ,MAAA;AAAA,QACd,KAAK,OAAO;AACV,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GAAG;AACxD,sBAAU;AACV,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,QACA,KAAK,UAAU;AACb,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,IAAI,GAAG;AACtD,sBAAU;AACV,kBAAM,QAAQ;AAAA,UAChB;AACA;AAAA,QACF;AAAA,QACA,KAAK,QAAQ;AACX,cACE,CAAC,kBACD,OAAO,YAAY,QAAQ,QAAQ,KAAK,KAAK,GAAG,IAAI,GACpD;AACA,6BAAiB;AACjB,gBAAI,gBAAgB;AAClB,wBAAU;AAAA,YACZ;AACA,kBAAM,QAAQ;AAAA,UAChB;AACA,cACE,CAAC,kBACD,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GACnD;AACA,6BAAiB;AACjB,gBAAI,gBAAgB;AAClB,wBAAU;AAAA,YACZ;AACA,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,QACA,KAAK,SAAS;AACZ,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GAAG;AACxD,sBAAU;AACV,kBAAM;AAAA,cACJ,KAAK,KAAK;AAAA,cACV,eAAe;AAAA,gBACb,GAAG,KAAK;AAAA,gBACR,CAAC,QAAQ,MAAM,gBAAgB,GAAG,MAChC;AAAA,kBACE,KAAK,cAAc,QAAQ,MAAM,gBAAgB,EAAA;AAAA,kBACjD,QAAQ,MAAM;AAAA,kBACd,OAAO,cAAc,QAAQ,MAAM,gBAAgB;AAAA,gBAAA;AAAA,cACrD;AAAA,YACJ;AAEF,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI,WAAW;AACb,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,QAAI,QAAQ,SAAS,UAAU;AAC7B,gBAAU;AACV,YAAM,QAAQ;AAAA,IAChB,WAAW,QAAQ,SAAS,QAAQ;AAClC,aAAO,cAAc;AACrB,uBAAiB;AACjB,gBAAU;AACV,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAEO,SAAS,wBACd,GACA,GACA,KACS;AACT,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,QAAI,cAAc,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG;AAC7C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,YACd,QACA,WACA,OACA,UACA;AACA,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,QAAI,CAAC,YAAY,OAAO,UAAU,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,GAAG;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"join-utils.js","sources":["../../../../../zql/src/ivm/join-utils.ts"],"sourcesContent":["import type {Row} 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(editNewApplied);\n editOldApplied = true;\n applied = true;\n yield overlay.oldNode;\n }\n }\n\n assert(applied);\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"],"names":[],"mappings":";;AAaO,SAAS,2BACd,QACA,SACA,QACc;AACd,SAAO,oBAAoB,QAAQ,SAAS,MAAM;AACpD;AAEO,UAAU,oBACf,QACA,SACA,QACwB;AACxB,MAAI,UAAU;AACd,MAAI,iBAAiB;AACrB,MAAI,iBAAiB;AACrB,aAAW,QAAQ,QAAQ;AACzB,QAAI,SAAS,SAAS;AACpB,YAAM;AACN;AAAA,IACF;AACA,QAAI,YAAY;AAChB,QAAI,CAAC,SAAS;AACZ,cAAQ,QAAQ,MAAA;AAAA,QACd,KAAK,OAAO;AACV,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GAAG;AACxD,sBAAU;AACV,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,QACA,KAAK,UAAU;AACb,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,IAAI,GAAG;AACtD,sBAAU;AACV,kBAAM,QAAQ;AAAA,UAChB;AACA;AAAA,QACF;AAAA,QACA,KAAK,QAAQ;AACX,cACE,CAAC,kBACD,OAAO,YAAY,QAAQ,QAAQ,KAAK,KAAK,GAAG,IAAI,GACpD;AACA,6BAAiB;AACjB,gBAAI,gBAAgB;AAClB,wBAAU;AAAA,YACZ;AACA,kBAAM,QAAQ;AAAA,UAChB;AACA,cACE,CAAC,kBACD,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GACnD;AACA,6BAAiB;AACjB,gBAAI,gBAAgB;AAClB,wBAAU;AAAA,YACZ;AACA,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,QACA,KAAK,SAAS;AACZ,cAAI,OAAO,YAAY,QAAQ,KAAK,KAAK,KAAK,GAAG,MAAM,GAAG;AACxD,sBAAU;AACV,kBAAM;AAAA,cACJ,KAAK,KAAK;AAAA,cACV,eAAe;AAAA,gBACb,GAAG,KAAK;AAAA,gBACR,CAAC,QAAQ,MAAM,gBAAgB,GAAG,MAChC;AAAA,kBACE,KAAK,cAAc,QAAQ,MAAM,gBAAgB,EAAA;AAAA,kBACjD,QAAQ,MAAM;AAAA,kBACd,OAAO,cAAc,QAAQ,MAAM,gBAAgB;AAAA,gBAAA;AAAA,cACrD;AAAA,YACJ;AAEF,wBAAY;AAAA,UACd;AACA;AAAA,QACF;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI,WAAW;AACb,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,QAAI,QAAQ,SAAS,UAAU;AAC7B,gBAAU;AACV,YAAM,QAAQ;AAAA,IAChB,WAAW,QAAQ,SAAS,QAAQ;AAClC,aAAO,cAAc;AACrB,uBAAiB;AACjB,gBAAU;AACV,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAEO,SAAS,wBACd,GACA,GACA,KACS;AACT,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,QAAI,cAAc,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG;AAC7C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,YACd,QACA,WACA,OACA,UACA;AACA,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,QAAI,CAAC,YAAY,OAAO,UAAU,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,GAAG;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;"}
@@ -31,7 +31,7 @@ export declare class Join implements Input {
31
31
  destroy(): void;
32
32
  setOutput(output: Output): void;
33
33
  getSchema(): SourceSchema;
34
- fetch(req: FetchRequest): Stream<Node>;
34
+ fetch(req: FetchRequest): Stream<Node | 'yield'>;
35
35
  cleanup(req: FetchRequest): Stream<Node>;
36
36
  }
37
37
  /** Exported for testing. */
@@ -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;AAC3E,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAE1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAO,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IAEjB,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,OAAO,EACP,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAmCP,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,CAAC;IAUtC,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAoO1C;AAID,4BAA4B;AAC5B,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAGxE;AAED,4BAA4B;AAC5B,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAEvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,GAAG,GACP,MAAM,CAMR"}
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;AAC3E,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAE1E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAO,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IAEjB,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,OAAO,EACP,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAmCP,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;IAchD,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;CAyO1C;AAID,4BAA4B;AAC5B,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAGxE;AAED,4BAA4B;AAC5B,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAEvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,GAAG,GACP,MAAM,CAMR"}
@@ -1,6 +1,6 @@
1
1
  import { assert, unreachable } from "../../../shared/src/asserts.js";
2
2
  import { rowEqualsForCompoundKey, isJoinMatch, generateWithOverlay } from "./join-utils.js";
3
- import { throwOutput } from "./operator.js";
3
+ import { throwOutput, skipYields } from "./operator.js";
4
4
  import { take } from "./stream.js";
5
5
  class Join {
6
6
  #parent;
@@ -65,6 +65,10 @@ class Join {
65
65
  }
66
66
  *fetch(req) {
67
67
  for (const parentNode of this.#parent.fetch(req)) {
68
+ if (parentNode === "yield") {
69
+ yield parentNode;
70
+ continue;
71
+ }
68
72
  yield this.#processParentNode(
69
73
  parentNode.row,
70
74
  parentNode.relationships,
@@ -161,11 +165,16 @@ class Join {
161
165
  position: void 0
162
166
  };
163
167
  try {
164
- const parentNodes = this.#parent.fetch({
165
- constraint: Object.fromEntries(
166
- this.#parentKey.map((key, i) => [key, childRow[this.#childKey[i]]])
167
- )
168
- });
168
+ const parentNodes = skipYields(
169
+ this.#parent.fetch({
170
+ constraint: Object.fromEntries(
171
+ this.#parentKey.map((key, i) => [
172
+ key,
173
+ childRow[this.#childKey[i]]
174
+ ])
175
+ )
176
+ })
177
+ );
169
178
  for (const parentNode of parentNodes) {
170
179
  this.#inprogressChildChange.position = parentNode.row;
171
180
  const childChange = {