@rocicorp/zero 1.12.0-canary.2 → 1.12.0-canary.4

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 (803) hide show
  1. package/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js +2 -1
  3. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  4. package/out/analyze-query/src/bin-analyze.js +5 -3
  5. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  6. package/out/analyze-query/src/bin-transform.js +3 -2
  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 +3 -2
  10. package/out/ast-to-zql/src/bin.js.map +1 -1
  11. package/out/ast-to-zql/src/format.js.map +1 -1
  12. package/out/datadog/src/datadog-log-sink.js +5 -4
  13. package/out/datadog/src/datadog-log-sink.js.map +1 -1
  14. package/out/otel/src/log-options.js.map +1 -1
  15. package/out/replicache/src/btree/node.js +13 -11
  16. package/out/replicache/src/btree/node.js.map +1 -1
  17. package/out/replicache/src/btree/read.js +4 -2
  18. package/out/replicache/src/btree/read.js.map +1 -1
  19. package/out/replicache/src/btree/splice.js.map +1 -1
  20. package/out/replicache/src/btree/write.js +9 -5
  21. package/out/replicache/src/btree/write.js.map +1 -1
  22. package/out/replicache/src/config.js +1 -2
  23. package/out/replicache/src/connection-loop.js.map +1 -1
  24. package/out/replicache/src/dag/chunk.js +1 -1
  25. package/out/replicache/src/dag/gc.js.map +1 -1
  26. package/out/replicache/src/dag/lazy-store.js +8 -7
  27. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  28. package/out/replicache/src/dag/store-impl.js +1 -1
  29. package/out/replicache/src/dag/store-impl.js.map +1 -1
  30. package/out/replicache/src/dag/visitor.js.map +1 -1
  31. package/out/replicache/src/db/commit.js +5 -3
  32. package/out/replicache/src/db/commit.js.map +1 -1
  33. package/out/replicache/src/db/read.js +1 -1
  34. package/out/replicache/src/db/read.js.map +1 -1
  35. package/out/replicache/src/db/rebase.js.map +1 -1
  36. package/out/replicache/src/db/write.js +5 -2
  37. package/out/replicache/src/db/write.js.map +1 -1
  38. package/out/replicache/src/deleted-clients.js +3 -2
  39. package/out/replicache/src/deleted-clients.js.map +1 -1
  40. package/out/replicache/src/expo-sqlite.js +1 -2
  41. package/out/replicache/src/frozen-json.js +1 -1
  42. package/out/replicache/src/frozen-json.js.map +1 -1
  43. package/out/replicache/src/get-default-puller.js +1 -1
  44. package/out/replicache/src/hash.js +1 -1
  45. package/out/replicache/src/hash.js.map +1 -1
  46. package/out/replicache/src/impl.js +1 -2
  47. package/out/replicache/src/index-defs.js +5 -3
  48. package/out/replicache/src/index-defs.js.map +1 -1
  49. package/out/replicache/src/kv/expo-sqlite/store.js +1 -1
  50. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  51. package/out/replicache/src/kv/idb-store.js +1 -1
  52. package/out/replicache/src/kv/idb-store.js.map +1 -1
  53. package/out/replicache/src/kv/mem-fallback-store.js +1 -1
  54. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
  55. package/out/replicache/src/kv/mem-store.js.map +1 -1
  56. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  57. package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
  58. package/out/replicache/src/kv/read-impl.js.map +1 -1
  59. package/out/replicache/src/kv/sqlite-store.js +1 -1
  60. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  61. package/out/replicache/src/kv/write-impl-base.js +4 -1
  62. package/out/replicache/src/kv/write-impl-base.js.map +1 -1
  63. package/out/replicache/src/kv/write-impl.js.map +1 -1
  64. package/out/replicache/src/log-options.js +2 -1
  65. package/out/replicache/src/log-options.js.map +1 -1
  66. package/out/replicache/src/make-idb-name.js +1 -1
  67. package/out/replicache/src/new-client-channel.js +9 -7
  68. package/out/replicache/src/new-client-channel.js.map +1 -1
  69. package/out/replicache/src/on-persist-channel.js +1 -1
  70. package/out/replicache/src/on-persist-channel.js.map +1 -1
  71. package/out/replicache/src/op-sqlite.js +1 -2
  72. package/out/replicache/src/pending-mutations.js +2 -1
  73. package/out/replicache/src/pending-mutations.js.map +1 -1
  74. package/out/replicache/src/persist/client-gc.js +2 -2
  75. package/out/replicache/src/persist/client-gc.js.map +1 -1
  76. package/out/replicache/src/persist/client-group-gc.js +2 -2
  77. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  78. package/out/replicache/src/persist/client-groups.js +1 -1
  79. package/out/replicache/src/persist/client-groups.js.map +1 -1
  80. package/out/replicache/src/persist/clients.js +1 -1
  81. package/out/replicache/src/persist/clients.js.map +1 -1
  82. package/out/replicache/src/persist/collect-idb-databases.js +5 -4
  83. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  84. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
  85. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
  86. package/out/replicache/src/persist/heartbeat.js +2 -2
  87. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  88. package/out/replicache/src/persist/idb-databases-store.js +1 -1
  89. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  90. package/out/replicache/src/persist/make-client-id.js +1 -1
  91. package/out/replicache/src/persist/make-client-id.js.map +1 -1
  92. package/out/replicache/src/persist/persist.js +3 -2
  93. package/out/replicache/src/persist/persist.js.map +1 -1
  94. package/out/replicache/src/persist/refresh.js +8 -5
  95. package/out/replicache/src/persist/refresh.js.map +1 -1
  96. package/out/replicache/src/process-scheduler.js.map +1 -1
  97. package/out/replicache/src/replicache-impl.js +3 -3
  98. package/out/replicache/src/replicache-impl.js.map +1 -1
  99. package/out/replicache/src/scan-iterator.js.map +1 -1
  100. package/out/replicache/src/scan-options.js +7 -6
  101. package/out/replicache/src/scan-options.js.map +1 -1
  102. package/out/replicache/src/sqlite.js +1 -2
  103. package/out/replicache/src/subscriptions.js +1 -1
  104. package/out/replicache/src/subscriptions.js.map +1 -1
  105. package/out/replicache/src/sync/diff.js +3 -1
  106. package/out/replicache/src/sync/diff.js.map +1 -1
  107. package/out/replicache/src/sync/ids.js.map +1 -1
  108. package/out/replicache/src/sync/patch.js +2 -4
  109. package/out/replicache/src/sync/patch.js.map +1 -1
  110. package/out/replicache/src/sync/pull.js +3 -1
  111. package/out/replicache/src/sync/pull.js.map +1 -1
  112. package/out/replicache/src/sync/push.js.map +1 -1
  113. package/out/replicache/src/sync/request-id.js +1 -1
  114. package/out/replicache/src/sync/request-id.js.map +1 -1
  115. package/out/replicache/src/transactions.js +1 -1
  116. package/out/replicache/src/transactions.js.map +1 -1
  117. package/out/shared/src/arrays.js +4 -1
  118. package/out/shared/src/arrays.js.map +1 -1
  119. package/out/shared/src/asserts.js +1 -1
  120. package/out/shared/src/bigint-json.d.ts +9 -0
  121. package/out/shared/src/bigint-json.d.ts.map +1 -1
  122. package/out/shared/src/bigint-json.js +27 -2
  123. package/out/shared/src/bigint-json.js.map +1 -1
  124. package/out/shared/src/broadcast-channel.js +1 -1
  125. package/out/shared/src/btree-set.js +11 -8
  126. package/out/shared/src/btree-set.js.map +1 -1
  127. package/out/shared/src/cache.js.map +1 -1
  128. package/out/shared/src/config.js +1 -1
  129. package/out/shared/src/custom-key-map.js.map +1 -1
  130. package/out/shared/src/custom-key-set.js.map +1 -1
  131. package/out/shared/src/deep-clone.js +1 -1
  132. package/out/shared/src/document-visible.js.map +1 -1
  133. package/out/shared/src/dotenv.js.map +1 -1
  134. package/out/shared/src/error.js +1 -1
  135. package/out/shared/src/error.js.map +1 -1
  136. package/out/shared/src/hash.js +2 -2
  137. package/out/shared/src/hash.js.map +1 -1
  138. package/out/shared/src/iterables.js.map +1 -1
  139. package/out/shared/src/json-schema.js.map +1 -1
  140. package/out/shared/src/json.js.map +1 -1
  141. package/out/shared/src/logging-test-utils.js +1 -1
  142. package/out/shared/src/logging.js +1 -1
  143. package/out/shared/src/logging.js.map +1 -1
  144. package/out/shared/src/navigator.js +1 -1
  145. package/out/shared/src/options.js +9 -12
  146. package/out/shared/src/options.js.map +1 -1
  147. package/out/shared/src/promise-race.js.map +1 -1
  148. package/out/shared/src/queue.js.map +1 -1
  149. package/out/shared/src/record-proxy.js.map +1 -1
  150. package/out/shared/src/ring-buffer.js.map +1 -1
  151. package/out/shared/src/size-of-value.js +7 -10
  152. package/out/shared/src/size-of-value.js.map +1 -1
  153. package/out/shared/src/sorted-entries.js.map +1 -1
  154. package/out/shared/src/tdigest-schema.js.map +1 -1
  155. package/out/shared/src/tdigest.js.map +1 -1
  156. package/out/shared/src/valita.js +1 -1
  157. package/out/shared/src/valita.js.map +1 -1
  158. package/out/z2s/src/compiler.js +2 -4
  159. package/out/z2s/src/compiler.js.map +1 -1
  160. package/out/z2s/src/sql.js +1 -1
  161. package/out/z2s/src/sql.js.map +1 -1
  162. package/out/zero/package.js +212 -189
  163. package/out/zero/package.js.map +1 -1
  164. package/out/zero/src/adapters/drizzle.js +1 -2
  165. package/out/zero/src/adapters/kysely.js +1 -2
  166. package/out/zero/src/adapters/pg.js +1 -2
  167. package/out/zero/src/adapters/postgresjs.js +1 -2
  168. package/out/zero/src/adapters/prisma.js +1 -2
  169. package/out/zero/src/analyze.js +1 -2
  170. package/out/zero/src/change-protocol/v0.js +1 -2
  171. package/out/zero/src/expo-sqlite.js +1 -2
  172. package/out/zero/src/op-sqlite.js +1 -2
  173. package/out/zero/src/react-native.js.map +1 -1
  174. package/out/zero/src/sqlite.js +1 -2
  175. package/out/zero/src/zero-cache-dev.js +10 -9
  176. package/out/zero/src/zero-cache-dev.js.map +1 -1
  177. package/out/zero/src/zero-out.js +2 -1
  178. package/out/zero/src/zero-out.js.map +1 -1
  179. package/out/zero-cache/src/auth/auth.js +1 -1
  180. package/out/zero-cache/src/auth/auth.js.map +1 -1
  181. package/out/zero-cache/src/auth/jwt.js +4 -1
  182. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  183. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  184. package/out/zero-cache/src/auth/read-authorizer.js +3 -2
  185. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  186. package/out/zero-cache/src/auth/write-authorizer.js +5 -16
  187. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  188. package/out/zero-cache/src/config/network.js +1 -1
  189. package/out/zero-cache/src/config/network.js.map +1 -1
  190. package/out/zero-cache/src/config/server-context.js.map +1 -1
  191. package/out/zero-cache/src/config/zero-config.d.ts +9 -0
  192. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  193. package/out/zero-cache/src/config/zero-config.js +17 -2
  194. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  195. package/out/zero-cache/src/custom/fetch.js +1 -1
  196. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  197. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  198. package/out/zero-cache/src/db/create.js.map +1 -1
  199. package/out/zero-cache/src/db/index-predicate.js.map +1 -1
  200. package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
  201. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  202. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  203. package/out/zero-cache/src/db/migration-lite.js +1 -1
  204. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  205. package/out/zero-cache/src/db/migration.js +5 -3
  206. package/out/zero-cache/src/db/migration.js.map +1 -1
  207. package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
  208. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
  209. package/out/zero-cache/src/db/pg-copy.js +0 -1
  210. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  211. package/out/zero-cache/src/db/pg-to-lite.js +1 -1
  212. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  213. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  214. package/out/zero-cache/src/db/specs.js +7 -5
  215. package/out/zero-cache/src/db/specs.js.map +1 -1
  216. package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
  217. package/out/zero-cache/src/db/statements.d.ts.map +1 -1
  218. package/out/zero-cache/src/db/statements.js +9 -2
  219. package/out/zero-cache/src/db/statements.js.map +1 -1
  220. package/out/zero-cache/src/db/transaction-pool.js +5 -3
  221. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  222. package/out/zero-cache/src/db/warmup.js.map +1 -1
  223. package/out/zero-cache/src/observability/events.js.map +1 -1
  224. package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
  225. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  226. package/out/zero-cache/src/scripts/deploy-permissions.js +4 -2
  227. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  228. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  229. package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
  230. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  231. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  232. package/out/zero-cache/src/server/change-streamer.js +2 -1
  233. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  234. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  235. package/out/zero-cache/src/server/logging.js +1 -1
  236. package/out/zero-cache/src/server/logging.js.map +1 -1
  237. package/out/zero-cache/src/server/main.js.map +1 -1
  238. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  239. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  240. package/out/zero-cache/src/server/reaper.js +2 -2
  241. package/out/zero-cache/src/server/reaper.js.map +1 -1
  242. package/out/zero-cache/src/server/replicator.js.map +1 -1
  243. package/out/zero-cache/src/server/runner/run-worker.js +2 -1
  244. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  245. package/out/zero-cache/src/server/runner/runtime.js +2 -1
  246. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  247. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  248. package/out/zero-cache/src/server/shadow-syncer.js +1 -1
  249. package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
  250. package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
  251. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
  252. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  253. package/out/zero-cache/src/server/syncer.js +6 -1
  254. package/out/zero-cache/src/server/syncer.js.map +1 -1
  255. package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
  256. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  257. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  258. package/out/zero-cache/src/services/analyze.js +1 -1
  259. package/out/zero-cache/src/services/analyze.js.map +1 -1
  260. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +1 -1
  261. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  262. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  263. package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -1
  264. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
  265. package/out/zero-cache/src/services/change-source/common/replica-schema.js +3 -3
  266. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  267. package/out/zero-cache/src/services/change-source/custom/change-source.js +1 -1
  268. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  269. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
  270. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +3 -3
  271. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  272. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -1
  273. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +2 -2
  274. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
  275. package/out/zero-cache/src/services/change-source/pg/change-source.js +4 -6
  276. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  277. package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
  278. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  279. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +1 -0
  280. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  281. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +10 -8
  282. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  283. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  284. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  285. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +3 -2
  286. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  287. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  288. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
  289. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
  290. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
  291. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
  292. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +3 -3
  293. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  294. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +1 -1
  295. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  296. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +3 -3
  297. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  298. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +13 -12
  299. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  300. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +1 -1
  301. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  302. package/out/zero-cache/src/services/change-source/pg/schema/init.js +8 -8
  303. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  304. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +1 -1
  305. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
  306. package/out/zero-cache/src/services/change-source/pg/schema/published.js +3 -2
  307. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  308. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -1
  309. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +2 -2
  310. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  311. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +13 -10
  312. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  313. package/out/zero-cache/src/services/change-source/pg/schema/validation.js +1 -1
  314. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  315. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
  316. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
  317. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  318. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  319. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  320. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  321. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  322. package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
  323. package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
  324. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
  325. package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
  326. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
  327. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  328. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  329. package/out/zero-cache/src/services/change-streamer/broadcast.js +1 -1
  330. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  331. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +1 -1
  332. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
  333. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
  334. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  335. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +2 -2
  336. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
  337. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
  338. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +4 -2
  339. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  340. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +21 -21
  341. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  342. package/out/zero-cache/src/services/change-streamer/change-streamer.js +1 -1
  343. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  344. package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -1
  345. package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
  346. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  347. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +1 -1
  348. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
  349. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +3 -3
  350. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
  351. package/out/zero-cache/src/services/change-streamer/replica-poller.js +1 -1
  352. package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
  353. package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
  354. package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
  355. package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
  356. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  357. package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
  358. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  359. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -1
  360. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
  361. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  362. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +1 -1
  363. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
  364. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
  365. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
  366. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
  367. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
  368. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -1
  369. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
  370. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
  371. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +1 -3
  372. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  373. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  374. package/out/zero-cache/src/services/change-streamer/storer.js +2 -2
  375. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  376. package/out/zero-cache/src/services/change-streamer/subscribe.js +1 -1
  377. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
  378. package/out/zero-cache/src/services/change-streamer/subscriber.js +2 -2
  379. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  380. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
  381. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  382. package/out/zero-cache/src/services/heapz.js +2 -1
  383. package/out/zero-cache/src/services/heapz.js.map +1 -1
  384. package/out/zero-cache/src/services/http-service.js.map +1 -1
  385. package/out/zero-cache/src/services/life-cycle.js +1 -1
  386. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  387. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
  388. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  389. package/out/zero-cache/src/services/litestream/commands.js +1 -1
  390. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  391. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
  392. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  393. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  394. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  395. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
  396. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  397. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  398. package/out/zero-cache/src/services/mutagen/pusher.js +3 -2
  399. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  400. package/out/zero-cache/src/services/plannerz.js +4 -3
  401. package/out/zero-cache/src/services/plannerz.js.map +1 -1
  402. package/out/zero-cache/src/services/profz.js +5 -3
  403. package/out/zero-cache/src/services/profz.js.map +1 -1
  404. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  405. package/out/zero-cache/src/services/replicator/change-log-db.js +3 -2
  406. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
  407. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +1 -1
  408. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  409. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  410. package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
  411. package/out/zero-cache/src/services/replicator/incremental-sync.js +1 -1
  412. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  413. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  414. package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
  415. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  416. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  417. package/out/zero-cache/src/services/replicator/reporter/recorder.js +1 -1
  418. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  419. package/out/zero-cache/src/services/replicator/reporter/report-schema.js +1 -1
  420. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
  421. package/out/zero-cache/src/services/replicator/schema/backfilling.js +1 -1
  422. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  423. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -7
  424. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  425. package/out/zero-cache/src/services/replicator/schema/change-log.js +31 -15
  426. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  427. package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
  428. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  429. package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
  430. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  431. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  432. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
  433. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  434. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
  435. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
  436. package/out/zero-cache/src/services/replicator/write-worker-client.js +1 -1
  437. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  438. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  439. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  440. package/out/zero-cache/src/services/runner.js.map +1 -1
  441. package/out/zero-cache/src/services/running-state.js.map +1 -1
  442. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  443. package/out/zero-cache/src/services/statz.js +2 -1
  444. package/out/zero-cache/src/services/statz.js.map +1 -1
  445. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
  446. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  447. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
  448. package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
  449. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +18 -0
  450. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  451. package/out/zero-cache/src/services/view-syncer/client-handler.js +70 -23
  452. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  453. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +15 -2
  454. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +1 -1
  455. package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
  456. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  457. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  458. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
  459. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  460. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  461. package/out/zero-cache/src/services/view-syncer/cvr-store.js +10 -5
  462. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  463. package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
  464. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  465. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
  466. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
  467. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  468. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
  469. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
  470. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
  471. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
  472. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +5 -3
  473. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  474. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  475. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +8 -5
  476. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  477. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
  478. package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
  479. package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
  480. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  481. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
  482. package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
  483. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
  484. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  485. package/out/zero-cache/src/services/view-syncer/schema/cvr.js +1 -1
  486. package/out/zero-cache/src/services/view-syncer/schema/types.js +1 -1
  487. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  488. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
  489. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
  490. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +12 -4
  491. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  492. package/out/zero-cache/src/services/view-syncer/snapshotter.js +11 -7
  493. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  494. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  495. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  496. package/out/zero-cache/src/services/view-syncer/view-syncer.js +13 -9
  497. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  498. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  499. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  500. package/out/zero-cache/src/types/lite.js +1 -1
  501. package/out/zero-cache/src/types/lite.js.map +1 -1
  502. package/out/zero-cache/src/types/pg-data-type.js +1 -1
  503. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  504. package/out/zero-cache/src/types/pg.js +6 -4
  505. package/out/zero-cache/src/types/pg.js.map +1 -1
  506. package/out/zero-cache/src/types/poke-chunk.js +2 -2
  507. package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
  508. package/out/zero-cache/src/types/processes.js +1 -1
  509. package/out/zero-cache/src/types/processes.js.map +1 -1
  510. package/out/zero-cache/src/types/profiler.js.map +1 -1
  511. package/out/zero-cache/src/types/row-key.js.map +1 -1
  512. package/out/zero-cache/src/types/sql.js.map +1 -1
  513. package/out/zero-cache/src/types/streams.js +10 -9
  514. package/out/zero-cache/src/types/streams.js.map +1 -1
  515. package/out/zero-cache/src/types/strings.js.map +1 -1
  516. package/out/zero-cache/src/types/subscription.js.map +1 -1
  517. package/out/zero-cache/src/types/timeout.js +1 -1
  518. package/out/zero-cache/src/types/websocket-handoff.js +1 -1
  519. package/out/zero-cache/src/types/ws.js +1 -1
  520. package/out/zero-cache/src/workers/connection.js +2 -3
  521. package/out/zero-cache/src/workers/connection.js.map +1 -1
  522. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  523. package/out/zero-cache/src/workers/replicator.js +5 -4
  524. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  525. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  526. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +9 -1
  527. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  528. package/out/zero-cache/src/workers/syncer.js +2 -2
  529. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  530. package/out/zero-client/src/client/active-clients-manager.js +1 -1
  531. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  532. package/out/zero-client/src/client/bindings.js +11 -11
  533. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  534. package/out/zero-client/src/client/connection.js +1 -1
  535. package/out/zero-client/src/client/connection.js.map +1 -1
  536. package/out/zero-client/src/client/context.js.map +1 -1
  537. package/out/zero-client/src/client/crud-impl.js +1 -1
  538. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  539. package/out/zero-client/src/client/crud.js +1 -1
  540. package/out/zero-client/src/client/crud.js.map +1 -1
  541. package/out/zero-client/src/client/custom.js +1 -1
  542. package/out/zero-client/src/client/custom.js.map +1 -1
  543. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
  544. package/out/zero-client/src/client/enable-analytics.js +1 -1
  545. package/out/zero-client/src/client/enable-analytics.js.map +1 -1
  546. package/out/zero-client/src/client/error.js.map +1 -1
  547. package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
  548. package/out/zero-client/src/client/inspector/client.js.map +1 -1
  549. package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
  550. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
  551. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  552. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  553. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  554. package/out/zero-client/src/client/ivm-branch.js +1 -3
  555. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  556. package/out/zero-client/src/client/keys.js +2 -1
  557. package/out/zero-client/src/client/keys.js.map +1 -1
  558. package/out/zero-client/src/client/log-options.js.map +1 -1
  559. package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
  560. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  561. package/out/zero-client/src/client/metrics.js +3 -5
  562. package/out/zero-client/src/client/metrics.js.map +1 -1
  563. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  564. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  565. package/out/zero-client/src/client/options.js.map +1 -1
  566. package/out/zero-client/src/client/query-manager.js +2 -2
  567. package/out/zero-client/src/client/query-manager.js.map +1 -1
  568. package/out/zero-client/src/client/reload-error-handler.js +4 -3
  569. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  570. package/out/zero-client/src/client/version.js +1 -1
  571. package/out/zero-client/src/client/zero-poke-handler.js +1 -1
  572. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  573. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  574. package/out/zero-client/src/client/zero.js +19 -11
  575. package/out/zero-client/src/client/zero.js.map +1 -1
  576. package/out/zero-client/src/mod.js +23 -23
  577. package/out/zero-client/src/util/nanoid.js.map +1 -1
  578. package/out/zero-permissions/src/permissions.js +3 -2
  579. package/out/zero-permissions/src/permissions.js.map +1 -1
  580. package/out/zero-pg/src/mod.js +9 -9
  581. package/out/zero-protocol/src/analyze-query-result.js +1 -1
  582. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  583. package/out/zero-protocol/src/application-error.js.map +1 -1
  584. package/out/zero-protocol/src/ast.js +19 -9
  585. package/out/zero-protocol/src/ast.js.map +1 -1
  586. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  587. package/out/zero-protocol/src/client-schema.js +1 -1
  588. package/out/zero-protocol/src/client-schema.js.map +1 -1
  589. package/out/zero-protocol/src/close-connection.js +1 -1
  590. package/out/zero-protocol/src/close-connection.js.map +1 -1
  591. package/out/zero-protocol/src/connect.js +1 -1
  592. package/out/zero-protocol/src/connect.js.map +1 -1
  593. package/out/zero-protocol/src/custom-queries.js +1 -1
  594. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  595. package/out/zero-protocol/src/data.js +4 -2
  596. package/out/zero-protocol/src/data.js.map +1 -1
  597. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  598. package/out/zero-protocol/src/down.d.ts +27 -27
  599. package/out/zero-protocol/src/down.js.map +1 -1
  600. package/out/zero-protocol/src/error.js.map +1 -1
  601. package/out/zero-protocol/src/inspect-down.js +1 -1
  602. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  603. package/out/zero-protocol/src/inspect-up.js +1 -1
  604. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  605. package/out/zero-protocol/src/mutate-server.js +1 -1
  606. package/out/zero-protocol/src/mutate-server.js.map +1 -1
  607. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  608. package/out/zero-protocol/src/mutation.js +1 -1
  609. package/out/zero-protocol/src/mutation.js.map +1 -1
  610. package/out/zero-protocol/src/mutations-patch.js +1 -1
  611. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  612. package/out/zero-protocol/src/ping.js +1 -1
  613. package/out/zero-protocol/src/ping.js.map +1 -1
  614. package/out/zero-protocol/src/poke.js +1 -1
  615. package/out/zero-protocol/src/poke.js.map +1 -1
  616. package/out/zero-protocol/src/pong.js +1 -1
  617. package/out/zero-protocol/src/pong.js.map +1 -1
  618. package/out/zero-protocol/src/primary-key.js.map +1 -1
  619. package/out/zero-protocol/src/protocol-version.js +1 -0
  620. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  621. package/out/zero-protocol/src/pull.js +1 -1
  622. package/out/zero-protocol/src/pull.js.map +1 -1
  623. package/out/zero-protocol/src/push.js +1 -1
  624. package/out/zero-protocol/src/push.js.map +1 -1
  625. package/out/zero-protocol/src/queries-patch.js +1 -1
  626. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  627. package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
  628. package/out/zero-protocol/src/query-hash.js +2 -2
  629. package/out/zero-protocol/src/query-server.js +1 -1
  630. package/out/zero-protocol/src/query-server.js.map +1 -1
  631. package/out/zero-protocol/src/row-patch.js.map +1 -1
  632. package/out/zero-protocol/src/up.js.map +1 -1
  633. package/out/zero-protocol/src/update-auth.js.map +1 -1
  634. package/out/zero-protocol/src/version.js.map +1 -1
  635. package/out/zero-react/src/bindings.js +11 -11
  636. package/out/zero-react/src/mod.js +5 -5
  637. package/out/zero-react/src/use-query.js +1 -1
  638. package/out/zero-react/src/use-query.js.map +1 -1
  639. package/out/zero-react/src/zero-provider.d.ts +1 -1
  640. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  641. package/out/zero-react/src/zero-provider.js +2 -1
  642. package/out/zero-react/src/zero-provider.js.map +1 -1
  643. package/out/zero-react/src/zero.js +23 -23
  644. package/out/zero-schema/src/builder/schema-builder.js +3 -2
  645. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  646. package/out/zero-schema/src/builder/table-builder.js +1 -1
  647. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  648. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  649. package/out/zero-schema/src/name-mapper.js +7 -5
  650. package/out/zero-schema/src/name-mapper.js.map +1 -1
  651. package/out/zero-schema/src/schema-config.js +1 -1
  652. package/out/zero-schema/src/schema-config.js.map +1 -1
  653. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  654. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  655. package/out/zero-server/src/adapters/pg.js.map +1 -1
  656. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  657. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  658. package/out/zero-server/src/closable-db-transaction.js.map +1 -1
  659. package/out/zero-server/src/custom.js +1 -1
  660. package/out/zero-server/src/custom.js.map +1 -1
  661. package/out/zero-server/src/mod.js +8 -8
  662. package/out/zero-server/src/process-mutations.js.map +1 -1
  663. package/out/zero-server/src/push-processor.js.map +1 -1
  664. package/out/zero-server/src/queries/process-queries.js +2 -1
  665. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  666. package/out/zero-server/src/schema.js +7 -7
  667. package/out/zero-server/src/schema.js.map +1 -1
  668. package/out/zero-server/src/zql-database.js.map +1 -1
  669. package/out/zero-solid/src/bindings.js +11 -11
  670. package/out/zero-solid/src/mod.js +5 -5
  671. package/out/zero-solid/src/solid-view.js +1 -1
  672. package/out/zero-solid/src/solid-view.js.map +1 -1
  673. package/out/zero-solid/src/use-connection-state.js +2 -1
  674. package/out/zero-solid/src/use-connection-state.js.map +1 -1
  675. package/out/zero-solid/src/use-query.js.map +1 -1
  676. package/out/zero-solid/src/use-zero-online.js +2 -1
  677. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  678. package/out/zero-solid/src/use-zero.js +3 -2
  679. package/out/zero-solid/src/use-zero.js.map +1 -1
  680. package/out/zero-solid/src/zero.js +23 -23
  681. package/out/zero-types/src/name-mapper.js.map +1 -1
  682. package/out/zql/src/builder/builder.js +15 -13
  683. package/out/zql/src/builder/builder.js.map +1 -1
  684. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
  685. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  686. package/out/zql/src/builder/like.js +0 -1
  687. package/out/zql/src/builder/like.js.map +1 -1
  688. package/out/zql/src/ivm/array-view.js.map +1 -1
  689. package/out/zql/src/ivm/cap.js +2 -4
  690. package/out/zql/src/ivm/cap.js.map +1 -1
  691. package/out/zql/src/ivm/constraint.js +1 -1
  692. package/out/zql/src/ivm/constraint.js.map +1 -1
  693. package/out/zql/src/ivm/data.js.map +1 -1
  694. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  695. package/out/zql/src/ivm/exists.js +20 -18
  696. package/out/zql/src/ivm/exists.js.map +1 -1
  697. package/out/zql/src/ivm/fan-in.js.map +1 -1
  698. package/out/zql/src/ivm/fan-out.js.map +1 -1
  699. package/out/zql/src/ivm/filter-operators.js +1 -1
  700. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  701. package/out/zql/src/ivm/filter-push.js.map +1 -1
  702. package/out/zql/src/ivm/filter.js.map +1 -1
  703. package/out/zql/src/ivm/flipped-join.js +1 -3
  704. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  705. package/out/zql/src/ivm/join-index-tap.js.map +1 -1
  706. package/out/zql/src/ivm/join-index.js.map +1 -1
  707. package/out/zql/src/ivm/join-utils.js +11 -13
  708. package/out/zql/src/ivm/join-utils.js.map +1 -1
  709. package/out/zql/src/ivm/join.js.map +1 -1
  710. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  711. package/out/zql/src/ivm/memory-source.js +26 -22
  712. package/out/zql/src/ivm/memory-source.js.map +1 -1
  713. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  714. package/out/zql/src/ivm/operator.js +2 -2
  715. package/out/zql/src/ivm/push-accumulated.js +0 -1
  716. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  717. package/out/zql/src/ivm/skip-yields.js.map +1 -1
  718. package/out/zql/src/ivm/skip.js.map +1 -1
  719. package/out/zql/src/ivm/take-gate.js.map +1 -1
  720. package/out/zql/src/ivm/take.js +3 -5
  721. package/out/zql/src/ivm/take.js.map +1 -1
  722. package/out/zql/src/ivm/union-fan-in.js +1 -1
  723. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  724. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  725. package/out/zql/src/ivm/view-apply-change.js +1 -1
  726. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  727. package/out/zql/src/mutate/crud.js +3 -2
  728. package/out/zql/src/mutate/crud.js.map +1 -1
  729. package/out/zql/src/planner/planner-builder.js +1 -1
  730. package/out/zql/src/planner/planner-builder.js.map +1 -1
  731. package/out/zql/src/planner/planner-connection.js.map +1 -1
  732. package/out/zql/src/planner/planner-debug.js.map +1 -1
  733. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  734. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  735. package/out/zql/src/planner/planner-filter.js.map +1 -1
  736. package/out/zql/src/planner/planner-graph.js +1 -5
  737. package/out/zql/src/planner/planner-graph.js.map +1 -1
  738. package/out/zql/src/planner/planner-join.js +1 -1
  739. package/out/zql/src/planner/planner-join.js.map +1 -1
  740. package/out/zql/src/planner/planner-source.js.map +1 -1
  741. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  742. package/out/zql/src/query/create-builder.js +2 -1
  743. package/out/zql/src/query/create-builder.js.map +1 -1
  744. package/out/zql/src/query/expression.js +1 -1
  745. package/out/zql/src/query/expression.js.map +1 -1
  746. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  747. package/out/zql/src/query/named.js +2 -1
  748. package/out/zql/src/query/named.js.map +1 -1
  749. package/out/zql/src/query/query-delegate-base.js +1 -1
  750. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  751. package/out/zql/src/query/query-impl.js +3 -2
  752. package/out/zql/src/query/query-impl.js.map +1 -1
  753. package/out/zql/src/query/query-registry.js +1 -1
  754. package/out/zql/src/query/query-registry.js.map +1 -1
  755. package/out/zql/src/query/query-transitions.js +1 -1
  756. package/out/zql/src/query/query-transitions.js.map +1 -1
  757. package/out/zql/src/query/runnable-query-impl.js +3 -2
  758. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  759. package/out/zql/src/query/static-query.js.map +1 -1
  760. package/out/zql/src/query/ttl.js +8 -8
  761. package/out/zql/src/query/ttl.js.map +1 -1
  762. package/out/zql/src/query/validate-input.js.map +1 -1
  763. package/out/zqlite/src/database-storage.d.ts +27 -8
  764. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  765. package/out/zqlite/src/database-storage.js +195 -26
  766. package/out/zqlite/src/database-storage.js.map +1 -1
  767. package/out/zqlite/src/db.d.ts +47 -1
  768. package/out/zqlite/src/db.d.ts.map +1 -1
  769. package/out/zqlite/src/db.js +121 -21
  770. package/out/zqlite/src/db.js.map +1 -1
  771. package/out/zqlite/src/explain-queries.js.map +1 -1
  772. package/out/zqlite/src/fetch-sql.d.ts +27 -0
  773. package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
  774. package/out/zqlite/src/fetch-sql.js +112 -0
  775. package/out/zqlite/src/fetch-sql.js.map +1 -0
  776. package/out/zqlite/src/index-usage.js.map +1 -1
  777. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  778. package/out/zqlite/src/internal/sql.js.map +1 -1
  779. package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
  780. package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
  781. package/out/zqlite/src/internal/statement-cache.js +11 -4
  782. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  783. package/out/zqlite/src/mod.js +5 -5
  784. package/out/zqlite/src/pending-delta.js.map +1 -1
  785. package/out/zqlite/src/query-builder.d.ts +11 -1
  786. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  787. package/out/zqlite/src/query-builder.js +22 -7
  788. package/out/zqlite/src/query-builder.js.map +1 -1
  789. package/out/zqlite/src/query-delegate.js.map +1 -1
  790. package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
  791. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  792. package/out/zqlite/src/sqlite-cost-model.js +3 -2
  793. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  794. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  795. package/out/zqlite/src/table-source.d.ts +20 -2
  796. package/out/zqlite/src/table-source.d.ts.map +1 -1
  797. package/out/zqlite/src/table-source.js +73 -39
  798. package/out/zqlite/src/table-source.js.map +1 -1
  799. package/package.json +17 -15
  800. package/out/otel/src/maybe-time.d.ts +0 -3
  801. package/out/otel/src/maybe-time.d.ts.map +0 -1
  802. package/out/otel/src/maybe-time.js +0 -15
  803. package/out/otel/src/maybe-time.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"solid-view.js","names":["#input","#format","#onDestroy","#retry","#updateTTL","#onTransactionCommit","#createEmptyRoot","#applyChangesToRoot","#setState","#makeError","#builderRoot","#transitionResultType","#held","#hasUncommittedChanges","#pendingResultType","#pendingChanges","#applyChanges","#applyChangeToRoot"],"sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {ChangeIndex} from '../../zql/src/ivm/change-index.ts';\nimport {ChangeType} from '../../zql/src/ivm/change-type.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\nexport const CACHED: QueryResultDetails = Object.freeze({type: 'cached'});\n\n/**\n * SolidView bridges Zero's incremental view updates with Solid's reactive\n * store.\n *\n * The challenge: Zero pushes individual row changes (add/remove/edit) as they\n * arrive, but updating Solid's store on each push is expensive. We batch\n * changes until transaction commit, then apply them all at once.\n *\n * Two code paths optimize for different scenarios:\n *\n * 1. BULK INSERT (builderRoot path): When building from empty, we skip\n * Solid's reactive tracking entirely and build a plain JS object. This is\n * 5x faster for large initial loads. Uses reconcile() to diff the final\n * result into Solid.\n *\n * 2. INCREMENTAL UPDATE (#pendingChanges path): For existing views, we queue\n * changes and apply them in-place within a produce() draft. produce()\n * creates a mutable draft, applyChange mutates it directly, then produce()\n * handles diffing and reactivity.\n *\n *\n * push(change)\n * │\n * ▼\n * ┌─────────────────────────────────┐\n * │ builderRoot defined? │\n * │ (building from empty) │\n * └─────────────────────────────────┘\n * │yes │no\n * ▼ ▼\n * Build plain JS Queue in\n * object (fast) #pendingChanges\n * │ │\n * └───────┬───────────┘\n * ▼\n * onTransactionCommit()\n * │\n * ┌───────┴──────────┐\n * │ │\n * builderRoot produce(draft =>\n * → reconcile() applyChange(draft, ..., mutate: true))\n */\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n // A result type transition requested while row changes are waiting for the\n // next commit. It is applied with them, so a cached claim never reaches the\n // store before the rows it is about.\n #pendingResultType: ((prev: State) => State) | undefined;\n #held = false;\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n // Through the pending path: a deferred attach that fails is\n // published with the commit of its batch, not during it.\n this.#transitionResultType(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n /**\n * The store holds the server-confirmed result of this query from a\n * previous connection. Never downgrades 'complete'/'error'; freshness stays\n * a promise only the connection can keep, so nothing that waits on\n * 'complete' resolves here.\n */\n markCached(): void {\n this.#transitionResultType(prev =>\n prev[1].type === 'unknown' ? [prev[0], CACHED] : prev,\n );\n }\n\n /** The got key was deleted (eviction) before this connection confirmed it. */\n unmarkCached(): void {\n this.#transitionResultType(prev =>\n prev[1].type === 'cached' ? [prev[0], UNKNOWN] : prev,\n );\n }\n\n /**\n * Called before a deferred pipeline hydrates this view over several tasks\n * (see `ViewFactory`). Rows already only reach the store at commit; this\n * makes result type transitions wait for that commit too, including when\n * the hydration produced no rows.\n */\n holdData(): void {\n this.#held = true;\n }\n\n #transitionResultType(transition: (prev: State) => State): void {\n if (this.#held || this.#hasUncommittedChanges()) {\n // The last requested transition wins; each is a no-op unless the state\n // it expects is current, so the net effect at commit is correct.\n this.#pendingResultType = transition;\n } else {\n this.#setState(transition);\n }\n }\n\n #hasUncommittedChanges(): boolean {\n return (\n (this.#builderRoot !== undefined && !isEmptyRoot(this.#builderRoot)) ||\n this.#pendingChanges.length > 0\n );\n }\n\n #onTransactionCommit = () => {\n this.#held = false;\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n const pendingResultType = this.#pendingResultType;\n if (pendingResultType) {\n this.#pendingResultType = undefined;\n this.#setState(pendingResultType);\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(\n materializeRelationships(change),\n this.#builderRoot,\n );\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n true /* mutate */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n return {\n type: 'add',\n node: materializeNodeRelationships(change[ChangeIndex.NODE]),\n };\n case ChangeType.REMOVE:\n return {\n type: 'remove',\n node: materializeNodeRelationships(change[ChangeIndex.NODE]),\n };\n case ChangeType.CHILD:\n return {\n type: 'child',\n node: {row: change[ChangeIndex.NODE].row},\n child: {\n relationshipName: change[ChangeIndex.CHILD_DATA].relationshipName,\n change: materializeRelationships(\n change[ChangeIndex.CHILD_DATA].change,\n ),\n },\n };\n case ChangeType.EDIT:\n return {\n type: 'edit',\n node: {row: change[ChangeIndex.NODE].row},\n oldNode: {row: change[ChangeIndex.OLD_NODE].row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"solid-view.js","names":[],"sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {ChangeIndex} from '../../zql/src/ivm/change-index.ts';\nimport {ChangeType} from '../../zql/src/ivm/change-type.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\nexport const CACHED: QueryResultDetails = Object.freeze({type: 'cached'});\n\n/**\n * SolidView bridges Zero's incremental view updates with Solid's reactive\n * store.\n *\n * The challenge: Zero pushes individual row changes (add/remove/edit) as they\n * arrive, but updating Solid's store on each push is expensive. We batch\n * changes until transaction commit, then apply them all at once.\n *\n * Two code paths optimize for different scenarios:\n *\n * 1. BULK INSERT (builderRoot path): When building from empty, we skip\n * Solid's reactive tracking entirely and build a plain JS object. This is\n * 5x faster for large initial loads. Uses reconcile() to diff the final\n * result into Solid.\n *\n * 2. INCREMENTAL UPDATE (#pendingChanges path): For existing views, we queue\n * changes and apply them in-place within a produce() draft. produce()\n * creates a mutable draft, applyChange mutates it directly, then produce()\n * handles diffing and reactivity.\n *\n *\n * push(change)\n * │\n * ▼\n * ┌─────────────────────────────────┐\n * │ builderRoot defined? │\n * │ (building from empty) │\n * └─────────────────────────────────┘\n * │yes │no\n * ▼ ▼\n * Build plain JS Queue in\n * object (fast) #pendingChanges\n * │ │\n * └───────┬───────────┘\n * ▼\n * onTransactionCommit()\n * │\n * ┌───────┴──────────┐\n * │ │\n * builderRoot produce(draft =>\n * → reconcile() applyChange(draft, ..., mutate: true))\n */\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n // A result type transition requested while row changes are waiting for the\n // next commit. It is applied with them, so a cached claim never reaches the\n // store before the rows it is about.\n #pendingResultType: ((prev: State) => State) | undefined;\n #held = false;\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n // Through the pending path: a deferred attach that fails is\n // published with the commit of its batch, not during it.\n this.#transitionResultType(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n /**\n * The store holds the server-confirmed result of this query from a\n * previous connection. Never downgrades 'complete'/'error'; freshness stays\n * a promise only the connection can keep, so nothing that waits on\n * 'complete' resolves here.\n */\n markCached(): void {\n this.#transitionResultType(prev =>\n prev[1].type === 'unknown' ? [prev[0], CACHED] : prev,\n );\n }\n\n /** The got key was deleted (eviction) before this connection confirmed it. */\n unmarkCached(): void {\n this.#transitionResultType(prev =>\n prev[1].type === 'cached' ? [prev[0], UNKNOWN] : prev,\n );\n }\n\n /**\n * Called before a deferred pipeline hydrates this view over several tasks\n * (see `ViewFactory`). Rows already only reach the store at commit; this\n * makes result type transitions wait for that commit too, including when\n * the hydration produced no rows.\n */\n holdData(): void {\n this.#held = true;\n }\n\n #transitionResultType(transition: (prev: State) => State): void {\n if (this.#held || this.#hasUncommittedChanges()) {\n // The last requested transition wins; each is a no-op unless the state\n // it expects is current, so the net effect at commit is correct.\n this.#pendingResultType = transition;\n } else {\n this.#setState(transition);\n }\n }\n\n #hasUncommittedChanges(): boolean {\n return (\n (this.#builderRoot !== undefined && !isEmptyRoot(this.#builderRoot)) ||\n this.#pendingChanges.length > 0\n );\n }\n\n #onTransactionCommit = () => {\n this.#held = false;\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n const pendingResultType = this.#pendingResultType;\n if (pendingResultType) {\n this.#pendingResultType = undefined;\n this.#setState(pendingResultType);\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(\n materializeRelationships(change),\n this.#builderRoot,\n );\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n true /* mutate */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change[ChangeIndex.TYPE]) {\n case ChangeType.ADD:\n return {\n type: 'add',\n node: materializeNodeRelationships(change[ChangeIndex.NODE]),\n };\n case ChangeType.REMOVE:\n return {\n type: 'remove',\n node: materializeNodeRelationships(change[ChangeIndex.NODE]),\n };\n case ChangeType.CHILD:\n return {\n type: 'child',\n node: {row: change[ChangeIndex.NODE].row},\n child: {\n relationshipName: change[ChangeIndex.CHILD_DATA].relationshipName,\n change: materializeRelationships(\n change[ChangeIndex.CHILD_DATA].change,\n ),\n },\n };\n case ChangeType.EDIT:\n return {\n type: 'edit',\n node: {row: change[ChangeIndex.NODE].row},\n oldNode: {row: change[ChangeIndex.OLD_NODE].row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"mappings":";;;;;;;AA6BA,IAAa,WAA+B,OAAO,OAAO,EAAC,MAAM,WAAU,CAAC;AAC5E,IAAa,UAA8B,OAAO,OAAO,EAAC,MAAM,UAAS,CAAC;AAC1E,IAAa,SAA6B,OAAO,OAAO,EAAC,MAAM,SAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CxE,IAAa,YAAb,MAAyC;CACvC;CACA;CACA;CACA;CAEA;CAUA;CACA,kBAAgC,CAAC;CAIjC;CACA,QAAQ;CACR;CAEA,YACE,OACA,qBACA,QACA,WACA,eACA,WACA,UACA,OACA;EACA,KAAK,SAAS;EACd,oBAAoB,KAAK,oBAAoB;EAC7C,KAAK,UAAU;EACf,KAAK,aAAa;EAClB,KAAK,aAAa;EAClB,KAAK,SAAS;EAEd,MAAM,UAAU,IAAI;EAEpB,MAAM,cAAc,KAAK,iBAAiB;EAC1C,KAAK,oBACH,WAAW,MAAM,MAAM,CAAC,CAAC,CAAC,IAC1B,UAAS;GAAC,MAAM;GAAO;EAAI,IAC3B,WACF;EAEA,KAAK,YAAY;EACjB,KAAK,UACH,UACE,CACE,aACA,kBAAkB,OACd,WACA,WAAW,gBACT,KAAK,WAAW,aAAa,IAC7B,OACR,GACA,EAEE,KAAK,SACP,CACF,CACF;EAEA,IAAI,YAAY,WAAW,GACzB,KAAK,eAAe,KAAK,iBAAiB;EAG5C,IAAI,kBAAkB,QAAQ,EAAE,WAAW,gBACzC,cACG,WAAW;GACV,KAAK,WAAU,SAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC;EAC5C,CAAC,CAAC,CACD,OAAO,UAAwB;GAG9B,KAAK,uBAAsB,SAAQ,CAAC,KAAK,IAAI,KAAK,WAAW,KAAK,CAAC,CAAC;EACtE,CAAC;CAEP;CAEA,WAAW,OAAwC;EACjD,MAAM,UAAU,MAAM,WAAW;EACjC,OAAO;GACL,MAAM;GACN,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,OAAO;IACL,MAAM,MAAM;IACZ;IACA,GAAI,MAAM,UAAU,EAAC,SAAS,MAAM,QAAO,IAAI,CAAC;GAClD;EACF;CACF;CAEA,UAAgB;EACd,KAAK,WAAW;CAClB;;;;;;;CAQA,aAAmB;EACjB,KAAK,uBAAsB,SACzB,KAAK,EAAE,CAAC,SAAS,YAAY,CAAC,KAAK,IAAI,MAAM,IAAI,IACnD;CACF;;CAGA,eAAqB;EACnB,KAAK,uBAAsB,SACzB,KAAK,EAAE,CAAC,SAAS,WAAW,CAAC,KAAK,IAAI,OAAO,IAAI,IACnD;CACF;;;;;;;CAQA,WAAiB;EACf,KAAK,QAAQ;CACf;CAEA,sBAAsB,YAA0C;EAC9D,IAAI,KAAK,SAAS,KAAK,uBAAuB,GAG5C,KAAK,qBAAqB;OAE1B,KAAK,UAAU,UAAU;CAE7B;CAEA,yBAAkC;EAChC,OACG,KAAK,iBAAiB,KAAA,KAAa,CAAC,YAAY,KAAK,YAAY,KAClE,KAAK,gBAAgB,SAAS;CAElC;CAEA,6BAA6B;EAC3B,KAAK,QAAQ;EACb,MAAM,cAAc,KAAK;EACzB,IAAI,aACE;OAAA,CAAC,YAAY,WAAW,GAAG;IAC7B,KAAK,UACH,GACA,UAAU,aAAa,EAErB,KAAK,SACP,CAAC,CACH;IACA,KAAK,eAAe,KAAA;GACtB;SAEA,IAAI;GACF,KAAK,cAAc,KAAK,kBAAiB,MAAK,CAAC;EACjD,UAAU;GACR,KAAK,kBAAkB,CAAC;EAC1B;EAEF,MAAM,oBAAoB,KAAK;EAC/B,IAAI,mBAAmB;GACrB,KAAK,qBAAqB,KAAA;GAC1B,KAAK,UAAU,iBAAiB;EAClC;CACF;CAEA,KAAK,QAAgB;EAOnB,IAAI,KAAK,cACP,KAAK,mBACH,yBAAyB,MAAM,GAC/B,KAAK,YACP;OAEA,KAAK,gBAAgB,KAAK,yBAAyB,MAAM,CAAC;EAE5D,OAAO;CACT;CAEA,cAAiB,SAAsB,QAAoC;EACzE,KAAK,UACH,SAAS,eAAsB;GAC7B,KAAK,oBAAuB,SAAS,QAAQ,WAAW,EAAE;GAC1D,IAAI,YAAY,WAAW,EAAE,GAC3B,KAAK,eAAe,KAAK,iBAAiB;EAE9C,CAAC,CACH;CACF;CAEA,oBACE,SACA,QACA,MACA;EACA,KAAK,MAAM,UAAU,SACnB,KAAK,mBAAmB,OAAO,MAAM,GAAG,IAAI;CAEhD;CAEA,mBAAmB,QAAoB,MAAa;EAClD,YACE,MACA,QACA,KAAK,OAAO,UAAU,GACtB,IACA,KAAK,SACL,MACA,IACF;CACF;CAEA,mBAA0B;EACxB,OAAO,EACL,IAAI,KAAK,QAAQ,WAAW,KAAA,IAAY,CAAC,EAC3C;CACF;CAEA,UAAU,KAAgB;EACxB,KAAK,WAAW,GAAG;CACrB;AACF;AAEA,SAAS,yBAAyB,QAA4B;CAC5D,QAAQ,OAAO,IAAf;EACE,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,6BAA6B,OAAO,EAAiB;EAC7D;EACF,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,6BAA6B,OAAO,EAAiB;EAC7D;EACF,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,EAAC,KAAK,OAAO,EAAiB,CAAC,IAAG;GACxC,OAAO;IACL,kBAAkB,OAAO,EAAuB,CAAC;IACjD,QAAQ,yBACN,OAAO,EAAuB,CAAC,MACjC;GACF;EACF;EACF,KAAK,GACH,OAAO;GACL,MAAM;GACN,MAAM,EAAC,KAAK,OAAO,EAAiB,CAAC,IAAG;GACxC,SAAS,EAAC,KAAK,OAAO,EAAqB,CAAC,IAAG;EACjD;CACJ;AACF;AAEA,SAAS,6BAA6B,MAAkB;CACtD,MAAM,gBAAoD,CAAC;CAC3D,KAAK,MAAM,gBAAgB,KAAK,eAAe;EAC7C,MAAM,eAAuB,CAAC;EAC9B,KAAK,MAAM,KAAK,WAAW,KAAK,cAAc,aAAa,CAAC,CAAC,GAC3D,aAAa,KAAK,6BAA6B,CAAC,CAAC;EAEnD,cAAc,sBAAsB;CACtC;CACA,OAAO;EACL,KAAK,KAAK;EACV;CACF;AACF;AAEA,SAAS,YAAY,OAAc;CACjC,MAAM,OAAO,MAAM;CACnB,OAAO,SAAS,KAAA,KAAc,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW;AACvE;AAEA,SAAgB,uBACd,UACA,OACA;CACA,SAAS,iBAKP,QACA,OACA,QACA,WACA,qBACA,eACA,WACA;EACA,OAAO,IAAI,UACT,OACA,qBACA,QACA,WACA,eACA,WACA,UACA,gBAAgB,CAAC,EACnB;CACF;CAIA,OAAO;AACT"}
@@ -11,7 +11,8 @@ function useConnectionState() {
11
11
  const zero = useZero();
12
12
  const [connectionState, setConnectionState] = createSignal(zero().connection.state.current);
13
13
  createEffect(() => {
14
- onCleanup(zero().connection.state.subscribe(setConnectionState));
14
+ const unsubscribe = zero().connection.state.subscribe(setConnectionState);
15
+ onCleanup(unsubscribe);
15
16
  });
16
17
  return connectionState;
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-connection-state.js","names":[],"sources":["../../../../zero-solid/src/use-connection-state.ts"],"sourcesContent":["import {createEffect, createSignal, onCleanup, type Accessor} from 'solid-js';\nimport {useZero} from './use-zero.ts';\nimport type {ConnectionState} from './zero.ts';\n\n/**\n * Tracks the connection status of the current Zero instance.\n *\n * @returns The connection status of the Zero instance.\n * @see {@link ConnectionState} for more details on the connection state.\n */\nexport function useConnectionState(): Accessor<ConnectionState> {\n const zero = useZero();\n\n const [connectionState, setConnectionState] = createSignal<ConnectionState>(\n zero().connection.state.current,\n );\n\n createEffect(() => {\n const unsubscribe = zero().connection.state.subscribe(setConnectionState);\n\n onCleanup(unsubscribe);\n });\n\n return connectionState;\n}\n"],"mappings":";;;;;;;;;AAUA,SAAgB,qBAAgD;CAC9D,MAAM,OAAO,QAAQ;CAErB,MAAM,CAAC,iBAAiB,sBAAsB,aAC5C,KAAK,EAAE,WAAW,MAAM,OAC1B;CAEA,mBAAmB;EAGjB,UAFoB,KAAK,EAAE,WAAW,MAAM,UAAU,kBAE5C,CAAW;CACvB,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"use-connection-state.js","names":[],"sources":["../../../../zero-solid/src/use-connection-state.ts"],"sourcesContent":["import {createEffect, createSignal, onCleanup, type Accessor} from 'solid-js';\nimport {useZero} from './use-zero.ts';\nimport type {ConnectionState} from './zero.ts';\n\n/**\n * Tracks the connection status of the current Zero instance.\n *\n * @returns The connection status of the Zero instance.\n * @see {@link ConnectionState} for more details on the connection state.\n */\nexport function useConnectionState(): Accessor<ConnectionState> {\n const zero = useZero();\n\n const [connectionState, setConnectionState] = createSignal<ConnectionState>(\n zero().connection.state.current,\n );\n\n createEffect(() => {\n const unsubscribe = zero().connection.state.subscribe(setConnectionState);\n\n onCleanup(unsubscribe);\n });\n\n return connectionState;\n}\n"],"mappings":";;;;;;;;;AAUA,SAAgB,qBAAgD;CAC9D,MAAM,OAAO,QAAQ;CAErB,MAAM,CAAC,iBAAiB,sBAAsB,aAC5C,KAAK,CAAC,CAAC,WAAW,MAAM,OAC1B;CAEA,mBAAmB;EACjB,MAAM,cAAc,KAAK,CAAC,CAAC,WAAW,MAAM,UAAU,kBAAkB;EAExE,UAAU,WAAW;CACvB,CAAC;CAED,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-query.js","names":[],"sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type BaseDefaultContext,\n type BaseDefaultSchema,\n type DefaultContext,\n type DefaultSchema,\n type Falsy,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n/**\n * Result type for \"maybe queries\" - queries that may be falsy.\n * The data value can be undefined when the query is falsy/disabled.\n */\nexport type MaybeQueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn> | undefined>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@link UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@link useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\n// Overload 1: Query - returns QueryResult<TReturn>\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn>;\n\n// Overload 2: Maybe query\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): MaybeQueryResult<TReturn>;\n\n// Implementation\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> | MaybeQueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n\n // Handle possibly falsy queries\n const q = createMemo(() => {\n const query = querySignal();\n if (!query) return undefined;\n return addContextToQuery(query, zero().context);\n });\n\n const qi = createMemo(() => {\n const query = q();\n if (!query) return undefined;\n return asQueryInternals(query);\n });\n\n // Undefined rather than the string `undefined` + the client id: this feeds\n // the guard below, and concatenating a missing hash produced a string that\n // was never equal to undefined, leaving that guard unreachable.\n const hash = createMemo(() => {\n const internals = qi();\n return internals === undefined\n ? undefined\n : internals.hash() + zero().clientID;\n });\n const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);\n\n const view = createMemo(() => {\n // Depend on hash instead of query to avoid recreating the view when the\n // query object changes but the hash is the same.\n const currentHash = hash();\n refetchKey();\n\n // If query is falsy, don't create a view and reset state to undefined\n if (currentHash === undefined) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const untrackedQuery = untrack(q);\n if (!untrackedQuery) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const v = zero().materialize(\n untrackedQuery,\n createSolidViewFactory(setState, refetch),\n {\n // Untracked: a ttl change updates the live view through the effect\n // below, and depending on it here would tear the view down and build\n // a new one instead. Read at materialize time rather than once at\n // setup, so a view built later -- because the query changed -- gets\n // the ttl in effect by then rather than the one this hook started\n // with.\n ttl: untrack(ttl),\n },\n );\n\n onCleanup(() => v.destroy());\n\n return v;\n });\n\n // Update TTL on existing view when it changes.\n createEffect(\n on(\n ttl,\n currentTTL => {\n view()?.updateTTL(currentTTL);\n },\n {defer: true},\n ),\n );\n\n return [() => state[0][''] as HumanReadable<TReturn>, () => state[1]];\n}\n\nfunction normalize<T>(options?: T | Accessor<T | undefined>): T | undefined {\n return typeof options === 'function' ? (options as Accessor<T>)() : options;\n}\n"],"mappings":";;;;;;;;;;;;;AA6DA,SAAgB,YAQd,aAGA,SACsB;CACtB,OAAO,SAAS,aAAa,OAAO;AACtC;AAkCA,SAAgB,SAQd,aAIA,SACkD;CAClD,MAAM,CAAC,OAAO,YAAY,YAAmB,CAC3C,EACE,IAAI,KAAA,EACN,GACA,OACF,CAAC;CAED,MAAM,CAAC,YAAY,iBAAiB,aAAa,CAAiB;CAElE,MAAM,gBAAgB;EACpB,eAAc,MAAK,IAAI,CAAC;CAC1B;CAEA,MAAM,OAAO,QAAsC;CAGnD,MAAM,IAAI,iBAAiB;EACzB,MAAM,QAAQ,YAAY;EAC1B,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO,kBAAkB,OAAO,KAAK,EAAE,OAAO;CAChD,CAAC;CAED,MAAM,KAAK,iBAAiB;EAC1B,MAAM,QAAQ,EAAE;EAChB,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO,iBAAiB,KAAK;CAC/B,CAAC;CAKD,MAAM,OAAO,iBAAiB;EAC5B,MAAM,YAAY,GAAG;EACrB,OAAO,cAAc,KAAA,IACjB,KAAA,IACA,UAAU,KAAK,IAAI,KAAK,EAAE;CAChC,CAAC;CACD,MAAM,MAAM,iBAAiB,UAAU,OAAO,GAAG,OAAA,GAAqB;CAEtE,MAAM,OAAO,iBAAiB;EAG5B,MAAM,cAAc,KAAK;EACzB,WAAW;EAGX,IAAI,gBAAgB,KAAA,GAAW;GAC7B,SAAS,CAAC,EAAC,IAAI,KAAA,EAAS,GAAG,OAAO,CAAC;GACnC;EACF;EAEA,MAAM,iBAAiB,QAAQ,CAAC;EAChC,IAAI,CAAC,gBAAgB;GACnB,SAAS,CAAC,EAAC,IAAI,KAAA,EAAS,GAAG,OAAO,CAAC;GACnC;EACF;EAEA,MAAM,IAAI,KAAK,EAAE,YACf,gBACA,uBAAuB,UAAU,OAAO,GACxC,EAOE,KAAK,QAAQ,GAAG,EAClB,CACF;EAEA,gBAAgB,EAAE,QAAQ,CAAC;EAE3B,OAAO;CACT,CAAC;CAGD,aACE,GACE,MACA,eAAc;EACZ,KAAK,GAAG,UAAU,UAAU;CAC9B,GACA,EAAC,OAAO,KAAI,CACd,CACF;CAEA,OAAO,OAAO,MAAM,GAAG,WAAqC,MAAM,EAAE;AACtE;AAEA,SAAS,UAAa,SAAsD;CAC1E,OAAO,OAAO,YAAY,aAAc,QAAwB,IAAI;AACtE"}
1
+ {"version":3,"file":"use-query.js","names":[],"sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type BaseDefaultContext,\n type BaseDefaultSchema,\n type DefaultContext,\n type DefaultSchema,\n type Falsy,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n/**\n * Result type for \"maybe queries\" - queries that may be falsy.\n * The data value can be undefined when the query is falsy/disabled.\n */\nexport type MaybeQueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn> | undefined>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@link UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@link useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\n// Overload 1: Query - returns QueryResult<TReturn>\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn>;\n\n// Overload 2: Maybe query\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): MaybeQueryResult<TReturn>;\n\n// Implementation\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends BaseDefaultSchema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext extends BaseDefaultContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> | MaybeQueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n\n // Handle possibly falsy queries\n const q = createMemo(() => {\n const query = querySignal();\n if (!query) return undefined;\n return addContextToQuery(query, zero().context);\n });\n\n const qi = createMemo(() => {\n const query = q();\n if (!query) return undefined;\n return asQueryInternals(query);\n });\n\n // Undefined rather than the string `undefined` + the client id: this feeds\n // the guard below, and concatenating a missing hash produced a string that\n // was never equal to undefined, leaving that guard unreachable.\n const hash = createMemo(() => {\n const internals = qi();\n return internals === undefined\n ? undefined\n : internals.hash() + zero().clientID;\n });\n const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);\n\n const view = createMemo(() => {\n // Depend on hash instead of query to avoid recreating the view when the\n // query object changes but the hash is the same.\n const currentHash = hash();\n refetchKey();\n\n // If query is falsy, don't create a view and reset state to undefined\n if (currentHash === undefined) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const untrackedQuery = untrack(q);\n if (!untrackedQuery) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const v = zero().materialize(\n untrackedQuery,\n createSolidViewFactory(setState, refetch),\n {\n // Untracked: a ttl change updates the live view through the effect\n // below, and depending on it here would tear the view down and build\n // a new one instead. Read at materialize time rather than once at\n // setup, so a view built later -- because the query changed -- gets\n // the ttl in effect by then rather than the one this hook started\n // with.\n ttl: untrack(ttl),\n },\n );\n\n onCleanup(() => v.destroy());\n\n return v;\n });\n\n // Update TTL on existing view when it changes.\n createEffect(\n on(\n ttl,\n currentTTL => {\n view()?.updateTTL(currentTTL);\n },\n {defer: true},\n ),\n );\n\n return [() => state[0][''] as HumanReadable<TReturn>, () => state[1]];\n}\n\nfunction normalize<T>(options?: T | Accessor<T | undefined>): T | undefined {\n return typeof options === 'function' ? (options as Accessor<T>)() : options;\n}\n"],"mappings":";;;;;;;;;;;;;AA6DA,SAAgB,YAQd,aAGA,SACsB;CACtB,OAAO,SAAS,aAAa,OAAO;AACtC;AAkCA,SAAgB,SAQd,aAIA,SACkD;CAClD,MAAM,CAAC,OAAO,YAAY,YAAmB,CAC3C,EACE,IAAI,KAAA,EACN,GACA,OACF,CAAC;CAED,MAAM,CAAC,YAAY,iBAAiB,aAAa,CAAiB;CAElE,MAAM,gBAAgB;EACpB,eAAc,MAAK,IAAI,CAAC;CAC1B;CAEA,MAAM,OAAO,QAAsC;CAGnD,MAAM,IAAI,iBAAiB;EACzB,MAAM,QAAQ,YAAY;EAC1B,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO,kBAAkB,OAAO,KAAK,CAAC,CAAC,OAAO;CAChD,CAAC;CAED,MAAM,KAAK,iBAAiB;EAC1B,MAAM,QAAQ,EAAE;EAChB,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO,iBAAiB,KAAK;CAC/B,CAAC;CAKD,MAAM,OAAO,iBAAiB;EAC5B,MAAM,YAAY,GAAG;EACrB,OAAO,cAAc,KAAA,IACjB,KAAA,IACA,UAAU,KAAK,IAAI,KAAK,CAAC,CAAC;CAChC,CAAC;CACD,MAAM,MAAM,iBAAiB,UAAU,OAAO,CAAC,EAAE,OAAA,GAAqB;CAEtE,MAAM,OAAO,iBAAiB;EAG5B,MAAM,cAAc,KAAK;EACzB,WAAW;EAGX,IAAI,gBAAgB,KAAA,GAAW;GAC7B,SAAS,CAAC,EAAC,IAAI,KAAA,EAAS,GAAG,OAAO,CAAC;GACnC;EACF;EAEA,MAAM,iBAAiB,QAAQ,CAAC;EAChC,IAAI,CAAC,gBAAgB;GACnB,SAAS,CAAC,EAAC,IAAI,KAAA,EAAS,GAAG,OAAO,CAAC;GACnC;EACF;EAEA,MAAM,IAAI,KAAK,CAAC,CAAC,YACf,gBACA,uBAAuB,UAAU,OAAO,GACxC,EAOE,KAAK,QAAQ,GAAG,EAClB,CACF;EAEA,gBAAgB,EAAE,QAAQ,CAAC;EAE3B,OAAO;CACT,CAAC;CAGD,aACE,GACE,MACA,eAAc;EACZ,KAAK,CAAC,EAAE,UAAU,UAAU;CAC9B,GACA,EAAC,OAAO,KAAI,CACd,CACF;CAEA,OAAO,OAAO,MAAM,EAAE,CAAC,WAAqC,MAAM,EAAE;AACtE;AAEA,SAAS,UAAa,SAAsD;CAC1E,OAAO,OAAO,YAAY,aAAc,QAAwB,IAAI;AACtE"}
@@ -11,7 +11,8 @@ function useZeroOnline() {
11
11
  const zero = useZero();
12
12
  const [online, setOnline] = createSignal(zero().online);
13
13
  createEffect(() => {
14
- onCleanup(zero().onOnline(setOnline));
14
+ const unsubscribe = zero().onOnline(setOnline);
15
+ onCleanup(unsubscribe);
15
16
  });
16
17
  return online;
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-zero-online.js","names":[],"sources":["../../../../zero-solid/src/use-zero-online.ts"],"sourcesContent":["import {createEffect, createSignal, onCleanup, type Accessor} from 'solid-js';\nimport {useZero} from './use-zero.ts';\n\n/**\n * Tracks the online status of the current Zero instance.\n *\n * @returns An accessor — call `online()` to get a reactive `boolean`.\n * @deprecated Use {@link useConnectionState} instead, which provides more detailed connection state.\n */\nexport function useZeroOnline(): Accessor<boolean> {\n const zero = useZero();\n\n const [online, setOnline] = createSignal<boolean>(zero().online);\n\n createEffect(() => {\n const unsubscribe = zero().onOnline(setOnline);\n\n onCleanup(unsubscribe);\n });\n\n return online;\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,gBAAmC;CACjD,MAAM,OAAO,QAAQ;CAErB,MAAM,CAAC,QAAQ,aAAa,aAAsB,KAAK,EAAE,MAAM;CAE/D,mBAAmB;EAGjB,UAFoB,KAAK,EAAE,SAAS,SAE1B,CAAW;CACvB,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"use-zero-online.js","names":[],"sources":["../../../../zero-solid/src/use-zero-online.ts"],"sourcesContent":["import {createEffect, createSignal, onCleanup, type Accessor} from 'solid-js';\nimport {useZero} from './use-zero.ts';\n\n/**\n * Tracks the online status of the current Zero instance.\n *\n * @returns An accessor — call `online()` to get a reactive `boolean`.\n * @deprecated Use {@link useConnectionState} instead, which provides more detailed connection state.\n */\nexport function useZeroOnline(): Accessor<boolean> {\n const zero = useZero();\n\n const [online, setOnline] = createSignal<boolean>(zero().online);\n\n createEffect(() => {\n const unsubscribe = zero().onOnline(setOnline);\n\n onCleanup(unsubscribe);\n });\n\n return online;\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,gBAAmC;CACjD,MAAM,OAAO,QAAQ;CAErB,MAAM,CAAC,QAAQ,aAAa,aAAsB,KAAK,CAAC,CAAC,MAAM;CAE/D,mBAAmB;EACjB,MAAM,cAAc,KAAK,CAAC,CAAC,SAAS,SAAS;EAE7C,UAAU,WAAW;CACvB,CAAC;CAED,OAAO;AACT"}
@@ -7,10 +7,11 @@ var ZeroContext = createContext(void 0);
7
7
  * @deprecated Use {@link ZeroProvider} instead of managing your own Zero instance.
8
8
  */
9
9
  function createZero(options) {
10
- return new Zero({
10
+ const opts = {
11
11
  ...options,
12
12
  batchViewUpdates: batch
13
- });
13
+ };
14
+ return new Zero(opts);
14
15
  }
15
16
  function useZero() {
16
17
  const zero = useContext(ZeroContext);
@@ -1 +1 @@
1
- {"version":3,"file":"use-zero.js","names":[],"sources":["../../../../zero-solid/src/use-zero.ts"],"sourcesContent":["import {\n batch,\n createContext,\n createEffect,\n createMemo,\n createSignal,\n onCleanup,\n splitProps,\n untrack,\n useContext,\n type Accessor,\n type JSX,\n} from 'solid-js';\nimport {\n Zero,\n type BaseDefaultContext,\n type BaseDefaultSchema,\n type CustomMutatorDefs,\n type DefaultContext,\n type DefaultSchema,\n type ZeroOptions,\n} from './zero.ts';\n\nconst ZeroContext = createContext<\n // oxlint-disable-next-line no-explicit-any\n Accessor<Zero<any, any, any>> | undefined\n>(undefined);\n\n/**\n * @deprecated Use {@link ZeroProvider} instead of managing your own Zero instance.\n */\nexport function createZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(options: ZeroOptions<S, MD, Context>): Zero<S, MD, Context> {\n const opts = {\n ...options,\n batchViewUpdates: batch,\n };\n return new Zero<S, MD, Context>(opts);\n}\n\nexport function useZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(): () => Zero<S, MD, Context> {\n const zero = useContext(ZeroContext);\n\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero;\n}\n\n/**\n * @deprecated Use {@link useZero} instead, alongside default types defined with:\n *\n * ```ts\n * declare module '@rocicorp/zero' {\n * interface DefaultTypes {\n * schema: typeof schema;\n * context: Context;\n * }\n * }\n */\nexport function createUseZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>() {\n return () => useZero<S, MD, Context>();\n}\n\nexport function ZeroProvider<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(\n props: {\n children: JSX.Element;\n /**\n * Called after ZeroProvider constructs a new Zero instance.\n *\n * This runs only when the provider creates Zero from options, and is not\n * called when an existing instance is passed with `zero`.\n */\n init?: (zero: Zero<S, MD, Context>) => void;\n } & (\n | {\n zero: Zero<S, MD, Context>;\n }\n | ZeroOptions<S, MD, Context>\n ),\n) {\n let prevAuth = 'auth' in props ? props.auth : undefined;\n const [rotationGeneration, setRotationGeneration] = createSignal(0);\n\n const auth = createMemo(() => ('auth' in props ? props.auth : undefined));\n const hasAuth = createMemo(() => typeof auth() === 'string');\n\n const zero = createMemo(() => {\n rotationGeneration();\n\n if ('zero' in props) {\n return props.zero;\n }\n\n hasAuth();\n\n const [local, options] = splitProps(props, ['children', 'auth', 'init']);\n\n const authValue = untrack(auth);\n prevAuth = authValue;\n let rotationRequested = false;\n\n const scheduleRotation = () => {\n if (rotationRequested) {\n return;\n }\n rotationRequested = true;\n setRotationGeneration(gen => gen + 1);\n };\n\n const createdZero = new Zero({\n ...options,\n ...(authValue !== undefined ? {auth: authValue} : {}),\n batchViewUpdates: batch,\n onClientStateNotFound: () => {\n if (rotationRequested) {\n return;\n }\n\n if (options.onClientStateNotFound) {\n try {\n options.onClientStateNotFound();\n return;\n } catch {\n // rotate since zero client is now closed\n }\n }\n\n scheduleRotation();\n },\n });\n local.init?.(createdZero);\n onCleanup(() => createdZero.close());\n return createdZero;\n });\n\n createEffect(() => {\n const currentZero = zero();\n if (!currentZero || 'zero' in props) {\n return;\n }\n\n const currentAuth = auth();\n\n if (currentAuth !== prevAuth) {\n const previousAuth = prevAuth;\n prevAuth = currentAuth;\n\n if (typeof previousAuth === 'string' && typeof currentAuth === 'string') {\n void currentZero.connection.connect({auth: currentAuth});\n }\n }\n });\n\n return ZeroContext.Provider({\n value: zero,\n get children() {\n return props.children;\n },\n });\n}\n"],"mappings":";;;;AAuBA,IAAM,cAAc,cAGlB,KAAA,CAAS;;;;AAKX,SAAgB,WAId,SAA4D;CAK5D,OAAO,IAAI,KAAqB;EAH9B,GAAG;EACH,kBAAkB;CAEY,CAAI;AACtC;AAEA,SAAgB,UAIgB;CAC9B,MAAM,OAAO,WAAW,WAAW;CAEnC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,gBAIZ;CACF,aAAa,QAAwB;AACvC;AAEA,SAAgB,aAKd,OAeA;CACA,IAAI,WAAW,UAAU,QAAQ,MAAM,OAAO,KAAA;CAC9C,MAAM,CAAC,oBAAoB,yBAAyB,aAAa,CAAC;CAElE,MAAM,OAAO,iBAAkB,UAAU,QAAQ,MAAM,OAAO,KAAA,CAAU;CACxE,MAAM,UAAU,iBAAiB,OAAO,KAAK,MAAM,QAAQ;CAE3D,MAAM,OAAO,iBAAiB;EAC5B,mBAAmB;EAEnB,IAAI,UAAU,OACZ,OAAO,MAAM;EAGf,QAAQ;EAER,MAAM,CAAC,OAAO,WAAW,WAAW,OAAO;GAAC;GAAY;GAAQ;EAAM,CAAC;EAEvE,MAAM,YAAY,QAAQ,IAAI;EAC9B,WAAW;EACX,IAAI,oBAAoB;EAExB,MAAM,yBAAyB;GAC7B,IAAI,mBACF;GAEF,oBAAoB;GACpB,uBAAsB,QAAO,MAAM,CAAC;EACtC;EAEA,MAAM,cAAc,IAAI,KAAK;GAC3B,GAAG;GACH,GAAI,cAAc,KAAA,IAAY,EAAC,MAAM,UAAS,IAAI,CAAC;GACnD,kBAAkB;GAClB,6BAA6B;IAC3B,IAAI,mBACF;IAGF,IAAI,QAAQ,uBACV,IAAI;KACF,QAAQ,sBAAsB;KAC9B;IACF,QAAQ,CAER;IAGF,iBAAiB;GACnB;EACF,CAAC;EACD,MAAM,OAAO,WAAW;EACxB,gBAAgB,YAAY,MAAM,CAAC;EACnC,OAAO;CACT,CAAC;CAED,mBAAmB;EACjB,MAAM,cAAc,KAAK;EACzB,IAAI,CAAC,eAAe,UAAU,OAC5B;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,gBAAgB,UAAU;GAC5B,MAAM,eAAe;GACrB,WAAW;GAEX,IAAI,OAAO,iBAAiB,YAAY,OAAO,gBAAgB,UAC7D,YAAiB,WAAW,QAAQ,EAAC,MAAM,YAAW,CAAC;EAE3D;CACF,CAAC;CAED,OAAO,YAAY,SAAS;EAC1B,OAAO;EACP,IAAI,WAAW;GACb,OAAO,MAAM;EACf;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"use-zero.js","names":[],"sources":["../../../../zero-solid/src/use-zero.ts"],"sourcesContent":["import {\n batch,\n createContext,\n createEffect,\n createMemo,\n createSignal,\n onCleanup,\n splitProps,\n untrack,\n useContext,\n type Accessor,\n type JSX,\n} from 'solid-js';\nimport {\n Zero,\n type BaseDefaultContext,\n type BaseDefaultSchema,\n type CustomMutatorDefs,\n type DefaultContext,\n type DefaultSchema,\n type ZeroOptions,\n} from './zero.ts';\n\nconst ZeroContext = createContext<\n // oxlint-disable-next-line no-explicit-any\n Accessor<Zero<any, any, any>> | undefined\n>(undefined);\n\n/**\n * @deprecated Use {@link ZeroProvider} instead of managing your own Zero instance.\n */\nexport function createZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(options: ZeroOptions<S, MD, Context>): Zero<S, MD, Context> {\n const opts = {\n ...options,\n batchViewUpdates: batch,\n };\n return new Zero<S, MD, Context>(opts);\n}\n\nexport function useZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(): () => Zero<S, MD, Context> {\n const zero = useContext(ZeroContext);\n\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero;\n}\n\n/**\n * @deprecated Use {@link useZero} instead, alongside default types defined with:\n *\n * ```ts\n * declare module '@rocicorp/zero' {\n * interface DefaultTypes {\n * schema: typeof schema;\n * context: Context;\n * }\n * }\n */\nexport function createUseZero<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>() {\n return () => useZero<S, MD, Context>();\n}\n\nexport function ZeroProvider<\n S extends BaseDefaultSchema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context extends BaseDefaultContext = DefaultContext,\n>(\n props: {\n children: JSX.Element;\n /**\n * Called after ZeroProvider constructs a new Zero instance.\n *\n * This runs only when the provider creates Zero from options, and is not\n * called when an existing instance is passed with `zero`.\n */\n init?: (zero: Zero<S, MD, Context>) => void;\n } & (\n | {\n zero: Zero<S, MD, Context>;\n }\n | ZeroOptions<S, MD, Context>\n ),\n) {\n let prevAuth = 'auth' in props ? props.auth : undefined;\n const [rotationGeneration, setRotationGeneration] = createSignal(0);\n\n const auth = createMemo(() => ('auth' in props ? props.auth : undefined));\n const hasAuth = createMemo(() => typeof auth() === 'string');\n\n const zero = createMemo(() => {\n rotationGeneration();\n\n if ('zero' in props) {\n return props.zero;\n }\n\n hasAuth();\n\n const [local, options] = splitProps(props, ['children', 'auth', 'init']);\n\n const authValue = untrack(auth);\n prevAuth = authValue;\n let rotationRequested = false;\n\n const scheduleRotation = () => {\n if (rotationRequested) {\n return;\n }\n rotationRequested = true;\n setRotationGeneration(gen => gen + 1);\n };\n\n const createdZero = new Zero({\n ...options,\n ...(authValue !== undefined ? {auth: authValue} : {}),\n batchViewUpdates: batch,\n onClientStateNotFound: () => {\n if (rotationRequested) {\n return;\n }\n\n if (options.onClientStateNotFound) {\n try {\n options.onClientStateNotFound();\n return;\n } catch {\n // rotate since zero client is now closed\n }\n }\n\n scheduleRotation();\n },\n });\n local.init?.(createdZero);\n onCleanup(() => createdZero.close());\n return createdZero;\n });\n\n createEffect(() => {\n const currentZero = zero();\n if (!currentZero || 'zero' in props) {\n return;\n }\n\n const currentAuth = auth();\n\n if (currentAuth !== prevAuth) {\n const previousAuth = prevAuth;\n prevAuth = currentAuth;\n\n if (typeof previousAuth === 'string' && typeof currentAuth === 'string') {\n void currentZero.connection.connect({auth: currentAuth});\n }\n }\n });\n\n return ZeroContext.Provider({\n value: zero,\n get children() {\n return props.children;\n },\n });\n}\n"],"mappings":";;;;AAuBA,IAAM,cAAc,cAGlB,KAAA,CAAS;;;;AAKX,SAAgB,WAId,SAA4D;CAC5D,MAAM,OAAO;EACX,GAAG;EACH,kBAAkB;CACpB;CACA,OAAO,IAAI,KAAqB,IAAI;AACtC;AAEA,SAAgB,UAIgB;CAC9B,MAAM,OAAO,WAAW,WAAW;CAEnC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,gBAIZ;CACF,aAAa,QAAwB;AACvC;AAEA,SAAgB,aAKd,OAeA;CACA,IAAI,WAAW,UAAU,QAAQ,MAAM,OAAO,KAAA;CAC9C,MAAM,CAAC,oBAAoB,yBAAyB,aAAa,CAAC;CAElE,MAAM,OAAO,iBAAkB,UAAU,QAAQ,MAAM,OAAO,KAAA,CAAU;CACxE,MAAM,UAAU,iBAAiB,OAAO,KAAK,MAAM,QAAQ;CAE3D,MAAM,OAAO,iBAAiB;EAC5B,mBAAmB;EAEnB,IAAI,UAAU,OACZ,OAAO,MAAM;EAGf,QAAQ;EAER,MAAM,CAAC,OAAO,WAAW,WAAW,OAAO;GAAC;GAAY;GAAQ;EAAM,CAAC;EAEvE,MAAM,YAAY,QAAQ,IAAI;EAC9B,WAAW;EACX,IAAI,oBAAoB;EAExB,MAAM,yBAAyB;GAC7B,IAAI,mBACF;GAEF,oBAAoB;GACpB,uBAAsB,QAAO,MAAM,CAAC;EACtC;EAEA,MAAM,cAAc,IAAI,KAAK;GAC3B,GAAG;GACH,GAAI,cAAc,KAAA,IAAY,EAAC,MAAM,UAAS,IAAI,CAAC;GACnD,kBAAkB;GAClB,6BAA6B;IAC3B,IAAI,mBACF;IAGF,IAAI,QAAQ,uBACV,IAAI;KACF,QAAQ,sBAAsB;KAC9B;IACF,QAAQ,CAER;IAGF,iBAAiB;GACnB;EACF,CAAC;EACD,MAAM,OAAO,WAAW;EACxB,gBAAgB,YAAY,MAAM,CAAC;EACnC,OAAO;CACT,CAAC;CAED,mBAAmB;EACjB,MAAM,cAAc,KAAK;EACzB,IAAI,CAAC,eAAe,UAAU,OAC5B;EAGF,MAAM,cAAc,KAAK;EAEzB,IAAI,gBAAgB,UAAU;GAC5B,MAAM,eAAe;GACrB,WAAW;GAEX,IAAI,OAAO,iBAAiB,YAAY,OAAO,gBAAgB,UAC7D,YAAiB,WAAW,QAAQ,EAAC,MAAM,YAAW,CAAC;EAE3D;CACF,CAAC;CAED,OAAO,YAAY,SAAS;EAC1B,OAAO;EACP,IAAI,WAAW;GACb,OAAO,MAAM;EACf;CACF,CAAC;AACH"}
@@ -1,24 +1,24 @@
1
- import "../../replicache/src/get-default-puller.js";
2
- import "../../replicache/src/storage-failure.js";
3
- import "../../replicache/src/kv/idb-store.js";
4
- import "../../replicache/src/make-idb-name.js";
5
- import "../../replicache/src/persist/collect-idb-databases.js";
6
- import "../../replicache/src/transaction-closed-error.js";
7
- import "../../zero-permissions/src/permissions.js";
8
- import "../../zero-protocol/src/application-error.js";
9
- import "../../zero-protocol/src/custom-queries.js";
10
- import "../../zero-schema/src/builder/relationship-builder.js";
11
- import "../../zero-schema/src/builder/table-builder.js";
12
- import "../../zero-schema/src/builder/schema-builder.js";
13
- import "../../zql/src/query/validate-input.js";
14
- import "../../zql/src/mutate/mutator.js";
15
- import "../../zql/src/mutate/mutator-registry.js";
16
- import "../../zql/src/query/create-builder.js";
17
- import "../../zql/src/query/escape-like.js";
18
- import "../../zql/src/query/named.js";
19
- import "../../zql/src/query/query-registry.js";
20
- import "../../zero-client/src/client/connection-status-enum.js";
21
- import "../../zero-client/src/client/update-needed-reason-type-enum.js";
22
- import "../../zero-client/src/client/zero.js";
1
+ import { getDefaultPuller } from "../../replicache/src/get-default-puller.js";
2
+ import { StorageFailureError } from "../../replicache/src/storage-failure.js";
3
+ import { IDBNotFoundError } from "../../replicache/src/kv/idb-store.js";
4
+ import { makeIDBName } from "../../replicache/src/make-idb-name.js";
5
+ import { dropAllDatabases, dropDatabase } from "../../replicache/src/persist/collect-idb-databases.js";
6
+ import { TransactionClosedError } from "../../replicache/src/transaction-closed-error.js";
7
+ import { ANYONE_CAN, ANYONE_CAN_DO_ANYTHING, NOBODY_CAN, definePermissions } from "../../zero-permissions/src/permissions.js";
8
+ import { ApplicationError } from "../../zero-protocol/src/application-error.js";
9
+ import { transformRequestMessageSchema, transformResponseMessageSchema } from "../../zero-protocol/src/custom-queries.js";
10
+ import { relationships } from "../../zero-schema/src/builder/relationship-builder.js";
11
+ import { boolean, enumeration, json, number, string, table } from "../../zero-schema/src/builder/table-builder.js";
12
+ import { createSchema } from "../../zero-schema/src/builder/schema-builder.js";
13
+ import { InputValidationError } from "../../zql/src/query/validate-input.js";
14
+ import { defineMutator, defineMutatorWithType, isMutator, isMutatorDefinition } from "../../zql/src/mutate/mutator.js";
15
+ import { defineMutators, defineMutatorsWithType, getMutator, isMutatorRegistry, mustGetMutator } from "../../zql/src/mutate/mutator-registry.js";
16
+ import { createBuilder } from "../../zql/src/query/create-builder.js";
17
+ import { escapeLike } from "../../zql/src/query/escape-like.js";
18
+ import { syncedQuery, syncedQueryWithContext, withValidation } from "../../zql/src/query/named.js";
19
+ import { defineQueries, defineQueriesWithType, defineQuery, defineQueryWithType, getQuery, isQuery, isQueryDefinition, isQueryRegistry, mustGetQuery } from "../../zql/src/query/query-registry.js";
20
+ import { connection_status_enum_exports } from "../../zero-client/src/client/connection-status-enum.js";
21
+ import { update_needed_reason_type_enum_exports } from "../../zero-client/src/client/update-needed-reason-type-enum.js";
22
+ import { Zero } from "../../zero-client/src/client/zero.js";
23
23
  import "../../zero-client/src/mod.js";
24
- export {};
24
+ export { ANYONE_CAN, ANYONE_CAN_DO_ANYTHING, ApplicationError, connection_status_enum_exports as ConnectionStatus, IDBNotFoundError, InputValidationError, NOBODY_CAN, StorageFailureError, TransactionClosedError, update_needed_reason_type_enum_exports as UpdateNeededReasonType, Zero, boolean, createBuilder, createSchema, defineMutator, defineMutatorWithType, defineMutators, defineMutatorsWithType, definePermissions, defineQueries, defineQueriesWithType, defineQuery, defineQueryWithType, dropAllDatabases, dropDatabase, enumeration, escapeLike, getDefaultPuller, getMutator, getQuery, isMutator, isMutatorDefinition, isMutatorRegistry, isQuery, isQueryDefinition, isQueryRegistry, json, makeIDBName, mustGetMutator, mustGetQuery, number, relationships, string, syncedQuery, syncedQueryWithContext, table, transformRequestMessageSchema, transformResponseMessageSchema, withValidation };
@@ -1 +1 @@
1
- {"version":3,"file":"name-mapper.js","names":["#tables","#getTable"],"sources":["../../../../zero-types/src/name-mapper.ts"],"sourcesContent":["import type {JSONValue, ReadonlyJSONValue} from '../../shared/src/json.ts';\n\n// Value type from zero-protocol (JSONValue/ReadonlyJSONValue | undefined)\n// Defined here to avoid circular dependency with zero-protocol\nexport type Value = JSONValue | ReadonlyJSONValue | undefined;\n\nexport type ColumnNames = {[src: string]: string};\n\nexport type DestNames = {\n tableName: string;\n columns: ColumnNames;\n allColumnsSame: boolean;\n};\n\nexport class NameMapper {\n readonly #tables = new Map<string, DestNames>();\n\n constructor(tables: Map<string, DestNames>) {\n this.#tables = tables;\n }\n\n #getTable(src: string): DestNames {\n const table = this.#tables.get(src);\n if (!table) {\n // log-leak-ignore -- a table name is schema, not customer data\n throw new Error(`unknown table \"${src}\"`);\n }\n return table;\n }\n\n tableName(src: string): string {\n return this.#getTable(src).tableName;\n }\n\n tableNameIfKnown(src: string): string | undefined {\n return this.#tables.get(src)?.tableName;\n }\n\n columnName(table: string, src: string): string {\n const dst = this.#getTable(table).columns[src];\n if (!dst) {\n // log-leak-ignore -- table and column names are schema, not customer data\n throw new Error(`unknown column \"${src}\" of \"${table}\" table`);\n }\n return dst;\n }\n\n row<V extends Value>(\n table: string,\n row: Readonly<Record<string, V>>,\n ): Readonly<Record<string, V>> {\n const dest = this.#getTable(table);\n const {allColumnsSame, columns} = dest;\n if (allColumnsSame) {\n return row;\n }\n const clientRow: Record<string, V> = {};\n for (const col in row) {\n // Note: columns with unknown names simply pass through.\n clientRow[columns[col] ?? col] = row[col];\n }\n return clientRow;\n }\n\n columns<Columns extends readonly string[] | undefined>(\n table: string,\n cols: Columns,\n ): Columns {\n const dest = this.#getTable(table);\n const {allColumnsSame, columns} = dest;\n\n // Note: Columns not defined in the schema simply pass through.\n return cols === undefined || allColumnsSame\n ? cols\n : (cols.map(col => columns[col] ?? col) as unknown as Columns);\n }\n}\n"],"mappings":";AAcA,IAAa,aAAb,MAAwB;CACtB,0BAAmB,IAAI,IAAuB;CAE9C,YAAY,QAAgC;EAC1C,KAAKA,UAAU;CACjB;CAEA,UAAU,KAAwB;EAChC,MAAM,QAAQ,KAAKA,QAAQ,IAAI,GAAG;EAClC,IAAI,CAAC,OAEH,MAAM,IAAI,MAAM,kBAAkB,IAAI,EAAE;EAE1C,OAAO;CACT;CAEA,UAAU,KAAqB;EAC7B,OAAO,KAAKC,UAAU,GAAG,EAAE;CAC7B;CAEA,iBAAiB,KAAiC;EAChD,OAAO,KAAKD,QAAQ,IAAI,GAAG,GAAG;CAChC;CAEA,WAAW,OAAe,KAAqB;EAC7C,MAAM,MAAM,KAAKC,UAAU,KAAK,EAAE,QAAQ;EAC1C,IAAI,CAAC,KAEH,MAAM,IAAI,MAAM,mBAAmB,IAAI,QAAQ,MAAM,QAAQ;EAE/D,OAAO;CACT;CAEA,IACE,OACA,KAC6B;EAE7B,MAAM,EAAC,gBAAgB,YADV,KAAKA,UAAU,KACM;EAClC,IAAI,gBACF,OAAO;EAET,MAAM,YAA+B,CAAC;EACtC,KAAK,MAAM,OAAO,KAEhB,UAAU,QAAQ,QAAQ,OAAO,IAAI;EAEvC,OAAO;CACT;CAEA,QACE,OACA,MACS;EAET,MAAM,EAAC,gBAAgB,YADV,KAAKA,UAAU,KACM;EAGlC,OAAO,SAAS,KAAA,KAAa,iBACzB,OACC,KAAK,KAAI,QAAO,QAAQ,QAAQ,GAAG;CAC1C;AACF"}
1
+ {"version":3,"file":"name-mapper.js","names":[],"sources":["../../../../zero-types/src/name-mapper.ts"],"sourcesContent":["import type {JSONValue, ReadonlyJSONValue} from '../../shared/src/json.ts';\n\n// Value type from zero-protocol (JSONValue/ReadonlyJSONValue | undefined)\n// Defined here to avoid circular dependency with zero-protocol\nexport type Value = JSONValue | ReadonlyJSONValue | undefined;\n\nexport type ColumnNames = {[src: string]: string};\n\nexport type DestNames = {\n tableName: string;\n columns: ColumnNames;\n allColumnsSame: boolean;\n};\n\nexport class NameMapper {\n readonly #tables = new Map<string, DestNames>();\n\n constructor(tables: Map<string, DestNames>) {\n this.#tables = tables;\n }\n\n #getTable(src: string): DestNames {\n const table = this.#tables.get(src);\n if (!table) {\n // log-leak-ignore -- a table name is schema, not customer data\n throw new Error(`unknown table \"${src}\"`);\n }\n return table;\n }\n\n tableName(src: string): string {\n return this.#getTable(src).tableName;\n }\n\n tableNameIfKnown(src: string): string | undefined {\n return this.#tables.get(src)?.tableName;\n }\n\n columnName(table: string, src: string): string {\n const dst = this.#getTable(table).columns[src];\n if (!dst) {\n // log-leak-ignore -- table and column names are schema, not customer data\n throw new Error(`unknown column \"${src}\" of \"${table}\" table`);\n }\n return dst;\n }\n\n row<V extends Value>(\n table: string,\n row: Readonly<Record<string, V>>,\n ): Readonly<Record<string, V>> {\n const dest = this.#getTable(table);\n const {allColumnsSame, columns} = dest;\n if (allColumnsSame) {\n return row;\n }\n const clientRow: Record<string, V> = {};\n for (const col in row) {\n // Note: columns with unknown names simply pass through.\n clientRow[columns[col] ?? col] = row[col];\n }\n return clientRow;\n }\n\n columns<Columns extends readonly string[] | undefined>(\n table: string,\n cols: Columns,\n ): Columns {\n const dest = this.#getTable(table);\n const {allColumnsSame, columns} = dest;\n\n // Note: Columns not defined in the schema simply pass through.\n return cols === undefined || allColumnsSame\n ? cols\n : (cols.map(col => columns[col] ?? col) as unknown as Columns);\n }\n}\n"],"mappings":";AAcA,IAAa,aAAb,MAAwB;CACtB,0BAAmB,IAAI,IAAuB;CAE9C,YAAY,QAAgC;EAC1C,KAAK,UAAU;CACjB;CAEA,UAAU,KAAwB;EAChC,MAAM,QAAQ,KAAK,QAAQ,IAAI,GAAG;EAClC,IAAI,CAAC,OAEH,MAAM,IAAI,MAAM,kBAAkB,IAAI,EAAE;EAE1C,OAAO;CACT;CAEA,UAAU,KAAqB;EAC7B,OAAO,KAAK,UAAU,GAAG,CAAC,CAAC;CAC7B;CAEA,iBAAiB,KAAiC;EAChD,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,EAAE;CAChC;CAEA,WAAW,OAAe,KAAqB;EAC7C,MAAM,MAAM,KAAK,UAAU,KAAK,CAAC,CAAC,QAAQ;EAC1C,IAAI,CAAC,KAEH,MAAM,IAAI,MAAM,mBAAmB,IAAI,QAAQ,MAAM,QAAQ;EAE/D,OAAO;CACT;CAEA,IACE,OACA,KAC6B;EAE7B,MAAM,EAAC,gBAAgB,YADV,KAAK,UAAU,KACM;EAClC,IAAI,gBACF,OAAO;EAET,MAAM,YAA+B,CAAC;EACtC,KAAK,MAAM,OAAO,KAEhB,UAAU,QAAQ,QAAQ,OAAO,IAAI;EAEvC,OAAO;CACT;CAEA,QACE,OACA,MACS;EAET,MAAM,EAAC,gBAAgB,YADV,KAAK,UAAU,KACM;EAGlC,OAAO,SAAS,KAAA,KAAa,iBACzB,OACC,KAAK,KAAI,QAAO,QAAQ,QAAQ,GAAG;CAC1C;AACF"}
@@ -178,18 +178,20 @@ function buildPipelineInternal(ast, delegate, queryID, name, partitionKey, isNon
178
178
  });
179
179
  }
180
180
  if (ast.where && (!fullyAppliedFilters || delegate.applyFiltersAnyway)) end = applyWhere(end, ast.where, delegate, name, partitionKey, takeGate, existsParentIndexes);
181
- if (ast.limit !== void 0) if (useCap) {
182
- const capName = `${name}:cap`;
183
- const cap = new Cap(end, delegate.createStorage(capName), ast.limit, partitionKey);
184
- delegate.addEdge(end, cap);
185
- end = delegate.decorateInput(cap, capName);
186
- } else {
187
- const takeName = `${name}:take`;
188
- const take = new Take(end, delegate.createStorage(takeName), ast.limit, partitionKey);
189
- delegate.addEdge(end, take);
190
- end = delegate.decorateInput(take, takeName);
191
- takeGate?.setBoundProvider(take);
192
- if (takeGate) take.setTakeGate(takeGate);
181
+ if (ast.limit !== void 0) {
182
+ if (useCap) {
183
+ const capName = `${name}:cap`;
184
+ const cap = new Cap(end, delegate.createStorage(capName), ast.limit, partitionKey);
185
+ delegate.addEdge(end, cap);
186
+ end = delegate.decorateInput(cap, capName);
187
+ } else {
188
+ const takeName = `${name}:take`;
189
+ const take = new Take(end, delegate.createStorage(takeName), ast.limit, partitionKey);
190
+ delegate.addEdge(end, take);
191
+ end = delegate.decorateInput(take, takeName);
192
+ takeGate?.setBoundProvider(take);
193
+ if (takeGate) take.setTakeGate(takeGate);
194
+ }
193
195
  }
194
196
  if (existsParentIndexes.length > 0) {
195
197
  const tapName = `${name}:join-index`;
@@ -432,6 +434,6 @@ function partitionBranches(conditions, predicate) {
432
434
  return [matched, notMatched];
433
435
  }
434
436
  //#endregion
435
- export { bindStaticParameters, buildPipeline };
437
+ export { applyOr, assertNoNotExists, bindStaticParameters, buildPipeline, conditionIncludesFlippedSubqueryAtAnyLevel, groupSubqueryConditions, isNotAndDoesNotContainSubquery, partitionBranches };
436
438
 
437
439
  //# sourceMappingURL=builder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder.js","names":[],"sources":["../../../../../zql/src/builder/builder.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {JSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {\n AST,\n ColumnReference,\n CompoundKey,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralValue,\n Ordering,\n Parameter,\n SimpleCondition,\n ValuePosition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {Cap} from '../ivm/cap.ts';\nimport {Exists} from '../ivm/exists.ts';\nimport {FanIn} from '../ivm/fan-in.ts';\nimport {FanOut} from '../ivm/fan-out.ts';\nimport {\n buildFilterPipeline,\n type FilterInput,\n} from '../ivm/filter-operators.ts';\nimport {Filter} from '../ivm/filter.ts';\nimport {FlippedJoin} from '../ivm/flipped-join.ts';\nimport {JoinIndexTap} from '../ivm/join-index-tap.ts';\nimport {JoinIndex} from '../ivm/join-index.ts';\nimport {Join, type ExistsJoin} from '../ivm/join.ts';\nimport type {Input, InputBase, Storage} from '../ivm/operator.ts';\nimport {Skip} from '../ivm/skip.ts';\nimport type {Source, SourceInput} from '../ivm/source.ts';\nimport {TakeGate, type TakeBoundProvider} from '../ivm/take-gate.ts';\nimport {Take} from '../ivm/take.ts';\nimport {UnionFanIn} from '../ivm/union-fan-in.ts';\nimport {UnionFanOut} from '../ivm/union-fan-out.ts';\nimport {planQuery, type PlanWarningSink} from '../planner/planner-builder.ts';\nimport type {ConnectionCostModel} from '../planner/planner-connection.ts';\nimport type {PlanDebugger} from '../planner/planner-debug.ts';\nimport {completeOrdering} from '../query/complete-ordering.ts';\nimport {pushDownCorrelatedPredicates} from './correlated-predicate-pushdown.ts';\nimport type {DebugDelegate} from './debug-delegate.ts';\nimport {\n createPredicate,\n transformFilters,\n type NoSubqueryCondition,\n} from './filter.ts';\n\nexport type StaticQueryParameters = {\n authData: Record<string, JSONValue>;\n preMutationRow?: Row | undefined;\n};\n\n/**\n * Interface required of caller to buildPipeline. Connects to constructed\n * pipeline to delegate environment to provide sources and storage.\n */\nexport interface BuilderDelegate {\n readonly applyFiltersAnyway?: boolean | undefined;\n debug?: DebugDelegate | undefined;\n\n /**\n * When true, allows NOT EXISTS conditions in queries.\n * Defaults to false.\n *\n * We only set this to true on the server.\n * The client-side query engine cannot support NOT EXISTS because:\n * 1. Zero only syncs a subset of data to the client\n * 2. On the client, we can't distinguish between a row not existing vs.\n * a row not being synced to the client\n * 3. NOT EXISTS requires complete knowledge of what doesn't exist\n */\n readonly enableNotExists?: boolean | undefined;\n\n /**\n * When true, does not copy a parent's conditions on correlation columns\n * into its subqueries (see {@link pushDownCorrelatedPredicates}).\n * Defaults to false.\n *\n * Only zero-cache sets this, as a kill switch.\n */\n readonly disableCorrelatedPredicatePushdown?: boolean | undefined;\n\n /**\n * When true, copies a parent's conditions into its subqueries before\n * planning instead of after, and tells the planner which conditions it\n * copied. The planner then sees when a copied condition makes a flipped\n * join cheap. Has no effect when `disableCorrelatedPredicatePushdown` is\n * true. Defaults to false.\n *\n * Only zero-cache sets this. This changes plans, and the pushdown alone\n * does not.\n */\n readonly enablePlannerAwarePushdown?: boolean | undefined;\n\n /**\n * Called once for each source needed by the AST.\n * Might be called multiple times with same tableName. It is OK to return\n * same storage instance in that case.\n */\n getSource(tableName: string): Source | undefined;\n\n /**\n * Called once for each operator that requires storage. Should return a new\n * unique storage object for each call.\n */\n createStorage(name: string): Storage;\n\n decorateInput(input: Input, name: string): Input;\n\n addEdge(source: InputBase, dest: InputBase): void;\n\n decorateFilterInput(input: FilterInput, name: string): FilterInput;\n\n decorateSourceInput(input: SourceInput, queryID: string): Input;\n\n /**\n * Receives warnings about the plan the planner chose for the query, when\n * there is a cost model to plan with. Only zero-cache sets this.\n */\n readonly planWarnings?: PlanWarningSink | undefined;\n\n /**\n * The AST is mapped on-the-wire between client and server names.\n *\n * There is no \"wire\" for zqlite tests so this function is provided\n * to allow tests to remap the AST.\n */\n mapAst?: ((ast: AST) => AST) | undefined;\n}\n\n/**\n * Builds a pipeline from an AST. Caller must provide a delegate to create source\n * and storage interfaces as necessary.\n *\n * Usage:\n *\n * ```ts\n * class MySink implements Output {\n * readonly #input: Input;\n *\n * constructor(input: Input) {\n * this.#input = input;\n * input.setOutput(this);\n * }\n *\n * push(change: Change, _: Operator) {\n * console.log(change);\n * }\n * }\n *\n * const input = buildPipeline(ast, myDelegate, hash(ast));\n * const sink = new MySink(input);\n * ```\n */\nexport function buildPipeline(\n ast: AST,\n delegate: BuilderDelegate,\n queryID: string,\n costModel?: ConnectionCostModel,\n lc?: LogContext,\n planDebugger?: PlanDebugger,\n): Input {\n ast = delegate.mapAst ? delegate.mapAst(ast) : ast;\n ast = completeOrdering(\n ast,\n tableName => must(delegate.getSource(tableName)).tableSchema.primaryKey,\n );\n\n const columnsOf = (tableName: string) =>\n must(delegate.getSource(tableName)).tableSchema.columns;\n const {planWarnings} = delegate;\n if (delegate.disableCorrelatedPredicatePushdown) {\n if (costModel) {\n ast = planQuery(\n ast,\n costModel,\n planDebugger,\n lc,\n undefined,\n planWarnings,\n );\n }\n } else if (delegate.enablePlannerAwarePushdown) {\n const pushed = new Set<SimpleCondition>();\n ast = pushDownCorrelatedPredicates(ast, columnsOf, pushed);\n if (costModel) {\n ast = planQuery(ast, costModel, planDebugger, lc, pushed, planWarnings);\n }\n } else {\n if (costModel) {\n ast = planQuery(\n ast,\n costModel,\n planDebugger,\n lc,\n undefined,\n planWarnings,\n );\n }\n // After planning, so that the planner does not read the pushed conditions\n // as selective filters.\n ast = pushDownCorrelatedPredicates(ast, columnsOf);\n }\n return buildPipelineInternal(ast, delegate, queryID, '');\n}\n\nexport function bindStaticParameters(\n ast: AST,\n staticQueryParameters: StaticQueryParameters | undefined,\n) {\n const visit = (node: AST): AST => ({\n ...node,\n where: node.where ? bindCondition(node.where) : undefined,\n related: node.related?.map(sq => ({\n ...sq,\n subquery: visit(sq.subquery),\n })),\n });\n\n function bindCondition(condition: Condition): Condition {\n if (condition.type === 'simple') {\n return {\n ...condition,\n left: bindValue(condition.left),\n right: bindValue(condition.right) as Exclude<\n ValuePosition,\n ColumnReference\n >,\n };\n }\n if (condition.type === 'correlatedSubquery') {\n return {\n ...condition,\n related: {\n ...condition.related,\n subquery: visit(condition.related.subquery),\n },\n };\n }\n\n return {\n ...condition,\n conditions: condition.conditions.map(bindCondition),\n };\n }\n\n const bindValue = (value: ValuePosition): ValuePosition => {\n if (isParameter(value)) {\n const anchor = must(\n staticQueryParameters,\n 'Static query params do not exist',\n )[value.anchor];\n const resolvedValue = resolveField(anchor, value.field);\n return {\n type: 'literal',\n value: resolvedValue as LiteralValue,\n };\n }\n return value;\n };\n\n return visit(ast);\n}\n\nfunction resolveField(\n anchor: Record<string, JSONValue> | Row | undefined,\n field: string | string[],\n): unknown {\n if (anchor === undefined) {\n return null;\n }\n\n if (Array.isArray(field)) {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return field.reduce((acc, f) => (acc as any)?.[f], anchor) ?? null;\n }\n\n return anchor[field] ?? null;\n}\n\nfunction isParameter(value: ValuePosition): value is Parameter {\n return value.type === 'static';\n}\n\nconst EXISTS_LIMIT = 3;\nconst PERMISSIONS_EXISTS_LIMIT = 1;\n\n/**\n * Checks if a condition tree contains any NOT EXISTS operations.\n * Recursively checks AND/OR branches but does not recurse into nested subqueries\n * (those are checked when buildPipelineInternal processes them).\n */\nexport function assertNoNotExists(condition: Condition): void {\n switch (condition.type) {\n case 'simple':\n return;\n\n case 'correlatedSubquery':\n if (condition.op === 'NOT EXISTS') {\n throw new Error(\n 'not(exists()) is not supported on the client - see https://bugs.rocicorp.dev/issue/3438',\n );\n }\n return;\n\n case 'and':\n case 'or':\n for (const c of condition.conditions) {\n assertNoNotExists(c);\n }\n return;\n default:\n unreachable(condition);\n }\n}\n\nfunction buildPipelineInternal(\n ast: AST,\n delegate: BuilderDelegate,\n queryID: string,\n name: string,\n partitionKey?: CompoundKey,\n isNonFlippedExistsChild?: boolean,\n): Input {\n const source = delegate.getSource(ast.table);\n if (!source) {\n throw new Error(`Source not found: ${ast.table}`);\n }\n\n ast = uniquifyCorrelatedSubqueryConditionAliases(ast);\n\n if (!delegate.enableNotExists && ast.where) {\n assertNoNotExists(ast.where);\n }\n\n const csqConditions = gatherCorrelatedSubqueryQueryConditions(ast.where);\n const splitEditKeys: Set<string> = partitionKey\n ? new Set(partitionKey)\n : new Set();\n const aliases = new Set<string>();\n for (const csq of csqConditions) {\n aliases.add(csq.related.subquery.alias || '');\n for (const key of csq.related.correlation.parentField) {\n splitEditKeys.add(key);\n }\n }\n if (ast.related) {\n for (const csq of ast.related) {\n for (const key of csq.correlation.parentField) {\n splitEditKeys.add(key);\n }\n }\n }\n if (isNonFlippedExistsChild) {\n assert(ast.start === undefined, 'EXISTS subqueries must not have start');\n assert(\n ast.related === undefined,\n 'EXISTS subqueries must not have related',\n );\n }\n\n // The Cap optimization needs the source connect to be unordered, but\n // applyFilterWithFlips builds a UnionFanIn over the source whenever\n // ast.where contains a flipped subquery, and UnionFanIn requires a\n // sort on its inputs. In that case, fall back to the ordered + Take\n // path for this EXISTS child.\n const useCap =\n isNonFlippedExistsChild &&\n !(ast.where && conditionIncludesFlippedSubqueryAtAnyLevel(ast.where));\n\n const conn = source.connect(\n // exists pipelines are unordered — orderBy is ignored here.\n // Non-exists pipelines always have orderBy completed with PKs.\n useCap ? undefined : must(ast.orderBy),\n ast.where,\n splitEditKeys,\n delegate.debug,\n );\n\n let end: Input = delegate.decorateSourceInput(conn, queryID);\n end = delegate.decorateInput(end, `${name}:source(${ast.table})`);\n const {fullyAppliedFilters} = conn;\n\n if (ast.start) {\n const skip = new Skip(end, ast.start);\n delegate.addEdge(end, skip);\n end = delegate.decorateInput(skip, `${name}:skip)`);\n }\n\n let takeGate: TakeGate | undefined;\n if (ast.limit !== undefined && !useCap) {\n const takeGateName = `${name}:take-gate`;\n takeGate = new TakeGate(end);\n delegate.addEdge(end, takeGate);\n end = delegate.decorateInput(takeGate, takeGateName);\n }\n\n // The parent indexes of the EXISTS joins below. They hold the rows this\n // pipeline emits, which the JoinIndexTap after the limit maintains.\n const existsParentIndexes: JoinIndex[] = [];\n for (const csqCondition of csqConditions) {\n // flipped EXISTS are handled in applyWhere\n if (!csqCondition.flip) {\n const parentIndex = new JoinIndex(\n csqCondition.related.correlation.parentField,\n end.getSchema().primaryKey,\n );\n existsParentIndexes.push(parentIndex);\n end = applyCorrelatedSubQuery(\n {\n ...csqCondition.related,\n subquery: {\n ...csqCondition.related.subquery,\n limit:\n csqCondition.related.system === 'permissions'\n ? PERMISSIONS_EXISTS_LIMIT\n : EXISTS_LIMIT,\n },\n },\n delegate,\n queryID,\n end,\n name,\n true,\n undefined,\n takeGate,\n {op: csqCondition.op, parentIndex},\n );\n }\n }\n\n if (ast.where && (!fullyAppliedFilters || delegate.applyFiltersAnyway)) {\n end = applyWhere(\n end,\n ast.where,\n delegate,\n name,\n partitionKey,\n takeGate,\n existsParentIndexes,\n );\n }\n\n if (ast.limit !== undefined) {\n // We end `exists` pipelines with `cap`\n // The reason is that `cap` does not care about the order of the pipeline.\n // This allows SQLite to chose the order and never end up creating temp b-trees.\n // The problem with SQLite creating a temp b-tree is it will incur a scan of the entire\n // result set where exists only needs the first row.\n if (useCap) {\n const capName = `${name}:cap`;\n const cap = new Cap(\n end,\n delegate.createStorage(capName),\n ast.limit,\n partitionKey,\n );\n delegate.addEdge(end, cap);\n end = delegate.decorateInput(cap, capName);\n } else {\n const takeName = `${name}:take`;\n const take = new Take(\n end,\n delegate.createStorage(takeName),\n ast.limit,\n partitionKey,\n );\n delegate.addEdge(end, take);\n end = delegate.decorateInput(take, takeName);\n takeGate?.setBoundProvider(take);\n if (takeGate) {\n take.setTakeGate(takeGate);\n }\n }\n }\n\n if (existsParentIndexes.length > 0) {\n const tapName = `${name}:join-index`;\n const tap = new JoinIndexTap(end, existsParentIndexes);\n delegate.addEdge(end, tap);\n end = delegate.decorateInput(tap, tapName);\n }\n\n if (ast.related) {\n // Dedupe by alias - last one wins (LWW), like limit(5).limit(10)\n const byAlias = new Map<string, CorrelatedSubquery>();\n for (const csq of ast.related) {\n byAlias.set(csq.subquery.alias ?? '', csq);\n }\n for (const csq of byAlias.values()) {\n end = applyCorrelatedSubQuery(\n csq,\n delegate,\n queryID,\n end,\n name,\n false,\n partitionKey,\n );\n }\n }\n\n return end;\n}\n\nfunction applyWhere(\n input: Input,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n existsParentIndexes?: JoinIndex[],\n): Input {\n if (!conditionIncludesFlippedSubqueryAtAnyLevel(condition)) {\n return buildFilterPipeline(\n input,\n delegate,\n filterInput => applyFilter(filterInput, condition, delegate, name),\n transformFilters(condition).filters,\n );\n }\n\n return applyFilterWithFlips(\n input,\n condition,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n );\n}\n\nfunction applyFilterWithFlips(\n input: Input,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n existsParentIndexes?: JoinIndex[],\n): Input {\n let end = input;\n assert(condition.type !== 'simple', 'Simple conditions cannot have flips');\n\n switch (condition.type) {\n case 'and': {\n const [withFlipped, withoutFlipped] = partitionBranches(\n condition.conditions,\n conditionIncludesFlippedSubqueryAtAnyLevel,\n );\n if (withoutFlipped.length > 0) {\n const andCondition: Conjunction = {\n type: 'and',\n conditions: withoutFlipped,\n };\n end = buildFilterPipeline(\n input,\n delegate,\n filterInput => applyAnd(filterInput, andCondition, delegate, name),\n transformFilters(andCondition).filters,\n );\n }\n assert(withFlipped.length > 0, 'Impossible to have no flips here');\n for (const cond of withFlipped) {\n end = applyFilterWithFlips(\n end,\n cond,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n );\n }\n break;\n }\n case 'or': {\n const [withFlipped, withoutFlipped] = partitionBranches(\n condition.conditions,\n conditionIncludesFlippedSubqueryAtAnyLevel,\n );\n assert(withFlipped.length > 0, 'Impossible to have no flips here');\n\n const ufo = new UnionFanOut(end);\n delegate.addEdge(end, ufo);\n end = delegate.decorateInput(ufo, `${name}:ufo`);\n\n const branches: Input[] = [];\n if (withoutFlipped.length > 0) {\n const orCondition: Disjunction = {\n type: 'or',\n conditions: withoutFlipped,\n };\n branches.push(\n buildFilterPipeline(\n end,\n delegate,\n filterInput => applyOr(filterInput, orCondition, delegate, name),\n transformFilters(orCondition).filters,\n ),\n );\n }\n\n for (const cond of withFlipped) {\n branches.push(\n applyFilterWithFlips(\n end,\n cond,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n ),\n );\n }\n\n const ufi = new UnionFanIn(ufo, branches);\n for (const branch of branches) {\n delegate.addEdge(branch, ufi);\n }\n end = delegate.decorateInput(ufi, `${name}:ufi`);\n\n break;\n }\n case 'correlatedSubquery': {\n const sq = condition.related;\n const child = buildPipelineInternal(\n sq.subquery,\n delegate,\n '',\n `${name}.${sq.subquery.alias}`,\n sq.correlation.childField,\n false,\n );\n let parentIndex: JoinIndex | undefined;\n if (existsParentIndexes) {\n parentIndex = new JoinIndex(\n sq.correlation.parentField,\n end.getSchema().primaryKey,\n parentPartitionKey,\n );\n existsParentIndexes.push(parentIndex);\n }\n const flippedJoinName = `${name}:flipped-join(${sq.subquery.alias})`;\n const flippedJoin = new FlippedJoin({\n parent: end,\n child,\n parentKey: sq.correlation.parentField,\n childKey: sq.correlation.childField,\n relationshipName: must(\n sq.subquery.alias,\n 'Subquery must have an alias',\n ),\n hidden: sq.hidden ?? false,\n system: sq.system ?? 'client',\n parentPartitionKey,\n boundProvider,\n parentIndex,\n });\n delegate.addEdge(end, flippedJoin);\n delegate.addEdge(child, flippedJoin);\n end = delegate.decorateInput(flippedJoin, flippedJoinName);\n break;\n }\n }\n\n return end;\n}\n\nfunction applyFilter(\n input: FilterInput,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n switch (condition.type) {\n case 'and':\n return applyAnd(input, condition, delegate, name);\n case 'or':\n return applyOr(input, condition, delegate, name);\n case 'correlatedSubquery':\n return applyCorrelatedSubqueryCondition(input, condition, delegate, name);\n case 'simple':\n return applySimpleCondition(input, delegate, condition);\n }\n}\n\nfunction applyAnd(\n input: FilterInput,\n condition: Conjunction,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n for (const subCondition of condition.conditions) {\n input = applyFilter(input, subCondition, delegate, name);\n }\n return input;\n}\n\nexport function applyOr(\n input: FilterInput,\n condition: Disjunction,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n const [subqueryConditions, otherConditions] =\n groupSubqueryConditions(condition);\n // if there are no subquery conditions, no fan-in / fan-out is needed\n if (subqueryConditions.length === 0) {\n const filter = new Filter(\n input,\n createPredicate({\n type: 'or',\n conditions: otherConditions,\n }),\n );\n delegate.addEdge(input, filter);\n return filter;\n }\n\n const fanOut = new FanOut(input);\n delegate.addEdge(input, fanOut);\n const branches = subqueryConditions.map(subCondition =>\n applyFilter(fanOut, subCondition, delegate, name),\n );\n if (otherConditions.length > 0) {\n const filter = new Filter(\n fanOut,\n createPredicate({\n type: 'or',\n conditions: otherConditions,\n }),\n );\n delegate.addEdge(fanOut, filter);\n branches.push(filter);\n }\n const ret = new FanIn(fanOut, branches);\n for (const branch of branches) {\n delegate.addEdge(branch, ret);\n }\n fanOut.setFanIn(ret);\n return ret;\n}\n\nexport function groupSubqueryConditions(condition: Disjunction) {\n const partitioned: [\n subqueryConditions: Condition[],\n otherConditions: NoSubqueryCondition[],\n ] = [[], []];\n for (const subCondition of condition.conditions) {\n if (isNotAndDoesNotContainSubquery(subCondition)) {\n partitioned[1].push(subCondition);\n } else {\n partitioned[0].push(subCondition);\n }\n }\n return partitioned;\n}\n\nexport function isNotAndDoesNotContainSubquery(\n condition: Condition,\n): condition is NoSubqueryCondition {\n if (condition.type === 'correlatedSubquery') {\n return false;\n }\n if (condition.type === 'simple') {\n return true;\n }\n return condition.conditions.every(isNotAndDoesNotContainSubquery);\n}\n\nfunction applySimpleCondition(\n input: FilterInput,\n delegate: BuilderDelegate,\n condition: SimpleCondition,\n): FilterInput {\n const filter = new Filter(input, createPredicate(condition));\n delegate.decorateFilterInput(\n filter,\n `${valuePosName(condition.left)}:${condition.op}:${valuePosName(condition.right)}`,\n );\n delegate.addEdge(input, filter);\n return filter;\n}\n\nfunction valuePosName(left: ValuePosition) {\n switch (left.type) {\n case 'static':\n return left.field;\n case 'literal':\n return left.value;\n case 'column':\n return left.name;\n }\n}\n\nfunction applyCorrelatedSubQuery(\n sq: CorrelatedSubquery,\n delegate: BuilderDelegate,\n queryID: string,\n end: Input,\n name: string,\n fromCondition: boolean,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n exists?: ExistsJoin,\n) {\n // TODO: we only omit the join if the CSQ if from a condition since\n // we want to create an empty array for `related` fields that are `limit(0)`\n if (sq.subquery.limit === 0 && fromCondition) {\n return end;\n }\n\n assert(sq.subquery.alias, 'Subquery must have an alias');\n const child = buildPipelineInternal(\n sq.subquery,\n delegate,\n queryID,\n `${name}.${sq.subquery.alias}`,\n sq.correlation.childField,\n fromCondition,\n );\n\n const joinName = `${name}:join(${sq.subquery.alias})`;\n const join = new Join({\n parent: end,\n child,\n parentKey: sq.correlation.parentField,\n childKey: sq.correlation.childField,\n relationshipName: sq.subquery.alias,\n hidden: sq.hidden ?? false,\n system: sq.system ?? 'client',\n parentPartitionKey: fromCondition ? undefined : parentPartitionKey,\n boundProvider,\n exists,\n });\n delegate.addEdge(end, join);\n delegate.addEdge(child, join);\n return delegate.decorateInput(join, joinName);\n}\n\nfunction applyCorrelatedSubqueryCondition(\n input: FilterInput,\n condition: CorrelatedSubqueryCondition,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n assert(\n condition.op === 'EXISTS' || condition.op === 'NOT EXISTS',\n 'Expected EXISTS or NOT EXISTS operator',\n );\n if (condition.related.subquery.limit === 0) {\n if (condition.op === 'EXISTS') {\n const filter = new Filter(input, () => false);\n delegate.addEdge(input, filter);\n return filter;\n }\n const filter = new Filter(input, () => true);\n delegate.addEdge(input, filter);\n return filter;\n }\n const existsName = `${name}:exists(${condition.related.subquery.alias})`;\n const exists = new Exists(\n input,\n must(condition.related.subquery.alias),\n condition.related.correlation.parentField,\n condition.op,\n );\n delegate.addEdge(input, exists);\n return delegate.decorateFilterInput(exists, existsName);\n}\n\nfunction gatherCorrelatedSubqueryQueryConditions(\n condition: Condition | undefined,\n) {\n const csqs: CorrelatedSubqueryCondition[] = [];\n const gather = (condition: Condition) => {\n if (condition.type === 'correlatedSubquery') {\n csqs.push(condition);\n return;\n }\n if (condition.type === 'and' || condition.type === 'or') {\n for (const c of condition.conditions) {\n gather(c);\n }\n return;\n }\n };\n if (condition) {\n gather(condition);\n }\n return csqs;\n}\n\nexport function assertOrderingIncludesPK(\n ordering: Ordering,\n pk: PrimaryKey,\n): void {\n // oxlint-disable-next-line unicorn/prefer-set-has -- Array is more appropriate here for small collections\n const orderingFields = ordering.map(([field]) => field);\n const missingFields = pk.filter(pkField => !orderingFields.includes(pkField));\n\n if (missingFields.length > 0) {\n throw new Error(\n `Ordering must include all primary key fields. Missing: ${missingFields.join(\n ', ',\n )}. ZQL automatically appends primary key fields to the ordering if they are missing \n so a common cause of this error is a casing mismatch between Postgres and ZQL.\n E.g., \"userid\" vs \"userID\".\n You may want to add double-quotes around your Postgres column names to prevent Postgres from lower-casing them:\n https://www.postgresql.org/docs/current/sql-syntax-lexical.htm`,\n );\n }\n}\n\nfunction uniquifyCorrelatedSubqueryConditionAliases(ast: AST): AST {\n if (!ast.where) {\n return ast;\n }\n const {where} = ast;\n if (where.type !== 'and' && where.type !== 'or') {\n return ast;\n }\n\n let count = 0;\n const uniquifyCorrelatedSubquery = (csqc: CorrelatedSubqueryCondition) => ({\n ...csqc,\n related: {\n ...csqc.related,\n subquery: {\n ...csqc.related.subquery,\n alias: (csqc.related.subquery.alias ?? '') + '_' + count++,\n },\n },\n });\n\n const uniquify = (cond: Condition): Condition => {\n if (cond.type === 'simple') {\n return cond;\n } else if (cond.type === 'correlatedSubquery') {\n return uniquifyCorrelatedSubquery(cond);\n }\n const conditions = [];\n for (const c of cond.conditions) {\n conditions.push(uniquify(c));\n }\n return {\n type: cond.type,\n conditions,\n };\n };\n\n const result = {\n ...ast,\n where: uniquify(where),\n };\n return result;\n}\n\nexport function conditionIncludesFlippedSubqueryAtAnyLevel(\n cond: Condition,\n): boolean {\n if (cond.type === 'correlatedSubquery') {\n return !!cond.flip;\n }\n if (cond.type === 'and' || cond.type === 'or') {\n return cond.conditions.some(c =>\n conditionIncludesFlippedSubqueryAtAnyLevel(c),\n );\n }\n // simple conditions don't have flips\n return false;\n}\n\nexport function partitionBranches(\n conditions: readonly Condition[],\n predicate: (c: Condition) => boolean,\n) {\n const matched: Condition[] = [];\n const notMatched: Condition[] = [];\n for (const c of conditions) {\n if (predicate(c)) {\n matched.push(c);\n } else {\n notMatched.push(c);\n }\n }\n return [matched, notMatched] as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.js","names":[],"sources":["../../../../../zql/src/builder/builder.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {JSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {\n AST,\n ColumnReference,\n CompoundKey,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralValue,\n Ordering,\n Parameter,\n SimpleCondition,\n ValuePosition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {Cap} from '../ivm/cap.ts';\nimport {Exists} from '../ivm/exists.ts';\nimport {FanIn} from '../ivm/fan-in.ts';\nimport {FanOut} from '../ivm/fan-out.ts';\nimport {\n buildFilterPipeline,\n type FilterInput,\n} from '../ivm/filter-operators.ts';\nimport {Filter} from '../ivm/filter.ts';\nimport {FlippedJoin} from '../ivm/flipped-join.ts';\nimport {JoinIndexTap} from '../ivm/join-index-tap.ts';\nimport {JoinIndex} from '../ivm/join-index.ts';\nimport {Join, type ExistsJoin} from '../ivm/join.ts';\nimport type {Input, InputBase, Storage} from '../ivm/operator.ts';\nimport {Skip} from '../ivm/skip.ts';\nimport type {Source, SourceInput} from '../ivm/source.ts';\nimport {TakeGate, type TakeBoundProvider} from '../ivm/take-gate.ts';\nimport {Take} from '../ivm/take.ts';\nimport {UnionFanIn} from '../ivm/union-fan-in.ts';\nimport {UnionFanOut} from '../ivm/union-fan-out.ts';\nimport {planQuery, type PlanWarningSink} from '../planner/planner-builder.ts';\nimport type {ConnectionCostModel} from '../planner/planner-connection.ts';\nimport type {PlanDebugger} from '../planner/planner-debug.ts';\nimport {completeOrdering} from '../query/complete-ordering.ts';\nimport {pushDownCorrelatedPredicates} from './correlated-predicate-pushdown.ts';\nimport type {DebugDelegate} from './debug-delegate.ts';\nimport {\n createPredicate,\n transformFilters,\n type NoSubqueryCondition,\n} from './filter.ts';\n\nexport type StaticQueryParameters = {\n authData: Record<string, JSONValue>;\n preMutationRow?: Row | undefined;\n};\n\n/**\n * Interface required of caller to buildPipeline. Connects to constructed\n * pipeline to delegate environment to provide sources and storage.\n */\nexport interface BuilderDelegate {\n readonly applyFiltersAnyway?: boolean | undefined;\n debug?: DebugDelegate | undefined;\n\n /**\n * When true, allows NOT EXISTS conditions in queries.\n * Defaults to false.\n *\n * We only set this to true on the server.\n * The client-side query engine cannot support NOT EXISTS because:\n * 1. Zero only syncs a subset of data to the client\n * 2. On the client, we can't distinguish between a row not existing vs.\n * a row not being synced to the client\n * 3. NOT EXISTS requires complete knowledge of what doesn't exist\n */\n readonly enableNotExists?: boolean | undefined;\n\n /**\n * When true, does not copy a parent's conditions on correlation columns\n * into its subqueries (see {@link pushDownCorrelatedPredicates}).\n * Defaults to false.\n *\n * Only zero-cache sets this, as a kill switch.\n */\n readonly disableCorrelatedPredicatePushdown?: boolean | undefined;\n\n /**\n * When true, copies a parent's conditions into its subqueries before\n * planning instead of after, and tells the planner which conditions it\n * copied. The planner then sees when a copied condition makes a flipped\n * join cheap. Has no effect when `disableCorrelatedPredicatePushdown` is\n * true. Defaults to false.\n *\n * Only zero-cache sets this. This changes plans, and the pushdown alone\n * does not.\n */\n readonly enablePlannerAwarePushdown?: boolean | undefined;\n\n /**\n * Called once for each source needed by the AST.\n * Might be called multiple times with same tableName. It is OK to return\n * same storage instance in that case.\n */\n getSource(tableName: string): Source | undefined;\n\n /**\n * Called once for each operator that requires storage. Should return a new\n * unique storage object for each call.\n */\n createStorage(name: string): Storage;\n\n decorateInput(input: Input, name: string): Input;\n\n addEdge(source: InputBase, dest: InputBase): void;\n\n decorateFilterInput(input: FilterInput, name: string): FilterInput;\n\n decorateSourceInput(input: SourceInput, queryID: string): Input;\n\n /**\n * Receives warnings about the plan the planner chose for the query, when\n * there is a cost model to plan with. Only zero-cache sets this.\n */\n readonly planWarnings?: PlanWarningSink | undefined;\n\n /**\n * The AST is mapped on-the-wire between client and server names.\n *\n * There is no \"wire\" for zqlite tests so this function is provided\n * to allow tests to remap the AST.\n */\n mapAst?: ((ast: AST) => AST) | undefined;\n}\n\n/**\n * Builds a pipeline from an AST. Caller must provide a delegate to create source\n * and storage interfaces as necessary.\n *\n * Usage:\n *\n * ```ts\n * class MySink implements Output {\n * readonly #input: Input;\n *\n * constructor(input: Input) {\n * this.#input = input;\n * input.setOutput(this);\n * }\n *\n * push(change: Change, _: Operator) {\n * console.log(change);\n * }\n * }\n *\n * const input = buildPipeline(ast, myDelegate, hash(ast));\n * const sink = new MySink(input);\n * ```\n */\nexport function buildPipeline(\n ast: AST,\n delegate: BuilderDelegate,\n queryID: string,\n costModel?: ConnectionCostModel,\n lc?: LogContext,\n planDebugger?: PlanDebugger,\n): Input {\n ast = delegate.mapAst ? delegate.mapAst(ast) : ast;\n ast = completeOrdering(\n ast,\n tableName => must(delegate.getSource(tableName)).tableSchema.primaryKey,\n );\n\n const columnsOf = (tableName: string) =>\n must(delegate.getSource(tableName)).tableSchema.columns;\n const {planWarnings} = delegate;\n if (delegate.disableCorrelatedPredicatePushdown) {\n if (costModel) {\n ast = planQuery(\n ast,\n costModel,\n planDebugger,\n lc,\n undefined,\n planWarnings,\n );\n }\n } else if (delegate.enablePlannerAwarePushdown) {\n const pushed = new Set<SimpleCondition>();\n ast = pushDownCorrelatedPredicates(ast, columnsOf, pushed);\n if (costModel) {\n ast = planQuery(ast, costModel, planDebugger, lc, pushed, planWarnings);\n }\n } else {\n if (costModel) {\n ast = planQuery(\n ast,\n costModel,\n planDebugger,\n lc,\n undefined,\n planWarnings,\n );\n }\n // After planning, so that the planner does not read the pushed conditions\n // as selective filters.\n ast = pushDownCorrelatedPredicates(ast, columnsOf);\n }\n return buildPipelineInternal(ast, delegate, queryID, '');\n}\n\nexport function bindStaticParameters(\n ast: AST,\n staticQueryParameters: StaticQueryParameters | undefined,\n) {\n const visit = (node: AST): AST => ({\n ...node,\n where: node.where ? bindCondition(node.where) : undefined,\n related: node.related?.map(sq => ({\n ...sq,\n subquery: visit(sq.subquery),\n })),\n });\n\n function bindCondition(condition: Condition): Condition {\n if (condition.type === 'simple') {\n return {\n ...condition,\n left: bindValue(condition.left),\n right: bindValue(condition.right) as Exclude<\n ValuePosition,\n ColumnReference\n >,\n };\n }\n if (condition.type === 'correlatedSubquery') {\n return {\n ...condition,\n related: {\n ...condition.related,\n subquery: visit(condition.related.subquery),\n },\n };\n }\n\n return {\n ...condition,\n conditions: condition.conditions.map(bindCondition),\n };\n }\n\n const bindValue = (value: ValuePosition): ValuePosition => {\n if (isParameter(value)) {\n const anchor = must(\n staticQueryParameters,\n 'Static query params do not exist',\n )[value.anchor];\n const resolvedValue = resolveField(anchor, value.field);\n return {\n type: 'literal',\n value: resolvedValue as LiteralValue,\n };\n }\n return value;\n };\n\n return visit(ast);\n}\n\nfunction resolveField(\n anchor: Record<string, JSONValue> | Row | undefined,\n field: string | string[],\n): unknown {\n if (anchor === undefined) {\n return null;\n }\n\n if (Array.isArray(field)) {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return field.reduce((acc, f) => (acc as any)?.[f], anchor) ?? null;\n }\n\n return anchor[field] ?? null;\n}\n\nfunction isParameter(value: ValuePosition): value is Parameter {\n return value.type === 'static';\n}\n\nconst EXISTS_LIMIT = 3;\nconst PERMISSIONS_EXISTS_LIMIT = 1;\n\n/**\n * Checks if a condition tree contains any NOT EXISTS operations.\n * Recursively checks AND/OR branches but does not recurse into nested subqueries\n * (those are checked when buildPipelineInternal processes them).\n */\nexport function assertNoNotExists(condition: Condition): void {\n switch (condition.type) {\n case 'simple':\n return;\n\n case 'correlatedSubquery':\n if (condition.op === 'NOT EXISTS') {\n throw new Error(\n 'not(exists()) is not supported on the client - see https://bugs.rocicorp.dev/issue/3438',\n );\n }\n return;\n\n case 'and':\n case 'or':\n for (const c of condition.conditions) {\n assertNoNotExists(c);\n }\n return;\n default:\n unreachable(condition);\n }\n}\n\nfunction buildPipelineInternal(\n ast: AST,\n delegate: BuilderDelegate,\n queryID: string,\n name: string,\n partitionKey?: CompoundKey,\n isNonFlippedExistsChild?: boolean,\n): Input {\n const source = delegate.getSource(ast.table);\n if (!source) {\n throw new Error(`Source not found: ${ast.table}`);\n }\n\n ast = uniquifyCorrelatedSubqueryConditionAliases(ast);\n\n if (!delegate.enableNotExists && ast.where) {\n assertNoNotExists(ast.where);\n }\n\n const csqConditions = gatherCorrelatedSubqueryQueryConditions(ast.where);\n const splitEditKeys: Set<string> = partitionKey\n ? new Set(partitionKey)\n : new Set();\n const aliases = new Set<string>();\n for (const csq of csqConditions) {\n aliases.add(csq.related.subquery.alias || '');\n for (const key of csq.related.correlation.parentField) {\n splitEditKeys.add(key);\n }\n }\n if (ast.related) {\n for (const csq of ast.related) {\n for (const key of csq.correlation.parentField) {\n splitEditKeys.add(key);\n }\n }\n }\n if (isNonFlippedExistsChild) {\n assert(ast.start === undefined, 'EXISTS subqueries must not have start');\n assert(\n ast.related === undefined,\n 'EXISTS subqueries must not have related',\n );\n }\n\n // The Cap optimization needs the source connect to be unordered, but\n // applyFilterWithFlips builds a UnionFanIn over the source whenever\n // ast.where contains a flipped subquery, and UnionFanIn requires a\n // sort on its inputs. In that case, fall back to the ordered + Take\n // path for this EXISTS child.\n const useCap =\n isNonFlippedExistsChild &&\n !(ast.where && conditionIncludesFlippedSubqueryAtAnyLevel(ast.where));\n\n const conn = source.connect(\n // exists pipelines are unordered — orderBy is ignored here.\n // Non-exists pipelines always have orderBy completed with PKs.\n useCap ? undefined : must(ast.orderBy),\n ast.where,\n splitEditKeys,\n delegate.debug,\n );\n\n let end: Input = delegate.decorateSourceInput(conn, queryID);\n end = delegate.decorateInput(end, `${name}:source(${ast.table})`);\n const {fullyAppliedFilters} = conn;\n\n if (ast.start) {\n const skip = new Skip(end, ast.start);\n delegate.addEdge(end, skip);\n end = delegate.decorateInput(skip, `${name}:skip)`);\n }\n\n let takeGate: TakeGate | undefined;\n if (ast.limit !== undefined && !useCap) {\n const takeGateName = `${name}:take-gate`;\n takeGate = new TakeGate(end);\n delegate.addEdge(end, takeGate);\n end = delegate.decorateInput(takeGate, takeGateName);\n }\n\n // The parent indexes of the EXISTS joins below. They hold the rows this\n // pipeline emits, which the JoinIndexTap after the limit maintains.\n const existsParentIndexes: JoinIndex[] = [];\n for (const csqCondition of csqConditions) {\n // flipped EXISTS are handled in applyWhere\n if (!csqCondition.flip) {\n const parentIndex = new JoinIndex(\n csqCondition.related.correlation.parentField,\n end.getSchema().primaryKey,\n );\n existsParentIndexes.push(parentIndex);\n end = applyCorrelatedSubQuery(\n {\n ...csqCondition.related,\n subquery: {\n ...csqCondition.related.subquery,\n limit:\n csqCondition.related.system === 'permissions'\n ? PERMISSIONS_EXISTS_LIMIT\n : EXISTS_LIMIT,\n },\n },\n delegate,\n queryID,\n end,\n name,\n true,\n undefined,\n takeGate,\n {op: csqCondition.op, parentIndex},\n );\n }\n }\n\n if (ast.where && (!fullyAppliedFilters || delegate.applyFiltersAnyway)) {\n end = applyWhere(\n end,\n ast.where,\n delegate,\n name,\n partitionKey,\n takeGate,\n existsParentIndexes,\n );\n }\n\n if (ast.limit !== undefined) {\n // We end `exists` pipelines with `cap`\n // The reason is that `cap` does not care about the order of the pipeline.\n // This allows SQLite to chose the order and never end up creating temp b-trees.\n // The problem with SQLite creating a temp b-tree is it will incur a scan of the entire\n // result set where exists only needs the first row.\n if (useCap) {\n const capName = `${name}:cap`;\n const cap = new Cap(\n end,\n delegate.createStorage(capName),\n ast.limit,\n partitionKey,\n );\n delegate.addEdge(end, cap);\n end = delegate.decorateInput(cap, capName);\n } else {\n const takeName = `${name}:take`;\n const take = new Take(\n end,\n delegate.createStorage(takeName),\n ast.limit,\n partitionKey,\n );\n delegate.addEdge(end, take);\n end = delegate.decorateInput(take, takeName);\n takeGate?.setBoundProvider(take);\n if (takeGate) {\n take.setTakeGate(takeGate);\n }\n }\n }\n\n if (existsParentIndexes.length > 0) {\n const tapName = `${name}:join-index`;\n const tap = new JoinIndexTap(end, existsParentIndexes);\n delegate.addEdge(end, tap);\n end = delegate.decorateInput(tap, tapName);\n }\n\n if (ast.related) {\n // Dedupe by alias - last one wins (LWW), like limit(5).limit(10)\n const byAlias = new Map<string, CorrelatedSubquery>();\n for (const csq of ast.related) {\n byAlias.set(csq.subquery.alias ?? '', csq);\n }\n for (const csq of byAlias.values()) {\n end = applyCorrelatedSubQuery(\n csq,\n delegate,\n queryID,\n end,\n name,\n false,\n partitionKey,\n );\n }\n }\n\n return end;\n}\n\nfunction applyWhere(\n input: Input,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n existsParentIndexes?: JoinIndex[],\n): Input {\n if (!conditionIncludesFlippedSubqueryAtAnyLevel(condition)) {\n return buildFilterPipeline(\n input,\n delegate,\n filterInput => applyFilter(filterInput, condition, delegate, name),\n transformFilters(condition).filters,\n );\n }\n\n return applyFilterWithFlips(\n input,\n condition,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n );\n}\n\nfunction applyFilterWithFlips(\n input: Input,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n existsParentIndexes?: JoinIndex[],\n): Input {\n let end = input;\n assert(condition.type !== 'simple', 'Simple conditions cannot have flips');\n\n switch (condition.type) {\n case 'and': {\n const [withFlipped, withoutFlipped] = partitionBranches(\n condition.conditions,\n conditionIncludesFlippedSubqueryAtAnyLevel,\n );\n if (withoutFlipped.length > 0) {\n const andCondition: Conjunction = {\n type: 'and',\n conditions: withoutFlipped,\n };\n end = buildFilterPipeline(\n input,\n delegate,\n filterInput => applyAnd(filterInput, andCondition, delegate, name),\n transformFilters(andCondition).filters,\n );\n }\n assert(withFlipped.length > 0, 'Impossible to have no flips here');\n for (const cond of withFlipped) {\n end = applyFilterWithFlips(\n end,\n cond,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n );\n }\n break;\n }\n case 'or': {\n const [withFlipped, withoutFlipped] = partitionBranches(\n condition.conditions,\n conditionIncludesFlippedSubqueryAtAnyLevel,\n );\n assert(withFlipped.length > 0, 'Impossible to have no flips here');\n\n const ufo = new UnionFanOut(end);\n delegate.addEdge(end, ufo);\n end = delegate.decorateInput(ufo, `${name}:ufo`);\n\n const branches: Input[] = [];\n if (withoutFlipped.length > 0) {\n const orCondition: Disjunction = {\n type: 'or',\n conditions: withoutFlipped,\n };\n branches.push(\n buildFilterPipeline(\n end,\n delegate,\n filterInput => applyOr(filterInput, orCondition, delegate, name),\n transformFilters(orCondition).filters,\n ),\n );\n }\n\n for (const cond of withFlipped) {\n branches.push(\n applyFilterWithFlips(\n end,\n cond,\n delegate,\n name,\n parentPartitionKey,\n boundProvider,\n existsParentIndexes,\n ),\n );\n }\n\n const ufi = new UnionFanIn(ufo, branches);\n for (const branch of branches) {\n delegate.addEdge(branch, ufi);\n }\n end = delegate.decorateInput(ufi, `${name}:ufi`);\n\n break;\n }\n case 'correlatedSubquery': {\n const sq = condition.related;\n const child = buildPipelineInternal(\n sq.subquery,\n delegate,\n '',\n `${name}.${sq.subquery.alias}`,\n sq.correlation.childField,\n false,\n );\n let parentIndex: JoinIndex | undefined;\n if (existsParentIndexes) {\n parentIndex = new JoinIndex(\n sq.correlation.parentField,\n end.getSchema().primaryKey,\n parentPartitionKey,\n );\n existsParentIndexes.push(parentIndex);\n }\n const flippedJoinName = `${name}:flipped-join(${sq.subquery.alias})`;\n const flippedJoin = new FlippedJoin({\n parent: end,\n child,\n parentKey: sq.correlation.parentField,\n childKey: sq.correlation.childField,\n relationshipName: must(\n sq.subquery.alias,\n 'Subquery must have an alias',\n ),\n hidden: sq.hidden ?? false,\n system: sq.system ?? 'client',\n parentPartitionKey,\n boundProvider,\n parentIndex,\n });\n delegate.addEdge(end, flippedJoin);\n delegate.addEdge(child, flippedJoin);\n end = delegate.decorateInput(flippedJoin, flippedJoinName);\n break;\n }\n }\n\n return end;\n}\n\nfunction applyFilter(\n input: FilterInput,\n condition: Condition,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n switch (condition.type) {\n case 'and':\n return applyAnd(input, condition, delegate, name);\n case 'or':\n return applyOr(input, condition, delegate, name);\n case 'correlatedSubquery':\n return applyCorrelatedSubqueryCondition(input, condition, delegate, name);\n case 'simple':\n return applySimpleCondition(input, delegate, condition);\n }\n}\n\nfunction applyAnd(\n input: FilterInput,\n condition: Conjunction,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n for (const subCondition of condition.conditions) {\n input = applyFilter(input, subCondition, delegate, name);\n }\n return input;\n}\n\nexport function applyOr(\n input: FilterInput,\n condition: Disjunction,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n const [subqueryConditions, otherConditions] =\n groupSubqueryConditions(condition);\n // if there are no subquery conditions, no fan-in / fan-out is needed\n if (subqueryConditions.length === 0) {\n const filter = new Filter(\n input,\n createPredicate({\n type: 'or',\n conditions: otherConditions,\n }),\n );\n delegate.addEdge(input, filter);\n return filter;\n }\n\n const fanOut = new FanOut(input);\n delegate.addEdge(input, fanOut);\n const branches = subqueryConditions.map(subCondition =>\n applyFilter(fanOut, subCondition, delegate, name),\n );\n if (otherConditions.length > 0) {\n const filter = new Filter(\n fanOut,\n createPredicate({\n type: 'or',\n conditions: otherConditions,\n }),\n );\n delegate.addEdge(fanOut, filter);\n branches.push(filter);\n }\n const ret = new FanIn(fanOut, branches);\n for (const branch of branches) {\n delegate.addEdge(branch, ret);\n }\n fanOut.setFanIn(ret);\n return ret;\n}\n\nexport function groupSubqueryConditions(condition: Disjunction) {\n const partitioned: [\n subqueryConditions: Condition[],\n otherConditions: NoSubqueryCondition[],\n ] = [[], []];\n for (const subCondition of condition.conditions) {\n if (isNotAndDoesNotContainSubquery(subCondition)) {\n partitioned[1].push(subCondition);\n } else {\n partitioned[0].push(subCondition);\n }\n }\n return partitioned;\n}\n\nexport function isNotAndDoesNotContainSubquery(\n condition: Condition,\n): condition is NoSubqueryCondition {\n if (condition.type === 'correlatedSubquery') {\n return false;\n }\n if (condition.type === 'simple') {\n return true;\n }\n return condition.conditions.every(isNotAndDoesNotContainSubquery);\n}\n\nfunction applySimpleCondition(\n input: FilterInput,\n delegate: BuilderDelegate,\n condition: SimpleCondition,\n): FilterInput {\n const filter = new Filter(input, createPredicate(condition));\n delegate.decorateFilterInput(\n filter,\n `${valuePosName(condition.left)}:${condition.op}:${valuePosName(condition.right)}`,\n );\n delegate.addEdge(input, filter);\n return filter;\n}\n\nfunction valuePosName(left: ValuePosition) {\n switch (left.type) {\n case 'static':\n return left.field;\n case 'literal':\n return left.value;\n case 'column':\n return left.name;\n }\n}\n\nfunction applyCorrelatedSubQuery(\n sq: CorrelatedSubquery,\n delegate: BuilderDelegate,\n queryID: string,\n end: Input,\n name: string,\n fromCondition: boolean,\n parentPartitionKey?: CompoundKey,\n boundProvider?: TakeBoundProvider,\n exists?: ExistsJoin,\n) {\n // TODO: we only omit the join if the CSQ if from a condition since\n // we want to create an empty array for `related` fields that are `limit(0)`\n if (sq.subquery.limit === 0 && fromCondition) {\n return end;\n }\n\n assert(sq.subquery.alias, 'Subquery must have an alias');\n const child = buildPipelineInternal(\n sq.subquery,\n delegate,\n queryID,\n `${name}.${sq.subquery.alias}`,\n sq.correlation.childField,\n fromCondition,\n );\n\n const joinName = `${name}:join(${sq.subquery.alias})`;\n const join = new Join({\n parent: end,\n child,\n parentKey: sq.correlation.parentField,\n childKey: sq.correlation.childField,\n relationshipName: sq.subquery.alias,\n hidden: sq.hidden ?? false,\n system: sq.system ?? 'client',\n parentPartitionKey: fromCondition ? undefined : parentPartitionKey,\n boundProvider,\n exists,\n });\n delegate.addEdge(end, join);\n delegate.addEdge(child, join);\n return delegate.decorateInput(join, joinName);\n}\n\nfunction applyCorrelatedSubqueryCondition(\n input: FilterInput,\n condition: CorrelatedSubqueryCondition,\n delegate: BuilderDelegate,\n name: string,\n): FilterInput {\n assert(\n condition.op === 'EXISTS' || condition.op === 'NOT EXISTS',\n 'Expected EXISTS or NOT EXISTS operator',\n );\n if (condition.related.subquery.limit === 0) {\n if (condition.op === 'EXISTS') {\n const filter = new Filter(input, () => false);\n delegate.addEdge(input, filter);\n return filter;\n }\n const filter = new Filter(input, () => true);\n delegate.addEdge(input, filter);\n return filter;\n }\n const existsName = `${name}:exists(${condition.related.subquery.alias})`;\n const exists = new Exists(\n input,\n must(condition.related.subquery.alias),\n condition.related.correlation.parentField,\n condition.op,\n );\n delegate.addEdge(input, exists);\n return delegate.decorateFilterInput(exists, existsName);\n}\n\nfunction gatherCorrelatedSubqueryQueryConditions(\n condition: Condition | undefined,\n) {\n const csqs: CorrelatedSubqueryCondition[] = [];\n const gather = (condition: Condition) => {\n if (condition.type === 'correlatedSubquery') {\n csqs.push(condition);\n return;\n }\n if (condition.type === 'and' || condition.type === 'or') {\n for (const c of condition.conditions) {\n gather(c);\n }\n return;\n }\n };\n if (condition) {\n gather(condition);\n }\n return csqs;\n}\n\nexport function assertOrderingIncludesPK(\n ordering: Ordering,\n pk: PrimaryKey,\n): void {\n // oxlint-disable-next-line unicorn/prefer-set-has -- Array is more appropriate here for small collections\n const orderingFields = ordering.map(([field]) => field);\n const missingFields = pk.filter(pkField => !orderingFields.includes(pkField));\n\n if (missingFields.length > 0) {\n throw new Error(\n `Ordering must include all primary key fields. Missing: ${missingFields.join(\n ', ',\n )}. ZQL automatically appends primary key fields to the ordering if they are missing \n so a common cause of this error is a casing mismatch between Postgres and ZQL.\n E.g., \"userid\" vs \"userID\".\n You may want to add double-quotes around your Postgres column names to prevent Postgres from lower-casing them:\n https://www.postgresql.org/docs/current/sql-syntax-lexical.htm`,\n );\n }\n}\n\nfunction uniquifyCorrelatedSubqueryConditionAliases(ast: AST): AST {\n if (!ast.where) {\n return ast;\n }\n const {where} = ast;\n if (where.type !== 'and' && where.type !== 'or') {\n return ast;\n }\n\n let count = 0;\n const uniquifyCorrelatedSubquery = (csqc: CorrelatedSubqueryCondition) => ({\n ...csqc,\n related: {\n ...csqc.related,\n subquery: {\n ...csqc.related.subquery,\n alias: (csqc.related.subquery.alias ?? '') + '_' + count++,\n },\n },\n });\n\n const uniquify = (cond: Condition): Condition => {\n if (cond.type === 'simple') {\n return cond;\n } else if (cond.type === 'correlatedSubquery') {\n return uniquifyCorrelatedSubquery(cond);\n }\n const conditions = [];\n for (const c of cond.conditions) {\n conditions.push(uniquify(c));\n }\n return {\n type: cond.type,\n conditions,\n };\n };\n\n const result = {\n ...ast,\n where: uniquify(where),\n };\n return result;\n}\n\nexport function conditionIncludesFlippedSubqueryAtAnyLevel(\n cond: Condition,\n): boolean {\n if (cond.type === 'correlatedSubquery') {\n return !!cond.flip;\n }\n if (cond.type === 'and' || cond.type === 'or') {\n return cond.conditions.some(c =>\n conditionIncludesFlippedSubqueryAtAnyLevel(c),\n );\n }\n // simple conditions don't have flips\n return false;\n}\n\nexport function partitionBranches(\n conditions: readonly Condition[],\n predicate: (c: Condition) => boolean,\n) {\n const matched: Condition[] = [];\n const notMatched: Condition[] = [];\n for (const c of conditions) {\n if (predicate(c)) {\n matched.push(c);\n } else {\n notMatched.push(c);\n }\n }\n return [matched, notMatched] as const;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"correlated-predicate-pushdown.js","names":[],"sources":["../../../../../zql/src/builder/correlated-predicate-pushdown.ts"],"sourcesContent":["import {deepEqual} from '../../../shared/src/json.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n SimpleCondition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {SchemaValue} from '../../../zero-types/src/schema-value.ts';\nimport {simplifyCondition} from '../query/expression.ts';\n\n/**\n * The longest `IN` list that is copied into a child. `IN` compiles to\n * `IN (SELECT value FROM json_each(?))`, and every per-parent fetch of the\n * child carries the whole list.\n */\nexport const MAX_PUSHED_IN_VALUES = 32;\n\ntype ColumnCondition = SimpleCondition & {\n readonly left: {readonly type: 'column'; readonly name: string};\n};\n\n/**\n * Copies a parent's condition on a correlation column into the child\n * subquery, renamed to the matching child column. For example,\n * `user.where('user_id', X).related('reading')` becomes\n * `user.where('user_id', X).related('reading', r => r.where('user_id', X))`.\n *\n * The result is the same. Only child rows that cannot join to a parent that\n * matters are removed. But a push that climbs the tree then fetches parents\n * with SQL that includes the ancestor's condition, and a change to a child row\n * that cannot match stops at the child's source.\n *\n * Conditions are copied only when they are true for every parent row where\n * the edge can affect the result:\n * - for `related`, the top-level AND conjuncts of the parent's `where`;\n * - for EXISTS and NOT EXISTS, the conjuncts of every AND on the path from\n * the root of `where` to the subquery condition. An OR adds no facts.\n *\n * A condition is copied when it is `column = literal`, `column IS literal`, or\n * `column IN literal-list` (at most {@link MAX_PUSHED_IN_VALUES} values), the\n * column is a `parentField` of the correlation, and the parent and child\n * columns have the same Zero type, which is not `json`.\n *\n * A condition is not copied when the child already has the same condition as\n * a conjunct. So the pass does not change an AST that it already pushed.\n *\n * Does not change its input. Returns the same object for every part of the\n * AST that it does not change.\n *\n * @param pushed When given, receives each child conjunct that is a copy of a\n * parent condition: the copies that the pass adds, and the child's own\n * conjuncts that equal a copy. The parent's condition implies each of them\n * wherever the join binds its column, so the planner ignores them there.\n */\nexport function pushDownCorrelatedPredicates(\n ast: AST,\n columnsOf: (table: string) => Record<string, SchemaValue>,\n pushed?: Set<SimpleCondition> | undefined,\n): AST {\n function visit(ast: AST): AST {\n const where = ast.where && visitCondition(ast.where, ast.table, []);\n const facts = where ? simpleConjuncts(where) : [];\n const related =\n ast.related &&\n mapShared(ast.related, csq => {\n const subquery = visit(pushInto(csq, facts, ast.table));\n return subquery === csq.subquery ? csq : {...csq, subquery};\n });\n if (where === ast.where && related === ast.related) {\n return ast;\n }\n return {...ast, where, related};\n }\n\n function visitCondition(\n c: Condition,\n table: string,\n facts: readonly SimpleCondition[],\n ): Condition {\n switch (c.type) {\n case 'simple':\n return c;\n case 'and':\n return visitConjunction(c, table, [...facts, ...simpleConjuncts(c)]);\n case 'or': {\n const conditions = mapShared(c.conditions, x =>\n visitCondition(x, table, facts),\n );\n return conditions === c.conditions ? c : {...c, conditions};\n }\n case 'correlatedSubquery': {\n const subquery = visit(pushInto(c.related, facts, table));\n return subquery === c.related.subquery\n ? c\n : {...c, related: {...c.related, subquery}};\n }\n }\n }\n\n // `facts` already holds the simple conjuncts of `c` and of the ANDs nested\n // directly in it, so nested ANDs must not add them again.\n function visitConjunction(\n c: Conjunction,\n table: string,\n facts: readonly SimpleCondition[],\n ): Conjunction {\n const conditions = mapShared(c.conditions, x =>\n x.type === 'and'\n ? visitConjunction(x, table, facts)\n : visitCondition(x, table, facts),\n );\n return conditions === c.conditions ? c : {...c, conditions};\n }\n\n function pushInto(\n csq: CorrelatedSubquery,\n facts: readonly SimpleCondition[],\n parentTable: string,\n ): AST {\n const {parentField, childField} = csq.correlation;\n const {subquery} = csq;\n const conjuncts = subquery.where ? simpleConjuncts(subquery.where) : [];\n const added: SimpleCondition[] = [];\n for (const fact of facts) {\n if (!isPushable(fact)) {\n continue;\n }\n for (let i = 0; i < parentField.length; i++) {\n if (\n parentField[i] === fact.left.name &&\n haveSameScalarType(\n columnsOf(parentTable)[parentField[i]],\n columnsOf(subquery.table)[childField[i]],\n )\n ) {\n const copy: SimpleCondition = {\n ...fact,\n left: {type: 'column', name: childField[i]},\n };\n const same = conjuncts.find(c => isSameCondition(c, copy));\n if (same) {\n pushed?.add(same);\n } else {\n conjuncts.push(copy);\n added.push(copy);\n pushed?.add(copy);\n }\n }\n }\n }\n if (added.length === 0) {\n return subquery;\n }\n return {\n ...subquery,\n where: simplifyCondition({\n type: 'and',\n conditions: subquery.where ? [subquery.where, ...added] : added,\n }),\n };\n }\n\n return visit(ast);\n}\n\n/**\n * The simple conditions that are conjuncts of `c`, including those of ANDs\n * nested in ANDs.\n */\nfunction simpleConjuncts(c: Condition): SimpleCondition[] {\n switch (c.type) {\n case 'simple':\n return [c];\n case 'and':\n return c.conditions.flatMap(simpleConjuncts);\n default:\n return [];\n }\n}\n\nfunction isPushable(c: SimpleCondition): c is ColumnCondition {\n if (c.left.type !== 'column' || c.right.type !== 'literal') {\n return false;\n }\n switch (c.op) {\n case '=':\n case 'IS':\n return true;\n case 'IN':\n return (\n Array.isArray(c.right.value) &&\n c.right.value.length <= MAX_PUSHED_IN_VALUES\n );\n default:\n return false;\n }\n}\n\nfunction isSameCondition(a: SimpleCondition, b: SimpleCondition): boolean {\n return (\n a.op === b.op &&\n a.left.type === 'column' &&\n b.left.type === 'column' &&\n a.left.name === b.left.name &&\n a.right.type === 'literal' &&\n b.right.type === 'literal' &&\n deepEqual(a.right.value, b.right.value)\n );\n}\n\nfunction haveSameScalarType(\n parent: SchemaValue | undefined,\n child: SchemaValue | undefined,\n): boolean {\n return (\n parent !== undefined &&\n child !== undefined &&\n parent.type === child.type &&\n parent.type !== 'json'\n );\n}\n\n/**\n * Like `Array.prototype.map`, but returns `arr` itself when `f` returns every\n * element unchanged.\n */\nfunction mapShared<T>(arr: readonly T[], f: (x: T) => T): readonly T[] {\n let result: T[] | undefined;\n for (let i = 0; i < arr.length; i++) {\n const x = f(arr[i]);\n if (result === undefined && x !== arr[i]) {\n result = arr.slice(0, i);\n }\n result?.push(x);\n }\n return result ?? arr;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"correlated-predicate-pushdown.js","names":[],"sources":["../../../../../zql/src/builder/correlated-predicate-pushdown.ts"],"sourcesContent":["import {deepEqual} from '../../../shared/src/json.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n SimpleCondition,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {SchemaValue} from '../../../zero-types/src/schema-value.ts';\nimport {simplifyCondition} from '../query/expression.ts';\n\n/**\n * The longest `IN` list that is copied into a child. `IN` compiles to\n * `IN (SELECT value FROM json_each(?))`, and every per-parent fetch of the\n * child carries the whole list.\n */\nexport const MAX_PUSHED_IN_VALUES = 32;\n\ntype ColumnCondition = SimpleCondition & {\n readonly left: {readonly type: 'column'; readonly name: string};\n};\n\n/**\n * Copies a parent's condition on a correlation column into the child\n * subquery, renamed to the matching child column. For example,\n * `user.where('user_id', X).related('reading')` becomes\n * `user.where('user_id', X).related('reading', r => r.where('user_id', X))`.\n *\n * The result is the same. Only child rows that cannot join to a parent that\n * matters are removed. But a push that climbs the tree then fetches parents\n * with SQL that includes the ancestor's condition, and a change to a child row\n * that cannot match stops at the child's source.\n *\n * Conditions are copied only when they are true for every parent row where\n * the edge can affect the result:\n * - for `related`, the top-level AND conjuncts of the parent's `where`;\n * - for EXISTS and NOT EXISTS, the conjuncts of every AND on the path from\n * the root of `where` to the subquery condition. An OR adds no facts.\n *\n * A condition is copied when it is `column = literal`, `column IS literal`, or\n * `column IN literal-list` (at most {@link MAX_PUSHED_IN_VALUES} values), the\n * column is a `parentField` of the correlation, and the parent and child\n * columns have the same Zero type, which is not `json`.\n *\n * A condition is not copied when the child already has the same condition as\n * a conjunct. So the pass does not change an AST that it already pushed.\n *\n * Does not change its input. Returns the same object for every part of the\n * AST that it does not change.\n *\n * @param pushed When given, receives each child conjunct that is a copy of a\n * parent condition: the copies that the pass adds, and the child's own\n * conjuncts that equal a copy. The parent's condition implies each of them\n * wherever the join binds its column, so the planner ignores them there.\n */\nexport function pushDownCorrelatedPredicates(\n ast: AST,\n columnsOf: (table: string) => Record<string, SchemaValue>,\n pushed?: Set<SimpleCondition> | undefined,\n): AST {\n function visit(ast: AST): AST {\n const where = ast.where && visitCondition(ast.where, ast.table, []);\n const facts = where ? simpleConjuncts(where) : [];\n const related =\n ast.related &&\n mapShared(ast.related, csq => {\n const subquery = visit(pushInto(csq, facts, ast.table));\n return subquery === csq.subquery ? csq : {...csq, subquery};\n });\n if (where === ast.where && related === ast.related) {\n return ast;\n }\n return {...ast, where, related};\n }\n\n function visitCondition(\n c: Condition,\n table: string,\n facts: readonly SimpleCondition[],\n ): Condition {\n switch (c.type) {\n case 'simple':\n return c;\n case 'and':\n return visitConjunction(c, table, [...facts, ...simpleConjuncts(c)]);\n case 'or': {\n const conditions = mapShared(c.conditions, x =>\n visitCondition(x, table, facts),\n );\n return conditions === c.conditions ? c : {...c, conditions};\n }\n case 'correlatedSubquery': {\n const subquery = visit(pushInto(c.related, facts, table));\n return subquery === c.related.subquery\n ? c\n : {...c, related: {...c.related, subquery}};\n }\n }\n }\n\n // `facts` already holds the simple conjuncts of `c` and of the ANDs nested\n // directly in it, so nested ANDs must not add them again.\n function visitConjunction(\n c: Conjunction,\n table: string,\n facts: readonly SimpleCondition[],\n ): Conjunction {\n const conditions = mapShared(c.conditions, x =>\n x.type === 'and'\n ? visitConjunction(x, table, facts)\n : visitCondition(x, table, facts),\n );\n return conditions === c.conditions ? c : {...c, conditions};\n }\n\n function pushInto(\n csq: CorrelatedSubquery,\n facts: readonly SimpleCondition[],\n parentTable: string,\n ): AST {\n const {parentField, childField} = csq.correlation;\n const {subquery} = csq;\n const conjuncts = subquery.where ? simpleConjuncts(subquery.where) : [];\n const added: SimpleCondition[] = [];\n for (const fact of facts) {\n if (!isPushable(fact)) {\n continue;\n }\n for (let i = 0; i < parentField.length; i++) {\n if (\n parentField[i] === fact.left.name &&\n haveSameScalarType(\n columnsOf(parentTable)[parentField[i]],\n columnsOf(subquery.table)[childField[i]],\n )\n ) {\n const copy: SimpleCondition = {\n ...fact,\n left: {type: 'column', name: childField[i]},\n };\n const same = conjuncts.find(c => isSameCondition(c, copy));\n if (same) {\n pushed?.add(same);\n } else {\n conjuncts.push(copy);\n added.push(copy);\n pushed?.add(copy);\n }\n }\n }\n }\n if (added.length === 0) {\n return subquery;\n }\n return {\n ...subquery,\n where: simplifyCondition({\n type: 'and',\n conditions: subquery.where ? [subquery.where, ...added] : added,\n }),\n };\n }\n\n return visit(ast);\n}\n\n/**\n * The simple conditions that are conjuncts of `c`, including those of ANDs\n * nested in ANDs.\n */\nfunction simpleConjuncts(c: Condition): SimpleCondition[] {\n switch (c.type) {\n case 'simple':\n return [c];\n case 'and':\n return c.conditions.flatMap(simpleConjuncts);\n default:\n return [];\n }\n}\n\nfunction isPushable(c: SimpleCondition): c is ColumnCondition {\n if (c.left.type !== 'column' || c.right.type !== 'literal') {\n return false;\n }\n switch (c.op) {\n case '=':\n case 'IS':\n return true;\n case 'IN':\n return (\n Array.isArray(c.right.value) &&\n c.right.value.length <= MAX_PUSHED_IN_VALUES\n );\n default:\n return false;\n }\n}\n\nfunction isSameCondition(a: SimpleCondition, b: SimpleCondition): boolean {\n return (\n a.op === b.op &&\n a.left.type === 'column' &&\n b.left.type === 'column' &&\n a.left.name === b.left.name &&\n a.right.type === 'literal' &&\n b.right.type === 'literal' &&\n deepEqual(a.right.value, b.right.value)\n );\n}\n\nfunction haveSameScalarType(\n parent: SchemaValue | undefined,\n child: SchemaValue | undefined,\n): boolean {\n return (\n parent !== undefined &&\n child !== undefined &&\n parent.type === child.type &&\n parent.type !== 'json'\n );\n}\n\n/**\n * Like `Array.prototype.map`, but returns `arr` itself when `f` returns every\n * element unchanged.\n */\nfunction mapShared<T>(arr: readonly T[], f: (x: T) => T): readonly T[] {\n let result: T[] | undefined;\n for (let i = 0; i < arr.length; i++) {\n const x = f(arr[i]);\n if (result === undefined && x !== arr[i]) {\n result = arr.slice(0, i);\n }\n result?.push(x);\n }\n return result ?? arr;\n}\n"],"mappings":"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"}