@rocicorp/zero 1.10.0-canary.24 → 1.10.0-canary.26

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 (568) hide show
  1. package/out/analyze-query/src/bin-analyze.js +8 -9
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/replicache/src/btree/node.d.ts.map +1 -1
  4. package/out/replicache/src/btree/node.js +6 -3
  5. package/out/replicache/src/btree/node.js.map +1 -1
  6. package/out/replicache/src/btree/read.d.ts +1 -12
  7. package/out/replicache/src/btree/read.d.ts.map +1 -1
  8. package/out/replicache/src/btree/read.js +12 -24
  9. package/out/replicache/src/btree/read.js.map +1 -1
  10. package/out/replicache/src/dag/gc.d.ts.map +1 -1
  11. package/out/replicache/src/dag/gc.js +11 -8
  12. package/out/replicache/src/dag/gc.js.map +1 -1
  13. package/out/replicache/src/dag/store-impl.d.ts +2 -12
  14. package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
  15. package/out/replicache/src/dag/store-impl.js +8 -22
  16. package/out/replicache/src/dag/store-impl.js.map +1 -1
  17. package/out/replicache/src/db/rebase.d.ts +2 -14
  18. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  19. package/out/replicache/src/db/rebase.js +5 -27
  20. package/out/replicache/src/db/rebase.js.map +1 -1
  21. package/out/replicache/src/db/write.js.map +1 -1
  22. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  23. package/out/replicache/src/kv/expo-sqlite/store.js +5 -28
  24. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  25. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +5 -15
  26. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +1 -1
  27. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +25 -25
  28. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -1
  29. package/out/replicache/src/kv/idb-store.d.ts +0 -9
  30. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  31. package/out/replicache/src/kv/idb-store.js +2 -14
  32. package/out/replicache/src/kv/idb-store.js.map +1 -1
  33. package/out/replicache/src/kv/mem-store.d.ts +0 -1
  34. package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
  35. package/out/replicache/src/kv/mem-store.js +0 -3
  36. package/out/replicache/src/kv/mem-store.js.map +1 -1
  37. package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
  38. package/out/replicache/src/kv/op-sqlite/store.js +1 -1
  39. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  40. package/out/replicache/src/kv/sqlite-store.d.ts +1 -13
  41. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  42. package/out/replicache/src/kv/sqlite-store.js +6 -73
  43. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  44. package/out/replicache/src/kv/store.d.ts +0 -6
  45. package/out/replicache/src/kv/store.d.ts.map +1 -1
  46. package/out/replicache/src/persist/collect-idb-databases.d.ts +5 -10
  47. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  48. package/out/replicache/src/persist/collect-idb-databases.js +9 -16
  49. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  50. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  51. package/out/replicache/src/persist/persist.js +6 -13
  52. package/out/replicache/src/persist/persist.js.map +1 -1
  53. package/out/replicache/src/persist/refresh.js +2 -6
  54. package/out/replicache/src/persist/refresh.js.map +1 -1
  55. package/out/replicache/src/replicache-impl.d.ts +3 -14
  56. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  57. package/out/replicache/src/replicache-impl.js +11 -118
  58. package/out/replicache/src/replicache-impl.js.map +1 -1
  59. package/out/replicache/src/replicache-options.d.ts +0 -9
  60. package/out/replicache/src/replicache-options.d.ts.map +1 -1
  61. package/out/replicache/src/transactions.d.ts.map +1 -1
  62. package/out/replicache/src/transactions.js +1 -1
  63. package/out/replicache/src/transactions.js.map +1 -1
  64. package/out/shared/src/arrays.d.ts +0 -5
  65. package/out/shared/src/arrays.d.ts.map +1 -1
  66. package/out/shared/src/arrays.js +24 -8
  67. package/out/shared/src/arrays.js.map +1 -1
  68. package/out/shared/src/base64.d.ts +19 -0
  69. package/out/shared/src/base64.d.ts.map +1 -0
  70. package/out/shared/src/base64.js +40 -0
  71. package/out/shared/src/base64.js.map +1 -0
  72. package/out/shared/src/error.d.ts +0 -11
  73. package/out/shared/src/error.d.ts.map +1 -1
  74. package/out/shared/src/error.js +1 -35
  75. package/out/shared/src/error.js.map +1 -1
  76. package/out/shared/src/hash.d.ts +0 -1
  77. package/out/shared/src/hash.d.ts.map +1 -1
  78. package/out/shared/src/hash.js +10 -87
  79. package/out/shared/src/hash.js.map +1 -1
  80. package/out/shared/src/iterables.d.ts +0 -2
  81. package/out/shared/src/iterables.d.ts.map +1 -1
  82. package/out/shared/src/iterables.js +1 -18
  83. package/out/shared/src/iterables.js.map +1 -1
  84. package/out/shared/src/json.d.ts.map +1 -1
  85. package/out/shared/src/json.js +2 -2
  86. package/out/shared/src/json.js.map +1 -1
  87. package/out/shared/src/map.d.ts +2 -24
  88. package/out/shared/src/map.d.ts.map +1 -1
  89. package/out/shared/src/map.js +4 -18
  90. package/out/shared/src/map.js.map +1 -1
  91. package/out/shared/src/ring-buffer.d.ts +0 -8
  92. package/out/shared/src/ring-buffer.d.ts.map +1 -1
  93. package/out/shared/src/ring-buffer.js +1 -22
  94. package/out/shared/src/ring-buffer.js.map +1 -1
  95. package/out/z2s/src/sql.d.ts.map +1 -1
  96. package/out/z2s/src/sql.js +2 -2
  97. package/out/z2s/src/sql.js.map +1 -1
  98. package/out/zero/package.js +3 -2
  99. package/out/zero/package.js.map +1 -1
  100. package/out/zero-cache/src/auth/read-authorizer.js +1 -1
  101. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  102. package/out/zero-cache/src/auth/write-authorizer.js +0 -1
  103. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  104. package/out/zero-cache/src/config/zero-config.d.ts +2 -42
  105. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  106. package/out/zero-cache/src/config/zero-config.js +28 -149
  107. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  108. package/out/zero-cache/src/custom-queries/transform-query.js +1 -1
  109. package/out/zero-cache/src/db/create.d.ts.map +1 -1
  110. package/out/zero-cache/src/db/create.js +1 -4
  111. package/out/zero-cache/src/db/create.js.map +1 -1
  112. package/out/zero-cache/src/db/lite-tables.d.ts +2 -10
  113. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  114. package/out/zero-cache/src/db/lite-tables.js +6 -10
  115. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  116. package/out/zero-cache/src/db/specs.d.ts +0 -41
  117. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  118. package/out/zero-cache/src/db/specs.js +3 -30
  119. package/out/zero-cache/src/db/specs.js.map +1 -1
  120. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  121. package/out/zero-cache/src/observability/metrics.js +7 -2
  122. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  123. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  124. package/out/zero-cache/src/server/change-streamer.js +4 -13
  125. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  126. package/out/zero-cache/src/server/inspector-delegate.d.ts +2 -18
  127. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  128. package/out/zero-cache/src/server/inspector-delegate.js +17 -25
  129. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  130. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  131. package/out/zero-cache/src/server/main.js +1 -8
  132. package/out/zero-cache/src/server/main.js.map +1 -1
  133. package/out/zero-cache/src/server/mutator.js +0 -2
  134. package/out/zero-cache/src/server/mutator.js.map +1 -1
  135. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  136. package/out/zero-cache/src/server/reaper.js +0 -2
  137. package/out/zero-cache/src/server/reaper.js.map +1 -1
  138. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  139. package/out/zero-cache/src/server/replicator.js +2 -8
  140. package/out/zero-cache/src/server/replicator.js.map +1 -1
  141. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  142. package/out/zero-cache/src/server/runner/zero-dispatcher.js +0 -3
  143. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  144. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  145. package/out/zero-cache/src/server/syncer.js +1 -5
  146. package/out/zero-cache/src/server/syncer.js.map +1 -1
  147. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  148. package/out/zero-cache/src/services/analyze.js +9 -11
  149. package/out/zero-cache/src/services/analyze.js.map +1 -1
  150. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  151. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +1 -14
  152. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  153. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
  154. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +3 -15
  155. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  156. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +1 -11
  157. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  158. package/out/zero-cache/src/services/change-source/pg/change-source.js +2 -21
  159. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  160. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +0 -1
  161. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  162. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +7 -8
  163. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  164. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +229 -1513
  165. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  166. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +2 -2
  167. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  168. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +1 -1
  169. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  170. package/out/zero-cache/src/services/change-source/pg/schema/init.js +6 -15
  171. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  172. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +20 -137
  173. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
  174. package/out/zero-cache/src/services/change-source/pg/schema/published.js +13 -82
  175. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  176. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +21 -128
  177. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  178. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +5 -5
  179. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  180. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +0 -2
  181. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  182. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +0 -3
  183. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  184. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -3
  185. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  186. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +1 -3
  187. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  188. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +0 -1
  189. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  190. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  191. package/out/zero-cache/src/services/litestream/commands.js +3 -8
  192. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  193. package/out/zero-cache/src/services/litestream/config-v5.yml +1 -15
  194. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +0 -5
  195. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  196. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -7
  197. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  198. package/out/zero-cache/src/services/mutagen/pusher.d.ts +119 -119
  199. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  200. package/out/zero-cache/src/services/mutagen/pusher.js +6 -5
  201. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  202. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  203. package/out/zero-cache/src/services/replicator/change-processor.js +16 -16
  204. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  205. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  206. package/out/zero-cache/src/services/replicator/incremental-sync.js +0 -1
  207. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  208. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +2 -27
  209. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  210. package/out/zero-cache/src/services/replicator/write-worker-client.js +2 -3
  211. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  212. package/out/zero-cache/src/services/replicator/write-worker.js +5 -24
  213. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  214. package/out/zero-cache/src/services/run-ast.d.ts +0 -12
  215. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  216. package/out/zero-cache/src/services/run-ast.js +15 -27
  217. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  218. package/out/zero-cache/src/services/runner.d.ts.map +1 -1
  219. package/out/zero-cache/src/services/runner.js +1 -1
  220. package/out/zero-cache/src/services/runner.js.map +1 -1
  221. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -45
  222. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  223. package/out/zero-cache/src/services/view-syncer/cvr.js +1 -133
  224. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  225. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +1 -14
  226. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
  227. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +4 -30
  228. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  229. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +1 -1
  230. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  231. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -2
  232. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  233. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -2
  234. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  235. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +27 -48
  236. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  237. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +1 -1
  238. package/out/zero-cache/src/services/view-syncer/query-covering.js +6 -2
  239. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  240. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +4 -42
  241. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  242. package/out/zero-cache/src/services/view-syncer/snapshotter.js +28 -117
  243. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  244. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -11
  245. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  246. package/out/zero-cache/src/services/view-syncer/view-syncer.js +95 -466
  247. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  248. package/out/zero-cache/src/types/processes.d.ts +0 -32
  249. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  250. package/out/zero-cache/src/types/processes.js +4 -43
  251. package/out/zero-cache/src/types/processes.js.map +1 -1
  252. package/out/zero-cache/src/types/profiler.d.ts +0 -12
  253. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  254. package/out/zero-cache/src/types/profiler.js +1 -46
  255. package/out/zero-cache/src/types/profiler.js.map +1 -1
  256. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  257. package/out/zero-cache/src/types/row-key.js +5 -5
  258. package/out/zero-cache/src/types/row-key.js.map +1 -1
  259. package/out/zero-cache/src/workers/connect-params.d.ts +7 -0
  260. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  261. package/out/zero-cache/src/workers/connect-params.js +20 -1
  262. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  263. package/out/zero-cache/src/workers/connection.d.ts +4 -4
  264. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  265. package/out/zero-cache/src/workers/connection.js +8 -8
  266. package/out/zero-cache/src/workers/connection.js.map +1 -1
  267. package/out/zero-cache/src/workers/replicator.d.ts +0 -1
  268. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  269. package/out/zero-cache/src/workers/replicator.js +2 -4
  270. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  271. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  272. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +16 -21
  273. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  274. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  275. package/out/zero-cache/src/workers/syncer.js +1 -10
  276. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  277. package/out/zero-client/src/client/connection-manager.d.ts +0 -20
  278. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  279. package/out/zero-client/src/client/connection-manager.js +13 -77
  280. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  281. package/out/zero-client/src/client/connection-status-enum.d.ts +0 -2
  282. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
  283. package/out/zero-client/src/client/connection-status-enum.js +1 -3
  284. package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
  285. package/out/zero-client/src/client/connection.d.ts +0 -6
  286. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  287. package/out/zero-client/src/client/connection.js +1 -2
  288. package/out/zero-client/src/client/connection.js.map +1 -1
  289. package/out/zero-client/src/client/context.d.ts +2 -27
  290. package/out/zero-client/src/client/context.d.ts.map +1 -1
  291. package/out/zero-client/src/client/context.js +1 -112
  292. package/out/zero-client/src/client/context.js.map +1 -1
  293. package/out/zero-client/src/client/custom.js +2 -2
  294. package/out/zero-client/src/client/custom.js.map +1 -1
  295. package/out/zero-client/src/client/error.js +1 -1
  296. package/out/zero-client/src/client/inspector/lazy-inspector.js +2 -2
  297. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  298. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  299. package/out/zero-client/src/client/ivm-branch.js +3 -20
  300. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  301. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  302. package/out/zero-client/src/client/mutation-tracker.js +1 -1
  303. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  304. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
  305. package/out/zero-client/src/client/mutator-proxy.js +1 -2
  306. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  307. package/out/zero-client/src/client/options.d.ts +0 -3
  308. package/out/zero-client/src/client/options.d.ts.map +1 -1
  309. package/out/zero-client/src/client/options.js.map +1 -1
  310. package/out/zero-client/src/client/query-manager.d.ts +0 -2
  311. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  312. package/out/zero-client/src/client/query-manager.js +14 -50
  313. package/out/zero-client/src/client/query-manager.js.map +1 -1
  314. package/out/zero-client/src/client/version.js +1 -1
  315. package/out/zero-client/src/client/zero-rep.d.ts +0 -1
  316. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  317. package/out/zero-client/src/client/zero-rep.js +6 -9
  318. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  319. package/out/zero-client/src/client/zero.d.ts +3 -18
  320. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  321. package/out/zero-client/src/client/zero.js +36 -123
  322. package/out/zero-client/src/client/zero.js.map +1 -1
  323. package/out/zero-client/src/types/query-result.d.ts +0 -2
  324. package/out/zero-client/src/types/query-result.d.ts.map +1 -1
  325. package/out/zero-protocol/src/analyze-query-result.d.ts +5 -5
  326. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
  327. package/out/zero-protocol/src/analyze-query-result.js +1 -1
  328. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  329. package/out/zero-protocol/src/ast.d.ts +1 -64
  330. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  331. package/out/zero-protocol/src/ast.js +54 -225
  332. package/out/zero-protocol/src/ast.js.map +1 -1
  333. package/out/zero-protocol/src/connect.d.ts +13 -0
  334. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  335. package/out/zero-protocol/src/connect.js +30 -1
  336. package/out/zero-protocol/src/connect.js.map +1 -1
  337. package/out/zero-protocol/src/down.d.ts +2 -2
  338. package/out/zero-protocol/src/error.d.ts +1 -1
  339. package/out/zero-protocol/src/inspect-down.d.ts +6 -6
  340. package/out/zero-protocol/src/poke.d.ts +11 -4
  341. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  342. package/out/zero-protocol/src/poke.js +3 -2
  343. package/out/zero-protocol/src/poke.js.map +1 -1
  344. package/out/zero-protocol/src/protocol-flag-enum.d.ts +7 -0
  345. package/out/zero-protocol/src/protocol-flag-enum.d.ts.map +1 -0
  346. package/out/zero-protocol/src/protocol-flag-enum.js +7 -0
  347. package/out/zero-protocol/src/protocol-flag-enum.js.map +1 -0
  348. package/out/zero-protocol/src/protocol-flag.d.ts +14 -0
  349. package/out/zero-protocol/src/protocol-flag.d.ts.map +1 -0
  350. package/out/zero-protocol/src/protocol-flag.js +8 -0
  351. package/out/zero-protocol/src/protocol-flag.js.map +1 -0
  352. package/out/zero-protocol/src/protocol-version.d.ts +30 -6
  353. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  354. package/out/zero-protocol/src/protocol-version.js +1 -1
  355. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  356. package/out/zero-protocol/src/query-hash.d.ts +2 -7
  357. package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
  358. package/out/zero-protocol/src/query-hash.js +10 -10
  359. package/out/zero-protocol/src/query-hash.js.map +1 -1
  360. package/out/zero-react/src/use-query.d.ts +4 -5
  361. package/out/zero-react/src/use-query.d.ts.map +1 -1
  362. package/out/zero-react/src/use-query.js +9 -86
  363. package/out/zero-react/src/use-query.js.map +1 -1
  364. package/out/zero-solid/src/solid-view.d.ts +0 -17
  365. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  366. package/out/zero-solid/src/solid-view.js +1 -39
  367. package/out/zero-solid/src/solid-view.js.map +1 -1
  368. package/out/zero-solid/src/use-query.js +3 -5
  369. package/out/zero-solid/src/use-query.js.map +1 -1
  370. package/out/zql/src/builder/builder.d.ts +0 -19
  371. package/out/zql/src/builder/builder.d.ts.map +1 -1
  372. package/out/zql/src/builder/builder.js +11 -28
  373. package/out/zql/src/builder/builder.js.map +1 -1
  374. package/out/zql/src/builder/debug-delegate.d.ts +1 -6
  375. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  376. package/out/zql/src/builder/debug-delegate.js +2 -14
  377. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  378. package/out/zql/src/ivm/array-view.d.ts +0 -29
  379. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  380. package/out/zql/src/ivm/array-view.js +12 -63
  381. package/out/zql/src/ivm/array-view.js.map +1 -1
  382. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  383. package/out/zql/src/ivm/cap.js +3 -5
  384. package/out/zql/src/ivm/cap.js.map +1 -1
  385. package/out/zql/src/ivm/data.d.ts.map +1 -1
  386. package/out/zql/src/ivm/data.js +3 -8
  387. package/out/zql/src/ivm/data.js.map +1 -1
  388. package/out/zql/src/ivm/exists.d.ts +1 -1
  389. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  390. package/out/zql/src/ivm/exists.js.map +1 -1
  391. package/out/zql/src/ivm/fan-in.d.ts +2 -2
  392. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  393. package/out/zql/src/ivm/fan-in.js +5 -6
  394. package/out/zql/src/ivm/fan-in.js.map +1 -1
  395. package/out/zql/src/ivm/fan-out.d.ts +2 -2
  396. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  397. package/out/zql/src/ivm/fan-out.js.map +1 -1
  398. package/out/zql/src/ivm/filter-operators.d.ts +6 -7
  399. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  400. package/out/zql/src/ivm/filter-operators.js +12 -29
  401. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  402. package/out/zql/src/ivm/filter.d.ts +2 -2
  403. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  404. package/out/zql/src/ivm/filter.js +4 -7
  405. package/out/zql/src/ivm/filter.js.map +1 -1
  406. package/out/zql/src/ivm/flipped-join.js +2 -2
  407. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  408. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  409. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  410. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +4 -6
  411. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  412. package/out/zql/src/ivm/memory-source.d.ts +3 -15
  413. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  414. package/out/zql/src/ivm/memory-source.js +23 -57
  415. package/out/zql/src/ivm/memory-source.js.map +1 -1
  416. package/out/zql/src/ivm/operator.d.ts +0 -40
  417. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  418. package/out/zql/src/ivm/operator.js.map +1 -1
  419. package/out/zql/src/ivm/take.d.ts.map +1 -1
  420. package/out/zql/src/ivm/take.js +4 -3
  421. package/out/zql/src/ivm/take.js.map +1 -1
  422. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  423. package/out/zql/src/ivm/union-fan-in.js +7 -9
  424. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  425. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  426. package/out/zql/src/ivm/view-apply-change.js +4 -9
  427. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  428. package/out/zql/src/ivm/view.d.ts +0 -15
  429. package/out/zql/src/ivm/view.d.ts.map +1 -1
  430. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  431. package/out/zql/src/mutate/mutator-registry.js +2 -2
  432. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  433. package/out/zql/src/planner/planner-builder.d.ts +3 -12
  434. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  435. package/out/zql/src/planner/planner-builder.js +20 -40
  436. package/out/zql/src/planner/planner-builder.js.map +1 -1
  437. package/out/zql/src/planner/planner-connection.d.ts +2 -28
  438. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  439. package/out/zql/src/planner/planner-connection.js +8 -108
  440. package/out/zql/src/planner/planner-connection.js.map +1 -1
  441. package/out/zql/src/planner/planner-debug.d.ts +1 -1
  442. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  443. package/out/zql/src/planner/planner-debug.js +8 -3
  444. package/out/zql/src/planner/planner-debug.js.map +1 -1
  445. package/out/zql/src/planner/planner-fan-out.d.ts +0 -1
  446. package/out/zql/src/planner/planner-fan-out.d.ts.map +1 -1
  447. package/out/zql/src/planner/planner-fan-out.js +0 -3
  448. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  449. package/out/zql/src/planner/planner-graph.d.ts +0 -2
  450. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  451. package/out/zql/src/planner/planner-graph.js +0 -2
  452. package/out/zql/src/planner/planner-graph.js.map +1 -1
  453. package/out/zql/src/planner/planner-join.d.ts +0 -2
  454. package/out/zql/src/planner/planner-join.d.ts.map +1 -1
  455. package/out/zql/src/planner/planner-join.js +0 -7
  456. package/out/zql/src/planner/planner-join.js.map +1 -1
  457. package/out/zql/src/planner/planner-node.d.ts +1 -2
  458. package/out/zql/src/planner/planner-node.d.ts.map +1 -1
  459. package/out/zql/src/planner/planner-node.js.map +1 -1
  460. package/out/zql/src/planner/planner-source.d.ts +2 -2
  461. package/out/zql/src/planner/planner-source.d.ts.map +1 -1
  462. package/out/zql/src/planner/planner-source.js +2 -2
  463. package/out/zql/src/planner/planner-source.js.map +1 -1
  464. package/out/zql/src/query/query-delegate-base.d.ts +1 -9
  465. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  466. package/out/zql/src/query/query-delegate-base.js +36 -132
  467. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  468. package/out/zql/src/query/query-delegate.d.ts +1 -50
  469. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  470. package/out/zql/src/query/query-impl.d.ts +14 -25
  471. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  472. package/out/zql/src/query/query-impl.js +94 -397
  473. package/out/zql/src/query/query-impl.js.map +1 -1
  474. package/out/zql/src/query/query-internals.d.ts +11 -21
  475. package/out/zql/src/query/query-internals.d.ts.map +1 -1
  476. package/out/zql/src/query/query-internals.js.map +1 -1
  477. package/out/zql/src/query/query.d.ts +2 -11
  478. package/out/zql/src/query/query.d.ts.map +1 -1
  479. package/out/zql/src/query/runnable-query-impl.d.ts +2 -3
  480. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  481. package/out/zql/src/query/runnable-query-impl.js +2 -15
  482. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  483. package/out/zql/src/query/typed-view.d.ts +1 -1
  484. package/out/zql/src/query/typed-view.d.ts.map +1 -1
  485. package/out/zqlite/src/db.d.ts +1 -9
  486. package/out/zqlite/src/db.d.ts.map +1 -1
  487. package/out/zqlite/src/db.js +2 -8
  488. package/out/zqlite/src/db.js.map +1 -1
  489. package/out/zqlite/src/query-builder.d.ts +1 -1
  490. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  491. package/out/zqlite/src/query-builder.js +2 -4
  492. package/out/zqlite/src/query-builder.js.map +1 -1
  493. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  494. package/out/zqlite/src/query-delegate.js +6 -5
  495. package/out/zqlite/src/query-delegate.js.map +1 -1
  496. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  497. package/out/zqlite/src/sqlite-cost-model.js +30 -2
  498. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  499. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  500. package/out/zqlite/src/sqlite-stat-fanout.js +5 -4
  501. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  502. package/out/zqlite/src/table-source.d.ts +3 -16
  503. package/out/zqlite/src/table-source.d.ts.map +1 -1
  504. package/out/zqlite/src/table-source.js +14 -33
  505. package/out/zqlite/src/table-source.js.map +1 -1
  506. package/package.json +3 -2
  507. package/out/replicache/src/dag/invalid-ref-count-error.d.ts +0 -12
  508. package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +0 -1
  509. package/out/replicache/src/dag/invalid-ref-count-error.js +0 -19
  510. package/out/replicache/src/dag/invalid-ref-count-error.js.map +0 -1
  511. package/out/shared/src/xxhash32.d.ts +0 -36
  512. package/out/shared/src/xxhash32.d.ts.map +0 -1
  513. package/out/shared/src/xxhash32.js +0 -51
  514. package/out/shared/src/xxhash32.js.map +0 -1
  515. package/out/zero-cache/src/db/index-predicate.d.ts +0 -4
  516. package/out/zero-cache/src/db/index-predicate.d.ts.map +0 -1
  517. package/out/zero-cache/src/db/index-predicate.js +0 -46
  518. package/out/zero-cache/src/db/index-predicate.js.map +0 -1
  519. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +0 -19
  520. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +0 -1
  521. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +0 -581
  522. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +0 -1
  523. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +0 -131
  524. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +0 -1
  525. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +0 -70
  526. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +0 -1
  527. package/out/zero-cache/src/services/litestream/litestream-controller.js +0 -101
  528. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +0 -1
  529. package/out/zero-cache/src/services/profz.d.ts +0 -7
  530. package/out/zero-cache/src/services/profz.d.ts.map +0 -1
  531. package/out/zero-cache/src/services/profz.js +0 -103
  532. package/out/zero-cache/src/services/profz.js.map +0 -1
  533. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +0 -33
  534. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +0 -1
  535. package/out/zero-cache/src/services/view-syncer/hydration-budget.js +0 -62
  536. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +0 -1
  537. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +0 -51
  538. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +0 -1
  539. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +0 -78
  540. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +0 -1
  541. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +0 -95
  542. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +0 -1
  543. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +0 -155
  544. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +0 -1
  545. package/out/zero-protocol/src/query-hash-visitor.d.ts +0 -81
  546. package/out/zero-protocol/src/query-hash-visitor.d.ts.map +0 -1
  547. package/out/zero-protocol/src/query-hash-visitor.js +0 -324
  548. package/out/zero-protocol/src/query-hash-visitor.js.map +0 -1
  549. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts +0 -43
  550. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts.map +0 -1
  551. package/out/zql/src/builder/correlated-predicate-pushdown.js +0 -161
  552. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +0 -1
  553. package/out/zql/src/ivm/connection-index.d.ts +0 -68
  554. package/out/zql/src/ivm/connection-index.d.ts.map +0 -1
  555. package/out/zql/src/ivm/connection-index.js +0 -149
  556. package/out/zql/src/ivm/connection-index.js.map +0 -1
  557. package/out/zql/src/ivm/deferred-input.d.ts +0 -44
  558. package/out/zql/src/ivm/deferred-input.d.ts.map +0 -1
  559. package/out/zql/src/ivm/deferred-input.js +0 -89
  560. package/out/zql/src/ivm/deferred-input.js.map +0 -1
  561. package/out/zql/src/planner/planner-filter.d.ts +0 -59
  562. package/out/zql/src/planner/planner-filter.d.ts.map +0 -1
  563. package/out/zql/src/planner/planner-filter.js +0 -116
  564. package/out/zql/src/planner/planner-filter.js.map +0 -1
  565. package/out/zql/src/query/query-transitions.d.ts +0 -171
  566. package/out/zql/src/query/query-transitions.d.ts.map +0 -1
  567. package/out/zql/src/query/query-transitions.js +0 -204
  568. package/out/zql/src/query/query-transitions.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"query-covering.js","names":["#byRoot","#queryIDToRoot"],"sources":["../../../../../../zero-cache/src/services/view-syncer/query-covering.ts"],"sourcesContent":["import {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {getOrInsertComputed, newMap} from '../../../../shared/src/map.ts';\nimport {\n normalizeAST,\n type AST,\n type Condition,\n type CorrelatedSubquery,\n type CorrelatedSubqueryCondition,\n type LiteralValue,\n type NormalizedAST,\n type SimpleCondition,\n} from '../../../../zero-protocol/src/ast.ts';\n\nexport type RunningQuery = {\n readonly transformedAst: AST;\n readonly transformationHash: string;\n readonly queryName?: string | undefined;\n};\n\nexport type CoveringQuery = {\n readonly queryID: string;\n readonly transformationHash: string;\n readonly queryName?: string | undefined;\n};\n\ntype NonNullScalarLiteralValue = string | number | boolean;\ntype IndexedRunningQuery = RunningQuery & {\n readonly normalizedAst: NormalizedAST;\n};\n\n/**\n * Returns true when every row that can be produced by `covered` is also\n * produced by `covering`.\n *\n * This is intentionally conservative: unsupported cases return false rather\n * than guessing. It is used for shadow logging only.\n */\nexport function isQueryCoveredBy(covered: AST, covering: AST): boolean {\n return astCoveredBy(normalizeAST(covered), normalizeAST(covering));\n}\n\nexport function findCoveringQuery(\n coveredQueryID: string,\n coveredAst: AST,\n runningQueries: ReadonlyMap<string, RunningQuery>,\n): CoveringQuery | undefined {\n return new QueryCoveringIndex(runningQueries).findCoveringQuery(\n coveredQueryID,\n coveredAst,\n );\n}\n\nexport class QueryCoveringIndex {\n readonly #byRoot = new Map<string, Map<string, IndexedRunningQuery>>();\n readonly #queryIDToRoot = new Map<string, string>();\n\n constructor(runningQueries?: ReadonlyMap<string, RunningQuery>) {\n if (runningQueries) {\n for (const [queryID, query] of runningQueries) {\n this.add(queryID, query);\n }\n }\n }\n\n add(queryID: string, query: RunningQuery): void {\n this.remove(queryID);\n\n const normalizedAst = normalizeAST(query.transformedAst);\n const root = rootKey(normalizedAst);\n getOrInsertComputed(this.#byRoot, root, newMap).set(queryID, {\n ...query,\n normalizedAst,\n });\n this.#queryIDToRoot.set(queryID, root);\n }\n\n remove(queryID: string): void {\n const root = this.#queryIDToRoot.get(queryID);\n if (root === undefined) {\n return;\n }\n\n this.#queryIDToRoot.delete(queryID);\n const queries = this.#byRoot.get(root);\n if (!queries) {\n return;\n }\n\n queries.delete(queryID);\n if (queries.size === 0) {\n this.#byRoot.delete(root);\n }\n }\n\n findCoveringQuery(\n coveredQueryID: string,\n coveredAst: AST,\n ): CoveringQuery | undefined {\n const normalizedCoveredAst = normalizeAST(coveredAst);\n const queries = this.#byRoot.get(rootKey(normalizedCoveredAst));\n if (!queries) {\n return undefined;\n }\n\n for (const [queryID, query] of queries) {\n if (queryID === coveredQueryID) {\n continue;\n }\n if (astCoveredBy(normalizedCoveredAst, query.normalizedAst)) {\n return {\n queryID,\n transformationHash: query.transformationHash,\n ...(query.queryName !== undefined && {queryName: query.queryName}),\n };\n }\n }\n return undefined;\n }\n}\n\nfunction rootKey(ast: NormalizedAST): string {\n return JSON.stringify([ast.schema, ast.table, ast.alias]);\n}\n\nfunction astCoveredBy(\n covered: NormalizedAST,\n covering: NormalizedAST,\n): boolean {\n return (\n covered.schema === covering.schema &&\n covered.table === covering.table &&\n covered.alias === covering.alias &&\n conditionImplies(covered.where, covering.where) &&\n relatedCoveredBy(covered.related, covering.related) &&\n boundsCoveredBy(covered, covering)\n );\n}\n\nfunction boundsCoveredBy(\n covered: NormalizedAST,\n covering: NormalizedAST,\n): boolean {\n if (covering.limit === undefined) {\n if (covering.start === undefined) {\n return true;\n }\n return (\n jsonEqual(covered.start, covering.start) &&\n jsonEqual(covered.orderBy, covering.orderBy)\n );\n }\n\n if (covered.limit === undefined || covering.limit < covered.limit) {\n return false;\n }\n\n // A limited broader query does not necessarily contain a limited narrower\n // query. The ordered input to the limit must be equivalent.\n return (\n conditionEquivalent(covered.where, covering.where) &&\n jsonEqual(covered.start, covering.start) &&\n jsonEqual(covered.orderBy, covering.orderBy)\n );\n}\n\nfunction relatedCoveredBy(\n covered: readonly CorrelatedSubquery[] | undefined,\n covering: readonly CorrelatedSubquery[] | undefined,\n): boolean {\n if (covered === undefined || covered.length === 0) {\n return true;\n }\n if (covering === undefined) {\n return false;\n }\n return covered.every(coveredRelated =>\n covering.some(\n coveringRelated =>\n sameRelatedEdge(coveredRelated, coveringRelated) &&\n astCoveredBy(\n coveredRelated.subquery as NormalizedAST,\n coveringRelated.subquery as NormalizedAST,\n ),\n ),\n );\n}\n\nfunction conditionEquivalent(\n a: Condition | undefined,\n b: Condition | undefined,\n): boolean {\n return conditionImplies(a, b) && conditionImplies(b, a);\n}\n\nfunction conditionImplies(\n covered: Condition | undefined,\n covering: Condition | undefined,\n): boolean {\n if (covering === undefined) {\n return true;\n }\n if (covered === undefined) {\n return false;\n }\n if (jsonEqual(covered, covering)) {\n return true;\n }\n\n if (covered.type === 'or') {\n return covered.conditions.every(c => conditionImplies(c, covering));\n }\n if (covering.type === 'or') {\n return covering.conditions.some(c => conditionImplies(covered, c));\n }\n if (covering.type === 'and') {\n return covering.conditions.every(c => conditionImplies(covered, c));\n }\n if (covered.type === 'and') {\n return covered.conditions.some(c => conditionImplies(c, covering));\n }\n if (covered.type === 'simple' && covering.type === 'simple') {\n return simpleConditionImplies(covered, covering);\n }\n if (\n covered.type === 'correlatedSubquery' &&\n covering.type === 'correlatedSubquery'\n ) {\n return correlatedConditionImplies(covered, covering);\n }\n return false;\n}\n\nfunction correlatedConditionImplies(\n covered: CorrelatedSubqueryCondition,\n covering: CorrelatedSubqueryCondition,\n): boolean {\n if (\n covered.op !== covering.op ||\n covered.scalar !== covering.scalar ||\n !sameRelatedEdge(covered.related, covering.related)\n ) {\n return false;\n }\n\n if (covered.op === 'EXISTS') {\n return astCoveredBy(\n covered.related.subquery as NormalizedAST,\n covering.related.subquery as NormalizedAST,\n );\n }\n\n return astCoveredBy(\n covering.related.subquery as NormalizedAST,\n covered.related.subquery as NormalizedAST,\n );\n}\n\nfunction sameRelatedEdge(\n a: CorrelatedSubquery,\n b: CorrelatedSubquery,\n): boolean {\n return (\n jsonEqual(a.correlation, b.correlation) &&\n a.hidden === b.hidden &&\n a.system === b.system &&\n a.subquery.alias === b.subquery.alias\n );\n}\n\nfunction simpleConditionImplies(\n covered: SimpleCondition,\n covering: SimpleCondition,\n): boolean {\n const coveredParts = columnLiteralParts(covered);\n const coveringParts = columnLiteralParts(covering);\n if (!coveredParts || !coveringParts) {\n return false;\n }\n if (coveredParts.column !== coveringParts.column) {\n return false;\n }\n\n const {op: coveredOp, value: coveredValue} = coveredParts;\n const {op: coveringOp, value: coveringValue} = coveringParts;\n\n if (isEqualityOp(coveredOp) && isNonNullScalarLiteralValue(coveredValue)) {\n return equalityImplies(coveredValue, coveringOp, coveringValue);\n }\n\n if (\n coveredOp === 'IN' &&\n coveringOp === 'IN' &&\n Array.isArray(coveredValue) &&\n Array.isArray(coveringValue)\n ) {\n return coveredValue.every(v => literalArrayIncludes(coveringValue, v));\n }\n\n if (isNumericOrderOp(coveredOp) && isNumericOrderOp(coveringOp)) {\n return orderConditionImplies(\n coveredOp,\n coveredValue,\n coveringOp,\n coveringValue,\n );\n }\n\n return false;\n}\n\nfunction equalityImplies(\n value: NonNullScalarLiteralValue,\n coveringOp: SimpleCondition['op'],\n coveringValue: LiteralValue,\n): boolean {\n switch (coveringOp) {\n case '=':\n case 'IS':\n return jsonEqual(value, coveringValue);\n case '!=':\n case 'IS NOT':\n return !jsonEqual(value, coveringValue);\n case 'IN':\n return (\n Array.isArray(coveringValue) &&\n literalArrayIncludes(coveringValue, value)\n );\n case '<':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value < coveringValue\n );\n case '<=':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value <= coveringValue\n );\n case '>':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value > coveringValue\n );\n case '>=':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value >= coveringValue\n );\n case 'NOT IN':\n case 'LIKE':\n case 'NOT LIKE':\n case 'ILIKE':\n case 'NOT ILIKE':\n return false;\n }\n}\n\nfunction orderConditionImplies(\n coveredOp: '<' | '>' | '<=' | '>=',\n coveredValue: LiteralValue,\n coveringOp: '<' | '>' | '<=' | '>=',\n coveringValue: LiteralValue,\n): boolean {\n if (typeof coveredValue !== 'number' || typeof coveringValue !== 'number') {\n return false;\n }\n\n switch (coveredOp) {\n case '>':\n return (\n (coveringOp === '>' && coveredValue >= coveringValue) ||\n (coveringOp === '>=' && coveredValue >= coveringValue)\n );\n case '>=':\n return (\n (coveringOp === '>' && coveredValue > coveringValue) ||\n (coveringOp === '>=' && coveredValue >= coveringValue)\n );\n case '<':\n return (\n (coveringOp === '<' && coveredValue <= coveringValue) ||\n (coveringOp === '<=' && coveredValue <= coveringValue)\n );\n case '<=':\n return (\n (coveringOp === '<' && coveredValue < coveringValue) ||\n (coveringOp === '<=' && coveredValue <= coveringValue)\n );\n }\n}\n\nfunction columnLiteralParts(condition: SimpleCondition):\n | {\n readonly column: string;\n readonly op: SimpleCondition['op'];\n readonly value: LiteralValue;\n }\n | undefined {\n if (condition.left.type !== 'column' || condition.right.type !== 'literal') {\n return undefined;\n }\n return {\n column: condition.left.name,\n op: condition.op,\n value: condition.right.value,\n };\n}\n\nfunction isEqualityOp(op: SimpleCondition['op']): op is '=' | 'IS' {\n return op === '=' || op === 'IS';\n}\n\nfunction isNumericOrderOp(\n op: SimpleCondition['op'],\n): op is '<' | '>' | '<=' | '>=' {\n return op === '<' || op === '>' || op === '<=' || op === '>=';\n}\n\nfunction isNonNullScalarLiteralValue(\n value: LiteralValue,\n): value is NonNullScalarLiteralValue {\n return value !== null && !Array.isArray(value);\n}\n\nfunction literalArrayIncludes(\n values: ReadonlyArray<string | number | boolean>,\n value: string | number | boolean | null,\n): boolean {\n return values.some(v => jsonEqual(v, value));\n}\n\nfunction jsonEqual(a: unknown, b: unknown): boolean {\n return deepEqual(\n a as ReadonlyJSONValue | undefined,\n b as ReadonlyJSONValue | undefined,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"query-covering.js","names":["#byRoot","#queryIDToRoot"],"sources":["../../../../../../zero-cache/src/services/view-syncer/query-covering.ts"],"sourcesContent":["import {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {\n normalizeAST,\n type AST,\n type Condition,\n type CorrelatedSubquery,\n type CorrelatedSubqueryCondition,\n type LiteralValue,\n type SimpleCondition,\n} from '../../../../zero-protocol/src/ast.ts';\n\nexport type RunningQuery = {\n readonly transformedAst: AST;\n readonly transformationHash: string;\n readonly queryName?: string | undefined;\n};\n\nexport type CoveringQuery = {\n readonly queryID: string;\n readonly transformationHash: string;\n readonly queryName?: string | undefined;\n};\n\ntype NormalizedAST = Required<AST>;\ntype NonNullScalarLiteralValue = string | number | boolean;\ntype IndexedRunningQuery = RunningQuery & {\n readonly normalizedAst: NormalizedAST;\n};\n\n/**\n * Returns true when every row that can be produced by `covered` is also\n * produced by `covering`.\n *\n * This is intentionally conservative: unsupported cases return false rather\n * than guessing. It is used for shadow logging only.\n */\nexport function isQueryCoveredBy(covered: AST, covering: AST): boolean {\n return astCoveredBy(normalizeAST(covered), normalizeAST(covering));\n}\n\nexport function findCoveringQuery(\n coveredQueryID: string,\n coveredAst: AST,\n runningQueries: ReadonlyMap<string, RunningQuery>,\n): CoveringQuery | undefined {\n return new QueryCoveringIndex(runningQueries).findCoveringQuery(\n coveredQueryID,\n coveredAst,\n );\n}\n\nexport class QueryCoveringIndex {\n readonly #byRoot = new Map<string, Map<string, IndexedRunningQuery>>();\n readonly #queryIDToRoot = new Map<string, string>();\n\n constructor(runningQueries?: ReadonlyMap<string, RunningQuery>) {\n if (runningQueries) {\n for (const [queryID, query] of runningQueries) {\n this.add(queryID, query);\n }\n }\n }\n\n add(queryID: string, query: RunningQuery): void {\n this.remove(queryID);\n\n const normalizedAst = normalizeAST(query.transformedAst);\n const root = rootKey(normalizedAst);\n let queries = this.#byRoot.get(root);\n if (!queries) {\n queries = new Map();\n this.#byRoot.set(root, queries);\n }\n queries.set(queryID, {...query, normalizedAst});\n this.#queryIDToRoot.set(queryID, root);\n }\n\n remove(queryID: string): void {\n const root = this.#queryIDToRoot.get(queryID);\n if (root === undefined) {\n return;\n }\n\n this.#queryIDToRoot.delete(queryID);\n const queries = this.#byRoot.get(root);\n if (!queries) {\n return;\n }\n\n queries.delete(queryID);\n if (queries.size === 0) {\n this.#byRoot.delete(root);\n }\n }\n\n findCoveringQuery(\n coveredQueryID: string,\n coveredAst: AST,\n ): CoveringQuery | undefined {\n const normalizedCoveredAst = normalizeAST(coveredAst);\n const queries = this.#byRoot.get(rootKey(normalizedCoveredAst));\n if (!queries) {\n return undefined;\n }\n\n for (const [queryID, query] of queries) {\n if (queryID === coveredQueryID) {\n continue;\n }\n if (astCoveredBy(normalizedCoveredAst, query.normalizedAst)) {\n return {\n queryID,\n transformationHash: query.transformationHash,\n ...(query.queryName !== undefined && {queryName: query.queryName}),\n };\n }\n }\n return undefined;\n }\n}\n\nfunction rootKey(ast: NormalizedAST): string {\n return JSON.stringify([ast.schema, ast.table, ast.alias]);\n}\n\nfunction astCoveredBy(\n covered: NormalizedAST,\n covering: NormalizedAST,\n): boolean {\n return (\n covered.schema === covering.schema &&\n covered.table === covering.table &&\n covered.alias === covering.alias &&\n conditionImplies(covered.where, covering.where) &&\n relatedCoveredBy(covered.related, covering.related) &&\n boundsCoveredBy(covered, covering)\n );\n}\n\nfunction boundsCoveredBy(\n covered: NormalizedAST,\n covering: NormalizedAST,\n): boolean {\n if (covering.limit === undefined) {\n if (covering.start === undefined) {\n return true;\n }\n return (\n jsonEqual(covered.start, covering.start) &&\n jsonEqual(covered.orderBy, covering.orderBy)\n );\n }\n\n if (covered.limit === undefined || covering.limit < covered.limit) {\n return false;\n }\n\n // A limited broader query does not necessarily contain a limited narrower\n // query. The ordered input to the limit must be equivalent.\n return (\n conditionEquivalent(covered.where, covering.where) &&\n jsonEqual(covered.start, covering.start) &&\n jsonEqual(covered.orderBy, covering.orderBy)\n );\n}\n\nfunction relatedCoveredBy(\n covered: readonly CorrelatedSubquery[] | undefined,\n covering: readonly CorrelatedSubquery[] | undefined,\n): boolean {\n if (covered === undefined || covered.length === 0) {\n return true;\n }\n if (covering === undefined) {\n return false;\n }\n return covered.every(coveredRelated =>\n covering.some(\n coveringRelated =>\n sameRelatedEdge(coveredRelated, coveringRelated) &&\n astCoveredBy(\n coveredRelated.subquery as NormalizedAST,\n coveringRelated.subquery as NormalizedAST,\n ),\n ),\n );\n}\n\nfunction conditionEquivalent(\n a: Condition | undefined,\n b: Condition | undefined,\n): boolean {\n return conditionImplies(a, b) && conditionImplies(b, a);\n}\n\nfunction conditionImplies(\n covered: Condition | undefined,\n covering: Condition | undefined,\n): boolean {\n if (covering === undefined) {\n return true;\n }\n if (covered === undefined) {\n return false;\n }\n if (jsonEqual(covered, covering)) {\n return true;\n }\n\n if (covered.type === 'or') {\n return covered.conditions.every(c => conditionImplies(c, covering));\n }\n if (covering.type === 'or') {\n return covering.conditions.some(c => conditionImplies(covered, c));\n }\n if (covering.type === 'and') {\n return covering.conditions.every(c => conditionImplies(covered, c));\n }\n if (covered.type === 'and') {\n return covered.conditions.some(c => conditionImplies(c, covering));\n }\n if (covered.type === 'simple' && covering.type === 'simple') {\n return simpleConditionImplies(covered, covering);\n }\n if (\n covered.type === 'correlatedSubquery' &&\n covering.type === 'correlatedSubquery'\n ) {\n return correlatedConditionImplies(covered, covering);\n }\n return false;\n}\n\nfunction correlatedConditionImplies(\n covered: CorrelatedSubqueryCondition,\n covering: CorrelatedSubqueryCondition,\n): boolean {\n if (\n covered.op !== covering.op ||\n covered.scalar !== covering.scalar ||\n !sameRelatedEdge(covered.related, covering.related)\n ) {\n return false;\n }\n\n if (covered.op === 'EXISTS') {\n return astCoveredBy(\n covered.related.subquery as NormalizedAST,\n covering.related.subquery as NormalizedAST,\n );\n }\n\n return astCoveredBy(\n covering.related.subquery as NormalizedAST,\n covered.related.subquery as NormalizedAST,\n );\n}\n\nfunction sameRelatedEdge(\n a: CorrelatedSubquery,\n b: CorrelatedSubquery,\n): boolean {\n return (\n jsonEqual(a.correlation, b.correlation) &&\n a.hidden === b.hidden &&\n a.system === b.system &&\n a.subquery.alias === b.subquery.alias\n );\n}\n\nfunction simpleConditionImplies(\n covered: SimpleCondition,\n covering: SimpleCondition,\n): boolean {\n const coveredParts = columnLiteralParts(covered);\n const coveringParts = columnLiteralParts(covering);\n if (!coveredParts || !coveringParts) {\n return false;\n }\n if (coveredParts.column !== coveringParts.column) {\n return false;\n }\n\n const {op: coveredOp, value: coveredValue} = coveredParts;\n const {op: coveringOp, value: coveringValue} = coveringParts;\n\n if (isEqualityOp(coveredOp) && isNonNullScalarLiteralValue(coveredValue)) {\n return equalityImplies(coveredValue, coveringOp, coveringValue);\n }\n\n if (\n coveredOp === 'IN' &&\n coveringOp === 'IN' &&\n Array.isArray(coveredValue) &&\n Array.isArray(coveringValue)\n ) {\n return coveredValue.every(v => literalArrayIncludes(coveringValue, v));\n }\n\n if (isNumericOrderOp(coveredOp) && isNumericOrderOp(coveringOp)) {\n return orderConditionImplies(\n coveredOp,\n coveredValue,\n coveringOp,\n coveringValue,\n );\n }\n\n return false;\n}\n\nfunction equalityImplies(\n value: NonNullScalarLiteralValue,\n coveringOp: SimpleCondition['op'],\n coveringValue: LiteralValue,\n): boolean {\n switch (coveringOp) {\n case '=':\n case 'IS':\n return jsonEqual(value, coveringValue);\n case '!=':\n case 'IS NOT':\n return !jsonEqual(value, coveringValue);\n case 'IN':\n return (\n Array.isArray(coveringValue) &&\n literalArrayIncludes(coveringValue, value)\n );\n case '<':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value < coveringValue\n );\n case '<=':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value <= coveringValue\n );\n case '>':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value > coveringValue\n );\n case '>=':\n return (\n typeof value === 'number' &&\n typeof coveringValue === 'number' &&\n value >= coveringValue\n );\n case 'NOT IN':\n case 'LIKE':\n case 'NOT LIKE':\n case 'ILIKE':\n case 'NOT ILIKE':\n return false;\n }\n}\n\nfunction orderConditionImplies(\n coveredOp: '<' | '>' | '<=' | '>=',\n coveredValue: LiteralValue,\n coveringOp: '<' | '>' | '<=' | '>=',\n coveringValue: LiteralValue,\n): boolean {\n if (typeof coveredValue !== 'number' || typeof coveringValue !== 'number') {\n return false;\n }\n\n switch (coveredOp) {\n case '>':\n return (\n (coveringOp === '>' && coveredValue >= coveringValue) ||\n (coveringOp === '>=' && coveredValue >= coveringValue)\n );\n case '>=':\n return (\n (coveringOp === '>' && coveredValue > coveringValue) ||\n (coveringOp === '>=' && coveredValue >= coveringValue)\n );\n case '<':\n return (\n (coveringOp === '<' && coveredValue <= coveringValue) ||\n (coveringOp === '<=' && coveredValue <= coveringValue)\n );\n case '<=':\n return (\n (coveringOp === '<' && coveredValue < coveringValue) ||\n (coveringOp === '<=' && coveredValue <= coveringValue)\n );\n }\n}\n\nfunction columnLiteralParts(condition: SimpleCondition):\n | {\n readonly column: string;\n readonly op: SimpleCondition['op'];\n readonly value: LiteralValue;\n }\n | undefined {\n if (condition.left.type !== 'column' || condition.right.type !== 'literal') {\n return undefined;\n }\n return {\n column: condition.left.name,\n op: condition.op,\n value: condition.right.value,\n };\n}\n\nfunction isEqualityOp(op: SimpleCondition['op']): op is '=' | 'IS' {\n return op === '=' || op === 'IS';\n}\n\nfunction isNumericOrderOp(\n op: SimpleCondition['op'],\n): op is '<' | '>' | '<=' | '>=' {\n return op === '<' || op === '>' || op === '<=' || op === '>=';\n}\n\nfunction isNonNullScalarLiteralValue(\n value: LiteralValue,\n): value is NonNullScalarLiteralValue {\n return value !== null && !Array.isArray(value);\n}\n\nfunction literalArrayIncludes(\n values: ReadonlyArray<string | number | boolean>,\n value: string | number | boolean | null,\n): boolean {\n return values.some(v => jsonEqual(v, value));\n}\n\nfunction jsonEqual(a: unknown, b: unknown): boolean {\n return deepEqual(\n a as ReadonlyJSONValue | undefined,\n b as ReadonlyJSONValue | undefined,\n );\n}\n"],"mappings":"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"}
@@ -6,7 +6,6 @@ import type { LiteAndZqlSpec, LiteTableSpecWithKeysAndVersion } from '../../db/s
6
6
  import { StatementRunner } from '../../db/statements.ts';
7
7
  import { type RowKey, type RowValue } from '../../types/row-key.ts';
8
8
  import type { AppID } from '../../types/shards.ts';
9
- import type { SnapshotRowCache } from './snapshot-row-cache.ts';
10
9
  /**
11
10
  * A `Snapshotter` manages the progression of database snapshots for a
12
11
  * ViewSyncer.
@@ -68,13 +67,7 @@ import type { SnapshotRowCache } from './snapshot-row-cache.ts';
68
67
  */
69
68
  export declare class Snapshotter {
70
69
  #private;
71
- /**
72
- * @param rowCache An optional worker-wide {@link SnapshotRowCache} through
73
- * which the row reads performed when iterating over a
74
- * {@link SnapshotDiff} are shared with the other Snapshotters
75
- * (i.e. client groups) on the worker.
76
- */
77
- constructor(lc: LogContext, dbFile: string, { appID }: AppID, pageCacheSizeKib?: number, rowCache?: SnapshotRowCache);
70
+ constructor(lc: LogContext, dbFile: string, { appID }: AppID, pageCacheSizeKib?: number);
78
71
  /**
79
72
  * Initializes the snapshot to the current head of the database. This must be
80
73
  * only be called once. The state of whether a Snapshotter has been initialized
@@ -121,7 +114,7 @@ export declare class Snapshotter {
121
114
  * on `prev` before each iteration, and (2) rollback to the save point after
122
115
  * the iteration.
123
116
  */
124
- advance(syncableTables: Map<string, LiteAndZqlSpec>, allTableNames: Set<string>, observedTables?: TableFilter | undefined): SnapshotDiff;
117
+ advance(syncableTables: Map<string, LiteAndZqlSpec>, allTableNames: Set<string>): SnapshotDiff;
125
118
  advanceWithoutDiff(): {
126
119
  prev: Snapshot;
127
120
  curr: Snapshot;
@@ -144,9 +137,6 @@ export type Change = {
144
137
  readonly nextValue: Readonly<Row> | null;
145
138
  readonly rowKey: RowKey;
146
139
  };
147
- export interface TableFilter {
148
- has(table: string): boolean;
149
- }
150
140
  /**
151
141
  * Represents the difference between two database Snapshots.
152
142
  * Iterating over the object will produce a sequence of {@link Change}s
@@ -194,40 +184,12 @@ declare class Snapshot {
194
184
  readonly version: string;
195
185
  constructor(db: StatementRunner, appID: string);
196
186
  numChangesSince(prevVersion: string): any;
197
- /**
198
- * Whether any table-wide op (i.e. a RESET or TRUNCATE) was logged after
199
- * `prevVersion`. Iterating over a diff ending at this snapshot will
200
- * abort with a {@link ResetPipelinesSignal} if so.
201
- */
202
- hasTableWideOpSince(prevVersion: string): boolean;
203
187
  changesSince(prevVersion: string): {
204
188
  changes: IterableIterator<unknown>;
205
189
  cleanup: () => void;
206
190
  };
207
- /**
208
- * Reads the row with the given `rowKey`, or `undefined` if it does not
209
- * exist.
210
- *
211
- * @param cache An optional {@link SnapshotRowCache} through which to
212
- * perform the read, along with the `tag` that identifies the
213
- * version(s) of the replica that the result depends on.
214
- */
215
- getRow(table: LiteTableSpecWithKeysAndVersion, rowKey: JSONValue, cache?: SnapshotRowCache, tag?: string): any;
216
- /**
217
- * Reads the rows that conflict with `row` on any of the given unique
218
- * `keys` (which includes the row with the same primary key, if any).
219
- *
220
- * @param cache An optional {@link SnapshotRowCache} through which to
221
- * perform the read, along with the `tag` that identifies the
222
- * version(s) of the replica that the result depends on.
223
- */
224
- getRows(table: LiteTableSpecWithKeysAndVersion, keys: PrimaryKey[], row: RowValue, cache?: SnapshotRowCache, tag?: string): any[];
225
- /**
226
- * Whether the connection has been reset to a newer snapshot (i.e. via
227
- * {@link resetToHead()}), after which reads no longer reflect
228
- * {@link version}.
229
- */
230
- get reset(): boolean;
191
+ getRow(table: LiteTableSpecWithKeysAndVersion, rowKey: JSONValue): any;
192
+ getRows(table: LiteTableSpecWithKeysAndVersion, keys: PrimaryKey[], row: RowValue): any[];
231
193
  resetToHead(): Snapshot;
232
194
  }
233
195
  export declare class InvalidDiffError extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { assert } from "../../../../shared/src/asserts.js";
2
2
  import { parse } from "../../../../shared/src/valita.js";
3
- import { getOrInsertComputed } from "../../../../shared/src/map.js";
4
3
  import { stringify } from "../../../../shared/src/bigint-json.js";
5
4
  import { Database } from "../../../../zqlite/src/db.js";
6
5
  import { fromSQLiteTypes } from "../../../../zqlite/src/table-source.js";
@@ -75,21 +74,13 @@ var Snapshotter = class {
75
74
  #dbFile;
76
75
  #appID;
77
76
  #pageCacheSizeKib;
78
- #rowCache;
79
77
  #curr;
80
78
  #prev;
81
- /**
82
- * @param rowCache An optional worker-wide {@link SnapshotRowCache} through
83
- * which the row reads performed when iterating over a
84
- * {@link SnapshotDiff} are shared with the other Snapshotters
85
- * (i.e. client groups) on the worker.
86
- */
87
- constructor(lc, dbFile, { appID }, pageCacheSizeKib, rowCache) {
79
+ constructor(lc, dbFile, { appID }, pageCacheSizeKib) {
88
80
  this.#lc = lc;
89
81
  this.#dbFile = dbFile;
90
82
  this.#appID = appID;
91
83
  this.#pageCacheSizeKib = pageCacheSizeKib;
92
- this.#rowCache = rowCache;
93
84
  }
94
85
  /**
95
86
  * Initializes the snapshot to the current head of the database. This must be
@@ -147,9 +138,9 @@ var Snapshotter = class {
147
138
  * on `prev` before each iteration, and (2) rollback to the save point after
148
139
  * the iteration.
149
140
  */
150
- advance(syncableTables, allTableNames, observedTables) {
141
+ advance(syncableTables, allTableNames) {
151
142
  const { prev, curr } = this.advanceWithoutDiff();
152
- return new Diff(this.#appID, syncableTables, allTableNames, prev, curr, observedTables, this.#rowCache);
143
+ return new Diff(this.#appID, syncableTables, allTableNames, prev, curr);
153
144
  }
154
145
  advanceWithoutDiff() {
155
146
  assert(this.#curr !== void 0, "Snapshotter has not been initialized");
@@ -179,15 +170,6 @@ var ResetPipelinesSignal = class extends Error {
179
170
  this.reason = reason;
180
171
  }
181
172
  };
182
- var tableReads = /* @__PURE__ */ new WeakMap();
183
- function readsFor(table) {
184
- return getOrInsertComputed(tableReads, table, () => ({
185
- prefix: `SELECT ${Object.keys(table.columns).map((c) => id(c)).join(",")} FROM ${id(table.name)} WHERE `,
186
- byKeyColumns: /* @__PURE__ */ new Map(),
187
- byUniqueKeys: /* @__PURE__ */ new Map()
188
- }));
189
- }
190
- var MAX_MEMOIZED_UNIQUE_KEYS = 30;
191
173
  var Snapshot = class Snapshot {
192
174
  static create(lc, dbFile, appID, pageCacheSizeKib) {
193
175
  const conn = new Database(lc, dbFile);
@@ -200,7 +182,6 @@ var Snapshot = class Snapshot {
200
182
  db;
201
183
  #appID;
202
184
  version;
203
- #reset = false;
204
185
  constructor(db, appID) {
205
186
  db.beginConcurrent();
206
187
  const { stateVersion } = getReplicationState(db);
@@ -212,14 +193,6 @@ var Snapshot = class Snapshot {
212
193
  const { count } = this.db.get("SELECT COUNT(*) AS count FROM \"_zero.changeLog2\" WHERE stateVersion > ?", prevVersion);
213
194
  return count;
214
195
  }
215
- /**
216
- * Whether any table-wide op (i.e. a RESET or TRUNCATE) was logged after
217
- * `prevVersion`. Iterating over a diff ending at this snapshot will
218
- * abort with a {@link ResetPipelinesSignal} if so.
219
- */
220
- hasTableWideOpSince(prevVersion) {
221
- return this.db.get("SELECT 1 FROM \"_zero.changeLog2\" WHERE stateVersion > ? AND op IN (?, ?) LIMIT 1", prevVersion, "r", "t") !== void 0;
222
- }
223
196
  changesSince(prevVersion) {
224
197
  const cached = this.db.statementCache.get(`SELECT "stateVersion", "table", "rowKey", "op" FROM "_zero.changeLog2"
225
198
  WHERE "stateVersion" > ? ORDER BY "stateVersion" ASC, "pos" ASC`);
@@ -228,83 +201,32 @@ var Snapshot = class Snapshot {
228
201
  cleanup: () => this.db.statementCache.return(cached)
229
202
  };
230
203
  }
231
- /**
232
- * Reads the row with the given `rowKey`, or `undefined` if it does not
233
- * exist.
234
- *
235
- * @param cache An optional {@link SnapshotRowCache} through which to
236
- * perform the read, along with the `tag` that identifies the
237
- * version(s) of the replica that the result depends on.
238
- */
239
- getRow(table, rowKey, cache, tag) {
204
+ getRow(table, rowKey) {
240
205
  const key = normalizedKeyOrder(rowKey);
241
- const cols = Object.keys(key);
242
- const reads = readsFor(table);
243
- const sql = getOrInsertComputed(reads.byKeyColumns, cols.join("\0"), () => reads.prefix + cols.map((c) => `${id(c)}=?`).join(" AND "));
244
- const args = Object.values(key);
245
- const read = () => this.db.statementCache.use(sql, (cached) => {
246
- cached.statement.safeIntegers(true);
247
- return cached.statement.get(args);
248
- });
249
- return cache ? cache.getOrRead(tag ?? "", sql, "get", args, () => {
250
- const row = read();
251
- if (row !== void 0) this.#assertNotAdvanced(row);
252
- return row;
253
- }) : read();
254
- }
255
- /**
256
- * Reads the rows that conflict with `row` on any of the given unique
257
- * `keys` (which includes the row with the same primary key, if any).
258
- *
259
- * @param cache An optional {@link SnapshotRowCache} through which to
260
- * perform the read, along with the `tag` that identifies the
261
- * version(s) of the replica that the result depends on.
262
- */
263
- getRows(table, keys, row, cache, tag) {
264
- const validKeys = [];
265
- let mask = 0;
266
- for (let i = 0; i < keys.length; i++) {
267
- const key = keys[i];
268
- if (key.every((column) => row[column] !== null && row[column] !== void 0)) {
269
- validKeys.push(key);
270
- mask |= 1 << i;
271
- }
206
+ const conds = Object.keys(key).map((c) => `${id(c)}=?`);
207
+ const cols = Object.keys(table.columns);
208
+ const cached = this.db.statementCache.get(`SELECT ${cols.map((c) => id(c)).join(",")} FROM ${id(table.name)} WHERE ${conds.join(" AND ")}`);
209
+ cached.statement.safeIntegers(true);
210
+ try {
211
+ return cached.statement.get(Object.values(key));
212
+ } finally {
213
+ this.db.statementCache.return(cached);
272
214
  }
273
- if (validKeys.length === 0) return [];
274
- const reads = readsFor(table);
275
- const buildSQL = () => reads.prefix + validKeys.map((key) => key.map((c) => `${id(c)}=?`).join(" AND ")).join(" OR ");
276
- const sql = keys === table.uniqueKeys && keys.length <= MAX_MEMOIZED_UNIQUE_KEYS ? getOrInsertComputed(reads.byUniqueKeys, mask, buildSQL) : buildSQL();
277
- const args = validKeys.flatMap((key) => key.map((column) => row[column]));
278
- const read = () => this.db.statementCache.use(sql, (cached) => {
279
- cached.statement.safeIntegers(true);
280
- return cached.statement.all(args);
281
- });
282
- return cache ? cache.getOrRead(tag ?? "", sql, "all", args, () => {
283
- const rows = read();
284
- for (const row of rows) this.#assertNotAdvanced(row);
285
- return rows;
286
- }) : read();
287
- }
288
- /**
289
- * Rows are shared with other client groups via the SnapshotRowCache, so
290
- * one read from a connection that has advanced past this snapshot (i.e. a
291
- * {@link SnapshotDiff} used after its Snapshotter advanced) must fail
292
- * before it is cached, rather than be served to the valid Diffs of other
293
- * client groups (whose own validity checks would then fail).
294
- */
295
- #assertNotAdvanced(row) {
296
- if ((row["_0_version"] ?? "~") > this.version) throw new InvalidDiffError(`Diff is no longer valid. db has advanced past ${this.version}.`);
297
215
  }
298
- /**
299
- * Whether the connection has been reset to a newer snapshot (i.e. via
300
- * {@link resetToHead()}), after which reads no longer reflect
301
- * {@link version}.
302
- */
303
- get reset() {
304
- return this.#reset;
216
+ getRows(table, keys, row) {
217
+ const validKeys = keys.filter((key) => key.every((column) => row[column] !== null && row[column] !== void 0));
218
+ if (validKeys.length === 0) return [];
219
+ const conds = validKeys.map((key) => key.map((c) => `${id(c)}=?`));
220
+ const cols = Object.keys(table.columns);
221
+ const cached = this.db.statementCache.get(`SELECT ${cols.map((c) => id(c)).join(",")} FROM ${id(table.name)} WHERE ${conds.map((cond) => cond.join(" AND ")).join(" OR ")}`);
222
+ cached.statement.safeIntegers(true);
223
+ try {
224
+ return cached.statement.all(validKeys.flatMap((key) => key.map((column) => row[column])));
225
+ } finally {
226
+ this.db.statementCache.return(cached);
227
+ }
305
228
  }
306
229
  resetToHead() {
307
- this.#reset = true;
308
230
  this.db.rollback();
309
231
  return new Snapshot(this.db, this.#appID);
310
232
  }
@@ -313,20 +235,16 @@ var Diff = class {
313
235
  #permissionsTable;
314
236
  #syncableTables;
315
237
  #allTableNames;
316
- #observedTables;
317
- #rowCache;
318
238
  prev;
319
239
  curr;
320
240
  changes;
321
- constructor(appID, syncableTables, allTableNames, prev, curr, observedTables, rowCache) {
241
+ constructor(appID, syncableTables, allTableNames, prev, curr) {
322
242
  this.#permissionsTable = `${appID}.permissions`;
323
243
  this.#syncableTables = syncableTables;
324
244
  this.#allTableNames = allTableNames;
325
- this.#observedTables = observedTables;
326
245
  this.prev = prev;
327
246
  this.curr = curr;
328
247
  this.changes = curr.numChangesSince(prev.version);
329
- this.#rowCache = rowCache && !curr.hasTableWideOpSince(prev.version) ? rowCache : void 0;
330
248
  }
331
249
  [Symbol.iterator]() {
332
250
  const { changes, cleanup: done } = this.curr.changesSince(this.prev.version);
@@ -352,10 +270,6 @@ var Diff = class {
352
270
  const { table, rowKey, op, stateVersion } = parse(value, changeLogEntrySchema);
353
271
  if (op === "r") throw new ResetPipelinesSignal(`schema for table ${table} has changed`, "schema-change");
354
272
  if (op === "t") throw new ResetPipelinesSignal(`table ${table} has been truncated`, "truncation");
355
- if (this.#observedTables && !this.#observedTables.has(table) && table !== this.#permissionsTable) {
356
- if (this.#allTableNames.has(table)) continue;
357
- throw new Error(`change for unknown table ${table}`);
358
- }
359
273
  const specs = this.#syncableTables.get(table);
360
274
  if (!specs) {
361
275
  if (this.#allTableNames.has(table)) continue;
@@ -364,14 +278,11 @@ var Diff = class {
364
278
  const { tableSpec, zqlSpec } = specs;
365
279
  assert((tableSpec.minRowVersion ?? "") < stateVersion, () => `unexpected change @${stateVersion} for table ${table} with minRowVersion ${tableSpec.minRowVersion}: ${op}(${rowKey})`);
366
280
  assert(rowKey !== null, "rowKey must be present for row changes");
367
- if (this.prev.reset) throw new InvalidDiffError(`Diff is no longer valid. prev db has advanced past ${this.prev.version}.`);
368
- const cache = this.#rowCache;
369
- const prevTag = tableSpec.uniqueKeys.length <= 1 ? `p:${this.prev.version}` : `p:${this.prev.version}:${this.curr.version}`;
370
- const nextValue = op === "s" ? this.curr.getRow(tableSpec, rowKey, cache, `n:${stateVersion}`) : null;
281
+ const nextValue = op === "s" ? this.curr.getRow(tableSpec, rowKey) : null;
371
282
  let prevValues;
372
- if (nextValue) prevValues = this.prev.getRows(tableSpec, tableSpec.uniqueKeys, nextValue, cache, prevTag);
283
+ if (nextValue) prevValues = this.prev.getRows(tableSpec, tableSpec.uniqueKeys, nextValue);
373
284
  else {
374
- const prevValue = this.prev.getRow(tableSpec, rowKey, cache, prevTag);
285
+ const prevValue = this.prev.getRow(tableSpec, rowKey);
375
286
  prevValues = prevValue ? [prevValue] : [];
376
287
  }
377
288
  if (nextValue === void 0) throw new Error(`Missing value for ${table} ${stringify(rowKey)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotter.js","names":["#lc","#dbFile","#appID","#pageCacheSizeKib","#rowCache","#curr","#prev","#assertNotAdvanced","#reset","#permissionsTable","#syncableTables","#allTableNames","#observedTables"],"sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../../shared/src/bigint-json.ts';\nimport {getOrInsertComputed} from '../../../../shared/src/map.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-types/src/schema.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {fromSQLiteTypes} from '../../../../zqlite/src/table-source.ts';\nimport type {\n LiteAndZqlSpec,\n LiteTableSpecWithKeysAndVersion,\n} from '../../db/specs.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {\n normalizedKeyOrder,\n type RowKey,\n type RowValue,\n} from '../../types/row-key.ts';\nimport type {AppID} from '../../types/shards.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n RESET_OP,\n changeLogEntrySchema as schema,\n SET_OP,\n TRUNCATE_OP,\n} from '../replicator/schema/change-log.ts';\nimport {\n getReplicationState,\n ZERO_VERSION_COLUMN_NAME as ROW_VERSION,\n} from '../replicator/schema/replication-state.ts';\nimport type {SnapshotRowCache} from './snapshot-row-cache.ts';\n\n/**\n * A `Snapshotter` manages the progression of database snapshots for a\n * ViewSyncer.\n *\n * The Replicator and ViewSyncers operate on the same SQLite file, with the\n * Replicator being the sole writer to the database. The IVM logic in\n * ViewSyncers, however, rely on incrementally applying changes to the DB to\n * update the state of its pipelines.\n *\n * To avoid coupling the progress of the Replicator and all IVM pipelines on\n * each other, ViewSyncers operate on ephemeral forks of the database by holding\n * [concurrent](https://sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md)\n * snapshots of the database and simulating (but ultimately rolling back)\n * mutations on these snapshots.\n *\n * Example:\n * 1. ViewSyncer takes `snapshot_a` at version `t1` of the database and\n * hydrates its pipeline(s).\n * 2. Replicator applies a new transaction to the database and notifies\n * subscribers.\n * 3. ViewSyncer takes `snapshot_b` at `t2`, and queries the `ChangeLog` at\n * that snapshot for changes since `t1`.\n * 4. ViewSyncer applies those changes to `snapshot_a` for IVM, but does not\n * commit them. (Recall that the Replicator is the sole writer to the db, so\n * the ViewSyncer never commits any writes.)\n * 5. Replicator applies the next transaction and advances the database to `t3`.\n * 6. ViewSyncer rolls back `snapshot_a` and opens `snapshot_c` at `t3`, using\n * `snapshot_b` to simulate changes from `t2` to `t3`.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ```\n *\n * Note that the Replicator (and ViewSyncers) do not wait on the progress of\n * other ViewSyncers. If a ViewSyncer is busy hydrating at `t1`, the Replicator\n * and other ViewSyncers can progress through `t2`, `t3`, etc. independently,\n * as the busy ViewSyncer simply takes its own snapshot when it is ready.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer1: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ViewSyncer2: [.......... snapshot_a ..........] ----> [snapshot_b]\n * ```\n *\n * To minimize Database connections (and statement preparation, etc.), the\n * Snapshotter reuses the connection from the previous (rolled back)\n * snapshot when opening the new one.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * (conn_1) (conn_2) (conn_1)\n * ```\n *\n * In this manner, each ViewSyncer uses two connections that continually\n * \"leapfrog\" each other to replay the timeline of changes in isolation from\n * the Replicator and other ViewSyncers.\n */\nexport class Snapshotter {\n readonly #lc: LogContext;\n readonly #dbFile: string;\n readonly #appID: string;\n readonly #pageCacheSizeKib: number | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n #curr: Snapshot | undefined;\n #prev: Snapshot | undefined;\n\n /**\n * @param rowCache An optional worker-wide {@link SnapshotRowCache} through\n * which the row reads performed when iterating over a\n * {@link SnapshotDiff} are shared with the other Snapshotters\n * (i.e. client groups) on the worker.\n */\n constructor(\n lc: LogContext,\n dbFile: string,\n {appID}: AppID,\n pageCacheSizeKib?: number,\n rowCache?: SnapshotRowCache,\n ) {\n this.#lc = lc;\n this.#dbFile = dbFile;\n this.#appID = appID;\n this.#pageCacheSizeKib = pageCacheSizeKib;\n this.#rowCache = rowCache;\n }\n\n /**\n * Initializes the snapshot to the current head of the database. This must be\n * only be called once. The state of whether a Snapshotter has been initialized\n * can be determined by calling {@link initialized()}.\n */\n init(): this {\n assert(this.#curr === undefined, 'Already initialized');\n this.#curr = Snapshot.create(\n this.#lc,\n this.#dbFile,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#lc.debug?.(`Initial snapshot at version ${this.#curr.version}`);\n return this;\n }\n\n initialized(): boolean {\n return this.#curr !== undefined;\n }\n\n /** Returns the current snapshot. Asserts if {@link initialized()} is false. */\n current(): Snapshot {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n return this.#curr;\n }\n\n /**\n * Advances to the head of the Database, returning a diff between the\n * previously current Snapshot and a new Snapshot at head. This is called\n * in response to a notification from a Replicator subscription. Subsequent\n * calls to {@link current()} return the new Snapshot. Note that the Snapshotter\n * must be initialized before advancing.\n *\n * The returned {@link SnapshotDiff} contains snapshots at the endpoints\n * of the database timeline. Iterating over the diff generates a sequence\n * of {@link Change}s between the two snapshots.\n *\n * Note that this sequence is not chronological; rather, the sequence is\n * ordered by `<table, row-key>`, such that a row can appear at most once\n * in the common case, or twice if its table is `TRUNCATE`'d and a new value\n * is subsequently `INSERT`'ed. This results in dropping most intermediate\n * changes to a row and bounds the amount of work needed to catch up;\n * however, as a consequence, a consistent database state is only guaranteed\n * when the sequence has been fully consumed.\n *\n * Note that Change generation relies on the state of the underlying\n * database connections, and because the connection for the previous snapshot\n * is reused to produce the next snapshot, the diff object is only valid\n * until the next call to `advance()`.\n *\n * It is okay for the caller to apply `Change`s to the `prev` snapshot\n * during the iteration (e.g. this is necessary for IVM); the remainder\n * of the iteration is not affected because a given row can appear at most\n * once in the sequence (with the exception being TRUNCATE, after which the\n * deleted rows can be re-inserted, but this will also behave correctly if\n * the changes are applied).\n *\n * Once the changes have been applied, however, a _subsequent_ iteration\n * will not produce the correct results. In order to perform multiple\n * change-applying iterations, the caller must (1) create a save point\n * on `prev` before each iteration, and (2) rollback to the save point after\n * the iteration.\n */\n advance(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n observedTables?: TableFilter | undefined,\n ): SnapshotDiff {\n const {prev, curr} = this.advanceWithoutDiff();\n return new Diff(\n this.#appID,\n syncableTables,\n allTableNames,\n prev,\n curr,\n observedTables,\n this.#rowCache,\n );\n }\n\n advanceWithoutDiff() {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n const next = this.#prev\n ? this.#prev.resetToHead()\n : Snapshot.create(\n this.#lc,\n this.#curr.db.db.name,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#prev = this.#curr;\n this.#curr = next;\n return {prev: this.#prev, curr: this.#curr};\n }\n\n /**\n * Call this to close the database connections when the Snapshotter is\n * no longer needed.\n */\n destroy() {\n this.#curr?.db.db.close();\n this.#prev?.db.db.close();\n this.#lc.debug?.('closed database connections');\n }\n}\n\nexport type Change = {\n readonly table: string;\n /**\n * If this change represents a remove the row to remove,\n * if nextValue is not null then all rows that have a unique constraint\n * violation with nextValue.\n * In both cases these rows should be removed.\n */\n readonly prevValues: Readonly<Row>[];\n readonly nextValue: Readonly<Row> | null;\n readonly rowKey: RowKey;\n};\n\nexport interface TableFilter {\n has(table: string): boolean;\n}\n\n/**\n * Represents the difference between two database Snapshots.\n * Iterating over the object will produce a sequence of {@link Change}s\n * between the two snapshots.\n *\n * See {@link Snapshotter.advance()} for semantics and usage.\n */\nexport interface SnapshotDiff extends Iterable<Change> {\n readonly prev: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n readonly curr: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n\n /**\n * The number of ChangeLog entries between the snapshots. Note that this\n * may not necessarily equal the number of `Change` objects that the iteration\n * will produce, as `TRUNCATE` entries are counted as a single log entry which\n * may be expanded into many changes (i.e. row deletes).\n *\n * TODO: Determine if it is worth changing the definition to count the\n * truncated rows. This would make diff computation more expensive\n * (requiring the count to be aggregated by operation type), which\n * may not be worth it for a presumable rare operation.\n */\n readonly changes: number;\n}\n\n/**\n * Thrown during an iteration of a {@link SnapshotDiff} when a schema\n * change or truncate is encountered, which result in aborting the\n * advancement and resetting / rehydrating the pipelines.\n */\nexport type ResetPipelinesReason =\n | 'advancement-timeout'\n | 'scalar-subquery'\n | 'schema-change'\n | 'truncation'\n | 'permissions-change';\n\nexport class ResetPipelinesSignal extends Error {\n readonly name = 'ResetPipelinesSignal';\n readonly reason: ResetPipelinesReason;\n\n constructor(msg: string, reason: ResetPipelinesReason) {\n super(msg);\n this.reason = reason;\n }\n}\n\n// Memoizes, per table spec, the SQL of the row lookups performed for each\n// change, which would otherwise be rebuilt from the table spec for every\n// read. Handing out the same string for every read of a given shape also\n// lets the SnapshotRowCache and the statement cache look it up without\n// rehashing it. Specs are recreated whenever they are recomputed, so stale\n// SQL is never served.\ntype TableReads = {\n /** `SELECT <columns> FROM <table> WHERE ` */\n readonly prefix: string;\n /** {@link Snapshot.getRow} SQL, by the NUL-joined key columns. */\n readonly byKeyColumns: Map<string, string>;\n /**\n * {@link Snapshot.getRows} SQL, by the bitmask of the table's `uniqueKeys`\n * that are queried.\n */\n readonly byUniqueKeys: Map<number, string>;\n};\n\nconst tableReads = new WeakMap<LiteTableSpecWithKeysAndVersion, TableReads>();\n\nfunction readsFor(table: LiteTableSpecWithKeysAndVersion): TableReads {\n return getOrInsertComputed(tableReads, table, () => ({\n prefix: `SELECT ${Object.keys(table.columns)\n .map(c => id(c))\n .join(',')} FROM ${id(table.name)} WHERE `,\n byKeyColumns: new Map(),\n byUniqueKeys: new Map(),\n }));\n}\n\n// The byUniqueKeys bitmask must fit in a (positive) 31-bit integer.\nconst MAX_MEMOIZED_UNIQUE_KEYS = 30;\n\nclass Snapshot {\n static create(\n lc: LogContext,\n dbFile: string,\n appID: string,\n pageCacheSizeKib: number | undefined,\n ) {\n const conn = new Database(lc, dbFile);\n conn.pragma('synchronous = OFF'); // Applied changes are ephemeral; COMMIT is never called.\n if (pageCacheSizeKib !== undefined) {\n conn.pragma(`cache_size = -${pageCacheSizeKib}`); // Negative = size in KiB\n }\n const [{journal_mode: mode}] = conn.pragma('journal_mode') as [\n {journal_mode: string},\n ];\n // BEGIN CONCURRENT lets the Snapshotter simulate changes on a historic\n // snapshot without taking the WAL writer lock. These private changes are\n // always rolled back; the replicator is the only committer and can use\n // BEGIN IMMEDIATE on the same WAL2 database.\n assert(\n mode === 'wal2',\n `replica db must be in wal2 mode (current: ${mode})`,\n );\n\n const db = new StatementRunner(conn);\n return new Snapshot(db, appID);\n }\n\n readonly db: StatementRunner;\n readonly #appID: string;\n readonly version: string;\n #reset = false;\n\n constructor(db: StatementRunner, appID: string) {\n db.beginConcurrent();\n // Note: The subsequent read is necessary to acquire the read lock\n // (which results in the logical creation of the snapshot). Calling\n // `BEGIN CONCURRENT` alone does not result in acquiring the read lock.\n const {stateVersion} = getReplicationState(db);\n\n this.db = db;\n this.#appID = appID;\n this.version = stateVersion;\n }\n\n numChangesSince(prevVersion: string) {\n const {count} = this.db.get(\n 'SELECT COUNT(*) AS count FROM \"_zero.changeLog2\" WHERE stateVersion > ?',\n prevVersion,\n );\n return count;\n }\n\n /**\n * Whether any table-wide op (i.e. a RESET or TRUNCATE) was logged after\n * `prevVersion`. Iterating over a diff ending at this snapshot will\n * abort with a {@link ResetPipelinesSignal} if so.\n */\n hasTableWideOpSince(prevVersion: string): boolean {\n const row = this.db.get(\n 'SELECT 1 FROM \"_zero.changeLog2\" WHERE stateVersion > ? AND op IN (?, ?) LIMIT 1',\n prevVersion,\n RESET_OP,\n TRUNCATE_OP,\n );\n return row !== undefined;\n }\n\n changesSince(prevVersion: string) {\n // Note: The queried fields are constrained to only those that are relevant\n // to the snapshot diff, i.e. those defined in the changeLogEntrySchema.\n const cached = this.db.statementCache.get(\n `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n );\n return {\n changes: cached.statement.iterate(prevVersion),\n cleanup: () => this.db.statementCache.return(cached),\n };\n }\n\n /**\n * Reads the row with the given `rowKey`, or `undefined` if it does not\n * exist.\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRow(\n table: LiteTableSpecWithKeysAndVersion,\n rowKey: JSONValue,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n const key = normalizedKeyOrder(rowKey as RowKey);\n const cols = Object.keys(key);\n const reads = readsFor(table);\n const sql = getOrInsertComputed(\n reads.byKeyColumns,\n cols.join('\\0'),\n () => reads.prefix + cols.map(c => `${id(c)}=?`).join(' AND '),\n );\n const args = Object.values(key);\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return cached.statement.get<any>(args);\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'get', args, () => {\n const row = read();\n if (row !== undefined) {\n this.#assertNotAdvanced(row);\n }\n return row;\n })\n : read();\n }\n\n /**\n * Reads the rows that conflict with `row` on any of the given unique\n * `keys` (which includes the row with the same primary key, if any).\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRows(\n table: LiteTableSpecWithKeysAndVersion,\n keys: PrimaryKey[],\n row: RowValue,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n // Filter out keys where any column is NULL. This is both correct and\n // critical for performance:\n // 1. Correctness: NULL values can't violate uniqueness (NULL != NULL in SQL)\n // 2. Performance: SQLite's MULTI-INDEX OR optimization completely fails when\n // any branch involves NULL, falling back to a full table scan. This was\n // causing slowdowns of hundreds of times on tables with nullable unique columns.\n const validKeys: PrimaryKey[] = [];\n let mask = 0;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n if (\n key.every(column => row[column] !== null && row[column] !== undefined)\n ) {\n validKeys.push(key);\n mask |= 1 << i;\n }\n }\n if (validKeys.length === 0) {\n return [];\n }\n const reads = readsFor(table);\n const buildSQL = () =>\n reads.prefix +\n validKeys\n .map(key => key.map(c => `${id(c)}=?`).join(' AND '))\n .join(' OR ');\n const sql =\n keys === table.uniqueKeys && keys.length <= MAX_MEMOIZED_UNIQUE_KEYS\n ? getOrInsertComputed(reads.byUniqueKeys, mask, buildSQL)\n : buildSQL();\n const args = validKeys.flatMap(key => key.map(column => row[column]));\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return cached.statement.all<any>(args);\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'all', args, () => {\n const rows = read();\n for (const row of rows) {\n this.#assertNotAdvanced(row);\n }\n return rows;\n })\n : read();\n }\n\n /**\n * Rows are shared with other client groups via the SnapshotRowCache, so\n * one read from a connection that has advanced past this snapshot (i.e. a\n * {@link SnapshotDiff} used after its Snapshotter advanced) must fail\n * before it is cached, rather than be served to the valid Diffs of other\n * client groups (whose own validity checks would then fail).\n */\n #assertNotAdvanced(row: RowValue) {\n if ((row[ROW_VERSION] ?? '~') > this.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. db has advanced past ${this.version}.`,\n );\n }\n }\n\n /**\n * Whether the connection has been reset to a newer snapshot (i.e. via\n * {@link resetToHead()}), after which reads no longer reflect\n * {@link version}.\n */\n get reset(): boolean {\n return this.#reset;\n }\n\n resetToHead(): Snapshot {\n this.#reset = true;\n this.db.rollback();\n return new Snapshot(this.db, this.#appID);\n }\n}\n\nclass Diff implements SnapshotDiff {\n readonly #permissionsTable: string;\n readonly #syncableTables: Map<string, LiteAndZqlSpec>;\n readonly #allTableNames: Set<string>;\n readonly #observedTables: TableFilter | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n readonly prev: Snapshot;\n readonly curr: Snapshot;\n readonly changes: number;\n\n constructor(\n appID: string,\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n prev: Snapshot,\n curr: Snapshot,\n observedTables?: TableFilter | undefined,\n rowCache?: SnapshotRowCache | undefined,\n ) {\n this.#permissionsTable = `${appID}.permissions`;\n this.#syncableTables = syncableTables;\n this.#allTableNames = allTableNames;\n this.#observedTables = observedTables;\n this.prev = prev;\n this.curr = curr;\n this.changes = curr.numChangesSince(prev.version);\n // Row values are only shared (via the cache) between Diffs that do not\n // straddle a table-wide op. This guarantees that any two Diffs that\n // encounter the same change log entry read the row from tables with\n // the same schema (and contents), since a RESET or TRUNCATE between\n // their `curr` versions would necessarily fall within the range of the\n // later Diff. (Such a Diff aborts with a ResetPipelinesSignal anyway.)\n this.#rowCache =\n rowCache && !curr.hasTableWideOpSince(prev.version)\n ? rowCache\n : undefined;\n }\n\n [Symbol.iterator](): Iterator<Change> {\n const {changes, cleanup: done} = this.curr.changesSince(this.prev.version);\n\n const cleanup = () => {\n try {\n // Allow open iterators to clean up their state.\n changes.return?.(undefined);\n } finally {\n done();\n }\n };\n\n return {\n next: () => {\n try {\n for (;;) {\n const {value, done} = changes.next();\n if (done) {\n cleanup();\n return {value, done: true};\n }\n\n const {table, rowKey, op, stateVersion} = v.parse(value, schema);\n if (op === RESET_OP) {\n // The current map of `TableSpec`s may not have the correct or complete information.\n throw new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n );\n }\n if (op === TRUNCATE_OP) {\n // Truncates are also processed by rehydrating pipelines at current.\n throw new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n );\n }\n if (\n this.#observedTables &&\n !this.#observedTables.has(table) &&\n table !== this.#permissionsTable\n ) {\n if (this.#allTableNames.has(table)) {\n continue; // skip change log entries for unobserved tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const specs = this.#syncableTables.get(table);\n if (!specs) {\n if (this.#allTableNames.has(table)) {\n continue; // skip change log entries for non-syncable tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const {tableSpec, zqlSpec} = specs;\n\n // Sanity check: All change log ops should have a stateVersion\n // greater than minRowVersion in the table metadata. This is a\n // mini-proof that the overlay does not need to be applied to\n // rows produced in incremental catchup, based on the invariant in\n // change-processor's #bumpVersions(), whereby the setting of the\n // minRowVersion is always followed by a RESET OP, meaning that\n // subsequent change-log traversal happens at a later version.\n assert(\n (tableSpec.minRowVersion ?? '') < stateVersion,\n () =>\n `unexpected change @${stateVersion} for table ${table} with ` +\n `minRowVersion ${tableSpec.minRowVersion}: ${op}(${rowKey})`,\n );\n\n assert(rowKey !== null, 'rowKey must be present for row changes');\n\n // Row reads are shared with the other client groups on the\n // worker via the SnapshotRowCache (if configured):\n //\n // * The new value of the row is read from `curr`, which is\n // never written to during the iteration, and is the version\n // of the row at `stateVersion` (as verified by\n // checkThatDiffIsValid()). It is thus identical for every\n // Diff that encounters the change log entry.\n //\n // * Previous values are read from `prev`, at `prev.version`,\n // which the caller (i.e. IVM) writes to as the iteration\n // progresses. For a table whose only unique key is its\n // primary key, no change applied before this one can affect\n // this row, so the result depends solely on `prev.version`.\n // Otherwise, the result can include rows that conflict on\n // other unique keys, which may have been added or removed by\n // preceding changes; that sequence is determined by the\n // `<prev, curr>` versions of the Diff, both of which are then\n // included in the cache tag.\n // The first advance() after this Diff was created resets the\n // `prev` connection to head. Reads would then no longer reflect\n // `prev.version`, and cache hits would not reveal it (the cached\n // rows were read by valid Diffs), so this must be checked\n // explicitly rather than inferred from the rows' versions.\n if (this.prev.reset) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n\n const cache = this.#rowCache;\n const prevTag =\n tableSpec.uniqueKeys.length <= 1\n ? `p:${this.prev.version}`\n : `p:${this.prev.version}:${this.curr.version}`;\n const nextValue =\n op === SET_OP\n ? this.curr.getRow(\n tableSpec,\n rowKey,\n cache,\n `n:${stateVersion}`,\n )\n : null;\n let prevValues;\n if (nextValue) {\n prevValues = this.prev.getRows(\n tableSpec,\n tableSpec.uniqueKeys,\n nextValue,\n cache,\n prevTag,\n );\n } else {\n const prevValue = this.prev.getRow(\n tableSpec,\n rowKey,\n cache,\n prevTag,\n );\n prevValues = prevValue ? [prevValue] : [];\n }\n if (nextValue === undefined) {\n throw new Error(\n `Missing value for ${table} ${stringify(rowKey)}`,\n );\n }\n // Sanity check detects if the diff is being accessed after the Snapshots have advanced.\n this.checkThatDiffIsValid(stateVersion, op, prevValues, nextValue);\n\n if (prevValues.length === 0 && nextValue === null) {\n // Filter out no-op changes (e.g. a delete of a row that does not exist in prev).\n // TODO: Consider doing this for deep-equal values.\n continue;\n }\n\n if (\n table === this.#permissionsTable &&\n prevValues.some(\n prevValue => prevValue.permissions !== nextValue.permissions,\n )\n ) {\n throw new ResetPipelinesSignal(\n `Permissions have changed ${\n prevValues.find(\n prevValue =>\n prevValue.permissions !== nextValue.permissions,\n ).hash\n } => ${nextValue.hash}`,\n 'permissions-change',\n );\n }\n\n // Note: The raw SQLite rows may be shared with other client\n // groups via the SnapshotRowCache, so they must not be modified.\n // fromSQLiteTypes() produces new row objects.\n // TODO Can we get rid of these RowValue casts?\n return {\n value: {\n table,\n prevValues: prevValues.map(prevValue =>\n fromSQLiteTypes(zqlSpec, prevValue, table),\n ),\n nextValue: nextValue\n ? fromSQLiteTypes(zqlSpec, nextValue, table)\n : null,\n rowKey,\n } satisfies Change,\n };\n }\n } catch (e) {\n // This control flow path is not covered by the return() method (i.e. `break`).\n cleanup();\n throw e;\n }\n },\n\n return: (value: unknown) => {\n cleanup();\n return {value, done: true};\n },\n };\n }\n\n checkThatDiffIsValid(\n stateVersion: string,\n op: string,\n prevValues: RowValue[],\n nextValue: RowValue,\n ) {\n // Sanity checks to detect that the diff is not being accessed after\n // the Snapshots have advanced.\n if (stateVersion > this.curr.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. curr db has advanced past ${this.curr.version}`,\n );\n }\n if (\n prevValues.findIndex(\n prevValue => (prevValue[ROW_VERSION] ?? '~') > this.prev.version,\n ) !== -1\n ) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n if (op === SET_OP && nextValue[ROW_VERSION] !== stateVersion) {\n throw new InvalidDiffError(\n 'Diff is no longer valid. curr db has advanced.',\n );\n }\n }\n}\n\nexport class InvalidDiffError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"snapshotter.js","names":["#lc","#dbFile","#appID","#pageCacheSizeKib","#curr","#prev","#permissionsTable","#syncableTables","#allTableNames"],"sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-types/src/schema.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {fromSQLiteTypes} from '../../../../zqlite/src/table-source.ts';\nimport type {\n LiteAndZqlSpec,\n LiteTableSpecWithKeysAndVersion,\n} from '../../db/specs.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {\n normalizedKeyOrder,\n type RowKey,\n type RowValue,\n} from '../../types/row-key.ts';\nimport type {AppID} from '../../types/shards.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n RESET_OP,\n changeLogEntrySchema as schema,\n SET_OP,\n TRUNCATE_OP,\n} from '../replicator/schema/change-log.ts';\nimport {\n getReplicationState,\n ZERO_VERSION_COLUMN_NAME as ROW_VERSION,\n} from '../replicator/schema/replication-state.ts';\n\n/**\n * A `Snapshotter` manages the progression of database snapshots for a\n * ViewSyncer.\n *\n * The Replicator and ViewSyncers operate on the same SQLite file, with the\n * Replicator being the sole writer to the database. The IVM logic in\n * ViewSyncers, however, rely on incrementally applying changes to the DB to\n * update the state of its pipelines.\n *\n * To avoid coupling the progress of the Replicator and all IVM pipelines on\n * each other, ViewSyncers operate on ephemeral forks of the database by holding\n * [concurrent](https://sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md)\n * snapshots of the database and simulating (but ultimately rolling back)\n * mutations on these snapshots.\n *\n * Example:\n * 1. ViewSyncer takes `snapshot_a` at version `t1` of the database and\n * hydrates its pipeline(s).\n * 2. Replicator applies a new transaction to the database and notifies\n * subscribers.\n * 3. ViewSyncer takes `snapshot_b` at `t2`, and queries the `ChangeLog` at\n * that snapshot for changes since `t1`.\n * 4. ViewSyncer applies those changes to `snapshot_a` for IVM, but does not\n * commit them. (Recall that the Replicator is the sole writer to the db, so\n * the ViewSyncer never commits any writes.)\n * 5. Replicator applies the next transaction and advances the database to `t3`.\n * 6. ViewSyncer rolls back `snapshot_a` and opens `snapshot_c` at `t3`, using\n * `snapshot_b` to simulate changes from `t2` to `t3`.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ```\n *\n * Note that the Replicator (and ViewSyncers) do not wait on the progress of\n * other ViewSyncers. If a ViewSyncer is busy hydrating at `t1`, the Replicator\n * and other ViewSyncers can progress through `t2`, `t3`, etc. independently,\n * as the busy ViewSyncer simply takes its own snapshot when it is ready.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer1: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ViewSyncer2: [.......... snapshot_a ..........] ----> [snapshot_b]\n * ```\n *\n * To minimize Database connections (and statement preparation, etc.), the\n * Snapshotter reuses the connection from the previous (rolled back)\n * snapshot when opening the new one.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * (conn_1) (conn_2) (conn_1)\n * ```\n *\n * In this manner, each ViewSyncer uses two connections that continually\n * \"leapfrog\" each other to replay the timeline of changes in isolation from\n * the Replicator and other ViewSyncers.\n */\nexport class Snapshotter {\n readonly #lc: LogContext;\n readonly #dbFile: string;\n readonly #appID: string;\n readonly #pageCacheSizeKib: number | undefined;\n #curr: Snapshot | undefined;\n #prev: Snapshot | undefined;\n\n constructor(\n lc: LogContext,\n dbFile: string,\n {appID}: AppID,\n pageCacheSizeKib?: number,\n ) {\n this.#lc = lc;\n this.#dbFile = dbFile;\n this.#appID = appID;\n this.#pageCacheSizeKib = pageCacheSizeKib;\n }\n\n /**\n * Initializes the snapshot to the current head of the database. This must be\n * only be called once. The state of whether a Snapshotter has been initialized\n * can be determined by calling {@link initialized()}.\n */\n init(): this {\n assert(this.#curr === undefined, 'Already initialized');\n this.#curr = Snapshot.create(\n this.#lc,\n this.#dbFile,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#lc.debug?.(`Initial snapshot at version ${this.#curr.version}`);\n return this;\n }\n\n initialized(): boolean {\n return this.#curr !== undefined;\n }\n\n /** Returns the current snapshot. Asserts if {@link initialized()} is false. */\n current(): Snapshot {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n return this.#curr;\n }\n\n /**\n * Advances to the head of the Database, returning a diff between the\n * previously current Snapshot and a new Snapshot at head. This is called\n * in response to a notification from a Replicator subscription. Subsequent\n * calls to {@link current()} return the new Snapshot. Note that the Snapshotter\n * must be initialized before advancing.\n *\n * The returned {@link SnapshotDiff} contains snapshots at the endpoints\n * of the database timeline. Iterating over the diff generates a sequence\n * of {@link Change}s between the two snapshots.\n *\n * Note that this sequence is not chronological; rather, the sequence is\n * ordered by `<table, row-key>`, such that a row can appear at most once\n * in the common case, or twice if its table is `TRUNCATE`'d and a new value\n * is subsequently `INSERT`'ed. This results in dropping most intermediate\n * changes to a row and bounds the amount of work needed to catch up;\n * however, as a consequence, a consistent database state is only guaranteed\n * when the sequence has been fully consumed.\n *\n * Note that Change generation relies on the state of the underlying\n * database connections, and because the connection for the previous snapshot\n * is reused to produce the next snapshot, the diff object is only valid\n * until the next call to `advance()`.\n *\n * It is okay for the caller to apply `Change`s to the `prev` snapshot\n * during the iteration (e.g. this is necessary for IVM); the remainder\n * of the iteration is not affected because a given row can appear at most\n * once in the sequence (with the exception being TRUNCATE, after which the\n * deleted rows can be re-inserted, but this will also behave correctly if\n * the changes are applied).\n *\n * Once the changes have been applied, however, a _subsequent_ iteration\n * will not produce the correct results. In order to perform multiple\n * change-applying iterations, the caller must (1) create a save point\n * on `prev` before each iteration, and (2) rollback to the save point after\n * the iteration.\n */\n advance(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n ): SnapshotDiff {\n const {prev, curr} = this.advanceWithoutDiff();\n return new Diff(this.#appID, syncableTables, allTableNames, prev, curr);\n }\n\n advanceWithoutDiff() {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n const next = this.#prev\n ? this.#prev.resetToHead()\n : Snapshot.create(\n this.#lc,\n this.#curr.db.db.name,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#prev = this.#curr;\n this.#curr = next;\n return {prev: this.#prev, curr: this.#curr};\n }\n\n /**\n * Call this to close the database connections when the Snapshotter is\n * no longer needed.\n */\n destroy() {\n this.#curr?.db.db.close();\n this.#prev?.db.db.close();\n this.#lc.debug?.('closed database connections');\n }\n}\n\nexport type Change = {\n readonly table: string;\n /**\n * If this change represents a remove the row to remove,\n * if nextValue is not null then all rows that have a unique constraint\n * violation with nextValue.\n * In both cases these rows should be removed.\n */\n readonly prevValues: Readonly<Row>[];\n readonly nextValue: Readonly<Row> | null;\n readonly rowKey: RowKey;\n};\n\n/**\n * Represents the difference between two database Snapshots.\n * Iterating over the object will produce a sequence of {@link Change}s\n * between the two snapshots.\n *\n * See {@link Snapshotter.advance()} for semantics and usage.\n */\nexport interface SnapshotDiff extends Iterable<Change> {\n readonly prev: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n readonly curr: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n\n /**\n * The number of ChangeLog entries between the snapshots. Note that this\n * may not necessarily equal the number of `Change` objects that the iteration\n * will produce, as `TRUNCATE` entries are counted as a single log entry which\n * may be expanded into many changes (i.e. row deletes).\n *\n * TODO: Determine if it is worth changing the definition to count the\n * truncated rows. This would make diff computation more expensive\n * (requiring the count to be aggregated by operation type), which\n * may not be worth it for a presumable rare operation.\n */\n readonly changes: number;\n}\n\n/**\n * Thrown during an iteration of a {@link SnapshotDiff} when a schema\n * change or truncate is encountered, which result in aborting the\n * advancement and resetting / rehydrating the pipelines.\n */\nexport type ResetPipelinesReason =\n | 'advancement-timeout'\n | 'scalar-subquery'\n | 'schema-change'\n | 'truncation'\n | 'permissions-change';\n\nexport class ResetPipelinesSignal extends Error {\n readonly name = 'ResetPipelinesSignal';\n readonly reason: ResetPipelinesReason;\n\n constructor(msg: string, reason: ResetPipelinesReason) {\n super(msg);\n this.reason = reason;\n }\n}\n\nclass Snapshot {\n static create(\n lc: LogContext,\n dbFile: string,\n appID: string,\n pageCacheSizeKib: number | undefined,\n ) {\n const conn = new Database(lc, dbFile);\n conn.pragma('synchronous = OFF'); // Applied changes are ephemeral; COMMIT is never called.\n if (pageCacheSizeKib !== undefined) {\n conn.pragma(`cache_size = -${pageCacheSizeKib}`); // Negative = size in KiB\n }\n const [{journal_mode: mode}] = conn.pragma('journal_mode') as [\n {journal_mode: string},\n ];\n // BEGIN CONCURRENT lets the Snapshotter simulate changes on a historic\n // snapshot without taking the WAL writer lock. These private changes are\n // always rolled back; the replicator is the only committer and can use\n // BEGIN IMMEDIATE on the same WAL2 database.\n assert(\n mode === 'wal2',\n `replica db must be in wal2 mode (current: ${mode})`,\n );\n\n const db = new StatementRunner(conn);\n return new Snapshot(db, appID);\n }\n\n readonly db: StatementRunner;\n readonly #appID: string;\n readonly version: string;\n\n constructor(db: StatementRunner, appID: string) {\n db.beginConcurrent();\n // Note: The subsequent read is necessary to acquire the read lock\n // (which results in the logical creation of the snapshot). Calling\n // `BEGIN CONCURRENT` alone does not result in acquiring the read lock.\n const {stateVersion} = getReplicationState(db);\n\n this.db = db;\n this.#appID = appID;\n this.version = stateVersion;\n }\n\n numChangesSince(prevVersion: string) {\n const {count} = this.db.get(\n 'SELECT COUNT(*) AS count FROM \"_zero.changeLog2\" WHERE stateVersion > ?',\n prevVersion,\n );\n return count;\n }\n\n changesSince(prevVersion: string) {\n // Note: The queried fields are constrained to only those that are relevant\n // to the snapshot diff, i.e. those defined in the changeLogEntrySchema.\n const cached = this.db.statementCache.get(\n `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n );\n return {\n changes: cached.statement.iterate(prevVersion),\n cleanup: () => this.db.statementCache.return(cached),\n };\n }\n\n getRow(table: LiteTableSpecWithKeysAndVersion, rowKey: JSONValue) {\n const key = normalizedKeyOrder(rowKey as RowKey);\n const conds = Object.keys(key).map(c => `${id(c)}=?`);\n const cols = Object.keys(table.columns);\n const cached = this.db.statementCache.get(\n `SELECT ${cols.map(c => id(c)).join(',')} FROM ${id(\n table.name,\n )} WHERE ${conds.join(' AND ')}`,\n );\n cached.statement.safeIntegers(true);\n try {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return cached.statement.get<any>(Object.values(key));\n } finally {\n this.db.statementCache.return(cached);\n }\n }\n\n getRows(\n table: LiteTableSpecWithKeysAndVersion,\n keys: PrimaryKey[],\n row: RowValue,\n ) {\n // Filter out keys where any column is NULL. This is both correct and\n // critical for performance:\n // 1. Correctness: NULL values can't violate uniqueness (NULL != NULL in SQL)\n // 2. Performance: SQLite's MULTI-INDEX OR optimization completely fails when\n // any branch involves NULL, falling back to a full table scan. This was\n // causing slowdowns of hundreds of times on tables with nullable unique columns.\n const validKeys = keys.filter(key =>\n key.every(column => row[column] !== null && row[column] !== undefined),\n );\n if (validKeys.length === 0) {\n return [];\n }\n const conds = validKeys.map(key => key.map(c => `${id(c)}=?`));\n const cols = Object.keys(table.columns);\n const cached = this.db.statementCache.get(\n `SELECT ${cols.map(c => id(c)).join(',')} FROM ${id(\n table.name,\n )} WHERE ${conds.map(cond => cond.join(' AND ')).join(' OR ')}`,\n );\n cached.statement.safeIntegers(true);\n try {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return cached.statement.all<any>(\n validKeys.flatMap(key => key.map(column => row[column])),\n );\n } finally {\n this.db.statementCache.return(cached);\n }\n }\n\n resetToHead(): Snapshot {\n this.db.rollback();\n return new Snapshot(this.db, this.#appID);\n }\n}\n\nclass Diff implements SnapshotDiff {\n readonly #permissionsTable: string;\n readonly #syncableTables: Map<string, LiteAndZqlSpec>;\n readonly #allTableNames: Set<string>;\n readonly prev: Snapshot;\n readonly curr: Snapshot;\n readonly changes: number;\n\n constructor(\n appID: string,\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n prev: Snapshot,\n curr: Snapshot,\n ) {\n this.#permissionsTable = `${appID}.permissions`;\n this.#syncableTables = syncableTables;\n this.#allTableNames = allTableNames;\n this.prev = prev;\n this.curr = curr;\n this.changes = curr.numChangesSince(prev.version);\n }\n\n [Symbol.iterator](): Iterator<Change> {\n const {changes, cleanup: done} = this.curr.changesSince(this.prev.version);\n\n const cleanup = () => {\n try {\n // Allow open iterators to clean up their state.\n changes.return?.(undefined);\n } finally {\n done();\n }\n };\n\n return {\n next: () => {\n try {\n for (;;) {\n const {value, done} = changes.next();\n if (done) {\n cleanup();\n return {value, done: true};\n }\n\n const {table, rowKey, op, stateVersion} = v.parse(value, schema);\n if (op === RESET_OP) {\n // The current map of `TableSpec`s may not have the correct or complete information.\n throw new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n );\n }\n if (op === TRUNCATE_OP) {\n // Truncates are also processed by rehydrating pipelines at current.\n throw new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n );\n }\n const specs = this.#syncableTables.get(table);\n if (!specs) {\n if (this.#allTableNames.has(table)) {\n continue; // skip change log entries for non-syncable tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const {tableSpec, zqlSpec} = specs;\n\n // Sanity check: All change log ops should have a stateVersion\n // greater than minRowVersion in the table metadata. This is a\n // mini-proof that the overlay does not need to be applied to\n // rows produced in incremental catchup, based on the invariant in\n // change-processor's #bumpVersions(), whereby the setting of the\n // minRowVersion is always followed by a RESET OP, meaning that\n // subsequent change-log traversal happens at a later version.\n assert(\n (tableSpec.minRowVersion ?? '') < stateVersion,\n () =>\n `unexpected change @${stateVersion} for table ${table} with ` +\n `minRowVersion ${tableSpec.minRowVersion}: ${op}(${rowKey})`,\n );\n\n assert(rowKey !== null, 'rowKey must be present for row changes');\n const nextValue =\n op === SET_OP ? this.curr.getRow(tableSpec, rowKey) : null;\n let prevValues;\n if (nextValue) {\n prevValues = this.prev.getRows(\n tableSpec,\n tableSpec.uniqueKeys,\n nextValue,\n );\n } else {\n const prevValue = this.prev.getRow(tableSpec, rowKey);\n prevValues = prevValue ? [prevValue] : [];\n }\n if (nextValue === undefined) {\n throw new Error(\n `Missing value for ${table} ${stringify(rowKey)}`,\n );\n }\n // Sanity check detects if the diff is being accessed after the Snapshots have advanced.\n this.checkThatDiffIsValid(stateVersion, op, prevValues, nextValue);\n\n if (prevValues.length === 0 && nextValue === null) {\n // Filter out no-op changes (e.g. a delete of a row that does not exist in prev).\n // TODO: Consider doing this for deep-equal values.\n continue;\n }\n\n if (\n table === this.#permissionsTable &&\n prevValues.some(\n prevValue => prevValue.permissions !== nextValue.permissions,\n )\n ) {\n throw new ResetPipelinesSignal(\n `Permissions have changed ${\n prevValues.find(\n prevValue =>\n prevValue.permissions !== nextValue.permissions,\n ).hash\n } => ${nextValue.hash}`,\n 'permissions-change',\n );\n }\n\n // Modify the values in place when converting to ZQL rows\n // This is safe since we're the first node in the iterator chain.\n // TODO Can we get rid of these RowValue casts?\n return {\n value: {\n table,\n prevValues: prevValues.map(prevValue =>\n fromSQLiteTypes(zqlSpec, prevValue, table),\n ),\n nextValue: nextValue\n ? fromSQLiteTypes(zqlSpec, nextValue, table)\n : null,\n rowKey,\n } satisfies Change,\n };\n }\n } catch (e) {\n // This control flow path is not covered by the return() method (i.e. `break`).\n cleanup();\n throw e;\n }\n },\n\n return: (value: unknown) => {\n cleanup();\n return {value, done: true};\n },\n };\n }\n\n checkThatDiffIsValid(\n stateVersion: string,\n op: string,\n prevValues: RowValue[],\n nextValue: RowValue,\n ) {\n // Sanity checks to detect that the diff is not being accessed after\n // the Snapshots have advanced.\n if (stateVersion > this.curr.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. curr db has advanced past ${this.curr.version}`,\n );\n }\n if (\n prevValues.findIndex(\n prevValue => (prevValue[ROW_VERSION] ?? '~') > this.prev.version,\n ) !== -1\n ) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n if (op === SET_OP && nextValue[ROW_VERSION] !== stateVersion) {\n throw new InvalidDiffError(\n 'Diff is no longer valid. curr db has advanced.',\n );\n }\n }\n}\n\nexport class InvalidDiffError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;CACA;CACA;CACA;CAEA,YACE,IACA,QACA,EAAC,SACD,kBACA;EACA,KAAKA,MAAM;EACX,KAAKC,UAAU;EACf,KAAKC,SAAS;EACd,KAAKC,oBAAoB;CAC3B;;;;;;CAOA,OAAa;EACX,OAAO,KAAKC,UAAU,KAAA,GAAW,qBAAqB;EACtD,KAAKA,QAAQ,SAAS,OACpB,KAAKJ,KACL,KAAKC,SACL,KAAKC,QACL,KAAKC,iBACP;EACA,KAAKH,IAAI,QAAQ,+BAA+B,KAAKI,MAAM,SAAS;EACpE,OAAO;CACT;CAEA,cAAuB;EACrB,OAAO,KAAKA,UAAU,KAAA;CACxB;;CAGA,UAAoB;EAClB,OAAO,KAAKA,UAAU,KAAA,GAAW,sCAAsC;EACvE,OAAO,KAAKA;CACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCA,QACE,gBACA,eACc;EACd,MAAM,EAAC,MAAM,SAAQ,KAAK,mBAAmB;EAC7C,OAAO,IAAI,KAAK,KAAKF,QAAQ,gBAAgB,eAAe,MAAM,IAAI;CACxE;CAEA,qBAAqB;EACnB,OAAO,KAAKE,UAAU,KAAA,GAAW,sCAAsC;EACvE,MAAM,OAAO,KAAKC,QACd,KAAKA,MAAM,YAAY,IACvB,SAAS,OACP,KAAKL,KACL,KAAKI,MAAM,GAAG,GAAG,MACjB,KAAKF,QACL,KAAKC,iBACP;EACJ,KAAKE,QAAQ,KAAKD;EAClB,KAAKA,QAAQ;EACb,OAAO;GAAC,MAAM,KAAKC;GAAO,MAAM,KAAKD;EAAK;CAC5C;;;;;CAMA,UAAU;EACR,KAAKA,OAAO,GAAG,GAAG,MAAM;EACxB,KAAKC,OAAO,GAAG,GAAG,MAAM;EACxB,KAAKL,IAAI,QAAQ,6BAA6B;CAChD;AACF;AA0DA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAgB;CAChB;CAEA,YAAY,KAAa,QAA8B;EACrD,MAAM,GAAG;EACT,KAAK,SAAS;CAChB;AACF;AAEA,IAAM,WAAN,MAAM,SAAS;CACb,OAAO,OACL,IACA,QACA,OACA,kBACA;EACA,MAAM,OAAO,IAAI,SAAS,IAAI,MAAM;EACpC,KAAK,OAAO,mBAAmB;EAC/B,IAAI,qBAAqB,KAAA,GACvB,KAAK,OAAO,iBAAiB,kBAAkB;EAEjD,MAAM,CAAC,EAAC,cAAc,UAAS,KAAK,OAAO,cAAc;EAOzD,OACE,SAAS,QACT,6CAA6C,KAAK,EACpD;EAGA,OAAO,IAAI,SAAS,IADL,gBAAgB,IACX,GAAI,KAAK;CAC/B;CAEA;CACA;CACA;CAEA,YAAY,IAAqB,OAAe;EAC9C,GAAG,gBAAgB;EAInB,MAAM,EAAC,iBAAgB,oBAAoB,EAAE;EAE7C,KAAK,KAAK;EACV,KAAKE,SAAS;EACd,KAAK,UAAU;CACjB;CAEA,gBAAgB,aAAqB;EACnC,MAAM,EAAC,UAAS,KAAK,GAAG,IACtB,6EACA,WACF;EACA,OAAO;CACT;CAEA,aAAa,aAAqB;EAGhC,MAAM,SAAS,KAAK,GAAG,eAAe,IACpC;yEAEF;EACA,OAAO;GACL,SAAS,OAAO,UAAU,QAAQ,WAAW;GAC7C,eAAe,KAAK,GAAG,eAAe,OAAO,MAAM;EACrD;CACF;CAEA,OAAO,OAAwC,QAAmB;EAChE,MAAM,MAAM,mBAAmB,MAAgB;EAC/C,MAAM,QAAQ,OAAO,KAAK,GAAG,EAAE,KAAI,MAAK,GAAG,GAAG,CAAC,EAAE,GAAG;EACpD,MAAM,OAAO,OAAO,KAAK,MAAM,OAAO;EACtC,MAAM,SAAS,KAAK,GAAG,eAAe,IACpC,UAAU,KAAK,KAAI,MAAK,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,QAAQ,GAC/C,MAAM,IACR,EAAE,SAAS,MAAM,KAAK,OAAO,GAC/B;EACA,OAAO,UAAU,aAAa,IAAI;EAClC,IAAI;GAEF,OAAO,OAAO,UAAU,IAAS,OAAO,OAAO,GAAG,CAAC;EACrD,UAAU;GACR,KAAK,GAAG,eAAe,OAAO,MAAM;EACtC;CACF;CAEA,QACE,OACA,MACA,KACA;EAOA,MAAM,YAAY,KAAK,QAAO,QAC5B,IAAI,OAAM,WAAU,IAAI,YAAY,QAAQ,IAAI,YAAY,KAAA,CAAS,CACvE;EACA,IAAI,UAAU,WAAW,GACvB,OAAO,CAAC;EAEV,MAAM,QAAQ,UAAU,KAAI,QAAO,IAAI,KAAI,MAAK,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC;EAC7D,MAAM,OAAO,OAAO,KAAK,MAAM,OAAO;EACtC,MAAM,SAAS,KAAK,GAAG,eAAe,IACpC,UAAU,KAAK,KAAI,MAAK,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,QAAQ,GAC/C,MAAM,IACR,EAAE,SAAS,MAAM,KAAI,SAAQ,KAAK,KAAK,OAAO,CAAC,EAAE,KAAK,MAAM,GAC9D;EACA,OAAO,UAAU,aAAa,IAAI;EAClC,IAAI;GAEF,OAAO,OAAO,UAAU,IACtB,UAAU,SAAQ,QAAO,IAAI,KAAI,WAAU,IAAI,OAAO,CAAC,CACzD;EACF,UAAU;GACR,KAAK,GAAG,eAAe,OAAO,MAAM;EACtC;CACF;CAEA,cAAwB;EACtB,KAAK,GAAG,SAAS;EACjB,OAAO,IAAI,SAAS,KAAK,IAAI,KAAKA,MAAM;CAC1C;AACF;AAEA,IAAM,OAAN,MAAmC;CACjC;CACA;CACA;CACA;CACA;CACA;CAEA,YACE,OACA,gBACA,eACA,MACA,MACA;EACA,KAAKI,oBAAoB,GAAG,MAAM;EAClC,KAAKC,kBAAkB;EACvB,KAAKC,iBAAiB;EACtB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,UAAU,KAAK,gBAAgB,KAAK,OAAO;CAClD;CAEA,CAAC,OAAO,YAA8B;EACpC,MAAM,EAAC,SAAS,SAAS,SAAQ,KAAK,KAAK,aAAa,KAAK,KAAK,OAAO;EAEzE,MAAM,gBAAgB;GACpB,IAAI;IAEF,QAAQ,SAAS,KAAA,CAAS;GAC5B,UAAU;IACR,KAAK;GACP;EACF;EAEA,OAAO;GACL,YAAY;IACV,IAAI;KACF,SAAS;MACP,MAAM,EAAC,OAAO,SAAQ,QAAQ,KAAK;MACnC,IAAI,MAAM;OACR,QAAQ;OACR,OAAO;QAAC;QAAO,MAAM;OAAI;MAC3B;MAEA,MAAM,EAAC,OAAO,QAAQ,IAAI,iBAAgB,MAAQ,OAAO,oBAAM;MAC/D,IAAI,OAAA,KAEF,MAAM,IAAI,qBACR,oBAAoB,MAAM,eAC1B,eACF;MAEF,IAAI,OAAA,KAEF,MAAM,IAAI,qBACR,SAAS,MAAM,sBACf,YACF;MAEF,MAAM,QAAQ,KAAKD,gBAAgB,IAAI,KAAK;MAC5C,IAAI,CAAC,OAAO;OACV,IAAI,KAAKC,eAAe,IAAI,KAAK,GAC/B;OAEF,MAAM,IAAI,MAAM,4BAA4B,OAAO;MACrD;MACA,MAAM,EAAC,WAAW,YAAW;MAS7B,QACG,UAAU,iBAAiB,MAAM,oBAEhC,sBAAsB,aAAa,aAAa,MAAM,sBACrC,UAAU,cAAc,IAAI,GAAG,GAAG,OAAO,EAC9D;MAEA,OAAO,WAAW,MAAM,wCAAwC;MAChE,MAAM,YACJ,OAAA,MAAgB,KAAK,KAAK,OAAO,WAAW,MAAM,IAAI;MACxD,IAAI;MACJ,IAAI,WACF,aAAa,KAAK,KAAK,QACrB,WACA,UAAU,YACV,SACF;WACK;OACL,MAAM,YAAY,KAAK,KAAK,OAAO,WAAW,MAAM;OACpD,aAAa,YAAY,CAAC,SAAS,IAAI,CAAC;MAC1C;MACA,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MACR,qBAAqB,MAAM,GAAG,UAAU,MAAM,GAChD;MAGF,KAAK,qBAAqB,cAAc,IAAI,YAAY,SAAS;MAEjE,IAAI,WAAW,WAAW,KAAK,cAAc,MAG3C;MAGF,IACE,UAAU,KAAKF,qBACf,WAAW,MACT,cAAa,UAAU,gBAAgB,UAAU,WACnD,GAEA,MAAM,IAAI,qBACR,4BACE,WAAW,MACT,cACE,UAAU,gBAAgB,UAAU,WACxC,EAAE,KACH,MAAM,UAAU,QACjB,oBACF;MAMF,OAAO,EACL,OAAO;OACL;OACA,YAAY,WAAW,KAAI,cACzB,gBAAgB,SAAS,WAAW,KAAK,CAC3C;OACA,WAAW,YACP,gBAAgB,SAAS,WAAW,KAAK,IACzC;OACJ;MACF,EACF;KACF;IACF,SAAS,GAAG;KAEV,QAAQ;KACR,MAAM;IACR;GACF;GAEA,SAAS,UAAmB;IAC1B,QAAQ;IACR,OAAO;KAAC;KAAO,MAAM;IAAI;GAC3B;EACF;CACF;CAEA,qBACE,cACA,IACA,YACA,WACA;EAGA,IAAI,eAAe,KAAK,KAAK,SAC3B,MAAM,IAAI,iBACR,sDAAsD,KAAK,KAAK,SAClE;EAEF,IACE,WAAW,WACT,eAAc,UAAA,iBAA0B,OAAO,KAAK,KAAK,OAC3D,MAAM,IAEN,MAAM,IAAI,iBACR,sDAAsD,KAAK,KAAK,QAAQ,EAC1E;EAEF,IAAI,OAAA,OAAiB,UAAA,kBAA2B,cAC9C,MAAM,IAAI,iBACR,gDACF;CAEJ;AACF;AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C,YAAY,KAAa;EACvB,MAAM,GAAG;CACX;AACF"}
@@ -18,10 +18,7 @@ import type { ReplicaState } from '../replicator/replicator.ts';
18
18
  import type { ActivityBasedService } from '../service.ts';
19
19
  import type { ConnectionContextManager, ConnectionSelector } from './connection-context-manager.ts';
20
20
  import type { DrainCoordinator } from './drain-coordinator.ts';
21
- import { type MonotonicClock } from './hydration-budget.ts';
22
21
  import type { PipelineDriver } from './pipeline-driver.ts';
23
- import { type ClientQueryRecord, type CustomQueryRecord, type InternalQueryRecord } from './schema/types.ts';
24
- import { type TTLClock } from './ttl-clock.ts';
25
22
  export interface ViewSyncer {
26
23
  initConnection(selector: ConnectionSelector, initConnectionMessage: InitConnectionMessage): Source<ViewSyncerDownstream>;
27
24
  changeDesiredQueries(selector: ConnectionSelector, msg: ChangeDesiredQueriesMessage): Promise<void>;
@@ -70,7 +67,7 @@ export declare class ViewSyncerService implements ViewSyncer, ActivityBasedServi
70
67
  readonly id: string;
71
68
  readonly createdAtMs: number;
72
69
  readonly connContextManager: ConnectionContextManager;
73
- constructor(config: NormalizedZeroConfig, lc: LogContext, shard: ShardID, taskID: string, clientGroupID: string, cvrDb: PostgresDB, pipelineDriver: PipelineDriver, versionChanges: Subscription<ReplicaState>, drainCoordinator: DrainCoordinator, slowHydrateThreshold: number, inspectorDelegate: InspectorDelegate, connContextManager: ConnectionContextManager, customQueryTransformer: CustomQueryTransformer | undefined, runPriorityOp: <T>(lc: LogContext, description: string, op: () => Promise<T>) => Promise<T>, keepaliveMs?: number, setTimeoutFn?: SetTimeout, now?: MonotonicClock);
70
+ constructor(config: NormalizedZeroConfig, lc: LogContext, shard: ShardID, taskID: string, clientGroupID: string, cvrDb: PostgresDB, pipelineDriver: PipelineDriver, versionChanges: Subscription<ReplicaState>, drainCoordinator: DrainCoordinator, slowHydrateThreshold: number, inspectorDelegate: InspectorDelegate, connContextManager: ConnectionContextManager, customQueryTransformer: CustomQueryTransformer | undefined, runPriorityOp: <T>(lc: LogContext, description: string, op: () => Promise<T>) => Promise<T>, keepaliveMs?: number, setTimeoutFn?: SetTimeout);
74
71
  readyState(): Promise<'initialized' | 'draining'>;
75
72
  run(): Promise<void>;
76
73
  get queryCount(): number;
@@ -101,13 +98,6 @@ export declare class ViewSyncerService implements ViewSyncer, ActivityBasedServi
101
98
  */
102
99
  markInitialized(): void;
103
100
  }
104
- /**
105
- * Whether a query's TTL has elapsed. A query must be expired for all clients
106
- * in order to be considered expired.
107
- *
108
- * Exported for testing.
109
- */
110
- export declare function expired(ttlClock: TTLClock, q: InternalQueryRecord | ClientQueryRecord | CustomQueryRecord): boolean;
111
101
  export declare class TimeSliceTimer {
112
102
  #private;
113
103
  constructor(lc: LogContext);