@rocicorp/zero 0.25.0-canary.13 → 0.25.0-canary.15

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 (169) hide show
  1. package/out/shared/src/record-proxy.d.ts +13 -0
  2. package/out/shared/src/record-proxy.d.ts.map +1 -0
  3. package/out/shared/src/record-proxy.js +59 -0
  4. package/out/shared/src/record-proxy.js.map +1 -0
  5. package/out/zero/package.json.js +1 -1
  6. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  7. package/out/zero-cache/src/auth/write-authorizer.js +20 -13
  8. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  9. package/out/zero-cache/src/config/zero-config.d.ts +8 -0
  10. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  11. package/out/zero-cache/src/config/zero-config.js +12 -0
  12. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  13. package/out/zero-cache/src/server/otel-start.d.ts.map +1 -1
  14. package/out/zero-cache/src/server/otel-start.js +1 -5
  15. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  16. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  17. package/out/zero-cache/src/server/syncer.js +6 -1
  18. package/out/zero-cache/src/server/syncer.js.map +1 -1
  19. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +8 -9
  20. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  21. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +17 -11
  22. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  23. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +2 -2
  24. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  25. package/out/zero-cache/src/services/view-syncer/snapshotter.js +19 -4
  26. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  27. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  28. package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -7
  29. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  30. package/out/zero-client/src/client/crud.d.ts +3 -3
  31. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  32. package/out/zero-client/src/client/crud.js +23 -13
  33. package/out/zero-client/src/client/crud.js.map +1 -1
  34. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  35. package/out/zero-client/src/client/custom.js +4 -11
  36. package/out/zero-client/src/client/custom.js.map +1 -1
  37. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  38. package/out/zero-client/src/client/ivm-branch.js +20 -13
  39. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  40. package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
  41. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
  42. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  43. package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -1
  44. package/out/zero-client/src/client/make-replicache-mutators.js +10 -6
  45. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  46. package/out/zero-client/src/client/version.js +1 -1
  47. package/out/zero-client/src/client/zero.js +1 -1
  48. package/out/zero-client/src/client/zero.js.map +1 -1
  49. package/out/zero-server/src/custom.d.ts +2 -2
  50. package/out/zero-server/src/custom.d.ts.map +1 -1
  51. package/out/zero-server/src/custom.js +52 -32
  52. package/out/zero-server/src/custom.js.map +1 -1
  53. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  54. package/out/zero-server/src/zql-database.js +1 -5
  55. package/out/zero-server/src/zql-database.js.map +1 -1
  56. package/out/zero-solid/src/solid-view.d.ts +1 -1
  57. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  58. package/out/zero-solid/src/solid-view.js +2 -0
  59. package/out/zero-solid/src/solid-view.js.map +1 -1
  60. package/out/zero-types/src/schema.d.ts +4 -4
  61. package/out/zql/src/builder/builder.d.ts.map +1 -1
  62. package/out/zql/src/builder/builder.js +1 -11
  63. package/out/zql/src/builder/builder.js.map +1 -1
  64. package/out/zql/src/error.js +1 -10
  65. package/out/zql/src/error.js.map +1 -1
  66. package/out/zql/src/ivm/array-view.d.ts +1 -1
  67. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  68. package/out/zql/src/ivm/array-view.js +2 -0
  69. package/out/zql/src/ivm/array-view.js.map +1 -1
  70. package/out/zql/src/ivm/exists.d.ts +3 -2
  71. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  72. package/out/zql/src/ivm/exists.js +25 -23
  73. package/out/zql/src/ivm/exists.js.map +1 -1
  74. package/out/zql/src/ivm/fan-in.d.ts +3 -3
  75. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  76. package/out/zql/src/ivm/fan-in.js +6 -5
  77. package/out/zql/src/ivm/fan-in.js.map +1 -1
  78. package/out/zql/src/ivm/fan-out.d.ts +2 -2
  79. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  80. package/out/zql/src/ivm/fan-out.js +5 -5
  81. package/out/zql/src/ivm/fan-out.js.map +1 -1
  82. package/out/zql/src/ivm/filter-operators.d.ts +5 -5
  83. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  84. package/out/zql/src/ivm/filter-operators.js +8 -8
  85. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  86. package/out/zql/src/ivm/filter-push.d.ts +2 -1
  87. package/out/zql/src/ivm/filter-push.d.ts.map +1 -1
  88. package/out/zql/src/ivm/filter-push.js +5 -5
  89. package/out/zql/src/ivm/filter-push.js.map +1 -1
  90. package/out/zql/src/ivm/filter.d.ts +2 -2
  91. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  92. package/out/zql/src/ivm/filter.js +4 -4
  93. package/out/zql/src/ivm/filter.js.map +1 -1
  94. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  95. package/out/zql/src/ivm/flipped-join.js +100 -83
  96. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  97. package/out/zql/src/ivm/join.d.ts.map +1 -1
  98. package/out/zql/src/ivm/join.js +52 -50
  99. package/out/zql/src/ivm/join.js.map +1 -1
  100. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  101. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  102. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +4 -4
  103. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  104. package/out/zql/src/ivm/memory-source.d.ts +3 -3
  105. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  106. package/out/zql/src/ivm/memory-source.js +7 -4
  107. package/out/zql/src/ivm/memory-source.js.map +1 -1
  108. package/out/zql/src/ivm/operator.d.ts +10 -3
  109. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  110. package/out/zql/src/ivm/operator.js.map +1 -1
  111. package/out/zql/src/ivm/push-accumulated.d.ts +1 -1
  112. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  113. package/out/zql/src/ivm/push-accumulated.js +8 -8
  114. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  115. package/out/zql/src/ivm/skip.d.ts +1 -1
  116. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  117. package/out/zql/src/ivm/skip.js +8 -3
  118. package/out/zql/src/ivm/skip.js.map +1 -1
  119. package/out/zql/src/ivm/source.d.ts +15 -7
  120. package/out/zql/src/ivm/source.d.ts.map +1 -1
  121. package/out/zql/src/ivm/stream.d.ts +2 -0
  122. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  123. package/out/zql/src/ivm/stream.js +5 -14
  124. package/out/zql/src/ivm/stream.js.map +1 -1
  125. package/out/zql/src/ivm/take.d.ts +1 -1
  126. package/out/zql/src/ivm/take.d.ts.map +1 -1
  127. package/out/zql/src/ivm/take.js +164 -147
  128. package/out/zql/src/ivm/take.js.map +1 -1
  129. package/out/zql/src/ivm/union-fan-in.d.ts +2 -2
  130. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  131. package/out/zql/src/ivm/union-fan-in.js +7 -7
  132. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  133. package/out/zql/src/ivm/union-fan-out.d.ts +1 -1
  134. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  135. package/out/zql/src/ivm/union-fan-out.js +3 -3
  136. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  137. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  138. package/out/zql/src/mutate/mutator-registry.js +1 -0
  139. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  140. package/out/zql/src/mutate/mutator.d.ts +10 -0
  141. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  142. package/out/zql/src/mutate/mutator.js.map +1 -1
  143. package/out/zql/src/planner/planner-builder.d.ts +2 -1
  144. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  145. package/out/zql/src/planner/planner-builder.js +5 -5
  146. package/out/zql/src/planner/planner-builder.js.map +1 -1
  147. package/out/zql/src/planner/planner-graph.d.ts +3 -1
  148. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  149. package/out/zql/src/planner/planner-graph.js +5 -5
  150. package/out/zql/src/planner/planner-graph.js.map +1 -1
  151. package/out/zql/src/query/create-builder.d.ts.map +1 -1
  152. package/out/zql/src/query/create-builder.js +7 -36
  153. package/out/zql/src/query/create-builder.js.map +1 -1
  154. package/out/zql/src/query/measure-push-operator.d.ts +1 -1
  155. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  156. package/out/zql/src/query/measure-push-operator.js +2 -2
  157. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  158. package/out/zqlite/src/internal/sql-inline.d.ts +13 -0
  159. package/out/zqlite/src/internal/sql-inline.d.ts.map +1 -0
  160. package/out/zqlite/src/internal/sql-inline.js +45 -0
  161. package/out/zqlite/src/internal/sql-inline.js.map +1 -0
  162. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  163. package/out/zqlite/src/sqlite-cost-model.js +2 -2
  164. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  165. package/out/zqlite/src/table-source.d.ts +3 -2
  166. package/out/zqlite/src/table-source.d.ts.map +1 -1
  167. package/out/zqlite/src/table-source.js +5 -2
  168. package/out/zqlite/src/table-source.js.map +1 -1
  169. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","sources":["../../../../zql/src/error.ts"],"sourcesContent":["export class NotImplementedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\nexport type PlannerExceptionKind = 'max_flippable_joins';\n\nexport class PlannerException extends Error {\n readonly kind: PlannerExceptionKind;\n\n constructor(kind: PlannerExceptionKind, message: string) {\n super(message);\n this.name = 'PlannerException';\n this.kind = kind;\n }\n}\n"],"names":[],"mappings":"AAAO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAIO,MAAM,yBAAyB,MAAM;AAAA,EACjC;AAAA,EAET,YAAY,MAA4B,SAAiB;AACvD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;"}
1
+ {"version":3,"file":"error.js","sources":["../../../../zql/src/error.ts"],"sourcesContent":["export class NotImplementedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\nexport type PlannerExceptionKind = 'max_flippable_joins';\n\nexport class PlannerException extends Error {\n readonly kind: PlannerExceptionKind;\n\n constructor(kind: PlannerExceptionKind, message: string) {\n super(message);\n this.name = 'PlannerException';\n this.kind = kind;\n }\n}\n"],"names":[],"mappings":"AAAO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;"}
@@ -22,7 +22,7 @@ export declare class ArrayView<V extends View> implements Output, TypedView<V> {
22
22
  get data(): V;
23
23
  addListener(listener: Listener<V>): () => void;
24
24
  destroy(): void;
25
- push(change: Change): void;
25
+ push(change: Change): readonly never[];
26
26
  flush(): void;
27
27
  updateTTL(ttl: TTL): void;
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"array-view.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/array-view.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAC;AACzC,OAAO,KAAK,EAAC,QAAQ,EAAc,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAa,KAAK,KAAK,EAAE,KAAK,MAAM,EAAC,MAAM,eAAe,CAAC;AAGlE,OAAO,KAAK,EAAQ,MAAM,EAAE,IAAI,EAAC,MAAM,WAAW,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,qBAAa,SAAS,CAAC,CAAC,SAAS,IAAI,CAAE,YAAW,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;;IAUpE,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;gBAQlC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,IAAI,GAAG,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,EAClD,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI;IA6B/B,IAAI,IAAI,IACmB,CAAC,CAC3B;IAED,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAqBjC,OAAO;IAkBP,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK1B,KAAK;IAQL,SAAS,CAAC,GAAG,EAAE,GAAG;CAGnB"}
1
+ {"version":3,"file":"array-view.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/array-view.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,8CAA8C,CAAC;AAC/E,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAC;AACzC,OAAO,KAAK,EAAC,QAAQ,EAAc,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAa,KAAK,KAAK,EAAE,KAAK,MAAM,EAAC,MAAM,eAAe,CAAC;AAGlE,OAAO,KAAK,EAAQ,MAAM,EAAE,IAAI,EAAC,MAAM,WAAW,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,qBAAa,SAAS,CAAC,CAAC,SAAS,IAAI,CAAE,YAAW,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;;IAUpE,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;gBAQlC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,IAAI,GAAG,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,EAClD,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI;IA6B/B,IAAI,IAAI,IACmB,CAAC,CAC3B;IAED,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAqBjC,OAAO;IAkBP,IAAI,CAAC,MAAM,EAAE,MAAM;IAMnB,KAAK;IAQL,SAAS,CAAC,GAAG,EAAE,GAAG;CAGnB"}
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../../../shared/src/asserts.js";
2
+ import { emptyArray } from "../../../shared/src/sentinels.js";
2
3
  import { skipYields } from "./operator.js";
3
4
  import { applyChange } from "./view-apply-change.js";
4
5
  class ArrayView {
@@ -76,6 +77,7 @@ class ArrayView {
76
77
  push(change) {
77
78
  this.#dirty = true;
78
79
  applyChange(this.#root, change, this.#schema, "", this.#format);
80
+ return emptyArray;
79
81
  }
80
82
  flush() {
81
83
  if (!this.#dirty) {
@@ -1 +1 @@
1
- {"version":3,"file":"array-view.js","sources":["../../../../../zql/src/ivm/array-view.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Immutable} from '../../../shared/src/immutable.ts';\nimport type {ErroredQuery} from '../../../zero-protocol/src/custom-queries.ts';\nimport type {TTL} from '../query/ttl.ts';\nimport type {Listener, ResultType, TypedView} from '../query/typed-view.ts';\nimport type {Change} from './change.ts';\nimport {skipYields, type Input, type Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {applyChange} from './view-apply-change.ts';\nimport type {Entry, Format, View} from './view.ts';\n\n/**\n * Implements a materialized view of the output of an operator.\n *\n * It might seem more efficient to use an immutable b-tree for the\n * materialization, but it's not so clear. Inserts in the middle are\n * asymptotically slower in an array, but can often be done with zero\n * allocations, where changes to the b-tree will often require several allocs.\n *\n * Also the plain array view is more convenient for consumers since you can dump\n * it into console to see what it is, rather than having to iterate it.\n */\nexport class ArrayView<V extends View> implements Output, TypedView<V> {\n readonly #input: Input;\n readonly #listeners = new Set<Listener<V>>();\n readonly #schema: SourceSchema;\n readonly #format: Format;\n\n // Synthetic \"root\" entry that has a single \"\" relationship, so that we can\n // treat all changes, including the root change, generically.\n readonly #root: Entry;\n\n onDestroy: (() => void) | undefined;\n\n #dirty = false;\n #resultType: ResultType = 'unknown';\n #error: ErroredQuery | undefined;\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n format: Format,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n this.#input = input;\n this.#schema = input.getSchema();\n this.#format = format;\n this.#updateTTL = updateTTL;\n this.#root = {'': format.singular ? undefined : []};\n input.setOutput(this);\n\n if (queryComplete === true) {\n this.#resultType = 'complete';\n } else if ('error' in queryComplete) {\n this.#resultType = 'error';\n this.#error = queryComplete;\n } else {\n void queryComplete\n .then(() => {\n this.#resultType = 'complete';\n this.#fireListeners();\n })\n .catch(e => {\n this.#resultType = 'error';\n this.#error = e;\n this.#fireListeners();\n });\n }\n this.#hydrate();\n }\n\n get data() {\n return this.#root[''] as V;\n }\n\n addListener(listener: Listener<V>) {\n assert(!this.#listeners.has(listener), 'Listener already registered');\n this.#listeners.add(listener);\n\n this.#fireListener(listener);\n\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n #fireListeners() {\n for (const listener of this.#listeners) {\n this.#fireListener(listener);\n }\n }\n\n #fireListener(listener: Listener<V>) {\n listener(this.data as Immutable<V>, this.#resultType, this.#error);\n }\n\n destroy() {\n this.onDestroy?.();\n }\n\n #hydrate() {\n this.#dirty = true;\n for (const node of skipYields(this.#input.fetch({}))) {\n applyChange(\n this.#root,\n {type: 'add', node},\n this.#schema,\n '',\n this.#format,\n );\n }\n this.flush();\n }\n\n push(change: Change): void {\n this.#dirty = true;\n applyChange(this.#root, change, this.#schema, '', this.#format);\n }\n\n flush() {\n if (!this.#dirty) {\n return;\n }\n this.#dirty = false;\n this.#fireListeners();\n }\n\n updateTTL(ttl: TTL) {\n this.#updateTTL(ttl);\n }\n}\n"],"names":[],"mappings":";;;AAsBO,MAAM,UAA0D;AAAA,EAC5D;AAAA,EACA,iCAAiB,IAAA;AAAA,EACjB;AAAA,EACA;AAAA;AAAA;AAAA,EAIA;AAAA,EAET;AAAA,EAEA,SAAS;AAAA,EACT,cAA0B;AAAA,EAC1B;AAAA,EACS;AAAA,EAET,YACE,OACA,QACA,eACA,WACA;AACA,SAAK,SAAS;AACd,SAAK,UAAU,MAAM,UAAA;AACrB,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,QAAQ,EAAC,IAAI,OAAO,WAAW,SAAY,GAAC;AACjD,UAAM,UAAU,IAAI;AAEpB,QAAI,kBAAkB,MAAM;AAC1B,WAAK,cAAc;AAAA,IACrB,WAAW,WAAW,eAAe;AACnC,WAAK,cAAc;AACnB,WAAK,SAAS;AAAA,IAChB,OAAO;AACL,WAAK,cACF,KAAK,MAAM;AACV,aAAK,cAAc;AACnB,aAAK,eAAA;AAAA,MACP,CAAC,EACA,MAAM,CAAA,MAAK;AACV,aAAK,cAAc;AACnB,aAAK,SAAS;AACd,aAAK,eAAA;AAAA,MACP,CAAC;AAAA,IACL;AACA,SAAK,SAAA;AAAA,EACP;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK,MAAM,EAAE;AAAA,EACtB;AAAA,EAEA,YAAY,UAAuB;AACjC,WAAO,CAAC,KAAK,WAAW,IAAI,QAAQ,GAAG,6BAA6B;AACpE,SAAK,WAAW,IAAI,QAAQ;AAE5B,SAAK,cAAc,QAAQ;AAE3B,WAAO,MAAM;AACX,WAAK,WAAW,OAAO,QAAQ;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,iBAAiB;AACf,eAAW,YAAY,KAAK,YAAY;AACtC,WAAK,cAAc,QAAQ;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,cAAc,UAAuB;AACnC,aAAS,KAAK,MAAsB,KAAK,aAAa,KAAK,MAAM;AAAA,EACnE;AAAA,EAEA,UAAU;AACR,SAAK,YAAA;AAAA,EACP;AAAA,EAEA,WAAW;AACT,SAAK,SAAS;AACd,eAAW,QAAQ,WAAW,KAAK,OAAO,MAAM,CAAA,CAAE,CAAC,GAAG;AACpD;AAAA,QACE,KAAK;AAAA,QACL,EAAC,MAAM,OAAO,KAAA;AAAA,QACd,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,MAAA;AAAA,IAET;AACA,SAAK,MAAA;AAAA,EACP;AAAA,EAEA,KAAK,QAAsB;AACzB,SAAK,SAAS;AACd,gBAAY,KAAK,OAAO,QAAQ,KAAK,SAAS,IAAI,KAAK,OAAO;AAAA,EAChE;AAAA,EAEA,QAAQ;AACN,QAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,IACF;AACA,SAAK,SAAS;AACd,SAAK,eAAA;AAAA,EACP;AAAA,EAEA,UAAU,KAAU;AAClB,SAAK,WAAW,GAAG;AAAA,EACrB;AACF;"}
1
+ {"version":3,"file":"array-view.js","sources":["../../../../../zql/src/ivm/array-view.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Immutable} from '../../../shared/src/immutable.ts';\nimport {emptyArray} from '../../../shared/src/sentinels.ts';\nimport type {ErroredQuery} from '../../../zero-protocol/src/custom-queries.ts';\nimport type {TTL} from '../query/ttl.ts';\nimport type {Listener, ResultType, TypedView} from '../query/typed-view.ts';\nimport type {Change} from './change.ts';\nimport {skipYields, type Input, type Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {applyChange} from './view-apply-change.ts';\nimport type {Entry, Format, View} from './view.ts';\n\n/**\n * Implements a materialized view of the output of an operator.\n *\n * It might seem more efficient to use an immutable b-tree for the\n * materialization, but it's not so clear. Inserts in the middle are\n * asymptotically slower in an array, but can often be done with zero\n * allocations, where changes to the b-tree will often require several allocs.\n *\n * Also the plain array view is more convenient for consumers since you can dump\n * it into console to see what it is, rather than having to iterate it.\n */\nexport class ArrayView<V extends View> implements Output, TypedView<V> {\n readonly #input: Input;\n readonly #listeners = new Set<Listener<V>>();\n readonly #schema: SourceSchema;\n readonly #format: Format;\n\n // Synthetic \"root\" entry that has a single \"\" relationship, so that we can\n // treat all changes, including the root change, generically.\n readonly #root: Entry;\n\n onDestroy: (() => void) | undefined;\n\n #dirty = false;\n #resultType: ResultType = 'unknown';\n #error: ErroredQuery | undefined;\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n format: Format,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n this.#input = input;\n this.#schema = input.getSchema();\n this.#format = format;\n this.#updateTTL = updateTTL;\n this.#root = {'': format.singular ? undefined : []};\n input.setOutput(this);\n\n if (queryComplete === true) {\n this.#resultType = 'complete';\n } else if ('error' in queryComplete) {\n this.#resultType = 'error';\n this.#error = queryComplete;\n } else {\n void queryComplete\n .then(() => {\n this.#resultType = 'complete';\n this.#fireListeners();\n })\n .catch(e => {\n this.#resultType = 'error';\n this.#error = e;\n this.#fireListeners();\n });\n }\n this.#hydrate();\n }\n\n get data() {\n return this.#root[''] as V;\n }\n\n addListener(listener: Listener<V>) {\n assert(!this.#listeners.has(listener), 'Listener already registered');\n this.#listeners.add(listener);\n\n this.#fireListener(listener);\n\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n #fireListeners() {\n for (const listener of this.#listeners) {\n this.#fireListener(listener);\n }\n }\n\n #fireListener(listener: Listener<V>) {\n listener(this.data as Immutable<V>, this.#resultType, this.#error);\n }\n\n destroy() {\n this.onDestroy?.();\n }\n\n #hydrate() {\n this.#dirty = true;\n for (const node of skipYields(this.#input.fetch({}))) {\n applyChange(\n this.#root,\n {type: 'add', node},\n this.#schema,\n '',\n this.#format,\n );\n }\n this.flush();\n }\n\n push(change: Change) {\n this.#dirty = true;\n applyChange(this.#root, change, this.#schema, '', this.#format);\n return emptyArray;\n }\n\n flush() {\n if (!this.#dirty) {\n return;\n }\n this.#dirty = false;\n this.#fireListeners();\n }\n\n updateTTL(ttl: TTL) {\n this.#updateTTL(ttl);\n }\n}\n"],"names":[],"mappings":";;;;AAuBO,MAAM,UAA0D;AAAA,EAC5D;AAAA,EACA,iCAAiB,IAAA;AAAA,EACjB;AAAA,EACA;AAAA;AAAA;AAAA,EAIA;AAAA,EAET;AAAA,EAEA,SAAS;AAAA,EACT,cAA0B;AAAA,EAC1B;AAAA,EACS;AAAA,EAET,YACE,OACA,QACA,eACA,WACA;AACA,SAAK,SAAS;AACd,SAAK,UAAU,MAAM,UAAA;AACrB,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,QAAQ,EAAC,IAAI,OAAO,WAAW,SAAY,GAAC;AACjD,UAAM,UAAU,IAAI;AAEpB,QAAI,kBAAkB,MAAM;AAC1B,WAAK,cAAc;AAAA,IACrB,WAAW,WAAW,eAAe;AACnC,WAAK,cAAc;AACnB,WAAK,SAAS;AAAA,IAChB,OAAO;AACL,WAAK,cACF,KAAK,MAAM;AACV,aAAK,cAAc;AACnB,aAAK,eAAA;AAAA,MACP,CAAC,EACA,MAAM,CAAA,MAAK;AACV,aAAK,cAAc;AACnB,aAAK,SAAS;AACd,aAAK,eAAA;AAAA,MACP,CAAC;AAAA,IACL;AACA,SAAK,SAAA;AAAA,EACP;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK,MAAM,EAAE;AAAA,EACtB;AAAA,EAEA,YAAY,UAAuB;AACjC,WAAO,CAAC,KAAK,WAAW,IAAI,QAAQ,GAAG,6BAA6B;AACpE,SAAK,WAAW,IAAI,QAAQ;AAE5B,SAAK,cAAc,QAAQ;AAE3B,WAAO,MAAM;AACX,WAAK,WAAW,OAAO,QAAQ;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,iBAAiB;AACf,eAAW,YAAY,KAAK,YAAY;AACtC,WAAK,cAAc,QAAQ;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,cAAc,UAAuB;AACnC,aAAS,KAAK,MAAsB,KAAK,aAAa,KAAK,MAAM;AAAA,EACnE;AAAA,EAEA,UAAU;AACR,SAAK,YAAA;AAAA,EACP;AAAA,EAEA,WAAW;AACT,SAAK,SAAS;AACd,eAAW,QAAQ,WAAW,KAAK,OAAO,MAAM,CAAA,CAAE,CAAC,GAAG;AACpD;AAAA,QACE,KAAK;AAAA,QACL,EAAC,MAAM,OAAO,KAAA;AAAA,QACd,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,MAAA;AAAA,IAET;AACA,SAAK,MAAA;AAAA,EACP;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,SAAS;AACd,gBAAY,KAAK,OAAO,QAAQ,KAAK,SAAS,IAAI,KAAK,OAAO;AAC9D,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ;AACN,QAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,IACF;AACA,SAAK,SAAS;AACd,SAAK,eAAA;AAAA,EACP;AAAA,EAEA,UAAU,KAAU;AAClB,SAAK,WAAW,GAAG;AAAA,EACrB;AACF;"}
@@ -3,6 +3,7 @@ import { type Change } from './change.ts';
3
3
  import { type Node } from './data.ts';
4
4
  import { type FilterInput, type FilterOperator, type FilterOutput } from './filter-operators.ts';
5
5
  import type { SourceSchema } from './schema.ts';
6
+ import { type Stream } from './stream.ts';
6
7
  /**
7
8
  * The Exists operator filters data based on whether or not a relationship is
8
9
  * non-empty.
@@ -13,9 +14,9 @@ export declare class Exists implements FilterOperator {
13
14
  setFilterOutput(output: FilterOutput): void;
14
15
  beginFilter(): void;
15
16
  endFilter(): void;
16
- filter(node: Node): boolean;
17
+ filter(node: Node): Generator<'yield', boolean>;
17
18
  destroy(): void;
18
19
  getSchema(): SourceSchema;
19
- push(change: Change): void;
20
+ push(change: Change): Stream<'yield'>;
20
21
  }
21
22
  //# sourceMappingURL=exists.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"exists.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/exists.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAqB,KAAK,IAAI,EAAuB,MAAM,WAAW,CAAC;AAC9E,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAqBzC,KAAK,EAAE,WAAW,EAClB,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE,QAAQ,GAAG,YAAY,EAC7B,wBAAwB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAqBhD,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,WAAW;IAIX,SAAS;IAKT,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAoB3B,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM;CA6JpB"}
1
+ {"version":3,"file":"exists.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/exists.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAqB,KAAK,IAAI,EAAuB,MAAM,WAAW,CAAC;AAC9E,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC;;;GAGG;AACH,qBAAa,MAAO,YAAW,cAAc;;gBAqBzC,KAAK,EAAE,WAAW,EAClB,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE,QAAQ,GAAG,YAAY,EAC7B,wBAAwB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAqBhD,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,WAAW;IAIX,SAAS;IAKR,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAqBhD,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;CA+JvC"}
@@ -47,13 +47,13 @@ class Exists {
47
47
  this.#cache = /* @__PURE__ */ new Map();
48
48
  this.#output.endFilter();
49
49
  }
50
- filter(node) {
50
+ *filter(node) {
51
51
  let exists;
52
52
  if (!this.#noSizeReuse && !this.#inPush) {
53
53
  const key = this.#getCacheKey(node, this.#parentJoinKey);
54
54
  exists = this.#cache.get(key);
55
55
  if (exists === void 0) {
56
- exists = this.#fetchExists(node);
56
+ exists = yield* this.#fetchExists(node);
57
57
  this.#cache.set(key, exists);
58
58
  } else if (this.#cacheHitCountsForTesting) {
59
59
  this.#cacheHitCountsForTesting.set(
@@ -62,7 +62,7 @@ class Exists {
62
62
  );
63
63
  }
64
64
  }
65
- const result = this.#filter(node, exists) && this.#output.filter(node);
65
+ const result = (yield* this.#filter(node, exists)) && (yield* this.#output.filter(node));
66
66
  return result;
67
67
  }
68
68
  destroy() {
@@ -71,7 +71,7 @@ class Exists {
71
71
  getSchema() {
72
72
  return this.#input.getSchema();
73
73
  }
74
- push(change) {
74
+ *push(change) {
75
75
  assert(!this.#inPush, "Unexpected re-entrancy");
76
76
  this.#inPush = true;
77
77
  try {
@@ -81,20 +81,20 @@ class Exists {
81
81
  case "add":
82
82
  case "edit":
83
83
  case "remove": {
84
- this.#pushWithFilter(change);
84
+ yield* this.#pushWithFilter(change);
85
85
  return;
86
86
  }
87
87
  case "child":
88
88
  if (change.child.relationshipName !== this.#relationshipName || change.child.change.type === "edit" || change.child.change.type === "child") {
89
- this.#pushWithFilter(change);
89
+ yield* this.#pushWithFilter(change);
90
90
  return;
91
91
  }
92
92
  switch (change.child.change.type) {
93
93
  case "add": {
94
- const size = this.#fetchSize(change.node);
94
+ const size = yield* this.#fetchSize(change.node);
95
95
  if (size === 1) {
96
96
  if (this.#not) {
97
- this.#output.push(
97
+ yield* this.#output.push(
98
98
  {
99
99
  type: "remove",
100
100
  node: {
@@ -108,7 +108,7 @@ class Exists {
108
108
  this
109
109
  );
110
110
  } else {
111
- this.#output.push(
111
+ yield* this.#output.push(
112
112
  {
113
113
  type: "add",
114
114
  node: change.node
@@ -117,15 +117,15 @@ class Exists {
117
117
  );
118
118
  }
119
119
  } else {
120
- this.#pushWithFilter(change, size > 0);
120
+ yield* this.#pushWithFilter(change, size > 0);
121
121
  }
122
122
  return;
123
123
  }
124
124
  case "remove": {
125
- const size = this.#fetchSize(change.node);
125
+ const size = yield* this.#fetchSize(change.node);
126
126
  if (size === 0) {
127
127
  if (this.#not) {
128
- this.#output.push(
128
+ yield* this.#output.push(
129
129
  {
130
130
  type: "add",
131
131
  node: change.node
@@ -133,7 +133,7 @@ class Exists {
133
133
  this
134
134
  );
135
135
  } else {
136
- this.#output.push(
136
+ yield* this.#output.push(
137
137
  {
138
138
  type: "remove",
139
139
  node: {
@@ -150,7 +150,7 @@ class Exists {
150
150
  );
151
151
  }
152
152
  } else {
153
- this.#pushWithFilter(change, size > 0);
153
+ yield* this.#pushWithFilter(change, size > 0);
154
154
  }
155
155
  return;
156
156
  }
@@ -172,8 +172,8 @@ class Exists {
172
172
  * relationship with this.#relationshipName (this computed size is also
173
173
  * stored).
174
174
  */
175
- #filter(node, exists) {
176
- exists = exists ?? this.#fetchExists(node);
175
+ *#filter(node, exists) {
176
+ exists = exists ?? (yield* this.#fetchExists(node));
177
177
  return this.#not ? !exists : exists;
178
178
  }
179
179
  #getCacheKey(node, def) {
@@ -186,20 +186,22 @@ class Exists {
186
186
  /**
187
187
  * Pushes a change if this.#filter is true for its row.
188
188
  */
189
- #pushWithFilter(change, exists) {
190
- if (this.#filter(change.node, exists)) {
191
- this.#output.push(change, this);
189
+ *#pushWithFilter(change, exists) {
190
+ if (yield* this.#filter(change.node, exists)) {
191
+ yield* this.#output.push(change, this);
192
192
  }
193
193
  }
194
- #fetchExists(node) {
195
- return this.#fetchSize(node) > 0;
194
+ *#fetchExists(node) {
195
+ return (yield* this.#fetchSize(node)) > 0;
196
196
  }
197
- #fetchSize(node) {
197
+ *#fetchSize(node) {
198
198
  const relationship = node.relationships[this.#relationshipName];
199
199
  assert(relationship);
200
200
  let size = 0;
201
201
  for (const n of relationship()) {
202
- if (n !== "yield") {
202
+ if (n === "yield") {
203
+ yield "yield";
204
+ } else {
203
205
  size++;
204
206
  }
205
207
  }
@@ -1 +1 @@
1
- {"version":3,"file":"exists.js","sources":["../../../../../zql/src/ivm/exists.ts"],"sourcesContent":["import {areEqual} from '../../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\nimport {type Change} from './change.ts';\nimport {normalizeUndefined, type Node, type NormalizedValue} from './data.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport type {SourceSchema} from './schema.ts';\n\n/**\n * The Exists operator filters data based on whether or not a relationship is\n * non-empty.\n */\nexport class Exists implements FilterOperator {\n readonly #input: FilterInput;\n readonly #relationshipName: string;\n readonly #not: boolean;\n readonly #parentJoinKey: CompoundKey;\n readonly #noSizeReuse: boolean;\n #cache: Map<string, boolean>;\n #cacheHitCountsForTesting: Map<string, number> | undefined;\n #output: FilterOutput = throwFilterOutput;\n\n /**\n * This instance variable is `true` when this operator is processing a `push`,\n * and is used to disable reuse of cached sizes across rows with the\n * same parent join key value.\n * This is necessary because during a push relationships can be inconsistent\n * due to push communicating changes (which may change multiple Nodes) one\n * Node at a time.\n */\n #inPush = false;\n\n constructor(\n input: FilterInput,\n relationshipName: string,\n parentJoinKey: CompoundKey,\n type: 'EXISTS' | 'NOT EXISTS',\n cacheHitCountsForTesting?: Map<string, number>,\n ) {\n this.#input = input;\n this.#relationshipName = relationshipName;\n this.#input.setFilterOutput(this);\n this.#cache = new Map();\n this.#cacheHitCountsForTesting = cacheHitCountsForTesting;\n assert(\n this.#input.getSchema().relationships[relationshipName],\n `Input schema missing ${relationshipName}`,\n );\n this.#not = type === 'NOT EXISTS';\n this.#parentJoinKey = parentJoinKey;\n\n // If the parentJoinKey is the primary key, no sense in trying to reuse.\n this.#noSizeReuse = areEqual(\n parentJoinKey,\n this.#input.getSchema().primaryKey,\n );\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#output = output;\n }\n\n beginFilter() {\n this.#output.beginFilter();\n }\n\n endFilter() {\n this.#cache = new Map();\n this.#output.endFilter();\n }\n\n filter(node: Node): boolean {\n let exists: boolean | undefined;\n if (!this.#noSizeReuse && !this.#inPush) {\n const key = this.#getCacheKey(node, this.#parentJoinKey);\n exists = this.#cache.get(key);\n if (exists === undefined) {\n exists = this.#fetchExists(node);\n this.#cache.set(key, exists);\n } else if (this.#cacheHitCountsForTesting) {\n this.#cacheHitCountsForTesting.set(\n key,\n (this.#cacheHitCountsForTesting.get(key) ?? 0) + 1,\n );\n }\n }\n\n const result = this.#filter(node, exists) && this.#output.filter(node);\n return result;\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 assert(!this.#inPush, 'Unexpected re-entrancy');\n this.#inPush = true;\n try {\n switch (change.type) {\n // add, remove and edit cannot change the size of the\n // this.#relationshipName relationship, so simply #pushWithFilter\n case 'add':\n case 'edit':\n case 'remove': {\n this.#pushWithFilter(change);\n return;\n }\n case 'child':\n // Only add and remove child changes for the\n // this.#relationshipName relationship, can change the size\n // of the this.#relationshipName relationship, for other\n // child changes simply #pushWithFilter\n if (\n change.child.relationshipName !== this.#relationshipName ||\n change.child.change.type === 'edit' ||\n change.child.change.type === 'child'\n ) {\n this.#pushWithFilter(change);\n return;\n }\n switch (change.child.change.type) {\n case 'add': {\n const size = this.#fetchSize(change.node);\n if (size === 1) {\n if (this.#not) {\n // Since the add child change currently being processed is not\n // pushed to output, the added child needs to be excluded from\n // the remove being pushed to output (since the child has\n // never been added to the output).\n this.#output.push(\n {\n type: 'remove',\n node: {\n row: change.node.row,\n relationships: {\n ...change.node.relationships,\n [this.#relationshipName]: () => [],\n },\n },\n },\n this,\n );\n } else {\n this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n }\n } else {\n this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n case 'remove': {\n const size = this.#fetchSize(change.node);\n if (size === 0) {\n if (this.#not) {\n this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n } else {\n // Since the remove child change currently being processed is\n // not pushed to output, the removed child needs to be added to\n // the remove being pushed to output.\n this.#output.push(\n {\n type: 'remove',\n node: {\n row: change.node.row,\n relationships: {\n ...change.node.relationships,\n [this.#relationshipName]: () => [\n change.child.change.node,\n ],\n },\n },\n },\n this,\n );\n }\n } else {\n this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n }\n return;\n default:\n unreachable(change);\n }\n } finally {\n this.#inPush = false;\n }\n }\n\n /**\n * Returns whether or not the node's this.#relationshipName\n * relationship passes the exist/not exists filter condition.\n * If the optional `size` is passed it is used.\n * Otherwise, if there is a stored size for the row it is used.\n * Otherwise the size is computed by streaming the node's\n * relationship with this.#relationshipName (this computed size is also\n * stored).\n */\n #filter(node: Node, exists?: boolean): boolean {\n exists = exists ?? this.#fetchExists(node);\n return this.#not ? !exists : exists;\n }\n\n #getCacheKey(node: Node, def: CompoundKey): string {\n const values: NormalizedValue[] = [];\n for (const key of def) {\n values.push(normalizeUndefined(node.row[key]));\n }\n return JSON.stringify(values);\n }\n\n /**\n * Pushes a change if this.#filter is true for its row.\n */\n #pushWithFilter(change: Change, exists?: boolean): void {\n if (this.#filter(change.node, exists)) {\n this.#output.push(change, this);\n }\n }\n\n #fetchExists(node: Node): boolean {\n // While it seems like this should be able to fetch just 1 node\n // to check for exists, we can't because Take does not support\n // early return during initial fetch.\n return this.#fetchSize(node) > 0;\n }\n\n #fetchSize(node: Node): number {\n const relationship = node.relationships[this.#relationshipName];\n assert(relationship);\n let size = 0;\n for (const n of relationship()) {\n if (n !== 'yield') {\n size++;\n }\n }\n return size;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exists.js","sources":["../../../../../zql/src/ivm/exists.ts"],"sourcesContent":["import {areEqual} from '../../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\nimport {type Change} from './change.ts';\nimport {normalizeUndefined, type Node, type NormalizedValue} from './data.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\n\n/**\n * The Exists operator filters data based on whether or not a relationship is\n * non-empty.\n */\nexport class Exists implements FilterOperator {\n readonly #input: FilterInput;\n readonly #relationshipName: string;\n readonly #not: boolean;\n readonly #parentJoinKey: CompoundKey;\n readonly #noSizeReuse: boolean;\n #cache: Map<string, boolean>;\n #cacheHitCountsForTesting: Map<string, number> | undefined;\n #output: FilterOutput = throwFilterOutput;\n\n /**\n * This instance variable is `true` when this operator is processing a `push`,\n * and is used to disable reuse of cached sizes across rows with the\n * same parent join key value.\n * This is necessary because during a push relationships can be inconsistent\n * due to push communicating changes (which may change multiple Nodes) one\n * Node at a time.\n */\n #inPush = false;\n\n constructor(\n input: FilterInput,\n relationshipName: string,\n parentJoinKey: CompoundKey,\n type: 'EXISTS' | 'NOT EXISTS',\n cacheHitCountsForTesting?: Map<string, number>,\n ) {\n this.#input = input;\n this.#relationshipName = relationshipName;\n this.#input.setFilterOutput(this);\n this.#cache = new Map();\n this.#cacheHitCountsForTesting = cacheHitCountsForTesting;\n assert(\n this.#input.getSchema().relationships[relationshipName],\n `Input schema missing ${relationshipName}`,\n );\n this.#not = type === 'NOT EXISTS';\n this.#parentJoinKey = parentJoinKey;\n\n // If the parentJoinKey is the primary key, no sense in trying to reuse.\n this.#noSizeReuse = areEqual(\n parentJoinKey,\n this.#input.getSchema().primaryKey,\n );\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#output = output;\n }\n\n beginFilter() {\n this.#output.beginFilter();\n }\n\n endFilter() {\n this.#cache = new Map();\n this.#output.endFilter();\n }\n\n *filter(node: Node): Generator<'yield', boolean> {\n let exists: boolean | undefined;\n if (!this.#noSizeReuse && !this.#inPush) {\n const key = this.#getCacheKey(node, this.#parentJoinKey);\n exists = this.#cache.get(key);\n if (exists === undefined) {\n exists = yield* this.#fetchExists(node);\n this.#cache.set(key, exists);\n } else if (this.#cacheHitCountsForTesting) {\n this.#cacheHitCountsForTesting.set(\n key,\n (this.#cacheHitCountsForTesting.get(key) ?? 0) + 1,\n );\n }\n }\n\n const result =\n (yield* this.#filter(node, exists)) && (yield* this.#output.filter(node));\n return result;\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): Stream<'yield'> {\n assert(!this.#inPush, 'Unexpected re-entrancy');\n this.#inPush = true;\n try {\n switch (change.type) {\n // add, remove and edit cannot change the size of the\n // this.#relationshipName relationship, so simply #pushWithFilter\n case 'add':\n case 'edit':\n case 'remove': {\n yield* this.#pushWithFilter(change);\n return;\n }\n case 'child':\n // Only add and remove child changes for the\n // this.#relationshipName relationship, can change the size\n // of the this.#relationshipName relationship, for other\n // child changes simply #pushWithFilter\n if (\n change.child.relationshipName !== this.#relationshipName ||\n change.child.change.type === 'edit' ||\n change.child.change.type === 'child'\n ) {\n yield* this.#pushWithFilter(change);\n return;\n }\n switch (change.child.change.type) {\n case 'add': {\n const size = yield* this.#fetchSize(change.node);\n if (size === 1) {\n if (this.#not) {\n // Since the add child change currently being processed is not\n // pushed to output, the added child needs to be excluded from\n // the remove being pushed to output (since the child has\n // never been added to the output).\n yield* this.#output.push(\n {\n type: 'remove',\n node: {\n row: change.node.row,\n relationships: {\n ...change.node.relationships,\n [this.#relationshipName]: () => [],\n },\n },\n },\n this,\n );\n } else {\n yield* this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n }\n } else {\n yield* this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n case 'remove': {\n const size = yield* this.#fetchSize(change.node);\n if (size === 0) {\n if (this.#not) {\n yield* this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n } else {\n // Since the remove child change currently being processed is\n // not pushed to output, the removed child needs to be added to\n // the remove being pushed to output.\n yield* this.#output.push(\n {\n type: 'remove',\n node: {\n row: change.node.row,\n relationships: {\n ...change.node.relationships,\n [this.#relationshipName]: () => [\n change.child.change.node,\n ],\n },\n },\n },\n this,\n );\n }\n } else {\n yield* this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n }\n return;\n default:\n unreachable(change);\n }\n } finally {\n this.#inPush = false;\n }\n }\n\n /**\n * Returns whether or not the node's this.#relationshipName\n * relationship passes the exist/not exists filter condition.\n * If the optional `size` is passed it is used.\n * Otherwise, if there is a stored size for the row it is used.\n * Otherwise the size is computed by streaming the node's\n * relationship with this.#relationshipName (this computed size is also\n * stored).\n */\n *#filter(node: Node, exists?: boolean): Generator<'yield', boolean> {\n exists = exists ?? (yield* this.#fetchExists(node));\n return this.#not ? !exists : exists;\n }\n\n #getCacheKey(node: Node, def: CompoundKey): string {\n const values: NormalizedValue[] = [];\n for (const key of def) {\n values.push(normalizeUndefined(node.row[key]));\n }\n return JSON.stringify(values);\n }\n\n /**\n * Pushes a change if this.#filter is true for its row.\n */\n *#pushWithFilter(change: Change, exists?: boolean): Stream<'yield'> {\n if (yield* this.#filter(change.node, exists)) {\n yield* this.#output.push(change, this);\n }\n }\n\n *#fetchExists(node: Node): Generator<'yield', boolean> {\n // While it seems like this should be able to fetch just 1 node\n // to check for exists, we can't because Take does not support\n // early return during initial fetch.\n return (yield* this.#fetchSize(node)) > 0;\n }\n\n *#fetchSize(node: Node): Generator<'yield', number> {\n const relationship = node.relationships[this.#relationshipName];\n assert(relationship);\n let size = 0;\n for (const n of relationship()) {\n if (n === 'yield') {\n yield 'yield';\n } else {\n size++;\n }\n }\n return size;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -25,8 +25,8 @@ export declare class FanIn implements FilterOperator {
25
25
  getSchema(): SourceSchema;
26
26
  beginFilter(): void;
27
27
  endFilter(): void;
28
- filter(node: Node): boolean;
29
- push(change: Change): void;
30
- fanOutDonePushingToAllBranches(fanOutChangeType: Change['type']): void;
28
+ filter(node: Node): Generator<'yield', boolean>;
29
+ push(change: Change): readonly never[];
30
+ fanOutDonePushingToAllBranches(fanOutChangeType: Change['type']): Generator<"yield", void, any>;
31
31
  }
32
32
  //# sourceMappingURL=fan-in.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fan-in.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/fan-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACzC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAM,YAAW,cAAc;;gBAM9B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;IASjD,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAMf,SAAS;IAIT,WAAW,IAAI,IAAI;IAInB,SAAS,IAAI,IAAI;IAIjB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAI3B,IAAI,CAAC,MAAM,EAAE,MAAM;IAInB,8BAA8B,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;CAkBhE"}
1
+ {"version":3,"file":"fan-in.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/fan-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACzC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAM,YAAW,cAAc;;gBAM9B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;IASjD,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAMf,SAAS;IAIT,WAAW,IAAI,IAAI;IAInB,SAAS,IAAI,IAAI;IAIhB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAIhD,IAAI,CAAC,MAAM,EAAE,MAAM;IAKlB,8BAA8B,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;CAkBjE"}
@@ -1,5 +1,5 @@
1
1
  import { assert } from "../../../shared/src/asserts.js";
2
- import { identity } from "../../../shared/src/sentinels.js";
2
+ import { emptyArray, identity } from "../../../shared/src/sentinels.js";
3
3
  import "compare-utf8";
4
4
  import { throwFilterOutput } from "./filter-operators.js";
5
5
  import { pushAccumulatedChanges } from "./push-accumulated.js";
@@ -33,13 +33,14 @@ class FanIn {
33
33
  endFilter() {
34
34
  this.#output.endFilter();
35
35
  }
36
- filter(node) {
37
- return this.#output.filter(node);
36
+ *filter(node) {
37
+ return yield* this.#output.filter(node);
38
38
  }
39
39
  push(change) {
40
40
  this.#accumulatedPushes.push(change);
41
+ return emptyArray;
41
42
  }
42
- fanOutDonePushingToAllBranches(fanOutChangeType) {
43
+ *fanOutDonePushingToAllBranches(fanOutChangeType) {
43
44
  if (this.#inputs.length === 0) {
44
45
  assert(
45
46
  this.#accumulatedPushes.length === 0,
@@ -47,7 +48,7 @@ class FanIn {
47
48
  );
48
49
  return;
49
50
  }
50
- pushAccumulatedChanges(
51
+ yield* pushAccumulatedChanges(
51
52
  this.#accumulatedPushes,
52
53
  this.#output,
53
54
  this,
@@ -1 +1 @@
1
- {"version":3,"file":"fan-in.js","sources":["../../../../../zql/src/ivm/fan-in.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {identity} from '../../../shared/src/sentinels.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.ts';\nimport type {FanOut} from './fan-out.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport {pushAccumulatedChanges} from './push-accumulated.ts';\nimport type {SourceSchema} from './schema.ts';\n\n/**\n * The FanIn operator merges multiple streams into one.\n * It eliminates duplicates and must be paired with a fan-out operator\n * somewhere upstream of the fan-in.\n *\n * issue\n * |\n * fan-out\n * / \\\n * a b\n * \\ /\n * fan-in\n * |\n */\nexport class FanIn implements FilterOperator {\n readonly #inputs: readonly FilterInput[];\n readonly #schema: SourceSchema;\n #output: FilterOutput = throwFilterOutput;\n #accumulatedPushes: Change[] = [];\n\n constructor(fanOut: FanOut, inputs: FilterInput[]) {\n this.#inputs = inputs;\n this.#schema = fanOut.getSchema();\n for (const input of inputs) {\n input.setFilterOutput(this);\n assert(this.#schema === input.getSchema(), `Schema mismatch in fan-in`);\n }\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#output = output;\n }\n\n destroy(): void {\n for (const input of this.#inputs) {\n input.destroy();\n }\n }\n\n getSchema() {\n return this.#schema;\n }\n\n beginFilter(): void {\n this.#output.beginFilter();\n }\n\n endFilter(): void {\n this.#output.endFilter();\n }\n\n filter(node: Node): boolean {\n return this.#output.filter(node);\n }\n\n push(change: Change) {\n this.#accumulatedPushes.push(change);\n }\n\n fanOutDonePushingToAllBranches(fanOutChangeType: Change['type']) {\n if (this.#inputs.length === 0) {\n assert(\n this.#accumulatedPushes.length === 0,\n 'If there are no inputs then fan-in should not receive any pushes.',\n );\n return;\n }\n\n pushAccumulatedChanges(\n this.#accumulatedPushes,\n this.#output,\n this,\n fanOutChangeType,\n identity,\n identity,\n );\n }\n}\n"],"names":[],"mappings":";;;;;AA4BO,MAAM,MAAgC;AAAA,EAClC;AAAA,EACA;AAAA,EACT,UAAwB;AAAA,EACxB,qBAA+B,CAAA;AAAA,EAE/B,YAAY,QAAgB,QAAuB;AACjD,SAAK,UAAU;AACf,SAAK,UAAU,OAAO,UAAA;AACtB,eAAW,SAAS,QAAQ;AAC1B,YAAM,gBAAgB,IAAI;AAC1B,aAAO,KAAK,YAAY,MAAM,UAAA,GAAa,2BAA2B;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,gBAAgB,QAA4B;AAC1C,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,eAAW,SAAS,KAAK,SAAS;AAChC,YAAM,QAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAoB;AAClB,SAAK,QAAQ,YAAA;AAAA,EACf;AAAA,EAEA,YAAkB;AAChB,SAAK,QAAQ,UAAA;AAAA,EACf;AAAA,EAEA,OAAO,MAAqB;AAC1B,WAAO,KAAK,QAAQ,OAAO,IAAI;AAAA,EACjC;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,mBAAmB,KAAK,MAAM;AAAA,EACrC;AAAA,EAEA,+BAA+B,kBAAkC;AAC/D,QAAI,KAAK,QAAQ,WAAW,GAAG;AAC7B;AAAA,QACE,KAAK,mBAAmB,WAAW;AAAA,QACnC;AAAA,MAAA;AAEF;AAAA,IACF;AAEA;AAAA,MACE,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;"}
1
+ {"version":3,"file":"fan-in.js","sources":["../../../../../zql/src/ivm/fan-in.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {emptyArray, identity} from '../../../shared/src/sentinels.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.ts';\nimport type {FanOut} from './fan-out.ts';\nimport {\n throwFilterOutput,\n type FilterInput,\n type FilterOperator,\n type FilterOutput,\n} from './filter-operators.ts';\nimport {pushAccumulatedChanges} from './push-accumulated.ts';\nimport type {SourceSchema} from './schema.ts';\n\n/**\n * The FanIn operator merges multiple streams into one.\n * It eliminates duplicates and must be paired with a fan-out operator\n * somewhere upstream of the fan-in.\n *\n * issue\n * |\n * fan-out\n * / \\\n * a b\n * \\ /\n * fan-in\n * |\n */\nexport class FanIn implements FilterOperator {\n readonly #inputs: readonly FilterInput[];\n readonly #schema: SourceSchema;\n #output: FilterOutput = throwFilterOutput;\n #accumulatedPushes: Change[] = [];\n\n constructor(fanOut: FanOut, inputs: FilterInput[]) {\n this.#inputs = inputs;\n this.#schema = fanOut.getSchema();\n for (const input of inputs) {\n input.setFilterOutput(this);\n assert(this.#schema === input.getSchema(), `Schema mismatch in fan-in`);\n }\n }\n\n setFilterOutput(output: FilterOutput): void {\n this.#output = output;\n }\n\n destroy(): void {\n for (const input of this.#inputs) {\n input.destroy();\n }\n }\n\n getSchema() {\n return this.#schema;\n }\n\n beginFilter(): void {\n this.#output.beginFilter();\n }\n\n endFilter(): void {\n this.#output.endFilter();\n }\n\n *filter(node: Node): Generator<'yield', boolean> {\n return yield* this.#output.filter(node);\n }\n\n push(change: Change) {\n this.#accumulatedPushes.push(change);\n return emptyArray;\n }\n\n *fanOutDonePushingToAllBranches(fanOutChangeType: Change['type']) {\n if (this.#inputs.length === 0) {\n assert(\n this.#accumulatedPushes.length === 0,\n 'If there are no inputs then fan-in should not receive any pushes.',\n );\n return;\n }\n\n yield* pushAccumulatedChanges(\n this.#accumulatedPushes,\n this.#output,\n this,\n fanOutChangeType,\n identity,\n identity,\n );\n }\n}\n"],"names":[],"mappings":";;;;;AA4BO,MAAM,MAAgC;AAAA,EAClC;AAAA,EACA;AAAA,EACT,UAAwB;AAAA,EACxB,qBAA+B,CAAA;AAAA,EAE/B,YAAY,QAAgB,QAAuB;AACjD,SAAK,UAAU;AACf,SAAK,UAAU,OAAO,UAAA;AACtB,eAAW,SAAS,QAAQ;AAC1B,YAAM,gBAAgB,IAAI;AAC1B,aAAO,KAAK,YAAY,MAAM,UAAA,GAAa,2BAA2B;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,gBAAgB,QAA4B;AAC1C,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,eAAW,SAAS,KAAK,SAAS;AAChC,YAAM,QAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAoB;AAClB,SAAK,QAAQ,YAAA;AAAA,EACf;AAAA,EAEA,YAAkB;AAChB,SAAK,QAAQ,UAAA;AAAA,EACf;AAAA,EAEA,CAAC,OAAO,MAAyC;AAC/C,WAAO,OAAO,KAAK,QAAQ,OAAO,IAAI;AAAA,EACxC;AAAA,EAEA,KAAK,QAAgB;AACnB,SAAK,mBAAmB,KAAK,MAAM;AACnC,WAAO;AAAA,EACT;AAAA,EAEA,CAAC,+BAA+B,kBAAkC;AAChE,QAAI,KAAK,QAAQ,WAAW,GAAG;AAC7B;AAAA,QACE,KAAK,mBAAmB,WAAW;AAAA,QACnC;AAAA,MAAA;AAEF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;"}
@@ -16,7 +16,7 @@ export declare class FanOut implements FilterOperator {
16
16
  getSchema(): import("./schema.ts").SourceSchema;
17
17
  beginFilter(): void;
18
18
  endFilter(): void;
19
- filter(node: Node): boolean;
20
- push(change: Change): void;
19
+ filter(node: Node): Generator<'yield', boolean>;
20
+ push(change: Change): Generator<"yield", void, any>;
21
21
  }
22
22
  //# sourceMappingURL=fan-out.d.ts.map
@@ -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,WAAW,IAAI,IAAI;IAMnB,SAAS,IAAI,IAAI;IAMjB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAW3B,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;IAMnB,SAAS,IAAI,IAAI;IAMhB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAW/C,IAAI,CAAC,MAAM,EAAE,MAAM;CASrB"}
@@ -37,21 +37,21 @@ class FanOut {
37
37
  output.endFilter();
38
38
  }
39
39
  }
40
- filter(node) {
40
+ *filter(node) {
41
41
  let result = false;
42
42
  for (const output of this.#outputs) {
43
- result = output.filter(node) || result;
43
+ result = (yield* output.filter(node)) || result;
44
44
  if (result) {
45
45
  return true;
46
46
  }
47
47
  }
48
48
  return result;
49
49
  }
50
- push(change) {
50
+ *push(change) {
51
51
  for (const out of this.#outputs) {
52
- out.push(change, this);
52
+ yield* out.push(change, this);
53
53
  }
54
- must(
54
+ yield* must(
55
55
  this.#fanIn,
56
56
  "fan-out must have a corresponding fan-in set!"
57
57
  ).fanOutDonePushingToAllBranches(change.type);
@@ -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 beginFilter(): void {\n for (const output of this.#outputs) {\n output.beginFilter();\n }\n }\n\n endFilter(): void {\n for (const output of this.#outputs) {\n output.endFilter();\n }\n }\n\n filter(node: Node): boolean {\n let result = false;\n for (const output of this.#outputs) {\n result = output.filter(node) || result;\n if (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;AAClB,eAAW,UAAU,KAAK,UAAU;AAClC,aAAO,YAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,eAAW,UAAU,KAAK,UAAU;AAClC,aAAO,UAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO,MAAqB;AAC1B,QAAI,SAAS;AACb,eAAW,UAAU,KAAK,UAAU;AAClC,eAAS,OAAO,OAAO,IAAI,KAAK;AAChC,UAAI,QAAQ;AACV,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 for (const output of this.#outputs) {\n output.beginFilter();\n }\n }\n\n endFilter(): void {\n for (const output of this.#outputs) {\n output.endFilter();\n }\n }\n\n *filter(node: Node): Generator<'yield', boolean> {\n let result = false;\n for (const output of this.#outputs) {\n result = (yield* output.filter(node)) || result;\n if (result) {\n return true;\n }\n }\n return result;\n }\n\n *push(change: Change) {\n for (const out of this.#outputs) {\n yield* out.push(change, this);\n }\n yield* 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;AAClB,eAAW,UAAU,KAAK,UAAU;AAClC,aAAO,YAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,eAAW,UAAU,KAAK,UAAU;AAClC,aAAO,UAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,CAAC,OAAO,MAAyC;AAC/C,QAAI,SAAS;AACb,eAAW,UAAU,KAAK,UAAU;AAClC,gBAAU,OAAO,OAAO,OAAO,IAAI,MAAM;AACzC,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,CAAC,KAAK,QAAgB;AACpB,eAAW,OAAO,KAAK,UAAU;AAC/B,aAAO,IAAI,KAAK,QAAQ,IAAI;AAAA,IAC9B;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IAAA,EACA,+BAA+B,OAAO,IAAI;AAAA,EAC9C;AACF;"}
@@ -2,7 +2,7 @@ import type { FetchRequest, Input, InputBase, Output } from './operator.ts';
2
2
  import { type Node } from './data.ts';
3
3
  import type { Change } from './change.ts';
4
4
  import type { SourceSchema } from './schema.ts';
5
- import type { Stream } from './stream.ts';
5
+ import { type Stream } from './stream.ts';
6
6
  import type { BuilderDelegate } from '../builder/builder.ts';
7
7
  /**
8
8
  * The `where` clause of a ZQL query is implemented using a sub-graph of
@@ -28,7 +28,7 @@ export interface FilterInput extends InputBase {
28
28
  }
29
29
  export interface FilterOutput extends Output {
30
30
  beginFilter(): void;
31
- filter(node: Node): boolean;
31
+ filter(node: Node): Generator<'yield', boolean>;
32
32
  endFilter(): void;
33
33
  }
34
34
  export interface FilterOperator extends FilterInput, FilterOutput {
@@ -45,7 +45,7 @@ export declare class FilterStart implements FilterInput, Output {
45
45
  setFilterOutput(output: FilterOutput): void;
46
46
  destroy(): void;
47
47
  getSchema(): SourceSchema;
48
- push(change: Change): void;
48
+ push(change: Change): Generator<"yield", void, any>;
49
49
  fetch(req: FetchRequest): Stream<Node | 'yield'>;
50
50
  }
51
51
  export declare class FilterEnd implements Input, FilterOutput {
@@ -54,11 +54,11 @@ export declare class FilterEnd implements Input, FilterOutput {
54
54
  fetch(req: FetchRequest): Stream<Node | 'yield'>;
55
55
  beginFilter(): void;
56
56
  endFilter(): void;
57
- filter(_node: Node): boolean;
57
+ filter(_node: Node): Generator<never, boolean, unknown>;
58
58
  setOutput(output: Output): void;
59
59
  destroy(): void;
60
60
  getSchema(): SourceSchema;
61
- push(change: Change): void;
61
+ push(change: Change): Generator<"yield", void, any>;
62
62
  }
63
63
  export declare function buildFilterPipeline(input: Input, delegate: BuilderDelegate, pipeline: (filterInput: FilterInput) => FilterInput): Input;
64
64
  //# sourceMappingURL=filter-operators.d.ts.map
@@ -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,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,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,GAAG,OAAO,CAAC;IAC5B,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;CAkBlD;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;IAET,MAAM,CAAC,KAAK,EAAE,IAAI;IAIlB,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,EAAC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,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,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,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;IAIxB,IAAI,CAAC,MAAM,EAAE,MAAM;IAInB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;CAkBlD;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,MAAM,CAAC,KAAK,EAAE,IAAI;IAInB,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,YAAY;IAIxB,IAAI,CAAC,MAAM,EAAE,MAAM;CAGrB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,WAAW,GAClD,KAAK,CAQP"}
@@ -1,9 +1,9 @@
1
1
  import "compare-utf8";
2
2
  const throwFilterOutput = {
3
- push(_change) {
3
+ *push(_change) {
4
4
  throw new Error("Output not set");
5
5
  },
6
- filter(_node) {
6
+ *filter(_node) {
7
7
  throw new Error("Output not set");
8
8
  },
9
9
  beginFilter() {
@@ -27,8 +27,8 @@ class FilterStart {
27
27
  getSchema() {
28
28
  return this.#input.getSchema();
29
29
  }
30
- push(change) {
31
- this.#output.push(change, this);
30
+ *push(change) {
31
+ yield* this.#output.push(change, this);
32
32
  }
33
33
  *fetch(req) {
34
34
  this.#output.beginFilter();
@@ -38,7 +38,7 @@ class FilterStart {
38
38
  yield node;
39
39
  continue;
40
40
  }
41
- if (this.#output.filter(node)) {
41
+ if (yield* this.#output.filter(node)) {
42
42
  yield node;
43
43
  }
44
44
  }
@@ -65,7 +65,7 @@ class FilterEnd {
65
65
  }
66
66
  endFilter() {
67
67
  }
68
- filter(_node) {
68
+ *filter(_node) {
69
69
  return true;
70
70
  }
71
71
  setOutput(output) {
@@ -77,8 +77,8 @@ class FilterEnd {
77
77
  getSchema() {
78
78
  return this.#input.getSchema();
79
79
  }
80
- push(change) {
81
- this.#output.push(change, this);
80
+ *push(change) {
81
+ yield* this.#output.push(change, this);
82
82
  }
83
83
  }
84
84
  function buildFilterPipeline(input, delegate, pipeline) {
@@ -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 {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` instead they have a\n * `filter(node: Node): 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): 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): 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 try {\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)) {\n yield node;\n }\n }\n } finally {\n // finally is important if an exception is thrown or\n // if the stream is not fully consumed.\n this.#output.endFilter();\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 | 'yield'> {\n for (const node of this.#start.fetch(req)) {\n yield node;\n }\n }\n\n beginFilter() {}\n endFilter() {}\n\n filter(_node: Node) {\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,OAAsB;AAC3B,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,QAAI;AACF,iBAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,YAAI,SAAS,SAAS;AACpB,gBAAM;AACN;AAAA,QACF;AACA,YAAI,KAAK,QAAQ,OAAO,IAAI,GAAG;AAC7B,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,UAAA;AAGE,WAAK,QAAQ,UAAA;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,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,OAAO,OAAa;AAClB,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 {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` instead they have a\n * `filter(node: Node): 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): Generator<'yield', 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): Stream<'yield'> {\n throw new Error('Output not set');\n },\n\n *filter(_node: Node): Generator<'yield', 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 yield* this.#output.push(change, this);\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n this.#output.beginFilter();\n try {\n for (const node of this.#input.fetch(req)) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (yield* this.#output.filter(node)) {\n yield node;\n }\n }\n } finally {\n // finally is important if an exception is thrown or\n // if the stream is not fully consumed.\n this.#output.endFilter();\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 | 'yield'> {\n for (const node of this.#start.fetch(req)) {\n yield node;\n }\n }\n\n beginFilter() {}\n endFilter() {}\n\n *filter(_node: Node) {\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 yield* 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,CAAC,KAAK,SAAkC;AACtC,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AAAA,EAEA,CAAC,OAAO,OAA0C;AAChD,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,CAAC,KAAK,QAAgB;AACpB,WAAO,KAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EACvC;AAAA,EAEA,CAAC,MAAM,KAA2C;AAChD,SAAK,QAAQ,YAAA;AACb,QAAI;AACF,iBAAW,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AACzC,YAAI,SAAS,SAAS;AACpB,gBAAM;AACN;AAAA,QACF;AACA,YAAI,OAAO,KAAK,QAAQ,OAAO,IAAI,GAAG;AACpC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,UAAA;AAGE,WAAK,QAAQ,UAAA;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,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,OAAO,OAAa;AACnB,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,CAAC,KAAK,QAAgB;AACpB,WAAO,KAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,EACvC;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,5 +1,6 @@
1
1
  import type { Row } from '../../../zero-protocol/src/data.ts';
2
2
  import type { Change } from './change.ts';
3
3
  import type { InputBase, Output } from './operator.ts';
4
- export declare function filterPush(change: Change, output: Output, pusher: InputBase, predicate?: (row: Row) => boolean): void;
4
+ import type { Stream } from './stream.ts';
5
+ export declare function filterPush(change: Change, output: Output, pusher: InputBase, predicate?: (row: Row) => boolean): Stream<'yield'>;
5
6
  //# sourceMappingURL=filter-push.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter-push.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter-push.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAErD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,QAwBlC"}
1
+ {"version":3,"file":"filter-push.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/filter-push.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,wBAAiB,UAAU,CACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,GAChC,MAAM,CAAC,OAAO,CAAC,CAuBjB"}
@@ -1,24 +1,24 @@
1
1
  import { unreachable } from "../../../shared/src/asserts.js";
2
2
  import { maybeSplitAndPushEditChange } from "./maybe-split-and-push-edit-change.js";
3
- function filterPush(change, output, pusher, predicate) {
3
+ function* filterPush(change, output, pusher, predicate) {
4
4
  if (!predicate) {
5
- output.push(change, pusher);
5
+ yield* output.push(change, pusher);
6
6
  return;
7
7
  }
8
8
  switch (change.type) {
9
9
  case "add":
10
10
  case "remove":
11
11
  if (predicate(change.node.row)) {
12
- output.push(change, pusher);
12
+ yield* output.push(change, pusher);
13
13
  }
14
14
  break;
15
15
  case "child":
16
16
  if (predicate(change.node.row)) {
17
- output.push(change, pusher);
17
+ yield* output.push(change, pusher);
18
18
  }
19
19
  break;
20
20
  case "edit":
21
- maybeSplitAndPushEditChange(change, predicate, output, pusher);
21
+ yield* maybeSplitAndPushEditChange(change, predicate, output, pusher);
22
22
  break;
23
23
  default:
24
24
  unreachable();