@rocicorp/zero 1.6.2 → 1.7.0-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (606) hide show
  1. package/README.md +28 -3
  2. package/out/_virtual/{_@oxc-project_runtime@0.122.0 → _@oxc-project_runtime@0.130.0}/helpers/usingCtx.js +1 -1
  3. package/out/analyze-query/src/analyze-cli.js +3 -3
  4. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  5. package/out/analyze-query/src/bin-analyze.js +7 -2
  6. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  7. package/out/analyze-query/src/bin-transform.js.map +1 -1
  8. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  9. package/out/ast-to-zql/src/bin.js.map +1 -1
  10. package/out/ast-to-zql/src/format.js.map +1 -1
  11. package/out/datadog/src/datadog-log-sink.js.map +1 -1
  12. package/out/otel/src/enabled.js.map +1 -1
  13. package/out/otel/src/log-options.js.map +1 -1
  14. package/out/otel/src/maybe-time.js.map +1 -1
  15. package/out/otel/src/span.js.map +1 -1
  16. package/out/replicache/src/async-iterable-to-array.js.map +1 -1
  17. package/out/replicache/src/bg-interval.js.map +1 -1
  18. package/out/replicache/src/btree/diff.js.map +1 -1
  19. package/out/replicache/src/btree/node.js.map +1 -1
  20. package/out/replicache/src/btree/read.js.map +1 -1
  21. package/out/replicache/src/btree/splice.js.map +1 -1
  22. package/out/replicache/src/btree/write.js +6 -3
  23. package/out/replicache/src/btree/write.js.map +1 -1
  24. package/out/replicache/src/call-default-fetch.js.map +1 -1
  25. package/out/replicache/src/connection-loop-delegates.js.map +1 -1
  26. package/out/replicache/src/connection-loop.js +13 -13
  27. package/out/replicache/src/connection-loop.js.map +1 -1
  28. package/out/replicache/src/cookies.js.map +1 -1
  29. package/out/replicache/src/dag/chunk.js.map +1 -1
  30. package/out/replicache/src/dag/gc.js.map +1 -1
  31. package/out/replicache/src/dag/key.js.map +1 -1
  32. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  33. package/out/replicache/src/dag/store-impl.js.map +1 -1
  34. package/out/replicache/src/dag/store.js.map +1 -1
  35. package/out/replicache/src/dag/visitor.js.map +1 -1
  36. package/out/replicache/src/db/commit.js.map +1 -1
  37. package/out/replicache/src/db/index.js.map +1 -1
  38. package/out/replicache/src/db/read.js.map +1 -1
  39. package/out/replicache/src/db/rebase.js.map +1 -1
  40. package/out/replicache/src/db/write.js.map +1 -1
  41. package/out/replicache/src/deleted-clients.js.map +1 -1
  42. package/out/replicache/src/error-responses.js.map +1 -1
  43. package/out/replicache/src/frozen-json.js.map +1 -1
  44. package/out/replicache/src/get-default-puller.js.map +1 -1
  45. package/out/replicache/src/get-default-pusher.js.map +1 -1
  46. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  47. package/out/replicache/src/hash.js.map +1 -1
  48. package/out/replicache/src/http-request-info.js.map +1 -1
  49. package/out/replicache/src/index-defs.js.map +1 -1
  50. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  51. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -1
  52. package/out/replicache/src/kv/idb-store.js.map +1 -1
  53. package/out/replicache/src/kv/mem-store.js.map +1 -1
  54. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  55. package/out/replicache/src/kv/read-impl.js.map +1 -1
  56. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  57. package/out/replicache/src/kv/sqlite-store.js +4 -1
  58. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  59. package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
  60. package/out/replicache/src/kv/write-impl-base.js.map +1 -1
  61. package/out/replicache/src/kv/write-impl.js.map +1 -1
  62. package/out/replicache/src/lazy.js.map +1 -1
  63. package/out/replicache/src/log-options.js.map +1 -1
  64. package/out/replicache/src/make-idb-name.js.map +1 -1
  65. package/out/replicache/src/new-client-channel.js.map +1 -1
  66. package/out/replicache/src/on-persist-channel.js.map +1 -1
  67. package/out/replicache/src/patch-operation.js.map +1 -1
  68. package/out/replicache/src/pending-mutations.js.map +1 -1
  69. package/out/replicache/src/persist/client-gc.js.map +1 -1
  70. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  71. package/out/replicache/src/persist/client-groups.js +40 -0
  72. package/out/replicache/src/persist/client-groups.js.map +1 -1
  73. package/out/replicache/src/persist/clients.js +28 -0
  74. package/out/replicache/src/persist/clients.js.map +1 -1
  75. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  76. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
  77. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
  78. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  79. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  80. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  81. package/out/replicache/src/persist/make-client-id.js.map +1 -1
  82. package/out/replicache/src/persist/persist.js.map +1 -1
  83. package/out/replicache/src/persist/refresh.js.map +1 -1
  84. package/out/replicache/src/process-scheduler.js.map +1 -1
  85. package/out/replicache/src/pusher.js.map +1 -1
  86. package/out/replicache/src/replicache-impl.js.map +1 -1
  87. package/out/replicache/src/report-error.js.map +1 -1
  88. package/out/replicache/src/request-idle.js.map +1 -1
  89. package/out/replicache/src/scan-iterator.js.map +1 -1
  90. package/out/replicache/src/scan-options.js.map +1 -1
  91. package/out/replicache/src/set-interval-with-signal.js.map +1 -1
  92. package/out/replicache/src/subscriptions.js.map +1 -1
  93. package/out/replicache/src/sync/diff.js.map +1 -1
  94. package/out/replicache/src/sync/ids.js.map +1 -1
  95. package/out/replicache/src/sync/patch.js.map +1 -1
  96. package/out/replicache/src/sync/pull-error.js.map +1 -1
  97. package/out/replicache/src/sync/pull.js.map +1 -1
  98. package/out/replicache/src/sync/push.js.map +1 -1
  99. package/out/replicache/src/sync/request-id.js.map +1 -1
  100. package/out/replicache/src/to-error.js.map +1 -1
  101. package/out/replicache/src/transaction-closed-error.js.map +1 -1
  102. package/out/replicache/src/transactions.js.map +1 -1
  103. package/out/replicache/src/with-transactions.js.map +1 -1
  104. package/out/shared/src/abort-error.js.map +1 -1
  105. package/out/shared/src/arrays.js.map +1 -1
  106. package/out/shared/src/asserts.js.map +1 -1
  107. package/out/shared/src/bigint-json.js.map +1 -1
  108. package/out/shared/src/binary-search.js.map +1 -1
  109. package/out/shared/src/broadcast-channel.js.map +1 -1
  110. package/out/shared/src/browser-env.js.map +1 -1
  111. package/out/shared/src/btree-set.js.map +1 -1
  112. package/out/shared/src/cache.js.map +1 -1
  113. package/out/shared/src/centroid.js.map +1 -1
  114. package/out/shared/src/custom-key-map.js.map +1 -1
  115. package/out/shared/src/custom-key-set.js.map +1 -1
  116. package/out/shared/src/deep-clone.js.map +1 -1
  117. package/out/shared/src/deep-merge.js.map +1 -1
  118. package/out/shared/src/document-visible.js.map +1 -1
  119. package/out/shared/src/dotenv.js.map +1 -1
  120. package/out/shared/src/enum.d.ts +1 -1
  121. package/out/shared/src/error.js.map +1 -1
  122. package/out/shared/src/hash.js.map +1 -1
  123. package/out/shared/src/iterables.d.ts +2 -0
  124. package/out/shared/src/iterables.d.ts.map +1 -1
  125. package/out/shared/src/iterables.js +9 -1
  126. package/out/shared/src/iterables.js.map +1 -1
  127. package/out/shared/src/json-schema.js.map +1 -1
  128. package/out/shared/src/json.js.map +1 -1
  129. package/out/shared/src/logging-test-utils.js.map +1 -1
  130. package/out/shared/src/logging.js.map +1 -1
  131. package/out/shared/src/map.js.map +1 -1
  132. package/out/shared/src/must.js.map +1 -1
  133. package/out/shared/src/object-traversal.js.map +1 -1
  134. package/out/shared/src/objects.js.map +1 -1
  135. package/out/shared/src/options.js.map +1 -1
  136. package/out/shared/src/parse-big-int.js.map +1 -1
  137. package/out/shared/src/promise-race.js.map +1 -1
  138. package/out/shared/src/queue.d.ts.map +1 -1
  139. package/out/shared/src/queue.js +15 -21
  140. package/out/shared/src/queue.js.map +1 -1
  141. package/out/shared/src/rand.js.map +1 -1
  142. package/out/shared/src/random-uint64.js.map +1 -1
  143. package/out/shared/src/random-values.js.map +1 -1
  144. package/out/shared/src/record-proxy.js.map +1 -1
  145. package/out/shared/src/resolved-promises.js.map +1 -1
  146. package/out/shared/src/ring-buffer.d.ts +32 -0
  147. package/out/shared/src/ring-buffer.d.ts.map +1 -0
  148. package/out/shared/src/ring-buffer.js +109 -0
  149. package/out/shared/src/ring-buffer.js.map +1 -0
  150. package/out/shared/src/sentinels.js.map +1 -1
  151. package/out/shared/src/set-utils.js.map +1 -1
  152. package/out/shared/src/size-of-value.js.map +1 -1
  153. package/out/shared/src/sleep.js.map +1 -1
  154. package/out/shared/src/sorted-entries.js.map +1 -1
  155. package/out/shared/src/string-compare.js.map +1 -1
  156. package/out/shared/src/subscribable.js.map +1 -1
  157. package/out/shared/src/tdigest-schema.js.map +1 -1
  158. package/out/shared/src/tdigest.js.map +1 -1
  159. package/out/shared/src/valita.js.map +1 -1
  160. package/out/z2s/src/compiler.js.map +1 -1
  161. package/out/z2s/src/sql.d.ts.map +1 -1
  162. package/out/z2s/src/sql.js +3 -2
  163. package/out/z2s/src/sql.js.map +1 -1
  164. package/out/zero/package.js +37 -28
  165. package/out/zero/package.js.map +1 -1
  166. package/out/zero/src/build-schema.js.map +1 -1
  167. package/out/zero/src/zero-cache-dev.js.map +1 -1
  168. package/out/zero/src/zero-out.js.map +1 -1
  169. package/out/zero/src/zero.js +1 -1
  170. package/out/zero-cache/src/auth/auth.js.map +1 -1
  171. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  172. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  173. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  174. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  175. package/out/zero-cache/src/config/network.js.map +1 -1
  176. package/out/zero-cache/src/config/normalize.js.map +1 -1
  177. package/out/zero-cache/src/config/server-context.js.map +1 -1
  178. package/out/zero-cache/src/config/zero-config.js +5 -0
  179. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  180. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  181. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  182. package/out/zero-cache/src/db/create.js.map +1 -1
  183. package/out/zero-cache/src/db/delete-lite-db.js.map +1 -1
  184. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  185. package/out/zero-cache/src/db/migration-lite.js +19 -0
  186. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  187. package/out/zero-cache/src/db/migration.js +19 -0
  188. package/out/zero-cache/src/db/migration.js.map +1 -1
  189. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
  190. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  191. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  192. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  193. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  194. package/out/zero-cache/src/db/specs.js.map +1 -1
  195. package/out/zero-cache/src/db/statements.js.map +1 -1
  196. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  197. package/out/zero-cache/src/db/warmup.js.map +1 -1
  198. package/out/zero-cache/src/observability/events.js.map +1 -1
  199. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  200. package/out/zero-cache/src/scripts/decommission.js.map +1 -1
  201. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  202. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  203. package/out/zero-cache/src/scripts/permissions.js +1 -2
  204. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  205. package/out/zero-cache/src/server/anonymous-otel-start.js +8 -7
  206. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  207. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  208. package/out/zero-cache/src/server/change-streamer.js +2 -2
  209. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  210. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  211. package/out/zero-cache/src/server/logging.js.map +1 -1
  212. package/out/zero-cache/src/server/main.js.map +1 -1
  213. package/out/zero-cache/src/server/mutator.js.map +1 -1
  214. package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
  215. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  216. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  217. package/out/zero-cache/src/server/priority-op.js.map +1 -1
  218. package/out/zero-cache/src/server/reaper.js.map +1 -1
  219. package/out/zero-cache/src/server/replicator.js.map +1 -1
  220. package/out/zero-cache/src/server/runner/main.js.map +1 -1
  221. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  222. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  223. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  224. package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
  225. package/out/zero-cache/src/server/syncer.js.map +1 -1
  226. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  227. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  228. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  229. package/out/zero-cache/src/services/analyze.js +5 -2
  230. package/out/zero-cache/src/services/analyze.js.map +1 -1
  231. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  232. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  233. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  234. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  235. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
  236. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  237. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  238. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  239. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  240. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  241. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  242. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  243. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  244. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  245. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  246. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  247. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  248. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  249. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  250. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  251. package/out/zero-cache/src/services/change-source/protocol/current/data.js +2 -0
  252. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  253. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  254. package/out/zero-cache/src/services/change-source/protocol/current/json.js.map +1 -1
  255. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  256. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  257. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +46 -1
  258. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  259. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +109 -12
  260. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  261. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  262. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  263. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  264. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  265. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  266. package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +1 -1
  267. package/out/zero-cache/src/services/change-streamer/schema/init.js +21 -25
  268. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  269. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  270. package/out/zero-cache/src/services/change-streamer/snapshot.js +15 -0
  271. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  272. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  273. package/out/zero-cache/src/services/change-streamer/storer.js +12 -2
  274. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  275. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  276. package/out/zero-cache/src/services/heapz.js.map +1 -1
  277. package/out/zero-cache/src/services/http-service.js.map +1 -1
  278. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  279. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  280. package/out/zero-cache/src/services/litestream/commands.d.ts +23 -0
  281. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  282. package/out/zero-cache/src/services/litestream/commands.js +89 -1
  283. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  284. package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
  285. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  286. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  287. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  288. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  289. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  290. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  291. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  292. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +1 -0
  293. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
  294. package/out/zero-cache/src/services/replicator/reporter/recorder.js +8 -0
  295. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  296. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
  297. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  298. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  299. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  300. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  301. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  302. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  303. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  304. package/out/zero-cache/src/services/run-ast.js +1 -0
  305. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  306. package/out/zero-cache/src/services/runner.js.map +1 -1
  307. package/out/zero-cache/src/services/running-state.js.map +1 -1
  308. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  309. package/out/zero-cache/src/services/statz.js.map +1 -1
  310. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  311. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  312. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +1 -1
  313. package/out/zero-cache/src/services/view-syncer/client-schema.js +10 -2
  314. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  315. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  316. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  317. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  318. package/out/zero-cache/src/services/view-syncer/cvr-store.js +2 -1
  319. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  320. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  321. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  322. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
  323. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  324. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +2 -1
  325. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  326. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +81 -7
  327. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  328. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  329. package/out/zero-cache/src/services/view-syncer/row-set-signature.js.map +1 -1
  330. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  331. package/out/zero-cache/src/services/view-syncer/schema/init.js +97 -113
  332. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
  333. package/out/zero-cache/src/services/view-syncer/schema/types.js +103 -1
  334. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  335. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  336. package/out/zero-cache/src/services/view-syncer/tracer.js.map +1 -1
  337. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  338. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  339. package/out/zero-cache/src/services/view-syncer/view-syncer.js +13 -6
  340. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  341. package/out/zero-cache/src/types/configuration-error.js.map +1 -1
  342. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  343. package/out/zero-cache/src/types/http.js.map +1 -1
  344. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  345. package/out/zero-cache/src/types/lite.js.map +1 -1
  346. package/out/zero-cache/src/types/names.js.map +1 -1
  347. package/out/zero-cache/src/types/pg-data-type.d.ts +53 -2
  348. package/out/zero-cache/src/types/pg-data-type.d.ts.map +1 -1
  349. package/out/zero-cache/src/types/pg-data-type.js +28 -3
  350. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  351. package/out/zero-cache/src/types/pg.js.map +1 -1
  352. package/out/zero-cache/src/types/processes.js.map +1 -1
  353. package/out/zero-cache/src/types/profiler.js.map +1 -1
  354. package/out/zero-cache/src/types/row-key.js.map +1 -1
  355. package/out/zero-cache/src/types/shards.js.map +1 -1
  356. package/out/zero-cache/src/types/sql.js.map +1 -1
  357. package/out/zero-cache/src/types/state-version.js.map +1 -1
  358. package/out/zero-cache/src/types/streams.js.map +1 -1
  359. package/out/zero-cache/src/types/strings.js.map +1 -1
  360. package/out/zero-cache/src/types/subscription.js.map +1 -1
  361. package/out/zero-cache/src/types/timeout.js.map +1 -1
  362. package/out/zero-cache/src/types/url-params.js.map +1 -1
  363. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  364. package/out/zero-cache/src/types/ws.js.map +1 -1
  365. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  366. package/out/zero-cache/src/workers/connection.js.map +1 -1
  367. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  368. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  369. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  370. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  371. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  372. package/out/zero-client/src/client/connection-manager.js +2 -1
  373. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  374. package/out/zero-client/src/client/connection.js.map +1 -1
  375. package/out/zero-client/src/client/context.js.map +1 -1
  376. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  377. package/out/zero-client/src/client/crud.js.map +1 -1
  378. package/out/zero-client/src/client/custom.js +2 -1
  379. package/out/zero-client/src/client/custom.js.map +1 -1
  380. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
  381. package/out/zero-client/src/client/enable-analytics.js.map +1 -1
  382. package/out/zero-client/src/client/error.js.map +1 -1
  383. package/out/zero-client/src/client/http-string.js.map +1 -1
  384. package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
  385. package/out/zero-client/src/client/inspector/client.js.map +1 -1
  386. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
  387. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  388. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  389. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  390. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  391. package/out/zero-client/src/client/keys.js.map +1 -1
  392. package/out/zero-client/src/client/log-options.js.map +1 -1
  393. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  394. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  395. package/out/zero-client/src/client/metrics.js.map +1 -1
  396. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  397. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  398. package/out/zero-client/src/client/options.js.map +1 -1
  399. package/out/zero-client/src/client/query-manager.js +1 -1
  400. package/out/zero-client/src/client/query-manager.js.map +1 -1
  401. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  402. package/out/zero-client/src/client/server-option.js.map +1 -1
  403. package/out/zero-client/src/client/version.js +1 -1
  404. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  405. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  406. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  407. package/out/zero-client/src/client/zero.js +58 -32
  408. package/out/zero-client/src/client/zero.js.map +1 -1
  409. package/out/zero-client/src/mod.d.ts +2 -2
  410. package/out/zero-client/src/mod.d.ts.map +1 -1
  411. package/out/zero-client/src/mod.js +1 -1
  412. package/out/zero-client/src/util/nanoid.js.map +1 -1
  413. package/out/{zero-schema → zero-permissions}/src/permissions.d.ts +1 -1
  414. package/out/zero-permissions/src/permissions.d.ts.map +1 -0
  415. package/out/{zero-schema → zero-permissions}/src/permissions.js +2 -2
  416. package/out/zero-permissions/src/permissions.js.map +1 -0
  417. package/out/zero-protocol/src/analyze-query-result.js +3 -0
  418. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  419. package/out/zero-protocol/src/application-error.js.map +1 -1
  420. package/out/zero-protocol/src/ast.js.map +1 -1
  421. package/out/zero-protocol/src/change-desired-queries.js +1 -0
  422. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  423. package/out/zero-protocol/src/client-schema.js.map +1 -1
  424. package/out/zero-protocol/src/close-connection.js.map +1 -1
  425. package/out/zero-protocol/src/connect.js +7 -0
  426. package/out/zero-protocol/src/connect.js.map +1 -1
  427. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  428. package/out/zero-protocol/src/data.js.map +1 -1
  429. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  430. package/out/zero-protocol/src/down.js.map +1 -1
  431. package/out/zero-protocol/src/error.js +7 -0
  432. package/out/zero-protocol/src/error.js.map +1 -1
  433. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  434. package/out/zero-protocol/src/inspect-up.js +1 -0
  435. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  436. package/out/zero-protocol/src/mutate-server.js.map +1 -1
  437. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  438. package/out/zero-protocol/src/mutation.js.map +1 -1
  439. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  440. package/out/zero-protocol/src/ping.js.map +1 -1
  441. package/out/zero-protocol/src/poke.js +4 -0
  442. package/out/zero-protocol/src/poke.js.map +1 -1
  443. package/out/zero-protocol/src/pong.js.map +1 -1
  444. package/out/zero-protocol/src/primary-key.js.map +1 -1
  445. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  446. package/out/zero-protocol/src/pull.js.map +1 -1
  447. package/out/zero-protocol/src/push.js +16 -0
  448. package/out/zero-protocol/src/push.js.map +1 -1
  449. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  450. package/out/zero-protocol/src/query-hash.js.map +1 -1
  451. package/out/zero-protocol/src/query-server.js.map +1 -1
  452. package/out/zero-protocol/src/row-patch.js.map +1 -1
  453. package/out/zero-protocol/src/up.js.map +1 -1
  454. package/out/zero-protocol/src/update-auth.js.map +1 -1
  455. package/out/zero-protocol/src/version.js.map +1 -1
  456. package/out/zero-react/src/use-connection-state.js.map +1 -1
  457. package/out/zero-react/src/use-query.d.ts.map +1 -1
  458. package/out/zero-react/src/use-query.js +2 -3
  459. package/out/zero-react/src/use-query.js.map +1 -1
  460. package/out/zero-react/src/use-zero-online.js.map +1 -1
  461. package/out/zero-react/src/zero-provider.js.map +1 -1
  462. package/out/zero-react/src/zero.js +1 -1
  463. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  464. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  465. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  466. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  467. package/out/zero-schema/src/name-mapper.js.map +1 -1
  468. package/out/zero-schema/src/schema-config.js.map +1 -1
  469. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  470. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  471. package/out/zero-server/src/adapters/pg.js.map +1 -1
  472. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  473. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  474. package/out/zero-server/src/custom.js +2 -1
  475. package/out/zero-server/src/custom.js.map +1 -1
  476. package/out/zero-server/src/logging.js.map +1 -1
  477. package/out/zero-server/src/pg-query-executor.js.map +1 -1
  478. package/out/zero-server/src/process-mutations.js.map +1 -1
  479. package/out/zero-server/src/push-processor.js.map +1 -1
  480. package/out/zero-server/src/queries/process-queries.js +1 -1
  481. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  482. package/out/zero-server/src/schema.d.ts.map +1 -1
  483. package/out/zero-server/src/schema.js +1 -0
  484. package/out/zero-server/src/schema.js.map +1 -1
  485. package/out/zero-server/src/zql-database.js.map +1 -1
  486. package/out/zero-solid/src/solid-view.d.ts +42 -0
  487. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  488. package/out/zero-solid/src/solid-view.js +43 -2
  489. package/out/zero-solid/src/solid-view.js.map +1 -1
  490. package/out/zero-solid/src/use-connection-state.js.map +1 -1
  491. package/out/zero-solid/src/use-query.js +1 -1
  492. package/out/zero-solid/src/use-query.js.map +1 -1
  493. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  494. package/out/zero-solid/src/use-zero.js.map +1 -1
  495. package/out/zero-solid/src/zero.js +1 -1
  496. package/out/zero-types/src/format.js.map +1 -1
  497. package/out/zero-types/src/name-mapper.js.map +1 -1
  498. package/out/zql/src/builder/builder.js.map +1 -1
  499. package/out/zql/src/builder/debug-delegate.d.ts +5 -0
  500. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  501. package/out/zql/src/builder/debug-delegate.js +10 -1
  502. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  503. package/out/zql/src/builder/filter.d.ts.map +1 -1
  504. package/out/zql/src/builder/filter.js +5 -4
  505. package/out/zql/src/builder/filter.js.map +1 -1
  506. package/out/zql/src/builder/like.js +1 -1
  507. package/out/zql/src/builder/like.js.map +1 -1
  508. package/out/zql/src/error.js.map +1 -1
  509. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  510. package/out/zql/src/ivm/array-view.js +5 -3
  511. package/out/zql/src/ivm/array-view.js.map +1 -1
  512. package/out/zql/src/ivm/cap.js.map +1 -1
  513. package/out/zql/src/ivm/change.js.map +1 -1
  514. package/out/zql/src/ivm/constraint.js +1 -1
  515. package/out/zql/src/ivm/constraint.js.map +1 -1
  516. package/out/zql/src/ivm/data.js.map +1 -1
  517. package/out/zql/src/ivm/exists.js.map +1 -1
  518. package/out/zql/src/ivm/fan-in.js.map +1 -1
  519. package/out/zql/src/ivm/fan-out.js.map +1 -1
  520. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  521. package/out/zql/src/ivm/filter-push.js.map +1 -1
  522. package/out/zql/src/ivm/filter.js.map +1 -1
  523. package/out/zql/src/ivm/flipped-join.d.ts +4 -8
  524. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  525. package/out/zql/src/ivm/flipped-join.js +59 -63
  526. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  527. package/out/zql/src/ivm/join-utils.js.map +1 -1
  528. package/out/zql/src/ivm/join.js.map +1 -1
  529. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  530. package/out/zql/src/ivm/memory-source.js.map +1 -1
  531. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  532. package/out/zql/src/ivm/operator.d.ts +1 -1
  533. package/out/zql/src/ivm/operator.js.map +1 -1
  534. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  535. package/out/zql/src/ivm/schema.d.ts +0 -8
  536. package/out/zql/src/ivm/schema.d.ts.map +1 -1
  537. package/out/zql/src/ivm/skip-yields.js.map +1 -1
  538. package/out/zql/src/ivm/skip.js.map +1 -1
  539. package/out/zql/src/ivm/source.js.map +1 -1
  540. package/out/zql/src/ivm/stream.js.map +1 -1
  541. package/out/zql/src/ivm/take.js.map +1 -1
  542. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  543. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  544. package/out/zql/src/ivm/view-apply-change.d.ts +57 -3
  545. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  546. package/out/zql/src/ivm/view-apply-change.js +296 -123
  547. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  548. package/out/zql/src/mutate/crud.js.map +1 -1
  549. package/out/zql/src/mutate/custom.js.map +1 -1
  550. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  551. package/out/zql/src/mutate/mutator.js.map +1 -1
  552. package/out/zql/src/planner/planner-builder.js.map +1 -1
  553. package/out/zql/src/planner/planner-connection.js.map +1 -1
  554. package/out/zql/src/planner/planner-constraint.js.map +1 -1
  555. package/out/zql/src/planner/planner-debug.js.map +1 -1
  556. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  557. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  558. package/out/zql/src/planner/planner-graph.js.map +1 -1
  559. package/out/zql/src/planner/planner-join.d.ts.map +1 -1
  560. package/out/zql/src/planner/planner-join.js +2 -1
  561. package/out/zql/src/planner/planner-join.js.map +1 -1
  562. package/out/zql/src/planner/planner-node.js.map +1 -1
  563. package/out/zql/src/planner/planner-source.js.map +1 -1
  564. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  565. package/out/zql/src/query/complete-ordering.js.map +1 -1
  566. package/out/zql/src/query/create-builder.js.map +1 -1
  567. package/out/zql/src/query/error.js.map +1 -1
  568. package/out/zql/src/query/escape-like.js.map +1 -1
  569. package/out/zql/src/query/expression.js.map +1 -1
  570. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  571. package/out/zql/src/query/metrics-delegate.js.map +1 -1
  572. package/out/zql/src/query/named.js.map +1 -1
  573. package/out/zql/src/query/query-delegate-base.js +1 -3
  574. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  575. package/out/zql/src/query/query-impl.js.map +1 -1
  576. package/out/zql/src/query/query-internals.js.map +1 -1
  577. package/out/zql/src/query/query-registry.js.map +1 -1
  578. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  579. package/out/zql/src/query/static-query.js.map +1 -1
  580. package/out/zql/src/query/ttl.js.map +1 -1
  581. package/out/zql/src/query/validate-input.js.map +1 -1
  582. package/out/zqlite/src/database-storage.js.map +1 -1
  583. package/out/zqlite/src/db.d.ts.map +1 -1
  584. package/out/zqlite/src/db.js +1 -0
  585. package/out/zqlite/src/db.js.map +1 -1
  586. package/out/zqlite/src/explain-queries.js.map +1 -1
  587. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  588. package/out/zqlite/src/internal/sql.js.map +1 -1
  589. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  590. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  591. package/out/zqlite/src/query-builder.js +12 -1
  592. package/out/zqlite/src/query-builder.js.map +1 -1
  593. package/out/zqlite/src/query-delegate.js.map +1 -1
  594. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  595. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  596. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  597. package/out/zqlite/src/table-source.d.ts.map +1 -1
  598. package/out/zqlite/src/table-source.js +6 -6
  599. package/out/zqlite/src/table-source.js.map +1 -1
  600. package/package.json +45 -28
  601. package/out/zero-client/src/util/socket.d.ts +0 -3
  602. package/out/zero-client/src/util/socket.d.ts.map +0 -1
  603. package/out/zero-client/src/util/socket.js +0 -8
  604. package/out/zero-client/src/util/socket.js.map +0 -1
  605. package/out/zero-schema/src/permissions.d.ts.map +0 -1
  606. package/out/zero-schema/src/permissions.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"array-view.js","names":["#input","#listeners","#schema","#format","#root","#updateTTL","#resultType","#error","#fireListeners","#hydrate","#fireListener","#dirty"],"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 {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport type {Change} from './change.ts';\nimport {skipYields, type Input, type Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {applyChange, type ViewChange} from './view-apply-change.ts';\nimport type {Entry, Format, View} from './view.ts';\n\nfunction changeToViewChange(change: Change): ViewChange {\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n return {type: 'add', node: change[ChangeIndex.NODE]};\n case ChangeType.REMOVE:\n return {type: 'remove', node: change[ChangeIndex.NODE]};\n case ChangeType.CHILD:\n return {\n type: 'child',\n node: change[ChangeIndex.NODE],\n child: {\n relationshipName: change[ChangeIndex.CHILD_DATA].relationshipName,\n change: changeToViewChange(change[ChangeIndex.CHILD_DATA].change),\n },\n };\n case ChangeType.EDIT:\n return {\n type: 'edit',\n node: change[ChangeIndex.NODE],\n oldNode: change[ChangeIndex.OLD_NODE],\n };\n }\n}\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(\n this.#root,\n changeToViewChange(change),\n this.#schema,\n '',\n this.#format,\n );\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"],"mappings":";;;;;AAcA,SAAS,mBAAmB,QAA4B;AACtD,SAAQ,OAAO,IAAf;EACE,KAAK,EACH,QAAO;GAAC,MAAM;GAAO,MAAM,OAAO;GAAkB;EACtD,KAAK,EACH,QAAO;GAAC,MAAM;GAAU,MAAM,OAAO;GAAkB;EACzD,KAAK,EACH,QAAO;GACL,MAAM;GACN,MAAM,OAAO;GACb,OAAO;IACL,kBAAkB,OAAO,GAAwB;IACjD,QAAQ,mBAAmB,OAAO,GAAwB,OAAO;IAClE;GACF;EACH,KAAK,EACH,QAAO;GACL,MAAM;GACN,MAAM,OAAO;GACb,SAAS,OAAO;GACjB;;;;;;;;;;;;;;AAeP,IAAa,YAAb,MAAuE;CACrE;CACA,6BAAsB,IAAI,KAAkB;CAC5C;CACA;CAIA;CAEA;CAEA,SAAS;CACT,cAA0B;CAC1B;CACA;CAEA,YACE,OACA,QACA,eACA,WACA;AACA,QAAA,QAAc;AACd,QAAA,SAAe,MAAM,WAAW;AAChC,QAAA,SAAe;AACf,QAAA,YAAkB;AAClB,QAAA,OAAa,EAAC,IAAI,OAAO,WAAW,KAAA,IAAY,EAAE,EAAC;AACnD,QAAM,UAAU,KAAK;AAErB,MAAI,kBAAkB,KACpB,OAAA,aAAmB;WACV,WAAW,eAAe;AACnC,SAAA,aAAmB;AACnB,SAAA,QAAc;QAET,eACF,WAAW;AACV,SAAA,aAAmB;AACnB,SAAA,eAAqB;IACrB,CACD,OAAM,MAAK;AACV,SAAA,aAAmB;AACnB,SAAA,QAAc;AACd,SAAA,eAAqB;IACrB;AAEN,QAAA,SAAe;;CAGjB,IAAI,OAAO;AACT,SAAO,MAAA,KAAW;;CAGpB,YAAY,UAAuB;AACjC,SAAO,CAAC,MAAA,UAAgB,IAAI,SAAS,EAAE,8BAA8B;AACrE,QAAA,UAAgB,IAAI,SAAS;AAE7B,QAAA,aAAmB,SAAS;AAE5B,eAAa;AACX,SAAA,UAAgB,OAAO,SAAS;;;CAIpC,iBAAiB;AACf,OAAK,MAAM,YAAY,MAAA,UACrB,OAAA,aAAmB,SAAS;;CAIhC,cAAc,UAAuB;AACnC,WAAS,KAAK,MAAsB,MAAA,YAAkB,MAAA,MAAY;;CAGpE,UAAU;AACR,OAAK,aAAa;;CAGpB,WAAW;AACT,QAAA,QAAc;AACd,OAAK,MAAM,QAAQ,WAAW,MAAA,MAAY,MAAM,EAAE,CAAC,CAAC,CAClD,aACE,MAAA,MACA;GAAC,MAAM;GAAO;GAAK,EACnB,MAAA,QACA,IACA,MAAA,OACD;AAEH,OAAK,OAAO;;CAGd,KAAK,QAAgB;AACnB,QAAA,QAAc;AACd,cACE,MAAA,MACA,mBAAmB,OAAO,EAC1B,MAAA,QACA,IACA,MAAA,OACD;AACD,SAAO;;CAGT,QAAQ;AACN,MAAI,CAAC,MAAA,MACH;AAEF,QAAA,QAAc;AACd,QAAA,eAAqB;;CAGvB,UAAU,KAAU;AAClB,QAAA,UAAgB,IAAI"}
1
+ {"version":3,"file":"array-view.js","names":["#input","#listeners","#schema","#format","#updateTTL","#root","#resultType","#error","#fireListeners","#hydrate","#fireListener","#dirty","#txnDirty"],"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 {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport type {Change} from './change.ts';\nimport {skipYields, type Input, type Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {applyChange, type ViewChange} from './view-apply-change.ts';\nimport type {Entry, Format, View} from './view.ts';\n\nfunction changeToViewChange(change: Change): ViewChange {\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n return {type: 'add', node: change[ChangeIndex.NODE]};\n case ChangeType.REMOVE:\n return {type: 'remove', node: change[ChangeIndex.NODE]};\n case ChangeType.CHILD:\n return {\n type: 'child',\n node: change[ChangeIndex.NODE],\n child: {\n relationshipName: change[ChangeIndex.CHILD_DATA].relationshipName,\n change: changeToViewChange(change[ChangeIndex.CHILD_DATA].change),\n },\n };\n case ChangeType.EDIT:\n return {\n type: 'edit',\n node: change[ChangeIndex.NODE],\n oldNode: change[ChangeIndex.OLD_NODE],\n };\n }\n}\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 //\n // applyChange is immutable: it returns a new root, preserving the references\n // of unchanged subtrees so consumers (React.memo / Solid) can skip them. We\n // therefore reassign #root on every change rather than mutating in place.\n #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 // Objects/arrays created or cloned during the current (un-flushed)\n // transaction. applyChange may mutate these in place rather than copying\n // again, since they are not yet observed by any listener. Replaced at\n // flush(), after which the committed snapshot must be copied-on-write again.\n // A WeakSet (not a Set) so it never extends the lifetime of transient clones.\n #txnDirty: WeakSet<object> = new WeakSet();\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 this.#root = applyChange(\n this.#root,\n {type: 'add', node},\n this.#schema,\n '',\n this.#format,\n false /* withIDs */,\n true /* mutate: #root is freshly created and not yet observed by any\n consumer, so build it in place to avoid O(N^2) array copies.\n Every later push() is immutable, preserving reference\n stability for unchanged subtrees. */,\n );\n }\n this.flush();\n }\n\n push(change: Change) {\n this.#dirty = true;\n this.#root = applyChange(\n this.#root,\n changeToViewChange(change),\n this.#schema,\n '',\n this.#format,\n false /* withIDs */,\n this.#txnDirty /* mutate: copy-on-write within this transaction */,\n );\n return emptyArray;\n }\n\n flush() {\n if (!this.#dirty) {\n return;\n }\n this.#dirty = false;\n this.#fireListeners();\n // The snapshot just handed to listeners is now observed; the next\n // transaction must copy-on-write rather than mutate these objects. A fresh\n // WeakSet drops all \"owned\" marks (WeakSet has no clear()).\n this.#txnDirty = new WeakSet();\n }\n\n updateTTL(ttl: TTL) {\n this.#updateTTL(ttl);\n }\n}\n"],"mappings":";;;;;AAcA,SAAS,mBAAmB,QAA4B;CACtD,QAAQ,OAAO,IAAf;EACE,KAAK,GACH,OAAO;GAAC,MAAM;GAAO,MAAM,OAAO;EAAiB;EACrD,KAAK,GACH,OAAO;GAAC,MAAM;GAAU,MAAM,OAAO;EAAiB;EACxD,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,OAAO;GACb,OAAO;IACL,kBAAkB,OAAO,GAAwB;IACjD,QAAQ,mBAAmB,OAAO,GAAwB,MAAM;GAClE;EACF;EACF,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,OAAO;GACb,SAAS,OAAO;EAClB;CACJ;AACF;;;;;;;;;;;;AAaA,IAAa,YAAb,MAAuE;CACrE;CACA,6BAAsB,IAAI,IAAiB;CAC3C;CACA;CAQA;CAEA;CAEA,SAAS;CACT,cAA0B;CAC1B;CACA;CAOA,4BAA6B,IAAI,QAAQ;CAEzC,YACE,OACA,QACA,eACA,WACA;EACA,KAAKA,SAAS;EACd,KAAKE,UAAU,MAAM,UAAU;EAC/B,KAAKC,UAAU;EACf,KAAKC,aAAa;EAClB,KAAKC,QAAQ,EAAC,IAAI,OAAO,WAAW,KAAA,IAAY,CAAC,EAAC;EAClD,MAAM,UAAU,IAAI;EAEpB,IAAI,kBAAkB,MACpB,KAAKC,cAAc;OACd,IAAI,WAAW,eAAe;GACnC,KAAKA,cAAc;GACnB,KAAKC,SAAS;EAChB,OACE,cACG,WAAW;GACV,KAAKD,cAAc;GACnB,KAAKE,eAAe;EACtB,CAAC,EACA,OAAM,MAAK;GACV,KAAKF,cAAc;GACnB,KAAKC,SAAS;GACd,KAAKC,eAAe;EACtB,CAAC;EAEL,KAAKC,SAAS;CAChB;CAEA,IAAI,OAAO;EACT,OAAO,KAAKJ,MAAM;CACpB;CAEA,YAAY,UAAuB;EACjC,OAAO,CAAC,KAAKJ,WAAW,IAAI,QAAQ,GAAG,6BAA6B;EACpE,KAAKA,WAAW,IAAI,QAAQ;EAE5B,KAAKS,cAAc,QAAQ;EAE3B,aAAa;GACX,KAAKT,WAAW,OAAO,QAAQ;EACjC;CACF;CAEA,iBAAiB;EACf,KAAK,MAAM,YAAY,KAAKA,YAC1B,KAAKS,cAAc,QAAQ;CAE/B;CAEA,cAAc,UAAuB;EACnC,SAAS,KAAK,MAAsB,KAAKJ,aAAa,KAAKC,MAAM;CACnE;CAEA,UAAU;EACR,KAAK,YAAY;CACnB;CAEA,WAAW;EACT,KAAKI,SAAS;EACd,KAAK,MAAM,QAAQ,WAAW,KAAKX,OAAO,MAAM,CAAC,CAAC,CAAC,GACjD,KAAKK,QAAQ,YACX,KAAKA,OACL;GAAC,MAAM;GAAO;EAAI,GAClB,KAAKH,SACL,IACA,KAAKC,SACL,OACA,IAIF;EAEF,KAAK,MAAM;CACb;CAEA,KAAK,QAAgB;EACnB,KAAKQ,SAAS;EACd,KAAKN,QAAQ,YACX,KAAKA,OACL,mBAAmB,MAAM,GACzB,KAAKH,SACL,IACA,KAAKC,SACL,OACA,KAAKS,SACP;EACA,OAAO;CACT;CAEA,QAAQ;EACN,IAAI,CAAC,KAAKD,QACR;EAEF,KAAKA,SAAS;EACd,KAAKH,eAAe;EAIpB,KAAKI,4BAAY,IAAI,QAAQ;CAC/B;CAEA,UAAU,KAAU;EAClB,KAAKR,WAAW,GAAG;CACrB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"cap.js","names":["#input","#storage","#limit","#partitionKey","#partitionKeyComparator","#primaryKey","#output","#initialFetch","#pushEditChange"],"sources":["../../../../../zql/src/ivm/cap.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {makeAddChange, type Change, type EditChange} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Comparator, Node} from './data.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\nimport {\n constraintMatchesPartitionKey,\n makePartitionKeyComparator,\n type PartitionKey,\n} from './take.ts';\n\ntype CapState = {\n size: number;\n pks: string[];\n};\n\ninterface CapStorage {\n get(key: string): CapState | undefined;\n set(key: string, value: CapState): void;\n del(key: string): void;\n}\n\n/**\n * The Cap operator is a count-based limiter for EXISTS subqueries that\n * does not require ordering. Unlike Take, it tracks membership by primary\n * key set rather than by a sorted bound. This means:\n *\n * - No comparator needed (no ordering requirement)\n * - No `start` or `reverse` fetch support\n * - No `#rowHiddenFromFetch` complexity (we can defer when adding to the pk set)\n *\n * Cap is used in EXISTS child pipelines where only the count of matching\n * rows matters, not their order. This allows SQLite to skip ORDER BY\n * entirely, enabling much faster query plans.\n *\n * Cap can count rows globally or by unique value of some partition key\n * (same as Take).\n */\nexport class Cap implements Operator {\n readonly #input: Input;\n readonly #storage: CapStorage;\n readonly #limit: number;\n readonly #partitionKey: PartitionKey | undefined;\n readonly #partitionKeyComparator: Comparator | undefined;\n readonly #primaryKey: PrimaryKey;\n\n #output: Output = throwOutput;\n\n constructor(\n input: Input,\n storage: Storage,\n limit: number,\n partitionKey?: PartitionKey,\n ) {\n assert(limit >= 0, 'Limit must be non-negative');\n input.setOutput(this);\n this.#input = input;\n this.#storage = storage as CapStorage;\n this.#limit = limit;\n this.#partitionKey = partitionKey;\n this.#partitionKeyComparator =\n partitionKey && makePartitionKeyComparator(partitionKey);\n this.#primaryKey = input.getSchema().primaryKey;\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n assert(!req.start, 'Cap does not support start');\n assert(!req.reverse, 'Cap does not support reverse');\n\n // Cap is only built for non-flipped EXISTS subqueries, whose only\n // downstream consumer is a Join that always fetches with a constraint\n // built from the correlation's childField — which is Cap's partition\n // key. So either partitionKey is undefined, or constraint matches.\n assert(\n !this.#partitionKey ||\n (req.constraint !== undefined &&\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey)),\n 'Cap fetch: constraint must match partition key when partitioned',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n yield* this.#initialFetch(req);\n return;\n }\n if (capState.size === 0) {\n return;\n }\n // PK-based point lookups: fetch each tracked row by its PK directly,\n // rather than scanning the partition and filtering.\n for (const pk of capState.pks) {\n const constraint = deserializePKToConstraint(pk, this.#primaryKey);\n for (const inputNode of this.#input.fetch({constraint})) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n yield inputNode;\n }\n }\n }\n\n *#initialFetch(req: FetchRequest): Stream<Node | 'yield'> {\n if (this.#limit === 0) {\n return;\n }\n\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n assert(\n this.#storage.get(capStateKey) === undefined,\n 'Cap state should be undefined',\n );\n\n let size = 0;\n const pks: string[] = [];\n let downstreamEarlyReturn = true;\n let exceptionThrown = false;\n try {\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield 'yield';\n continue;\n }\n yield inputNode;\n pks.push(serializePK(inputNode.row, this.#primaryKey));\n size++;\n if (size === this.#limit) {\n break;\n }\n }\n downstreamEarlyReturn = false;\n } catch (e) {\n exceptionThrown = true;\n throw e;\n } finally {\n if (!exceptionThrown) {\n this.#storage.set(capStateKey, {size, pks});\n // If it becomes necessary to support downstream early return, this\n // assert should be removed, and replaced with code that consumes\n // the input stream until limit is reached or the input stream is\n // exhausted so that capState is properly hydrated.\n assert(\n !downstreamEarlyReturn,\n 'Unexpected early return prevented full hydration',\n );\n }\n }\n }\n\n *push(change: Change): Stream<'yield'> {\n if (change[ChangeIndex.TYPE] === ChangeType.EDIT) {\n yield* this.#pushEditChange(change);\n return;\n }\n\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const pk = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n\n if (change[ChangeIndex.TYPE] === ChangeType.ADD) {\n if (capState.size < this.#limit) {\n const pks = [...capState.pks, pk];\n this.#storage.set(capStateKey, {size: capState.size + 1, pks});\n yield* this.#output.push(change, this);\n return;\n }\n // Full — drop\n return;\n } else if (change[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n const pkIndex = capState.pks.indexOf(pk);\n if (pkIndex === -1) {\n // Not in our set — drop\n return;\n }\n // Remove from set\n const pks = [...capState.pks];\n pks.splice(pkIndex, 1);\n const newSize = capState.size - 1;\n\n // Try to refill: fetch from input with partition constraint,\n // find first row NOT in PK set\n const pkSet = new Set(pks);\n const constraint = this.#partitionKey\n ? (Object.fromEntries(\n this.#partitionKey.map(\n key => [key, change[ChangeIndex.NODE].row[key]] as const,\n ),\n ) as Constraint)\n : undefined;\n\n let replacement: Node | undefined;\n for (const node of this.#input.fetch({constraint})) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const nodePK = serializePK(node.row, this.#primaryKey);\n if (!pkSet.has(nodePK)) {\n replacement = node;\n break;\n }\n }\n\n if (replacement) {\n // Store state WITHOUT replacement during remove forward,\n // matching Take's pattern of hiding in-flight changes from re-fetches.\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n // Now add replacement to set and forward the add.\n const replacementPK = serializePK(replacement.row, this.#primaryKey);\n pks.push(replacementPK);\n this.#storage.set(capStateKey, {size: newSize + 1, pks});\n yield* this.#output.push(makeAddChange(replacement), this);\n } else {\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n }\n } else if (change[ChangeIndex.TYPE] === ChangeType.CHILD) {\n const pkSet = new Set(capState.pks);\n if (pkSet.has(pk)) {\n yield* this.#output.push(change, this);\n }\n }\n }\n\n *#pushEditChange(change: EditChange): Stream<'yield'> {\n assert(\n !this.#partitionKeyComparator ||\n this.#partitionKeyComparator(\n change[ChangeIndex.OLD_NODE].row,\n change[ChangeIndex.NODE].row,\n ) === 0,\n 'Unexpected change of partition key',\n );\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.OLD_NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const oldPK = serializePK(\n change[ChangeIndex.OLD_NODE].row,\n this.#primaryKey,\n );\n const pkSet = new Set(capState.pks);\n if (pkSet.has(oldPK)) {\n // Update the PK in our set if it changed\n const newPK = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n if (oldPK !== newPK) {\n const pks = capState.pks.map(p => (p === oldPK ? newPK : p));\n this.#storage.set(capStateKey, {size: capState.size, pks});\n }\n yield* this.#output.push(change, this);\n }\n // If not in our set, drop\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n}\n\nfunction getCapStateKey(\n partitionKey: PartitionKey | undefined,\n rowOrConstraint: Row | Constraint | undefined,\n): string {\n const partitionValues: Value[] = [];\n\n if (partitionKey && rowOrConstraint) {\n for (const key of partitionKey) {\n partitionValues.push(rowOrConstraint[key]);\n }\n }\n\n return JSON.stringify(['cap', ...partitionValues]);\n}\n\nfunction serializePK(row: Row, primaryKey: PrimaryKey): string {\n return JSON.stringify(primaryKey.map(k => row[k]));\n}\n\nfunction deserializePKToConstraint(\n pk: string,\n primaryKey: PrimaryKey,\n): Constraint {\n const values = JSON.parse(pk) as Value[];\n const constraint: Record<string, Value> = {};\n for (let i = 0; i < primaryKey.length; i++) {\n constraint[primaryKey[i]] = values[i];\n }\n return constraint;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cap.js","names":["#input","#storage","#limit","#partitionKey","#partitionKeyComparator","#primaryKey","#output","#initialFetch","#pushEditChange"],"sources":["../../../../../zql/src/ivm/cap.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {makeAddChange, type Change, type EditChange} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Comparator, Node} from './data.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\nimport {\n constraintMatchesPartitionKey,\n makePartitionKeyComparator,\n type PartitionKey,\n} from './take.ts';\n\ntype CapState = {\n size: number;\n pks: string[];\n};\n\ninterface CapStorage {\n get(key: string): CapState | undefined;\n set(key: string, value: CapState): void;\n del(key: string): void;\n}\n\n/**\n * The Cap operator is a count-based limiter for EXISTS subqueries that\n * does not require ordering. Unlike Take, it tracks membership by primary\n * key set rather than by a sorted bound. This means:\n *\n * - No comparator needed (no ordering requirement)\n * - No `start` or `reverse` fetch support\n * - No `#rowHiddenFromFetch` complexity (we can defer when adding to the pk set)\n *\n * Cap is used in EXISTS child pipelines where only the count of matching\n * rows matters, not their order. This allows SQLite to skip ORDER BY\n * entirely, enabling much faster query plans.\n *\n * Cap can count rows globally or by unique value of some partition key\n * (same as Take).\n */\nexport class Cap implements Operator {\n readonly #input: Input;\n readonly #storage: CapStorage;\n readonly #limit: number;\n readonly #partitionKey: PartitionKey | undefined;\n readonly #partitionKeyComparator: Comparator | undefined;\n readonly #primaryKey: PrimaryKey;\n\n #output: Output = throwOutput;\n\n constructor(\n input: Input,\n storage: Storage,\n limit: number,\n partitionKey?: PartitionKey,\n ) {\n assert(limit >= 0, 'Limit must be non-negative');\n input.setOutput(this);\n this.#input = input;\n this.#storage = storage as CapStorage;\n this.#limit = limit;\n this.#partitionKey = partitionKey;\n this.#partitionKeyComparator =\n partitionKey && makePartitionKeyComparator(partitionKey);\n this.#primaryKey = input.getSchema().primaryKey;\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n assert(!req.start, 'Cap does not support start');\n assert(!req.reverse, 'Cap does not support reverse');\n\n // Cap is only built for non-flipped EXISTS subqueries, whose only\n // downstream consumer is a Join that always fetches with a constraint\n // built from the correlation's childField — which is Cap's partition\n // key. So either partitionKey is undefined, or constraint matches.\n assert(\n !this.#partitionKey ||\n (req.constraint !== undefined &&\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey)),\n 'Cap fetch: constraint must match partition key when partitioned',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n yield* this.#initialFetch(req);\n return;\n }\n if (capState.size === 0) {\n return;\n }\n // PK-based point lookups: fetch each tracked row by its PK directly,\n // rather than scanning the partition and filtering.\n for (const pk of capState.pks) {\n const constraint = deserializePKToConstraint(pk, this.#primaryKey);\n for (const inputNode of this.#input.fetch({constraint})) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n yield inputNode;\n }\n }\n }\n\n *#initialFetch(req: FetchRequest): Stream<Node | 'yield'> {\n if (this.#limit === 0) {\n return;\n }\n\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n assert(\n this.#storage.get(capStateKey) === undefined,\n 'Cap state should be undefined',\n );\n\n let size = 0;\n const pks: string[] = [];\n let downstreamEarlyReturn = true;\n let exceptionThrown = false;\n try {\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield 'yield';\n continue;\n }\n yield inputNode;\n pks.push(serializePK(inputNode.row, this.#primaryKey));\n size++;\n if (size === this.#limit) {\n break;\n }\n }\n downstreamEarlyReturn = false;\n } catch (e) {\n exceptionThrown = true;\n throw e;\n } finally {\n if (!exceptionThrown) {\n this.#storage.set(capStateKey, {size, pks});\n // If it becomes necessary to support downstream early return, this\n // assert should be removed, and replaced with code that consumes\n // the input stream until limit is reached or the input stream is\n // exhausted so that capState is properly hydrated.\n assert(\n !downstreamEarlyReturn,\n 'Unexpected early return prevented full hydration',\n );\n }\n }\n }\n\n *push(change: Change): Stream<'yield'> {\n if (change[ChangeIndex.TYPE] === ChangeType.EDIT) {\n yield* this.#pushEditChange(change);\n return;\n }\n\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const pk = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n\n if (change[ChangeIndex.TYPE] === ChangeType.ADD) {\n if (capState.size < this.#limit) {\n const pks = [...capState.pks, pk];\n this.#storage.set(capStateKey, {size: capState.size + 1, pks});\n yield* this.#output.push(change, this);\n return;\n }\n // Full — drop\n return;\n } else if (change[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n const pkIndex = capState.pks.indexOf(pk);\n if (pkIndex === -1) {\n // Not in our set — drop\n return;\n }\n // Remove from set\n const pks = [...capState.pks];\n pks.splice(pkIndex, 1);\n const newSize = capState.size - 1;\n\n // Try to refill: fetch from input with partition constraint,\n // find first row NOT in PK set\n const pkSet = new Set(pks);\n const constraint = this.#partitionKey\n ? (Object.fromEntries(\n this.#partitionKey.map(\n key => [key, change[ChangeIndex.NODE].row[key]] as const,\n ),\n ) as Constraint)\n : undefined;\n\n let replacement: Node | undefined;\n for (const node of this.#input.fetch({constraint})) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const nodePK = serializePK(node.row, this.#primaryKey);\n if (!pkSet.has(nodePK)) {\n replacement = node;\n break;\n }\n }\n\n if (replacement) {\n // Store state WITHOUT replacement during remove forward,\n // matching Take's pattern of hiding in-flight changes from re-fetches.\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n // Now add replacement to set and forward the add.\n const replacementPK = serializePK(replacement.row, this.#primaryKey);\n pks.push(replacementPK);\n this.#storage.set(capStateKey, {size: newSize + 1, pks});\n yield* this.#output.push(makeAddChange(replacement), this);\n } else {\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n }\n } else if (change[ChangeIndex.TYPE] === ChangeType.CHILD) {\n const pkSet = new Set(capState.pks);\n if (pkSet.has(pk)) {\n yield* this.#output.push(change, this);\n }\n }\n }\n\n *#pushEditChange(change: EditChange): Stream<'yield'> {\n assert(\n !this.#partitionKeyComparator ||\n this.#partitionKeyComparator(\n change[ChangeIndex.OLD_NODE].row,\n change[ChangeIndex.NODE].row,\n ) === 0,\n 'Unexpected change of partition key',\n );\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.OLD_NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const oldPK = serializePK(\n change[ChangeIndex.OLD_NODE].row,\n this.#primaryKey,\n );\n const pkSet = new Set(capState.pks);\n if (pkSet.has(oldPK)) {\n // Update the PK in our set if it changed\n const newPK = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n if (oldPK !== newPK) {\n const pks = capState.pks.map(p => (p === oldPK ? newPK : p));\n this.#storage.set(capStateKey, {size: capState.size, pks});\n }\n yield* this.#output.push(change, this);\n }\n // If not in our set, drop\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n}\n\nfunction getCapStateKey(\n partitionKey: PartitionKey | undefined,\n rowOrConstraint: Row | Constraint | undefined,\n): string {\n const partitionValues: Value[] = [];\n\n if (partitionKey && rowOrConstraint) {\n for (const key of partitionKey) {\n partitionValues.push(rowOrConstraint[key]);\n }\n }\n\n return JSON.stringify(['cap', ...partitionValues]);\n}\n\nfunction serializePK(row: Row, primaryKey: PrimaryKey): string {\n return JSON.stringify(primaryKey.map(k => row[k]));\n}\n\nfunction deserializePKToConstraint(\n pk: string,\n primaryKey: PrimaryKey,\n): Constraint {\n const values = JSON.parse(pk) as Value[];\n const constraint: Record<string, Value> = {};\n for (let i = 0; i < primaryKey.length; i++) {\n constraint[primaryKey[i]] = values[i];\n }\n return constraint;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"change.js","names":[],"sources":["../../../../../zql/src/ivm/change.ts"],"sourcesContent":["import {ChangeType} from './change-type.ts';\nimport type {Node} from './data.ts';\n\n/**\n * The `child` payload carried by a {@linkcode ChildChange}.\n */\nexport type ChildData = {\n relationshipName: string;\n change: Change;\n};\n\nexport type Change = AddChange | RemoveChange | ChildChange | EditChange;\n\n/**\n * Represents a node (and all its children) getting added to the result.\n */\nexport type AddChange = [type: ChangeType.ADD, node: Node, extra: null];\n\n/**\n * Represents a node (and all its children) getting removed from the result.\n */\nexport type RemoveChange = [type: ChangeType.REMOVE, node: Node, extra: null];\n\n/**\n * The node's row is unchanged, but one of its descendants has changed.\n * The node's relationships will reflect the change, `child` specifies the\n * specific descendant change.\n */\nexport type ChildChange = [\n type: ChangeType.CHILD,\n node: Node,\n child: ChildData,\n];\n\n/**\n * The row changed (in a way that the {@linkcode Source} determines). Most\n * likely the PK stayed the same but there is really no restriction in how it\n * can change.\n *\n * The edit changes flows down in a {@linkcode Output.push}.\n * There are cases where an edit change gets split into a remove and/or an add\n * change.\n * 1. when the presence of the row in the result changes (for example the row\n * is no longer present due to a filter)\n * 2. the edit results in the rows relationships changing\n *\n * If an edit is not split, the relationships of node and oldNode must\n * be the same, just the Row has changed.\n *\n * NOTE: It would be cleaner to just have the relationships once,\n * since they must be the same, however relationship Streams are single use\n * and if an Edit needs to be split into a remove and add a single map\n * of relationship Streams could not be used for the both the remove and\n * the add. This cleanup could be done if we move to multi-use Streams\n * for relationships.\n */\nexport type EditChange = [type: ChangeType.EDIT, node: Node, oldNode: Node];\n\n// Factory functions — prefer these over constructing tuple literals directly.\n\nexport function makeAddChange(node: Node): AddChange {\n return [ChangeType.ADD, node, null];\n}\n\nexport function makeRemoveChange(node: Node): RemoveChange {\n return [ChangeType.REMOVE, node, null];\n}\n\nexport function makeChildChange(node: Node, child: ChildData): ChildChange {\n return [ChangeType.CHILD, node, child];\n}\n\nexport function makeEditChange(node: Node, oldNode: Node): EditChange {\n return [ChangeType.EDIT, node, oldNode];\n}\n"],"mappings":";AA4DA,SAAgB,cAAc,MAAuB;AACnD,QAAO;EAAC;EAAgB;EAAM;EAAK;;AAGrC,SAAgB,iBAAiB,MAA0B;AACzD,QAAO;EAAC;EAAmB;EAAM;EAAK;;AAGxC,SAAgB,gBAAgB,MAAY,OAA+B;AACzE,QAAO;EAAC;EAAkB;EAAM;EAAM;;AAGxC,SAAgB,eAAe,MAAY,SAA2B;AACpE,QAAO;EAAC;EAAiB;EAAM;EAAQ"}
1
+ {"version":3,"file":"change.js","names":[],"sources":["../../../../../zql/src/ivm/change.ts"],"sourcesContent":["import {ChangeType} from './change-type.ts';\nimport type {Node} from './data.ts';\n\n/**\n * The `child` payload carried by a {@linkcode ChildChange}.\n */\nexport type ChildData = {\n relationshipName: string;\n change: Change;\n};\n\nexport type Change = AddChange | RemoveChange | ChildChange | EditChange;\n\n/**\n * Represents a node (and all its children) getting added to the result.\n */\nexport type AddChange = [type: ChangeType.ADD, node: Node, extra: null];\n\n/**\n * Represents a node (and all its children) getting removed from the result.\n */\nexport type RemoveChange = [type: ChangeType.REMOVE, node: Node, extra: null];\n\n/**\n * The node's row is unchanged, but one of its descendants has changed.\n * The node's relationships will reflect the change, `child` specifies the\n * specific descendant change.\n */\nexport type ChildChange = [\n type: ChangeType.CHILD,\n node: Node,\n child: ChildData,\n];\n\n/**\n * The row changed (in a way that the {@linkcode Source} determines). Most\n * likely the PK stayed the same but there is really no restriction in how it\n * can change.\n *\n * The edit changes flows down in a {@linkcode Output.push}.\n * There are cases where an edit change gets split into a remove and/or an add\n * change.\n * 1. when the presence of the row in the result changes (for example the row\n * is no longer present due to a filter)\n * 2. the edit results in the rows relationships changing\n *\n * If an edit is not split, the relationships of node and oldNode must\n * be the same, just the Row has changed.\n *\n * NOTE: It would be cleaner to just have the relationships once,\n * since they must be the same, however relationship Streams are single use\n * and if an Edit needs to be split into a remove and add a single map\n * of relationship Streams could not be used for the both the remove and\n * the add. This cleanup could be done if we move to multi-use Streams\n * for relationships.\n */\nexport type EditChange = [type: ChangeType.EDIT, node: Node, oldNode: Node];\n\n// Factory functions — prefer these over constructing tuple literals directly.\n\nexport function makeAddChange(node: Node): AddChange {\n return [ChangeType.ADD, node, null];\n}\n\nexport function makeRemoveChange(node: Node): RemoveChange {\n return [ChangeType.REMOVE, node, null];\n}\n\nexport function makeChildChange(node: Node, child: ChildData): ChildChange {\n return [ChangeType.CHILD, node, child];\n}\n\nexport function makeEditChange(node: Node, oldNode: Node): EditChange {\n return [ChangeType.EDIT, node, oldNode];\n}\n"],"mappings":";AA4DA,SAAgB,cAAc,MAAuB;CACnD,OAAO;EAAC;EAAgB;EAAM;CAAI;AACpC;AAEA,SAAgB,iBAAiB,MAA0B;CACzD,OAAO;EAAC;EAAmB;EAAM;CAAI;AACvC;AAEA,SAAgB,gBAAgB,MAAY,OAA+B;CACzE,OAAO;EAAC;EAAkB;EAAM;CAAK;AACvC;AAEA,SAAgB,eAAe,MAAY,SAA2B;CACpE,OAAO;EAAC;EAAiB;EAAM;CAAO;AACxC"}
@@ -77,6 +77,6 @@ function extractColumn(condition) {
77
77
  }
78
78
  }
79
79
  //#endregion
80
- export { constraintMatchesPrimaryKey, constraintMatchesRow, constraintsAreCompatible, keyMatchesPrimaryKey, primaryKeyConstraintFromFilters };
80
+ export { constraintMatchesPrimaryKey, constraintMatchesRow, constraintsAreCompatible, primaryKeyConstraintFromFilters };
81
81
 
82
82
  //# sourceMappingURL=constraint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constraint.js","names":["#data","#indexOf"],"sources":["../../../../../zql/src/ivm/constraint.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {stringCompare} from '../../../shared/src/string-compare.ts';\nimport {assertTesting} from '../../../shared/src/testing.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {\n Condition,\n SimpleCondition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {valuesEqual} from './data.ts';\n\nexport type Constraint = {\n readonly [key: string]: Value;\n};\n\nexport function constraintMatchesRow(\n constraint: Constraint,\n row: Row,\n): boolean {\n for (const key in constraint) {\n if (!valuesEqual(row[key], constraint[key])) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Constraints are compatible if:\n * 1. They do not have any keys in common\n * 2. They have keys in common, but the values for those keys are equal\n */\nexport function constraintsAreCompatible(\n left: Constraint,\n right: Constraint,\n): boolean {\n for (const key in left) {\n if (key in right && !valuesEqual(left[key], right[key])) {\n return false;\n }\n }\n return true;\n}\n\nexport function constraintMatchesPrimaryKey(\n constraint: Constraint,\n primary: PrimaryKey,\n): boolean {\n return keyMatchesPrimaryKey(Object.keys(constraint), primary);\n}\n\nexport function keyMatchesPrimaryKey(\n key: Iterable<string>,\n primary: PrimaryKey,\n): boolean {\n const constraintKeys = [...key];\n\n if (constraintKeys.length !== primary.length) {\n return false;\n }\n\n // Primary key is always sorted\n // Constraint does not have to be sorted\n constraintKeys.sort(stringCompare);\n\n for (let i = 0; i < constraintKeys.length; i++) {\n if (constraintKeys[i] !== primary[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Pulls top level `and` components out of a condition tree.\n * The resulting array of simple conditions would match a superset of\n * values that the original condition would match.\n *\n * Examples:\n * a AND b OR c\n *\n * In this case we cannot pull anything because the `or` is at the top level.\n *\n * a AND b AND c\n * We can pull all three.\n *\n * a AND (b OR c)\n * We can only pull `a`.\n */\nexport function pullSimpleAndComponents(\n condition: Condition,\n): SimpleCondition[] {\n if (condition.type === 'and') {\n return condition.conditions.flatMap(pullSimpleAndComponents);\n }\n\n if (condition.type === 'simple') {\n return [condition];\n }\n\n if (condition.type === 'or' && condition.conditions.length === 1) {\n return pullSimpleAndComponents(condition.conditions[0]);\n }\n\n return [];\n}\n\n/**\n * Checks if the supplied filters constitute a primary key lookup.\n * If so, returns the constraint that would be used to look up the primary key.\n * If not, returns undefined.\n */\nexport function primaryKeyConstraintFromFilters(\n condition: Condition | undefined,\n primary: PrimaryKey,\n): Constraint | undefined {\n if (condition === undefined) {\n return undefined;\n }\n\n const conditions = pullSimpleAndComponents(condition);\n if (conditions.length === 0) {\n return undefined;\n }\n\n const ret: Writable<Constraint> = {};\n for (const subCondition of conditions) {\n if (subCondition.op === '=') {\n const column = extractColumn(subCondition);\n if (column !== undefined) {\n if (!primary.includes(column.name)) {\n continue;\n }\n ret[column.name] = column.value;\n }\n }\n }\n\n if (Object.keys(ret).length !== primary.length) {\n return undefined;\n }\n\n return ret;\n}\n\nfunction extractColumn(\n condition: SimpleCondition,\n): {name: string; value: Value} | undefined {\n if (condition.left.type === 'column') {\n assert(\n condition.right.type === 'literal',\n () =>\n `extractColumn: expected right side to be literal, got ${condition.right.type}`,\n );\n return {name: condition.left.name, value: condition.right.value};\n }\n\n return undefined;\n}\n\nexport class SetOfConstraint {\n #data: Constraint[] = [];\n\n constructor() {\n assertTesting('SetOfConstraint is only available in testing');\n }\n\n #indexOf(value: Constraint): number {\n return this.#data.findIndex(v => constraintEquals(v, value));\n }\n\n has(value: Constraint): boolean {\n return this.#indexOf(value) !== -1;\n }\n\n add(value: Constraint): this {\n if (!this.has(value)) {\n this.#data.push(value);\n }\n return this;\n }\n}\n\nfunction constraintEquals(a: Constraint, b: Constraint): boolean {\n const aEntries = Object.entries(a);\n const bEntries = Object.entries(b);\n if (aEntries.length !== bEntries.length) {\n return false;\n }\n for (let i = 0; i < aEntries.length; i++) {\n if (\n aEntries[i][0] !== bEntries[i][0] ||\n !valuesEqual(aEntries[i][1], bEntries[i][1])\n ) {\n return false;\n }\n }\n return true;\n}\n"],"mappings":";;;;AAgBA,SAAgB,qBACd,YACA,KACS;AACT,MAAK,MAAM,OAAO,WAChB,KAAI,CAAC,YAAY,IAAI,MAAM,WAAW,KAAK,CACzC,QAAO;AAGX,QAAO;;;;;;;AAQT,SAAgB,yBACd,MACA,OACS;AACT,MAAK,MAAM,OAAO,KAChB,KAAI,OAAO,SAAS,CAAC,YAAY,KAAK,MAAM,MAAM,KAAK,CACrD,QAAO;AAGX,QAAO;;AAGT,SAAgB,4BACd,YACA,SACS;AACT,QAAO,qBAAqB,OAAO,KAAK,WAAW,EAAE,QAAQ;;AAG/D,SAAgB,qBACd,KACA,SACS;CACT,MAAM,iBAAiB,CAAC,GAAG,IAAI;AAE/B,KAAI,eAAe,WAAW,QAAQ,OACpC,QAAO;AAKT,gBAAe,KAAK,cAAc;AAElC,MAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,IACzC,KAAI,eAAe,OAAO,QAAQ,GAChC,QAAO;AAGX,QAAO;;;;;;;;;;;;;;;;;;AAmBT,SAAgB,wBACd,WACmB;AACnB,KAAI,UAAU,SAAS,MACrB,QAAO,UAAU,WAAW,QAAQ,wBAAwB;AAG9D,KAAI,UAAU,SAAS,SACrB,QAAO,CAAC,UAAU;AAGpB,KAAI,UAAU,SAAS,QAAQ,UAAU,WAAW,WAAW,EAC7D,QAAO,wBAAwB,UAAU,WAAW,GAAG;AAGzD,QAAO,EAAE;;;;;;;AAQX,SAAgB,gCACd,WACA,SACwB;AACxB,KAAI,cAAc,KAAA,EAChB;CAGF,MAAM,aAAa,wBAAwB,UAAU;AACrD,KAAI,WAAW,WAAW,EACxB;CAGF,MAAM,MAA4B,EAAE;AACpC,MAAK,MAAM,gBAAgB,WACzB,KAAI,aAAa,OAAO,KAAK;EAC3B,MAAM,SAAS,cAAc,aAAa;AAC1C,MAAI,WAAW,KAAA,GAAW;AACxB,OAAI,CAAC,QAAQ,SAAS,OAAO,KAAK,CAChC;AAEF,OAAI,OAAO,QAAQ,OAAO;;;AAKhC,KAAI,OAAO,KAAK,IAAI,CAAC,WAAW,QAAQ,OACtC;AAGF,QAAO;;AAGT,SAAS,cACP,WAC0C;AAC1C,KAAI,UAAU,KAAK,SAAS,UAAU;AACpC,SACE,UAAU,MAAM,SAAS,iBAEvB,yDAAyD,UAAU,MAAM,OAC5E;AACD,SAAO;GAAC,MAAM,UAAU,KAAK;GAAM,OAAO,UAAU,MAAM;GAAM"}
1
+ {"version":3,"file":"constraint.js","names":["#data","#indexOf"],"sources":["../../../../../zql/src/ivm/constraint.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {stringCompare} from '../../../shared/src/string-compare.ts';\nimport {assertTesting} from '../../../shared/src/testing.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {\n Condition,\n SimpleCondition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {valuesEqual} from './data.ts';\n\nexport type Constraint = {\n readonly [key: string]: Value;\n};\n\nexport function constraintMatchesRow(\n constraint: Constraint,\n row: Row,\n): boolean {\n for (const key in constraint) {\n if (!valuesEqual(row[key], constraint[key])) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Constraints are compatible if:\n * 1. They do not have any keys in common\n * 2. They have keys in common, but the values for those keys are equal\n */\nexport function constraintsAreCompatible(\n left: Constraint,\n right: Constraint,\n): boolean {\n for (const key in left) {\n if (key in right && !valuesEqual(left[key], right[key])) {\n return false;\n }\n }\n return true;\n}\n\nexport function constraintMatchesPrimaryKey(\n constraint: Constraint,\n primary: PrimaryKey,\n): boolean {\n return keyMatchesPrimaryKey(Object.keys(constraint), primary);\n}\n\nexport function keyMatchesPrimaryKey(\n key: Iterable<string>,\n primary: PrimaryKey,\n): boolean {\n const constraintKeys = [...key];\n\n if (constraintKeys.length !== primary.length) {\n return false;\n }\n\n // Primary key is always sorted\n // Constraint does not have to be sorted\n constraintKeys.sort(stringCompare);\n\n for (let i = 0; i < constraintKeys.length; i++) {\n if (constraintKeys[i] !== primary[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Pulls top level `and` components out of a condition tree.\n * The resulting array of simple conditions would match a superset of\n * values that the original condition would match.\n *\n * Examples:\n * a AND b OR c\n *\n * In this case we cannot pull anything because the `or` is at the top level.\n *\n * a AND b AND c\n * We can pull all three.\n *\n * a AND (b OR c)\n * We can only pull `a`.\n */\nexport function pullSimpleAndComponents(\n condition: Condition,\n): SimpleCondition[] {\n if (condition.type === 'and') {\n return condition.conditions.flatMap(pullSimpleAndComponents);\n }\n\n if (condition.type === 'simple') {\n return [condition];\n }\n\n if (condition.type === 'or' && condition.conditions.length === 1) {\n return pullSimpleAndComponents(condition.conditions[0]);\n }\n\n return [];\n}\n\n/**\n * Checks if the supplied filters constitute a primary key lookup.\n * If so, returns the constraint that would be used to look up the primary key.\n * If not, returns undefined.\n */\nexport function primaryKeyConstraintFromFilters(\n condition: Condition | undefined,\n primary: PrimaryKey,\n): Constraint | undefined {\n if (condition === undefined) {\n return undefined;\n }\n\n const conditions = pullSimpleAndComponents(condition);\n if (conditions.length === 0) {\n return undefined;\n }\n\n const ret: Writable<Constraint> = {};\n for (const subCondition of conditions) {\n if (subCondition.op === '=') {\n const column = extractColumn(subCondition);\n if (column !== undefined) {\n if (!primary.includes(column.name)) {\n continue;\n }\n ret[column.name] = column.value;\n }\n }\n }\n\n if (Object.keys(ret).length !== primary.length) {\n return undefined;\n }\n\n return ret;\n}\n\nfunction extractColumn(\n condition: SimpleCondition,\n): {name: string; value: Value} | undefined {\n if (condition.left.type === 'column') {\n assert(\n condition.right.type === 'literal',\n () =>\n `extractColumn: expected right side to be literal, got ${condition.right.type}`,\n );\n return {name: condition.left.name, value: condition.right.value};\n }\n\n return undefined;\n}\n\nexport class SetOfConstraint {\n #data: Constraint[] = [];\n\n constructor() {\n assertTesting('SetOfConstraint is only available in testing');\n }\n\n #indexOf(value: Constraint): number {\n return this.#data.findIndex(v => constraintEquals(v, value));\n }\n\n has(value: Constraint): boolean {\n return this.#indexOf(value) !== -1;\n }\n\n add(value: Constraint): this {\n if (!this.has(value)) {\n this.#data.push(value);\n }\n return this;\n }\n}\n\nfunction constraintEquals(a: Constraint, b: Constraint): boolean {\n const aEntries = Object.entries(a);\n const bEntries = Object.entries(b);\n if (aEntries.length !== bEntries.length) {\n return false;\n }\n for (let i = 0; i < aEntries.length; i++) {\n if (\n aEntries[i][0] !== bEntries[i][0] ||\n !valuesEqual(aEntries[i][1], bEntries[i][1])\n ) {\n return false;\n }\n }\n return true;\n}\n"],"mappings":";;;;AAgBA,SAAgB,qBACd,YACA,KACS;CACT,KAAK,MAAM,OAAO,YAChB,IAAI,CAAC,YAAY,IAAI,MAAM,WAAW,IAAI,GACxC,OAAO;CAGX,OAAO;AACT;;;;;;AAOA,SAAgB,yBACd,MACA,OACS;CACT,KAAK,MAAM,OAAO,MAChB,IAAI,OAAO,SAAS,CAAC,YAAY,KAAK,MAAM,MAAM,IAAI,GACpD,OAAO;CAGX,OAAO;AACT;AAEA,SAAgB,4BACd,YACA,SACS;CACT,OAAO,qBAAqB,OAAO,KAAK,UAAU,GAAG,OAAO;AAC9D;AAEA,SAAgB,qBACd,KACA,SACS;CACT,MAAM,iBAAiB,CAAC,GAAG,GAAG;CAE9B,IAAI,eAAe,WAAW,QAAQ,QACpC,OAAO;CAKT,eAAe,KAAK,aAAa;CAEjC,KAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,KACzC,IAAI,eAAe,OAAO,QAAQ,IAChC,OAAO;CAGX,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,SAAgB,wBACd,WACmB;CACnB,IAAI,UAAU,SAAS,OACrB,OAAO,UAAU,WAAW,QAAQ,uBAAuB;CAG7D,IAAI,UAAU,SAAS,UACrB,OAAO,CAAC,SAAS;CAGnB,IAAI,UAAU,SAAS,QAAQ,UAAU,WAAW,WAAW,GAC7D,OAAO,wBAAwB,UAAU,WAAW,EAAE;CAGxD,OAAO,CAAC;AACV;;;;;;AAOA,SAAgB,gCACd,WACA,SACwB;CACxB,IAAI,cAAc,KAAA,GAChB;CAGF,MAAM,aAAa,wBAAwB,SAAS;CACpD,IAAI,WAAW,WAAW,GACxB;CAGF,MAAM,MAA4B,CAAC;CACnC,KAAK,MAAM,gBAAgB,YACzB,IAAI,aAAa,OAAO,KAAK;EAC3B,MAAM,SAAS,cAAc,YAAY;EACzC,IAAI,WAAW,KAAA,GAAW;GACxB,IAAI,CAAC,QAAQ,SAAS,OAAO,IAAI,GAC/B;GAEF,IAAI,OAAO,QAAQ,OAAO;EAC5B;CACF;CAGF,IAAI,OAAO,KAAK,GAAG,EAAE,WAAW,QAAQ,QACtC;CAGF,OAAO;AACT;AAEA,SAAS,cACP,WAC0C;CAC1C,IAAI,UAAU,KAAK,SAAS,UAAU;EACpC,OACE,UAAU,MAAM,SAAS,iBAEvB,yDAAyD,UAAU,MAAM,MAC7E;EACA,OAAO;GAAC,MAAM,UAAU,KAAK;GAAM,OAAO,UAAU,MAAM;EAAK;CACjE;AAGF"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","names":[],"sources":["../../../../../zql/src/ivm/data.ts"],"sourcesContent":["import {compareUTF8} from 'compare-utf8';\nimport type {Ordering} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {Stream} from './stream.ts';\n\n/**\n * A row flowing through the pipeline, plus its relationships.\n * Relationships are generated lazily as read.\n */\nexport type Node = {\n row: Row;\n /**\n * Relationships are generated lazily as read.\n * The stream may contain 'yield' to indicate the operator has yielded control.\n * See {@linkcode Operator.fetch} for more details about yields.\n */\n relationships: Record<string, () => Stream<Node | 'yield'>>;\n};\n\n/**\n * Compare two values. The values must be of the same type. This function\n * throws at runtime if the types differ.\n *\n * Note, this function considers `null === null` and\n * `undefined === undefined`. This is different than SQL. In join code,\n * null must be treated separately.\n *\n * See: https://github.com/rocicorp/mono/pull/2116/files#r1704811479\n *\n * @returns < 0 if a < b, 0 if a === b, > 0 if a > b\n */\nexport function compareValues(a: Value, b: Value): number {\n a = a ?? null;\n b = b ?? null;\n\n if (a === b) {\n return 0;\n }\n\n if (typeof a === 'string' && typeof b === 'string') {\n // We compare all strings in Zero as UTF-8. This is the default on SQLite\n // and we need to match it. See:\n // https://blog.replicache.dev/blog/replicache-11-adventures-in-text-encoding.\n //\n // TODO: We could change this since SQLite supports UTF-16. Microbenchmark\n // to see if there's a big win.\n //\n // https://www.sqlite.org/c3ref/create_collation.html\n return compareUTF8(a, b);\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b;\n }\n\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return a ? 1 : -1;\n }\n\n // check with null after since it is less likely to be the common case and we\n // want to avoid the extra checks in that case\n if (a === null) {\n return -1;\n }\n if (b === null) {\n return 1;\n }\n\n if (typeof a !== typeof b) {\n throw new Error(\n `Cannot compare values of different types: ${typeof a} and ${typeof b}`,\n );\n }\n\n throw new Error(`Unsupported type: ${a}`);\n}\n\nexport type NormalizedValue = Exclude<Value, undefined>;\n\n/**\n * We allow undefined to be passed for the convenience of developers, but we\n * treat it equivalently to null. It's better for perf to not create an copy\n * of input values, so we just normalize at use when necessary.\n */\nexport function normalizeUndefined(v: Value): NormalizedValue {\n return v ?? null;\n}\n\nexport type Comparator = (r1: Row, r2: Row) => number;\n\nexport function makeComparator(order: Ordering, reverse?: boolean): Comparator {\n return (a, b) => {\n // Skip destructuring here since it is hot code.\n for (const ord of order) {\n const field = ord[0];\n const comp = compareValues(a[field], b[field]);\n if (comp !== 0) {\n const result = ord[1] === 'asc' ? comp : -comp;\n return reverse ? -result : result;\n }\n }\n return 0;\n };\n}\n\n/**\n * Determine if two values are equal. Note that unlike compareValues() above,\n * this function treats `null` as unequal to itself (and same for `undefined`).\n * This is required to make joins work correctly, but may not be the right\n * semantic for your application.\n */\nexport function valuesEqual(a: Value, b: Value): boolean {\n // oxlint-disable-next-line eqeqeq\n if (a == null || b == null) {\n return false;\n }\n return a === b;\n}\n\nexport function drainStreams(node: Node | 'yield') {\n if (node === 'yield') {\n return;\n }\n for (const stream of Object.values(node.relationships)) {\n for (const node of stream()) {\n drainStreams(node);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AA+BA,SAAgB,cAAc,GAAU,GAAkB;AACxD,KAAI,KAAK;AACT,KAAI,KAAK;AAET,KAAI,MAAM,EACR,QAAO;AAGT,KAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SASxC,QAAO,YAAY,GAAG,EAAE;AAG1B,KAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SACxC,QAAO,IAAI;AAGb,KAAI,OAAO,MAAM,aAAa,OAAO,MAAM,UACzC,QAAO,IAAI,IAAI;AAKjB,KAAI,MAAM,KACR,QAAO;AAET,KAAI,MAAM,KACR,QAAO;AAGT,KAAI,OAAO,MAAM,OAAO,EACtB,OAAM,IAAI,MACR,6CAA6C,OAAO,EAAE,OAAO,OAAO,IACrE;AAGH,OAAM,IAAI,MAAM,qBAAqB,IAAI;;;;;;;AAU3C,SAAgB,mBAAmB,GAA2B;AAC5D,QAAO,KAAK;;AAKd,SAAgB,eAAe,OAAiB,SAA+B;AAC7E,SAAQ,GAAG,MAAM;AAEf,OAAK,MAAM,OAAO,OAAO;GACvB,MAAM,QAAQ,IAAI;GAClB,MAAM,OAAO,cAAc,EAAE,QAAQ,EAAE,OAAO;AAC9C,OAAI,SAAS,GAAG;IACd,MAAM,SAAS,IAAI,OAAO,QAAQ,OAAO,CAAC;AAC1C,WAAO,UAAU,CAAC,SAAS;;;AAG/B,SAAO;;;;;;;;;AAUX,SAAgB,YAAY,GAAU,GAAmB;AAEvD,KAAI,KAAK,QAAQ,KAAK,KACpB,QAAO;AAET,QAAO,MAAM"}
1
+ {"version":3,"file":"data.js","names":[],"sources":["../../../../../zql/src/ivm/data.ts"],"sourcesContent":["import {compareUTF8} from 'compare-utf8';\nimport type {Ordering} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {Stream} from './stream.ts';\n\n/**\n * A row flowing through the pipeline, plus its relationships.\n * Relationships are generated lazily as read.\n */\nexport type Node = {\n row: Row;\n /**\n * Relationships are generated lazily as read.\n * The stream may contain 'yield' to indicate the operator has yielded control.\n * See {@linkcode Operator.fetch} for more details about yields.\n */\n relationships: Record<string, () => Stream<Node | 'yield'>>;\n};\n\n/**\n * Compare two values. The values must be of the same type. This function\n * throws at runtime if the types differ.\n *\n * Note, this function considers `null === null` and\n * `undefined === undefined`. This is different than SQL. In join code,\n * null must be treated separately.\n *\n * See: https://github.com/rocicorp/mono/pull/2116/files#r1704811479\n *\n * @returns < 0 if a < b, 0 if a === b, > 0 if a > b\n */\nexport function compareValues(a: Value, b: Value): number {\n a = a ?? null;\n b = b ?? null;\n\n if (a === b) {\n return 0;\n }\n\n if (typeof a === 'string' && typeof b === 'string') {\n // We compare all strings in Zero as UTF-8. This is the default on SQLite\n // and we need to match it. See:\n // https://blog.replicache.dev/blog/replicache-11-adventures-in-text-encoding.\n //\n // TODO: We could change this since SQLite supports UTF-16. Microbenchmark\n // to see if there's a big win.\n //\n // https://www.sqlite.org/c3ref/create_collation.html\n return compareUTF8(a, b);\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b;\n }\n\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return a ? 1 : -1;\n }\n\n // check with null after since it is less likely to be the common case and we\n // want to avoid the extra checks in that case\n if (a === null) {\n return -1;\n }\n if (b === null) {\n return 1;\n }\n\n if (typeof a !== typeof b) {\n throw new Error(\n `Cannot compare values of different types: ${typeof a} and ${typeof b}`,\n );\n }\n\n throw new Error(`Unsupported type: ${a}`);\n}\n\nexport type NormalizedValue = Exclude<Value, undefined>;\n\n/**\n * We allow undefined to be passed for the convenience of developers, but we\n * treat it equivalently to null. It's better for perf to not create an copy\n * of input values, so we just normalize at use when necessary.\n */\nexport function normalizeUndefined(v: Value): NormalizedValue {\n return v ?? null;\n}\n\nexport type Comparator = (r1: Row, r2: Row) => number;\n\nexport function makeComparator(order: Ordering, reverse?: boolean): Comparator {\n return (a, b) => {\n // Skip destructuring here since it is hot code.\n for (const ord of order) {\n const field = ord[0];\n const comp = compareValues(a[field], b[field]);\n if (comp !== 0) {\n const result = ord[1] === 'asc' ? comp : -comp;\n return reverse ? -result : result;\n }\n }\n return 0;\n };\n}\n\n/**\n * Determine if two values are equal. Note that unlike compareValues() above,\n * this function treats `null` as unequal to itself (and same for `undefined`).\n * This is required to make joins work correctly, but may not be the right\n * semantic for your application.\n */\nexport function valuesEqual(a: Value, b: Value): boolean {\n // oxlint-disable-next-line eqeqeq\n if (a == null || b == null) {\n return false;\n }\n return a === b;\n}\n\nexport function drainStreams(node: Node | 'yield') {\n if (node === 'yield') {\n return;\n }\n for (const stream of Object.values(node.relationships)) {\n for (const node of stream()) {\n drainStreams(node);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AA+BA,SAAgB,cAAc,GAAU,GAAkB;CACxD,IAAI,KAAK;CACT,IAAI,KAAK;CAET,IAAI,MAAM,GACR,OAAO;CAGT,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UASxC,OAAO,YAAY,GAAG,CAAC;CAGzB,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UACxC,OAAO,IAAI;CAGb,IAAI,OAAO,MAAM,aAAa,OAAO,MAAM,WACzC,OAAO,IAAI,IAAI;CAKjB,IAAI,MAAM,MACR,OAAO;CAET,IAAI,MAAM,MACR,OAAO;CAGT,IAAI,OAAO,MAAM,OAAO,GACtB,MAAM,IAAI,MACR,6CAA6C,OAAO,EAAE,OAAO,OAAO,GACtE;CAGF,MAAM,IAAI,MAAM,qBAAqB,GAAG;AAC1C;;;;;;AASA,SAAgB,mBAAmB,GAA2B;CAC5D,OAAO,KAAK;AACd;AAIA,SAAgB,eAAe,OAAiB,SAA+B;CAC7E,QAAQ,GAAG,MAAM;EAEf,KAAK,MAAM,OAAO,OAAO;GACvB,MAAM,QAAQ,IAAI;GAClB,MAAM,OAAO,cAAc,EAAE,QAAQ,EAAE,MAAM;GAC7C,IAAI,SAAS,GAAG;IACd,MAAM,SAAS,IAAI,OAAO,QAAQ,OAAO,CAAC;IAC1C,OAAO,UAAU,CAAC,SAAS;GAC7B;EACF;EACA,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,YAAY,GAAU,GAAmB;CAEvD,IAAI,KAAK,QAAQ,KAAK,MACpB,OAAO;CAET,OAAO,MAAM;AACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"exists.js","names":["#input","#relationshipName","#not","#parentJoinKey","#noSizeReuse","#cache","#cacheHitCountsForTesting","#output","#inPush","#getCacheKey","#fetchExists","#filter","#pushWithFilter","#fetchSize"],"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 {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {makeAddChange, makeRemoveChange, 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[ChangeIndex.TYPE]) {\n // add, remove and edit cannot change the size of the\n // this.#relationshipName relationship, so simply #pushWithFilter\n case ChangeType.ADD:\n case ChangeType.EDIT:\n case ChangeType.REMOVE: {\n yield* this.#pushWithFilter(change);\n return;\n }\n case ChangeType.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[ChangeIndex.CHILD_DATA].relationshipName !==\n this.#relationshipName ||\n change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE] ===\n ChangeType.EDIT ||\n change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE] ===\n ChangeType.CHILD\n ) {\n yield* this.#pushWithFilter(change);\n return;\n }\n switch (change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE]) {\n case ChangeType.ADD: {\n const size = yield* this.#fetchSize(change[ChangeIndex.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 makeRemoveChange({\n row: change[ChangeIndex.NODE].row,\n relationships: {\n ...change[ChangeIndex.NODE].relationships,\n [this.#relationshipName]: () => [],\n },\n }),\n this,\n );\n } else {\n yield* this.#output.push(\n makeAddChange(change[ChangeIndex.NODE]),\n this,\n );\n }\n } else {\n yield* this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n case ChangeType.REMOVE: {\n const size = yield* this.#fetchSize(change[ChangeIndex.NODE]);\n if (size === 0) {\n if (this.#not) {\n yield* this.#output.push(\n makeAddChange(change[ChangeIndex.NODE]),\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 makeRemoveChange({\n row: change[ChangeIndex.NODE].row,\n relationships: {\n ...change[ChangeIndex.NODE].relationships,\n [this.#relationshipName]: () => [\n change[ChangeIndex.CHILD_DATA].change[\n ChangeIndex.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[ChangeIndex.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(\n relationship,\n () =>\n `Exists: relationship \"${this.#relationshipName}\" not found on node`,\n );\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"],"mappings":"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"}
1
+ {"version":3,"file":"exists.js","names":["#input","#relationshipName","#not","#parentJoinKey","#noSizeReuse","#cache","#cacheHitCountsForTesting","#output","#inPush","#getCacheKey","#fetchExists","#filter","#pushWithFilter","#fetchSize"],"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 {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {makeAddChange, makeRemoveChange, 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[ChangeIndex.TYPE]) {\n // add, remove and edit cannot change the size of the\n // this.#relationshipName relationship, so simply #pushWithFilter\n case ChangeType.ADD:\n case ChangeType.EDIT:\n case ChangeType.REMOVE: {\n yield* this.#pushWithFilter(change);\n return;\n }\n case ChangeType.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[ChangeIndex.CHILD_DATA].relationshipName !==\n this.#relationshipName ||\n change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE] ===\n ChangeType.EDIT ||\n change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE] ===\n ChangeType.CHILD\n ) {\n yield* this.#pushWithFilter(change);\n return;\n }\n switch (change[ChangeIndex.CHILD_DATA].change[ChangeIndex.TYPE]) {\n case ChangeType.ADD: {\n const size = yield* this.#fetchSize(change[ChangeIndex.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 makeRemoveChange({\n row: change[ChangeIndex.NODE].row,\n relationships: {\n ...change[ChangeIndex.NODE].relationships,\n [this.#relationshipName]: () => [],\n },\n }),\n this,\n );\n } else {\n yield* this.#output.push(\n makeAddChange(change[ChangeIndex.NODE]),\n this,\n );\n }\n } else {\n yield* this.#pushWithFilter(change, size > 0);\n }\n return;\n }\n case ChangeType.REMOVE: {\n const size = yield* this.#fetchSize(change[ChangeIndex.NODE]);\n if (size === 0) {\n if (this.#not) {\n yield* this.#output.push(\n makeAddChange(change[ChangeIndex.NODE]),\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 makeRemoveChange({\n row: change[ChangeIndex.NODE].row,\n relationships: {\n ...change[ChangeIndex.NODE].relationships,\n [this.#relationshipName]: () => [\n change[ChangeIndex.CHILD_DATA].change[\n ChangeIndex.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[ChangeIndex.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(\n relationship,\n () =>\n `Exists: relationship \"${this.#relationshipName}\" not found on node`,\n );\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"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fan-in.js","names":["#inputs","#schema","#output","#accumulatedPushes"],"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 {ChangeType} from './change-type.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: ChangeType) {\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,QAAb,MAA6C;CAC3C;CACA;CACA,UAAwB;CACxB,qBAA+B,EAAE;CAEjC,YAAY,QAAgB,QAAuB;AACjD,QAAA,SAAe;AACf,QAAA,SAAe,OAAO,WAAW;AACjC,OAAK,MAAM,SAAS,QAAQ;AAC1B,SAAM,gBAAgB,KAAK;AAC3B,UAAO,MAAA,WAAiB,MAAM,WAAW,EAAE,4BAA4B;;;CAI3E,gBAAgB,QAA4B;AAC1C,QAAA,SAAe;;CAGjB,UAAgB;AACd,OAAK,MAAM,SAAS,MAAA,OAClB,OAAM,SAAS;;CAInB,YAAY;AACV,SAAO,MAAA;;CAGT,cAAoB;AAClB,QAAA,OAAa,aAAa;;CAG5B,YAAkB;AAChB,QAAA,OAAa,WAAW;;CAG1B,CAAC,OAAO,MAAyC;AAC/C,SAAO,OAAO,MAAA,OAAa,OAAO,KAAK;;CAGzC,KAAK,QAAgB;AACnB,QAAA,kBAAwB,KAAK,OAAO;AACpC,SAAO;;CAGT,CAAC,+BAA+B,kBAA8B;AAC5D,MAAI,MAAA,OAAa,WAAW,GAAG;AAC7B,UACE,MAAA,kBAAwB,WAAW,GACnC,oEACD;AACD;;AAGF,SAAO,uBACL,MAAA,mBACA,MAAA,QACA,MACA,kBACA,UACA,SACD"}
1
+ {"version":3,"file":"fan-in.js","names":["#inputs","#schema","#output","#accumulatedPushes"],"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 {ChangeType} from './change-type.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: ChangeType) {\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,QAAb,MAA6C;CAC3C;CACA;CACA,UAAwB;CACxB,qBAA+B,CAAC;CAEhC,YAAY,QAAgB,QAAuB;EACjD,KAAKA,UAAU;EACf,KAAKC,UAAU,OAAO,UAAU;EAChC,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,gBAAgB,IAAI;GAC1B,OAAO,KAAKA,YAAY,MAAM,UAAU,GAAG,2BAA2B;EACxE;CACF;CAEA,gBAAgB,QAA4B;EAC1C,KAAKC,UAAU;CACjB;CAEA,UAAgB;EACd,KAAK,MAAM,SAAS,KAAKF,SACvB,MAAM,QAAQ;CAElB;CAEA,YAAY;EACV,OAAO,KAAKC;CACd;CAEA,cAAoB;EAClB,KAAKC,QAAQ,YAAY;CAC3B;CAEA,YAAkB;EAChB,KAAKA,QAAQ,UAAU;CACzB;CAEA,CAAC,OAAO,MAAyC;EAC/C,OAAO,OAAO,KAAKA,QAAQ,OAAO,IAAI;CACxC;CAEA,KAAK,QAAgB;EACnB,KAAKC,mBAAmB,KAAK,MAAM;EACnC,OAAO;CACT;CAEA,CAAC,+BAA+B,kBAA8B;EAC5D,IAAI,KAAKH,QAAQ,WAAW,GAAG;GAC7B,OACE,KAAKG,mBAAmB,WAAW,GACnC,mEACF;GACA;EACF;EAEA,OAAO,uBACL,KAAKA,oBACL,KAAKD,SACL,MACA,kBACA,UACA,QACF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"fan-out.js","names":["#input","#outputs","#fanIn","#destroyCount"],"sources":["../../../../../zql/src/ivm/fan-out.ts"],"sourcesContent":["import {must} from '../../../shared/src/must.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport type {Change} from './change.ts';\nimport type {Node} from './data.ts';\nimport type {FanIn} from './fan-in.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[ChangeIndex.TYPE]);\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAa,SAAb,MAA8C;CAC5C;CACA,WAAoC,EAAE;CACtC;CACA,gBAAwB;CAExB,YAAY,OAAoB;AAC9B,QAAA,QAAc;AACd,QAAM,gBAAgB,KAAK;;CAG7B,SAAS,OAAc;AACrB,QAAA,QAAc;;CAGhB,gBAAgB,QAA4B;AAC1C,QAAA,QAAc,KAAK,OAAO;;CAG5B,UAAgB;AACd,MAAI,MAAA,eAAqB,MAAA,QAAc,QAAQ;AAC7C,KAAE,MAAA;AACF,OAAI,MAAA,iBAAuB,MAAA,QAAc,OACvC,OAAA,MAAY,SAAS;QAGvB,OAAM,IAAI,MAAM,gDAAgD;;CAIpE,YAAY;AACV,SAAO,MAAA,MAAY,WAAW;;CAGhC,cAAoB;AAClB,OAAK,MAAM,UAAU,MAAA,QACnB,QAAO,aAAa;;CAIxB,YAAkB;AAChB,OAAK,MAAM,UAAU,MAAA,QACnB,QAAO,WAAW;;CAItB,CAAC,OAAO,MAAyC;EAC/C,IAAI,SAAS;AACb,OAAK,MAAM,UAAU,MAAA,SAAe;AAClC,aAAU,OAAO,OAAO,OAAO,KAAK,KAAK;AACzC,OAAI,OACF,QAAO;;AAGX,SAAO;;CAGT,CAAC,KAAK,QAAgB;AACpB,OAAK,MAAM,OAAO,MAAA,QAChB,QAAO,IAAI,KAAK,QAAQ,KAAK;AAE/B,SAAO,KACL,MAAA,OACA,gDACD,CAAC,+BAA+B,OAAO,GAAkB"}
1
+ {"version":3,"file":"fan-out.js","names":["#input","#outputs","#fanIn","#destroyCount"],"sources":["../../../../../zql/src/ivm/fan-out.ts"],"sourcesContent":["import {must} from '../../../shared/src/must.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport type {Change} from './change.ts';\nimport type {Node} from './data.ts';\nimport type {FanIn} from './fan-in.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[ChangeIndex.TYPE]);\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAa,SAAb,MAA8C;CAC5C;CACA,WAAoC,CAAC;CACrC;CACA,gBAAwB;CAExB,YAAY,OAAoB;EAC9B,KAAKA,SAAS;EACd,MAAM,gBAAgB,IAAI;CAC5B;CAEA,SAAS,OAAc;EACrB,KAAKE,SAAS;CAChB;CAEA,gBAAgB,QAA4B;EAC1C,KAAKD,SAAS,KAAK,MAAM;CAC3B;CAEA,UAAgB;EACd,IAAI,KAAKE,gBAAgB,KAAKF,SAAS,QAAQ;GAC7C,EAAE,KAAKE;GACP,IAAI,KAAKA,kBAAkB,KAAKF,SAAS,QACvC,KAAKD,OAAO,QAAQ;EAExB,OACE,MAAM,IAAI,MAAM,+CAA+C;CAEnE;CAEA,YAAY;EACV,OAAO,KAAKA,OAAO,UAAU;CAC/B;CAEA,cAAoB;EAClB,KAAK,MAAM,UAAU,KAAKC,UACxB,OAAO,YAAY;CAEvB;CAEA,YAAkB;EAChB,KAAK,MAAM,UAAU,KAAKA,UACxB,OAAO,UAAU;CAErB;CAEA,CAAC,OAAO,MAAyC;EAC/C,IAAI,SAAS;EACb,KAAK,MAAM,UAAU,KAAKA,UAAU;GAClC,UAAU,OAAO,OAAO,OAAO,IAAI,MAAM;GACzC,IAAI,QACF,OAAO;EAEX;EACA,OAAO;CACT;CAEA,CAAC,KAAK,QAAgB;EACpB,KAAK,MAAM,OAAO,KAAKA,UACrB,OAAO,IAAI,KAAK,QAAQ,IAAI;EAE9B,OAAO,KACL,KAAKC,QACL,+CACF,EAAE,+BAA+B,OAAO,EAAiB;CAC3D;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter-operators.js","names":["#input","#output","#start"],"sources":["../../../../../zql/src/ivm/filter-operators.ts"],"sourcesContent":["import type {BuilderDelegate} from '../builder/builder.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.ts';\nimport type {FetchRequest, Input, InputBase, Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.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"],"mappings":";;;;;;;AA+CA,IAAa,oBAAkC;CAC7C,CAAC,KAAK,SAAkC;AACtC,QAAM,IAAI,MAAM,iBAAiB;;CAGnC,CAAC,OAAO,OAA0C;AAChD,QAAM,IAAI,MAAM,iBAAiB;;CAGnC,cAAc;CACd,YAAY;CACb;AAED,IAAa,cAAb,MAAwD;CACtD;CACA,UAAwB;CAExB,YAAY,OAAc;AACxB,QAAA,QAAc;AACd,QAAM,UAAU,KAAK;;CAGvB,gBAAgB,QAAsB;AACpC,QAAA,SAAe;;CAGjB,UAAgB;AACd,QAAA,MAAY,SAAS;;CAGvB,YAA0B;AACxB,SAAO,MAAA,MAAY,WAAW;;CAGhC,CAAC,KAAK,QAAgB;AACpB,SAAO,MAAA,OAAa,KAAK,QAAQ,KAAK;;CAGxC,CAAC,MAAM,KAA2C;AAChD,QAAA,OAAa,aAAa;AAC1B,MAAI;AACF,QAAK,MAAM,QAAQ,MAAA,MAAY,MAAM,IAAI,EAAE;AACzC,QAAI,SAAS,SAAS;AACpB,WAAM;AACN;;AAEF,QAAI,OAAO,MAAA,OAAa,OAAO,KAAK,CAClC,OAAM;;YAGF;AAGR,SAAA,OAAa,WAAW;;;;AAK9B,IAAa,YAAb,MAAsD;CACpD;CACA;CAEA,UAAkB;CAElB,YAAY,OAAoB,OAAoB;AAClD,QAAA,QAAc;AACd,QAAA,QAAc;AACd,QAAM,gBAAgB,KAAK;;CAG7B,CAAC,MAAM,KAA2C;AAChD,OAAK,MAAM,QAAQ,MAAA,MAAY,MAAM,IAAI,CACvC,OAAM;;CAIV,cAAc;CACd,YAAY;CAEZ,CAAC,OAAO,OAAa;AACnB,SAAO;;CAGT,UAAU,QAAgB;AACxB,QAAA,SAAe;;CAGjB,UAAgB;AACd,QAAA,MAAY,SAAS;;CAGvB,YAA0B;AACxB,SAAO,MAAA,MAAY,WAAW;;CAGhC,CAAC,KAAK,QAAgB;AACpB,SAAO,MAAA,OAAa,KAAK,QAAQ,KAAK;;;AAI1C,SAAgB,oBACd,OACA,UACA,UACO;CACP,MAAM,cAAc,IAAI,YAAY,MAAM;AAC1C,UAAS,QAAQ,OAAO,YAAY;CACpC,MAAM,SAAS,SAAS,YAAY;AACpC,UAAS,QAAQ,aAAa,OAAO;CACrC,MAAM,YAAY,IAAI,UAAU,aAAa,OAAO;AACpD,UAAS,QAAQ,QAAQ,UAAU;AACnC,QAAO"}
1
+ {"version":3,"file":"filter-operators.js","names":["#input","#output","#start"],"sources":["../../../../../zql/src/ivm/filter-operators.ts"],"sourcesContent":["import type {BuilderDelegate} from '../builder/builder.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.ts';\nimport type {FetchRequest, Input, InputBase, Output} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.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"],"mappings":";;;;;;;AA+CA,IAAa,oBAAkC;CAC7C,CAAC,KAAK,SAAkC;EACtC,MAAM,IAAI,MAAM,gBAAgB;CAClC;CAEA,CAAC,OAAO,OAA0C;EAChD,MAAM,IAAI,MAAM,gBAAgB;CAClC;CAEA,cAAc,CAAC;CACf,YAAY,CAAC;AACf;AAEA,IAAa,cAAb,MAAwD;CACtD;CACA,UAAwB;CAExB,YAAY,OAAc;EACxB,KAAKA,SAAS;EACd,MAAM,UAAU,IAAI;CACtB;CAEA,gBAAgB,QAAsB;EACpC,KAAKC,UAAU;CACjB;CAEA,UAAgB;EACd,KAAKD,OAAO,QAAQ;CACtB;CAEA,YAA0B;EACxB,OAAO,KAAKA,OAAO,UAAU;CAC/B;CAEA,CAAC,KAAK,QAAgB;EACpB,OAAO,KAAKC,QAAQ,KAAK,QAAQ,IAAI;CACvC;CAEA,CAAC,MAAM,KAA2C;EAChD,KAAKA,QAAQ,YAAY;EACzB,IAAI;GACF,KAAK,MAAM,QAAQ,KAAKD,OAAO,MAAM,GAAG,GAAG;IACzC,IAAI,SAAS,SAAS;KACpB,MAAM;KACN;IACF;IACA,IAAI,OAAO,KAAKC,QAAQ,OAAO,IAAI,GACjC,MAAM;GAEV;EACF,UAAU;GAGR,KAAKA,QAAQ,UAAU;EACzB;CACF;AACF;AAEA,IAAa,YAAb,MAAsD;CACpD;CACA;CAEA,UAAkB;CAElB,YAAY,OAAoB,OAAoB;EAClD,KAAKC,SAAS;EACd,KAAKF,SAAS;EACd,MAAM,gBAAgB,IAAI;CAC5B;CAEA,CAAC,MAAM,KAA2C;EAChD,KAAK,MAAM,QAAQ,KAAKE,OAAO,MAAM,GAAG,GACtC,MAAM;CAEV;CAEA,cAAc,CAAC;CACf,YAAY,CAAC;CAEb,CAAC,OAAO,OAAa;EACnB,OAAO;CACT;CAEA,UAAU,QAAgB;EACxB,KAAKD,UAAU;CACjB;CAEA,UAAgB;EACd,KAAKD,OAAO,QAAQ;CACtB;CAEA,YAA0B;EACxB,OAAO,KAAKA,OAAO,UAAU;CAC/B;CAEA,CAAC,KAAK,QAAgB;EACpB,OAAO,KAAKC,QAAQ,KAAK,QAAQ,IAAI;CACvC;AACF;AAEA,SAAgB,oBACd,OACA,UACA,UACO;CACP,MAAM,cAAc,IAAI,YAAY,KAAK;CACzC,SAAS,QAAQ,OAAO,WAAW;CACnC,MAAM,SAAS,SAAS,WAAW;CACnC,SAAS,QAAQ,aAAa,MAAM;CACpC,MAAM,YAAY,IAAI,UAAU,aAAa,MAAM;CACnD,SAAS,QAAQ,QAAQ,SAAS;CAClC,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter-push.js","names":[],"sources":["../../../../../zql/src/ivm/filter-push.ts"],"sourcesContent":["import {unreachable} from '../../../shared/src/asserts.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport type {Change} from './change.ts';\nimport {maybeSplitAndPushEditChange} from './maybe-split-and-push-edit-change.ts';\nimport type {InputBase, Output} from './operator.ts';\nimport type {Stream} from './stream.ts';\n\nexport function* filterPush(\n change: Change,\n output: Output,\n pusher: InputBase,\n predicate?: (row: Row) => boolean,\n): Stream<'yield'> {\n if (!predicate) {\n yield* output.push(change, pusher);\n return;\n }\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n case ChangeType.REMOVE:\n if (predicate(change[ChangeIndex.NODE].row)) {\n yield* output.push(change, pusher);\n }\n break;\n case ChangeType.CHILD:\n if (predicate(change[ChangeIndex.NODE].row)) {\n yield* output.push(change, pusher);\n }\n break;\n case ChangeType.EDIT:\n yield* maybeSplitAndPushEditChange(change, predicate, output, pusher);\n break;\n default:\n unreachable(change);\n }\n}\n"],"mappings":";;;AASA,UAAiB,WACf,QACA,QACA,QACA,WACiB;AACjB,KAAI,CAAC,WAAW;AACd,SAAO,OAAO,KAAK,QAAQ,OAAO;AAClC;;AAEF,SAAQ,OAAO,IAAf;EACE,KAAK;EACL,KAAK;AACH,OAAI,UAAU,OAAO,GAAkB,IAAI,CACzC,QAAO,OAAO,KAAK,QAAQ,OAAO;AAEpC;EACF,KAAK;AACH,OAAI,UAAU,OAAO,GAAkB,IAAI,CACzC,QAAO,OAAO,KAAK,QAAQ,OAAO;AAEpC;EACF,KAAK;AACH,UAAO,4BAA4B,QAAQ,WAAW,QAAQ,OAAO;AACrE;EACF,QACE,aAAY,OAAO"}
1
+ {"version":3,"file":"filter-push.js","names":[],"sources":["../../../../../zql/src/ivm/filter-push.ts"],"sourcesContent":["import {unreachable} from '../../../shared/src/asserts.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport type {Change} from './change.ts';\nimport {maybeSplitAndPushEditChange} from './maybe-split-and-push-edit-change.ts';\nimport type {InputBase, Output} from './operator.ts';\nimport type {Stream} from './stream.ts';\n\nexport function* filterPush(\n change: Change,\n output: Output,\n pusher: InputBase,\n predicate?: (row: Row) => boolean,\n): Stream<'yield'> {\n if (!predicate) {\n yield* output.push(change, pusher);\n return;\n }\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n case ChangeType.REMOVE:\n if (predicate(change[ChangeIndex.NODE].row)) {\n yield* output.push(change, pusher);\n }\n break;\n case ChangeType.CHILD:\n if (predicate(change[ChangeIndex.NODE].row)) {\n yield* output.push(change, pusher);\n }\n break;\n case ChangeType.EDIT:\n yield* maybeSplitAndPushEditChange(change, predicate, output, pusher);\n break;\n default:\n unreachable(change);\n }\n}\n"],"mappings":";;;AASA,UAAiB,WACf,QACA,QACA,QACA,WACiB;CACjB,IAAI,CAAC,WAAW;EACd,OAAO,OAAO,KAAK,QAAQ,MAAM;EACjC;CACF;CACA,QAAQ,OAAO,IAAf;EACE,KAAK;EACL,KAAK;GACH,IAAI,UAAU,OAAO,GAAkB,GAAG,GACxC,OAAO,OAAO,KAAK,QAAQ,MAAM;GAEnC;EACF,KAAK;GACH,IAAI,UAAU,OAAO,GAAkB,GAAG,GACxC,OAAO,OAAO,KAAK,QAAQ,MAAM;GAEnC;EACF,KAAK;GACH,OAAO,4BAA4B,QAAQ,WAAW,QAAQ,MAAM;GACpE;EACF,SACE,YAAY,MAAM;CACtB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","names":["#input","#predicate","#output"],"sources":["../../../../../zql/src/ivm/filter.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.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 {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 this.#output.beginFilter();\n }\n\n endFilter(): void {\n this.#output.endFilter();\n }\n\n *filter(node: Node): Generator<'yield', boolean> {\n return this.#predicate(node.row) && (yield* this.#output.filter(node));\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* filterPush(change, this.#output, this, this.#predicate);\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,SAAb,MAA8C;CAC5C;CACA;CAEA,UAAwB;CAExB,YAAY,OAAoB,WAAkC;AAChE,QAAA,QAAc;AACd,QAAA,YAAkB;AAClB,QAAM,gBAAgB,KAAK;;CAG7B,cAAoB;AAClB,QAAA,OAAa,aAAa;;CAG5B,YAAkB;AAChB,QAAA,OAAa,WAAW;;CAG1B,CAAC,OAAO,MAAyC;AAC/C,SAAO,MAAA,UAAgB,KAAK,IAAI,KAAK,OAAO,MAAA,OAAa,OAAO,KAAK;;CAGvE,gBAAgB,QAAsB;AACpC,QAAA,SAAe;;CAGjB,UAAgB;AACd,QAAA,MAAY,SAAS;;CAGvB,YAA0B;AACxB,SAAO,MAAA,MAAY,WAAW;;CAGhC,CAAC,KAAK,QAAgB;AACpB,SAAO,WAAW,QAAQ,MAAA,QAAc,MAAM,MAAA,UAAgB"}
1
+ {"version":3,"file":"filter.js","names":["#input","#predicate","#output"],"sources":["../../../../../zql/src/ivm/filter.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {type Node} from './data.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 {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 this.#output.beginFilter();\n }\n\n endFilter(): void {\n this.#output.endFilter();\n }\n\n *filter(node: Node): Generator<'yield', boolean> {\n return this.#predicate(node.row) && (yield* this.#output.filter(node));\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* filterPush(change, this.#output, this, this.#predicate);\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,SAAb,MAA8C;CAC5C;CACA;CAEA,UAAwB;CAExB,YAAY,OAAoB,WAAkC;EAChE,KAAKA,SAAS;EACd,KAAKC,aAAa;EAClB,MAAM,gBAAgB,IAAI;CAC5B;CAEA,cAAoB;EAClB,KAAKC,QAAQ,YAAY;CAC3B;CAEA,YAAkB;EAChB,KAAKA,QAAQ,UAAU;CACzB;CAEA,CAAC,OAAO,MAAyC;EAC/C,OAAO,KAAKD,WAAW,KAAK,GAAG,MAAM,OAAO,KAAKC,QAAQ,OAAO,IAAI;CACtE;CAEA,gBAAgB,QAAsB;EACpC,KAAKA,UAAU;CACjB;CAEA,UAAgB;EACd,KAAKF,OAAO,QAAQ;CACtB;CAEA,YAA0B;EACxB,OAAO,KAAKA,OAAO,UAAU;CAC/B;CAEA,CAAC,KAAK,QAAgB;EACpB,OAAO,WAAW,QAAQ,KAAKE,SAAS,MAAM,KAAKD,UAAU;CAC/D;AACF"}
@@ -4,6 +4,9 @@ import type { Node } from './data.ts';
4
4
  import { type FetchRequest, type Input, type Output } from './operator.ts';
5
5
  import type { SourceSchema } from './schema.ts';
6
6
  import { type Stream } from './stream.ts';
7
+ export declare function getMultiConstraintChunkSize(): number;
8
+ /** Test only. Returns a restore function. */
9
+ export declare function setMultiConstraintChunkSizeForTest(size: number): () => void;
7
10
  type Args = {
8
11
  parent: Input;
9
12
  child: Input;
@@ -29,13 +32,6 @@ export declare class FlippedJoin implements Input {
29
32
  getSchema(): SourceSchema;
30
33
  fetch(req: FetchRequest): Stream<Node | 'yield'>;
31
34
  }
32
- /**
33
- * Canonical string key over `keys` of `record`, used by `#fetchMergeSort`
34
- * both to dedupe per-child fetches and to map each returned parent row
35
- * back to the children that referenced its parent-key tuple.
36
- *
37
- * Exported for testing.
38
- */
39
- export declare function canonicalKey(record: Record<string, Value | undefined>, keys: CompoundKey): string;
35
+ export declare function canonicalKeyForTest(record: Record<string, Value | bigint | undefined>, keys: CompoundKey): string;
40
36
  export {};
41
37
  //# sourceMappingURL=flipped-join.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flipped-join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAM,KAAK,EAAC,MAAM,oCAAoC,CAAC;AAenE,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAQpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,KAAK;;gBAc3B,EACV,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAwCP,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;CAyalD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC,EACzC,IAAI,EAAE,WAAW,GAChB,MAAM,CAUR"}
1
+ {"version":3,"file":"flipped-join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAM,KAAK,EAAC,MAAM,oCAAoC,CAAC;AAWnE,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAQpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EAEV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AA6BxC,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAED,6CAA6C;AAC7C,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,IAAI,CAM3E;AAED,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;;gBAa3B,EACV,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAkCP,OAAO,IAAI,IAAI;IAKf,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;CAuZlD;AAID,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC,EAClD,IAAI,EAAE,WAAW,GAChB,MAAM,CAER"}