@rocicorp/zero 0.6.2024112102 → 0.7.2024120100

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 (243) hide show
  1. package/out/advanced.js +1 -1
  2. package/out/{chunk-QB7G63C6.js → chunk-4XX2NVJ7.js} +737 -738
  3. package/out/{chunk-QB7G63C6.js.map → chunk-4XX2NVJ7.js.map} +4 -4
  4. package/out/{chunk-5UY46OAF.js → chunk-C7M3BJ3Z.js} +16 -8
  5. package/out/chunk-C7M3BJ3Z.js.map +7 -0
  6. package/out/shared/src/expand.js +2 -0
  7. package/out/shared/src/expand.js.map +1 -0
  8. package/out/shared/src/immutable.js +2 -0
  9. package/out/shared/src/immutable.js.map +1 -0
  10. package/out/{zero-cache/src/config/config.d.ts → shared/src/options.d.ts} +3 -5
  11. package/out/shared/src/options.d.ts.map +1 -0
  12. package/out/{zero-cache/src/config/config.js → shared/src/options.js} +26 -26
  13. package/out/shared/src/options.js.map +1 -0
  14. package/out/shared/src/sorted-entries.js +6 -0
  15. package/out/shared/src/sorted-entries.js.map +1 -0
  16. package/out/shared/src/writable.js +2 -0
  17. package/out/shared/src/writable.js.map +1 -0
  18. package/out/solid.js +2 -2
  19. package/out/zero/src/build-schema.d.ts +3 -0
  20. package/out/zero/src/build-schema.d.ts.map +1 -0
  21. package/out/zero/src/build-schema.js +3 -0
  22. package/out/zero/src/build-schema.js.map +1 -0
  23. package/out/zero-cache/src/auth/load-schema.d.ts +8 -0
  24. package/out/zero-cache/src/auth/load-schema.d.ts.map +1 -0
  25. package/out/zero-cache/src/auth/load-schema.js +35 -0
  26. package/out/zero-cache/src/auth/load-schema.js.map +1 -0
  27. package/out/zero-cache/src/auth/read-authorizer.d.ts +25 -0
  28. package/out/zero-cache/src/auth/read-authorizer.d.ts.map +1 -0
  29. package/out/zero-cache/src/auth/read-authorizer.js +126 -0
  30. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -0
  31. package/out/zero-cache/src/auth/write-authorizer.d.ts +20 -0
  32. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -0
  33. package/out/zero-cache/src/auth/write-authorizer.js +320 -0
  34. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -0
  35. package/out/zero-cache/src/config/zero-config.d.ts +14 -4
  36. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  37. package/out/zero-cache/src/config/zero-config.js +27 -14
  38. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  39. package/out/zero-cache/src/server/main.js +7 -0
  40. package/out/zero-cache/src/server/main.js.map +1 -1
  41. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  42. package/out/zero-cache/src/server/replicator.js +4 -3
  43. package/out/zero-cache/src/server/replicator.js.map +1 -1
  44. package/out/zero-cache/src/server/runtime.d.ts +3 -0
  45. package/out/zero-cache/src/server/runtime.d.ts.map +1 -0
  46. package/out/zero-cache/src/server/runtime.js +19 -0
  47. package/out/zero-cache/src/server/runtime.js.map +1 -0
  48. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  49. package/out/zero-cache/src/server/syncer.js +7 -6
  50. package/out/zero-cache/src/server/syncer.js.map +1 -1
  51. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +1 -1
  52. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  53. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +7 -6
  54. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/mutagen/mutagen.js +19 -33
  56. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  57. package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
  58. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  59. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  60. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  61. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +1 -1
  62. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  63. package/out/zero-cache/src/services/view-syncer/client-handler.js +11 -8
  64. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  65. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +17 -8
  66. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  67. package/out/zero-cache/src/services/view-syncer/cvr-store.js +357 -94
  68. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  69. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +15 -10
  70. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  71. package/out/zero-cache/src/services/view-syncer/cvr.js +42 -23
  72. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  73. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  74. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -2
  75. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  76. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +22 -0
  77. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +1 -1
  78. package/out/zero-cache/src/services/view-syncer/schema/cvr.js +33 -7
  79. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  80. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +1 -1
  81. package/out/zero-cache/src/services/view-syncer/schema/init.js +44 -5
  82. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
  83. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +1 -0
  84. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
  85. package/out/zero-cache/src/services/view-syncer/schema/types.js +3 -0
  86. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  87. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  88. package/out/zero-cache/src/services/view-syncer/snapshotter.js +5 -0
  89. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  90. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +9 -1
  91. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  92. package/out/zero-cache/src/services/view-syncer/view-syncer.js +167 -50
  93. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  94. package/out/zero-cache/src/types/row-key.d.ts +6 -0
  95. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  96. package/out/zero-cache/src/types/row-key.js +16 -1
  97. package/out/zero-cache/src/types/row-key.js.map +1 -1
  98. package/out/zero-cache/src/workers/connection.d.ts +2 -3
  99. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  100. package/out/zero-cache/src/workers/connection.js +4 -3
  101. package/out/zero-cache/src/workers/connection.js.map +1 -1
  102. package/out/zero-cache/src/workers/replicator.d.ts +3 -1
  103. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  104. package/out/zero-cache/src/workers/replicator.js +2 -0
  105. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  106. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  107. package/out/zero-cache/src/workers/syncer.js +13 -3
  108. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  109. package/out/zero-client/src/client/options.d.ts +37 -8
  110. package/out/zero-client/src/client/options.d.ts.map +1 -1
  111. package/out/zero-client/src/client/reload-error-handler.d.ts +16 -1
  112. package/out/zero-client/src/client/reload-error-handler.d.ts.map +1 -1
  113. package/out/zero-client/src/client/zero.d.ts +7 -55
  114. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  115. package/out/zero-client/src/mod.d.ts +2 -2
  116. package/out/zero-client/src/mod.d.ts.map +1 -1
  117. package/out/zero-protocol/src/ast-hash.js +14 -0
  118. package/out/zero-protocol/src/ast-hash.js.map +1 -0
  119. package/out/zero-protocol/src/ast.d.ts +9 -9
  120. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  121. package/out/zero-protocol/src/ast.js +11 -12
  122. package/out/zero-protocol/src/ast.js.map +1 -1
  123. package/out/zero-protocol/src/down.d.ts +4 -4
  124. package/out/zero-protocol/src/poke.d.ts +16 -8
  125. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  126. package/out/zero-protocol/src/poke.js +8 -2
  127. package/out/zero-protocol/src/poke.js.map +1 -1
  128. package/out/zero-schema/src/build-schema.d.ts +14 -0
  129. package/out/zero-schema/src/build-schema.d.ts.map +1 -0
  130. package/out/zero-schema/src/build-schema.js +55 -0
  131. package/out/zero-schema/src/build-schema.js.map +1 -0
  132. package/out/zero-schema/src/compiled-permissions.d.ts +480 -0
  133. package/out/zero-schema/src/compiled-permissions.d.ts.map +1 -0
  134. package/out/zero-schema/src/compiled-permissions.js +20 -0
  135. package/out/zero-schema/src/compiled-permissions.js.map +1 -0
  136. package/out/zero-schema/src/mod.d.ts +1 -1
  137. package/out/zero-schema/src/mod.d.ts.map +1 -1
  138. package/out/zero-schema/src/normalize-table-schema.d.ts +19 -17
  139. package/out/zero-schema/src/normalize-table-schema.d.ts.map +1 -1
  140. package/out/zero-schema/src/normalize-table-schema.js +92 -0
  141. package/out/zero-schema/src/normalize-table-schema.js.map +1 -0
  142. package/out/zero-schema/src/normalized-schema.d.ts +6 -1
  143. package/out/zero-schema/src/normalized-schema.d.ts.map +1 -1
  144. package/out/zero-schema/src/normalized-schema.js +31 -0
  145. package/out/zero-schema/src/normalized-schema.js.map +1 -0
  146. package/out/zero-schema/src/permissions.d.ts +32 -0
  147. package/out/zero-schema/src/permissions.d.ts.map +1 -0
  148. package/out/zero-schema/src/schema-config.d.ts +43 -0
  149. package/out/zero-schema/src/schema-config.d.ts.map +1 -0
  150. package/out/zero-schema/src/schema-config.js +79 -0
  151. package/out/zero-schema/src/schema-config.js.map +1 -0
  152. package/out/zero-schema/src/schema.js +4 -0
  153. package/out/zero-schema/src/schema.js.map +1 -0
  154. package/out/zero-schema/src/table-schema.d.ts +15 -20
  155. package/out/zero-schema/src/table-schema.d.ts.map +1 -1
  156. package/out/zero-schema/src/table-schema.js +15 -2
  157. package/out/zero-schema/src/table-schema.js.map +1 -1
  158. package/out/zero.js +4 -4
  159. package/out/zql/src/builder/builder.d.ts +2 -2
  160. package/out/zql/src/builder/builder.d.ts.map +1 -1
  161. package/out/zql/src/builder/builder.js +15 -17
  162. package/out/zql/src/builder/builder.js.map +1 -1
  163. package/out/zql/src/builder/filter.d.ts +25 -2
  164. package/out/zql/src/builder/filter.d.ts.map +1 -1
  165. package/out/zql/src/builder/filter.js +91 -1
  166. package/out/zql/src/builder/filter.js.map +1 -1
  167. package/out/zql/src/ivm/array-view.js +70 -0
  168. package/out/zql/src/ivm/array-view.js.map +1 -0
  169. package/out/zql/src/ivm/change.d.ts +18 -6
  170. package/out/zql/src/ivm/change.d.ts.map +1 -1
  171. package/out/zql/src/ivm/change.js +1 -1
  172. package/out/zql/src/ivm/change.js.map +1 -1
  173. package/out/zql/src/ivm/constraint.d.ts +14 -0
  174. package/out/zql/src/ivm/constraint.d.ts.map +1 -0
  175. package/out/zql/src/ivm/constraint.js +60 -0
  176. package/out/zql/src/ivm/constraint.js.map +1 -0
  177. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  178. package/out/zql/src/ivm/exists.js +19 -2
  179. package/out/zql/src/ivm/exists.js.map +1 -1
  180. package/out/zql/src/ivm/join.d.ts +11 -5
  181. package/out/zql/src/ivm/join.d.ts.map +1 -1
  182. package/out/zql/src/ivm/join.js +49 -95
  183. package/out/zql/src/ivm/join.js.map +1 -1
  184. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  185. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +4 -13
  186. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  187. package/out/zql/src/ivm/memory-source.d.ts +5 -22
  188. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  189. package/out/zql/src/ivm/memory-source.js +61 -83
  190. package/out/zql/src/ivm/memory-source.js.map +1 -1
  191. package/out/zql/src/ivm/operator.d.ts +7 -10
  192. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  193. package/out/zql/src/ivm/operator.js +1 -1
  194. package/out/zql/src/ivm/operator.js.map +1 -1
  195. package/out/zql/src/ivm/take.d.ts +3 -1
  196. package/out/zql/src/ivm/take.d.ts.map +1 -1
  197. package/out/zql/src/ivm/take.js +95 -95
  198. package/out/zql/src/ivm/take.js.map +1 -1
  199. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  200. package/out/zql/src/ivm/view-apply-change.js +168 -0
  201. package/out/zql/src/ivm/view-apply-change.js.map +1 -0
  202. package/out/zql/src/ivm/view.js +2 -0
  203. package/out/zql/src/ivm/view.js.map +1 -0
  204. package/out/zql/src/query/auth-query.d.ts +3 -5
  205. package/out/zql/src/query/auth-query.d.ts.map +1 -1
  206. package/out/zql/src/query/auth-query.js +30 -0
  207. package/out/zql/src/query/auth-query.js.map +1 -0
  208. package/out/zql/src/query/dnf.js +57 -0
  209. package/out/zql/src/query/dnf.js.map +1 -0
  210. package/out/zql/src/query/expression.js +155 -0
  211. package/out/zql/src/query/expression.js.map +1 -0
  212. package/out/zql/src/query/query-impl.d.ts +4 -1
  213. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  214. package/out/zql/src/query/query-impl.js +353 -0
  215. package/out/zql/src/query/query-impl.js.map +1 -0
  216. package/out/zql/src/query/query-internal.js +2 -0
  217. package/out/zql/src/query/query-internal.js.map +1 -0
  218. package/out/zql/src/query/query.js +3 -0
  219. package/out/zql/src/query/query.js.map +1 -0
  220. package/out/zql/src/query/typed-view.js +2 -0
  221. package/out/zql/src/query/typed-view.js.map +1 -0
  222. package/out/zqlite/src/table-source.d.ts +2 -11
  223. package/out/zqlite/src/table-source.d.ts.map +1 -1
  224. package/out/zqlite/src/table-source.js +33 -82
  225. package/out/zqlite/src/table-source.js.map +1 -1
  226. package/package.json +5 -3
  227. package/out/chunk-5UY46OAF.js.map +0 -7
  228. package/out/zero-cache/src/auth/load-authorization.d.ts +0 -4
  229. package/out/zero-cache/src/auth/load-authorization.d.ts.map +0 -1
  230. package/out/zero-cache/src/auth/load-authorization.js +0 -20
  231. package/out/zero-cache/src/auth/load-authorization.js.map +0 -1
  232. package/out/zero-cache/src/config/config.d.ts.map +0 -1
  233. package/out/zero-cache/src/config/config.js.map +0 -1
  234. package/out/zero-cache/src/services/mutagen/write-authorizer.d.ts +0 -21
  235. package/out/zero-cache/src/services/mutagen/write-authorizer.d.ts.map +0 -1
  236. package/out/zero-cache/src/services/mutagen/write-authorizer.js +0 -168
  237. package/out/zero-cache/src/services/mutagen/write-authorizer.js.map +0 -1
  238. package/out/zero-schema/src/authorization.d.ts +0 -25
  239. package/out/zero-schema/src/authorization.d.ts.map +0 -1
  240. package/out/zero-schema/src/compiled-authorization.d.ts +0 -561
  241. package/out/zero-schema/src/compiled-authorization.d.ts.map +0 -1
  242. package/out/zero-schema/src/compiled-authorization.js +0 -15
  243. package/out/zero-schema/src/compiled-authorization.js.map +0 -1
@@ -14,7 +14,7 @@ import {
14
14
  must,
15
15
  throwInvalidType,
16
16
  unreachable
17
- } from "./chunk-5UY46OAF.js";
17
+ } from "./chunk-C7M3BJ3Z.js";
18
18
  import {
19
19
  __export,
20
20
  __reExport
@@ -3106,13 +3106,13 @@ var DataNodeImpl = class extends NodeImpl {
3106
3106
  }
3107
3107
  }
3108
3108
  };
3109
- function readonlySplice(array9, start, deleteCount, ...items) {
3110
- const arr = array9.slice(0, start);
3109
+ function readonlySplice(array10, start, deleteCount, ...items) {
3110
+ const arr = array10.slice(0, start);
3111
3111
  for (let i = 0; i < items.length; i++) {
3112
3112
  arr.push(items[i]);
3113
3113
  }
3114
- for (let i = start + deleteCount; i < array9.length; i++) {
3115
- arr.push(array9[i]);
3114
+ for (let i = start + deleteCount; i < array10.length; i++) {
3115
+ arr.push(array10[i]);
3116
3116
  }
3117
3117
  return arr;
3118
3118
  }
@@ -8091,14 +8091,14 @@ function diffBinarySearch(diff2, prefix, compareKey) {
8091
8091
  }
8092
8092
 
8093
8093
  // ../shared/src/random-values.ts
8094
- function getNonCryptoRandomValues(array9) {
8095
- if (array9 === null) {
8094
+ function getNonCryptoRandomValues(array10) {
8095
+ if (array10 === null) {
8096
8096
  throw new TypeError("array cannot be null");
8097
8097
  }
8098
- for (let i = 0; i < array9.length; i++) {
8099
- array9[i] = Math.floor(Math.random() * 256);
8098
+ for (let i = 0; i < array10.length; i++) {
8099
+ array10[i] = Math.floor(Math.random() * 256);
8100
8100
  }
8101
- return array9;
8101
+ return array10;
8102
8102
  }
8103
8103
 
8104
8104
  // ../replicache/src/sync/request-id.ts
@@ -9284,15 +9284,15 @@ function createTableSchema(schema) {
9284
9284
  return schema;
9285
9285
  }
9286
9286
  function isFieldRelationship(relationship) {
9287
- return relationship.junction === void 0;
9287
+ return !isJunctionRelationship(relationship);
9288
9288
  }
9289
9289
  function isJunctionRelationship(relationship) {
9290
- return !isFieldRelationship(relationship);
9290
+ return Array.isArray(relationship);
9291
9291
  }
9292
9292
 
9293
9293
  // ../shared/src/sorted-entries.ts
9294
- function sortedEntries(object16) {
9295
- return Object.entries(object16).sort((a, b) => stringCompare(a[0], b[0]));
9294
+ function sortedEntries(object17) {
9295
+ return Object.entries(object17).sort((a, b) => stringCompare(a[0], b[0]));
9296
9296
  }
9297
9297
 
9298
9298
  // ../zero-schema/src/normalize-table-schema.ts
@@ -9338,24 +9338,13 @@ function normalizeTableSchemaWithCache(tableSchema, expectedName, tableSchemaCac
9338
9338
  );
9339
9339
  return normalizedTableSchema;
9340
9340
  }
9341
- function isSorted(arr) {
9342
- for (let i = 1; i < arr.length; i++) {
9343
- if (arr[i - 1] >= arr[i]) {
9344
- return false;
9345
- }
9346
- }
9347
- return true;
9348
- }
9349
9341
  function assertNoDuplicates(arr) {
9350
- for (let i = 1; i < arr.length; i++) {
9351
- assert(arr[i - 1] !== arr[i], "Primary key must not contain duplicates");
9352
- }
9342
+ assert(
9343
+ new Set(arr).size === arr.length,
9344
+ "Primary key must not contain duplicates"
9345
+ );
9353
9346
  }
9354
9347
  function normalizePrimaryKey(arr) {
9355
- if (isSorted(arr)) {
9356
- return arr;
9357
- }
9358
- arr = [...arr].sort();
9359
9348
  assertNoDuplicates(arr);
9360
9349
  return arr;
9361
9350
  }
@@ -9396,36 +9385,24 @@ function normalizeRelationship(relationship, tableSchemaCache) {
9396
9385
  return normalizeJunctionRelationship(relationship, tableSchemaCache);
9397
9386
  }
9398
9387
  function normalizeFieldRelationship(relationship, tableSchemaCache) {
9388
+ assert(
9389
+ relationship.sourceField.length === relationship.destField.length,
9390
+ "Source and destination fields must have the same length"
9391
+ );
9399
9392
  return {
9400
- source: relationship.source,
9401
- dest: {
9402
- field: relationship.dest.field,
9403
- schema: normalizeLazyTableSchema(
9404
- relationship.dest.schema,
9405
- tableSchemaCache
9406
- )
9407
- }
9393
+ sourceField: relationship.sourceField,
9394
+ destField: relationship.destField,
9395
+ destSchema: normalizeLazyTableSchema(
9396
+ relationship.destSchema,
9397
+ tableSchemaCache
9398
+ )
9408
9399
  };
9409
9400
  }
9410
9401
  function normalizeJunctionRelationship(relationship, tableSchemaCache) {
9411
- return {
9412
- source: relationship.source,
9413
- junction: {
9414
- sourceField: relationship.junction.sourceField,
9415
- destField: relationship.junction.destField,
9416
- schema: normalizeLazyTableSchema(
9417
- relationship.junction.schema,
9418
- tableSchemaCache
9419
- )
9420
- },
9421
- dest: {
9422
- field: relationship.dest.field,
9423
- schema: normalizeLazyTableSchema(
9424
- relationship.dest.schema,
9425
- tableSchemaCache
9426
- )
9427
- }
9428
- };
9402
+ return [
9403
+ normalizeFieldRelationship(relationship[0], tableSchemaCache),
9404
+ normalizeFieldRelationship(relationship[1], tableSchemaCache)
9405
+ ];
9429
9406
  }
9430
9407
  function normalizeLazyTableSchema(tableSchema, buildCache) {
9431
9408
  const tableSchemaInstance = typeof tableSchema === "function" ? tableSchema() : tableSchema;
@@ -9461,6 +9438,158 @@ function normalizeTables(tables) {
9461
9438
  return rv;
9462
9439
  }
9463
9440
 
9441
+ // ../zql/src/query/expression.ts
9442
+ var ExpressionBuilder = class {
9443
+ #exists;
9444
+ constructor(exists) {
9445
+ this.#exists = exists;
9446
+ this.exists = this.exists.bind(this);
9447
+ }
9448
+ get eb() {
9449
+ return this;
9450
+ }
9451
+ cmp(field, opOrValue, value) {
9452
+ return cmp(field, opOrValue, value);
9453
+ }
9454
+ cmpLit(left, op, right) {
9455
+ return {
9456
+ type: "simple",
9457
+ left: isParameter(left) ? left : { type: "literal", value: left },
9458
+ right: isParameter(right) ? right : { type: "literal", value: right },
9459
+ op
9460
+ };
9461
+ }
9462
+ and = and;
9463
+ or = or;
9464
+ not = not;
9465
+ exists(relationship, cb) {
9466
+ return this.#exists(relationship, cb);
9467
+ }
9468
+ };
9469
+ function and(...conditions) {
9470
+ const expressions = filterTrue(filterUndefined(conditions));
9471
+ if (expressions.length === 1) {
9472
+ return expressions[0];
9473
+ }
9474
+ if (expressions.some(isAlwaysFalse)) {
9475
+ return FALSE;
9476
+ }
9477
+ return { type: "and", conditions: expressions };
9478
+ }
9479
+ function or(...conditions) {
9480
+ const expressions = filterFalse(filterUndefined(conditions));
9481
+ if (expressions.length === 1) {
9482
+ return expressions[0];
9483
+ }
9484
+ if (expressions.some(isAlwaysTrue)) {
9485
+ return TRUE;
9486
+ }
9487
+ return { type: "or", conditions: expressions };
9488
+ }
9489
+ function not(expression) {
9490
+ switch (expression.type) {
9491
+ case "and":
9492
+ return {
9493
+ type: "or",
9494
+ conditions: expression.conditions.map(not)
9495
+ };
9496
+ case "or":
9497
+ return {
9498
+ type: "and",
9499
+ conditions: expression.conditions.map(not)
9500
+ };
9501
+ case "correlatedSubquery":
9502
+ return {
9503
+ type: "correlatedSubquery",
9504
+ related: expression.related,
9505
+ op: negateOperator(expression.op)
9506
+ };
9507
+ case "simple":
9508
+ return {
9509
+ type: "simple",
9510
+ op: negateOperator(expression.op),
9511
+ left: expression.left,
9512
+ right: expression.right
9513
+ };
9514
+ }
9515
+ }
9516
+ function cmp(field, opOrValue, value) {
9517
+ let op;
9518
+ if (value === void 0) {
9519
+ value = opOrValue;
9520
+ op = "=";
9521
+ } else {
9522
+ op = opOrValue;
9523
+ }
9524
+ return {
9525
+ type: "simple",
9526
+ left: { type: "column", name: field },
9527
+ right: isParameter(value) ? value : { type: "literal", value },
9528
+ op
9529
+ };
9530
+ }
9531
+ function isParameter(value) {
9532
+ return typeof value === "object" && value?.type === "static";
9533
+ }
9534
+ var TRUE = {
9535
+ type: "and",
9536
+ conditions: []
9537
+ };
9538
+ var FALSE = {
9539
+ type: "or",
9540
+ conditions: []
9541
+ };
9542
+ function isAlwaysTrue(condition) {
9543
+ return condition.type === "and" && condition.conditions.length === 0;
9544
+ }
9545
+ function isAlwaysFalse(condition) {
9546
+ return condition.type === "or" && condition.conditions.length === 0;
9547
+ }
9548
+ function flatten(type, conditions) {
9549
+ const flattened2 = [];
9550
+ for (const c of conditions) {
9551
+ if (c.type === type) {
9552
+ flattened2.push(...c.conditions);
9553
+ } else {
9554
+ flattened2.push(c);
9555
+ }
9556
+ }
9557
+ return flattened2;
9558
+ }
9559
+ var negateSimpleOperatorMap = {
9560
+ ["="]: "!=",
9561
+ ["!="]: "=",
9562
+ ["<"]: ">=",
9563
+ [">"]: "<=",
9564
+ [">="]: "<",
9565
+ ["<="]: ">",
9566
+ ["IN"]: "NOT IN",
9567
+ ["NOT IN"]: "IN",
9568
+ ["LIKE"]: "NOT LIKE",
9569
+ ["NOT LIKE"]: "LIKE",
9570
+ ["ILIKE"]: "NOT ILIKE",
9571
+ ["NOT ILIKE"]: "ILIKE",
9572
+ ["IS"]: "IS NOT",
9573
+ ["IS NOT"]: "IS"
9574
+ };
9575
+ var negateOperatorMap = {
9576
+ ...negateSimpleOperatorMap,
9577
+ ["EXISTS"]: "NOT EXISTS",
9578
+ ["NOT EXISTS"]: "EXISTS"
9579
+ };
9580
+ function negateOperator(op) {
9581
+ return must(negateOperatorMap[op]);
9582
+ }
9583
+ function filterUndefined(array10) {
9584
+ return array10.filter((e) => e !== void 0);
9585
+ }
9586
+ function filterTrue(conditions) {
9587
+ return conditions.filter((c) => !isAlwaysTrue(c));
9588
+ }
9589
+ function filterFalse(conditions) {
9590
+ return conditions.filter((c) => !isAlwaysFalse(c));
9591
+ }
9592
+
9464
9593
  // ../zql/src/query/query-impl.ts
9465
9594
  import { resolver as resolver7 } from "@rocicorp/resolver";
9466
9595
 
@@ -9581,12 +9710,13 @@ var disjunctionSchema = readonlyObject({
9581
9710
  type: valita_exports.literal("or"),
9582
9711
  conditions: readonlyArray(conditionSchema)
9583
9712
  });
9713
+ var compoundKeySchema = valita_exports.tuple([valita_exports.string()]).concat(valita_exports.array(valita_exports.string()));
9714
+ var correlationSchema = readonlyObject({
9715
+ parentField: compoundKeySchema,
9716
+ childField: compoundKeySchema
9717
+ });
9584
9718
  var correlatedSubquerySchemaOmitSubquery = readonlyObject({
9585
- correlation: valita_exports.object({
9586
- parentField: valita_exports.string(),
9587
- childField: valita_exports.string(),
9588
- op: valita_exports.literal("=")
9589
- }),
9719
+ correlation: correlationSchema,
9590
9720
  hidden: valita_exports.boolean().optional()
9591
9721
  });
9592
9722
  var correlatedSubquerySchema = correlatedSubquerySchemaOmitSubquery.extend({
@@ -9620,11 +9750,7 @@ function normalizeAST(ast) {
9620
9750
  related: ast.related ? sortedRelated(
9621
9751
  ast.related.map(
9622
9752
  (r) => ({
9623
- correlation: {
9624
- parentField: r.correlation.parentField,
9625
- childField: r.correlation.childField,
9626
- op: r.correlation.op
9627
- },
9753
+ correlation: r.correlation,
9628
9754
  hidden: r.hidden,
9629
9755
  subquery: normalizeAST(r.subquery)
9630
9756
  })
@@ -9753,7 +9879,7 @@ function hashOfAST(ast) {
9753
9879
  // ../zql/src/ivm/change.ts
9754
9880
  function rowForChange(change) {
9755
9881
  const { type } = change;
9756
- return type === "add" || type === "remove" ? change.node.row : change.row;
9882
+ return type === "child" ? change.row : change.node.row;
9757
9883
  }
9758
9884
 
9759
9885
  // ../zql/src/ivm/data.ts
@@ -9895,8 +10021,12 @@ var Exists = class {
9895
10021
  size = this.#fetchSize(change.row);
9896
10022
  }
9897
10023
  if (size === 1) {
10024
+ const type = this.#not ? "remove" : "add";
10025
+ if (type === "remove") {
10026
+ this.#output.push(change);
10027
+ }
9898
10028
  this.#output.push({
9899
- type: this.#not ? "remove" : "add",
10029
+ type,
9900
10030
  node: this.#fetchNodeForRow(change.row)
9901
10031
  });
9902
10032
  } else {
@@ -9914,8 +10044,12 @@ var Exists = class {
9914
10044
  size = this.#fetchSize(change.row);
9915
10045
  }
9916
10046
  if (size === 0) {
10047
+ const type = this.#not ? "add" : "remove";
10048
+ if (type === "remove") {
10049
+ this.#output.push(change);
10050
+ }
9917
10051
  this.#output.push({
9918
- type: this.#not ? "add" : "remove",
10052
+ type,
9919
10053
  node: this.#fetchNodeForRow(change.row)
9920
10054
  });
9921
10055
  } else {
@@ -10092,25 +10226,19 @@ var FanOut = class {
10092
10226
 
10093
10227
  // ../zql/src/ivm/maybe-split-and-push-edit-change.ts
10094
10228
  function maybeSplitAndPushEditChange(change, predicate, output) {
10095
- const oldWasPresent = predicate(change.oldRow);
10096
- const newIsPresent = predicate(change.row);
10229
+ const oldWasPresent = predicate(change.oldNode.row);
10230
+ const newIsPresent = predicate(change.node.row);
10097
10231
  if (oldWasPresent && newIsPresent) {
10098
10232
  output.push(change);
10099
10233
  } else if (oldWasPresent && !newIsPresent) {
10100
10234
  output.push({
10101
10235
  type: "remove",
10102
- node: {
10103
- row: change.oldRow,
10104
- relationships: {}
10105
- }
10236
+ node: change.oldNode
10106
10237
  });
10107
10238
  } else if (!oldWasPresent && newIsPresent) {
10108
10239
  output.push({
10109
10240
  type: "add",
10110
- node: {
10111
- row: change.row,
10112
- relationships: {}
10113
- }
10241
+ node: change.node
10114
10242
  });
10115
10243
  }
10116
10244
  }
@@ -10192,6 +10320,10 @@ var Join = class {
10192
10320
  hidden
10193
10321
  }) {
10194
10322
  assert(parent !== child, "Parent and child must be different operators");
10323
+ assert(
10324
+ parentKey.length === childKey.length,
10325
+ "The parentKey and childKey keys must have same length"
10326
+ );
10195
10327
  this.#parent = parent;
10196
10328
  this.#child = child;
10197
10329
  this.#storage = storage;
@@ -10270,68 +10402,33 @@ var Join = class {
10270
10402
  this.#output.push(change);
10271
10403
  break;
10272
10404
  case "edit": {
10273
- this.#output.push({
10274
- type: "edit",
10275
- row: change.row,
10276
- oldRow: change.oldRow
10277
- });
10278
- const oldKeyValue = normalizeUndefined(change.oldRow[this.#parentKey]);
10279
- const newKeyValue = normalizeUndefined(change.row[this.#parentKey]);
10280
- if (newKeyValue !== oldKeyValue) {
10281
- const childrenToRemoveStream = this.#child.cleanup({
10282
- constraint: {
10283
- key: this.#childKey,
10284
- value: oldKeyValue
10285
- }
10405
+ if (rowEqualsForCompoundKey(
10406
+ change.oldNode.row,
10407
+ change.node.row,
10408
+ this.#parentKey
10409
+ )) {
10410
+ this.#output.push({
10411
+ type: "edit",
10412
+ oldNode: this.#processParentNode(
10413
+ change.oldNode.row,
10414
+ change.oldNode.relationships,
10415
+ "cleanup"
10416
+ ),
10417
+ node: this.#processParentNode(
10418
+ change.node.row,
10419
+ change.node.relationships,
10420
+ "fetch"
10421
+ )
10286
10422
  });
10287
- for (const childNode of childrenToRemoveStream) {
10288
- this.#output.push({
10289
- type: "child",
10290
- // This is the new row since we already changed it in the edit above.
10291
- row: change.row,
10292
- child: {
10293
- relationshipName: this.#relationshipName,
10294
- change: {
10295
- type: "remove",
10296
- node: childNode
10297
- }
10298
- }
10299
- });
10300
- }
10301
- const childrenToAddStream = this.#child.fetch({
10302
- constraint: {
10303
- key: this.#childKey,
10304
- value: newKeyValue
10305
- }
10423
+ } else {
10424
+ this.#pushParent({
10425
+ type: "remove",
10426
+ node: change.oldNode
10427
+ });
10428
+ this.#pushParent({
10429
+ type: "add",
10430
+ node: change.node
10306
10431
  });
10307
- for (const childNode of childrenToAddStream) {
10308
- this.#output.push({
10309
- type: "child",
10310
- row: change.row,
10311
- child: {
10312
- relationshipName: this.#relationshipName,
10313
- change: {
10314
- type: "add",
10315
- node: childNode
10316
- }
10317
- }
10318
- });
10319
- }
10320
- }
10321
- const { primaryKey } = this.#parent.getSchema();
10322
- const oldStorageKey = makeStorageKey(
10323
- oldKeyValue,
10324
- primaryKey,
10325
- change.oldRow
10326
- );
10327
- const newStorageKey = makeStorageKey(
10328
- newKeyValue,
10329
- primaryKey,
10330
- change.row
10331
- );
10332
- if (oldStorageKey !== newStorageKey) {
10333
- this.#storage.del(oldStorageKey);
10334
- this.#storage.set(newStorageKey, true);
10335
10432
  }
10336
10433
  break;
10337
10434
  }
@@ -10343,10 +10440,9 @@ var Join = class {
10343
10440
  const pushChildChange = (childRow, change2) => {
10344
10441
  assert(this.#output, "Output not set");
10345
10442
  const parentNodes = this.#parent.fetch({
10346
- constraint: {
10347
- key: this.#parentKey,
10348
- value: childRow[this.#childKey]
10349
- }
10443
+ constraint: Object.fromEntries(
10444
+ this.#parentKey.map((key, i) => [key, childRow[this.#childKey[i]]])
10445
+ )
10350
10446
  });
10351
10447
  for (const parentNode of parentNodes) {
10352
10448
  const childChange = {
@@ -10369,34 +10465,18 @@ var Join = class {
10369
10465
  pushChildChange(change.row, change);
10370
10466
  break;
10371
10467
  case "edit": {
10372
- const childRow = change.row;
10373
- const oldChildRow = change.oldRow;
10374
- if (normalizeUndefined(oldChildRow[this.#childKey]) === normalizeUndefined(childRow[this.#childKey])) {
10468
+ const childRow = change.node.row;
10469
+ const oldChildRow = change.oldNode.row;
10470
+ if (rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey)) {
10375
10471
  pushChildChange(childRow, change);
10376
10472
  } else {
10377
- const { relationships } = must(
10378
- first(
10379
- this.#child.fetch({
10380
- constraint: {
10381
- key: this.#childKey,
10382
- value: oldChildRow[this.#childKey]
10383
- }
10384
- })
10385
- )
10386
- );
10387
10473
  pushChildChange(oldChildRow, {
10388
10474
  type: "remove",
10389
- node: {
10390
- row: oldChildRow,
10391
- relationships
10392
- }
10475
+ node: change.oldNode
10393
10476
  });
10394
10477
  pushChildChange(childRow, {
10395
10478
  type: "add",
10396
- node: {
10397
- row: childRow,
10398
- relationships
10399
- }
10479
+ node: change.node
10400
10480
  });
10401
10481
  }
10402
10482
  break;
@@ -10406,9 +10486,8 @@ var Join = class {
10406
10486
  }
10407
10487
  }
10408
10488
  #processParentNode(parentNodeRow, parentNodeRelations, mode) {
10409
- const parentKeyValue = normalizeUndefined(parentNodeRow[this.#parentKey]);
10410
10489
  const storageKey = makeStorageKey(
10411
- parentKeyValue,
10490
+ this.#parentKey,
10412
10491
  this.#parent.getSchema().primaryKey,
10413
10492
  parentNodeRow
10414
10493
  );
@@ -10416,17 +10495,19 @@ var Join = class {
10416
10495
  if (mode === "cleanup") {
10417
10496
  const [, second] = take(
10418
10497
  this.#storage.scan({
10419
- prefix: createPrimaryKeySetStorageKeyPrefix(parentKeyValue)
10498
+ prefix: makeStorageKeyPrefix(parentNodeRow, this.#parentKey)
10420
10499
  }),
10421
10500
  2
10422
10501
  );
10423
10502
  method = second ? "fetch" : "cleanup";
10424
10503
  }
10425
10504
  const childStream = this.#child[method]({
10426
- constraint: {
10427
- key: this.#childKey,
10428
- value: parentKeyValue
10429
- }
10505
+ constraint: Object.fromEntries(
10506
+ this.#childKey.map((key, i) => [
10507
+ key,
10508
+ parentNodeRow[this.#parentKey[i]]
10509
+ ])
10510
+ )
10430
10511
  });
10431
10512
  if (mode === "fetch") {
10432
10513
  this.#storage.set(storageKey, true);
@@ -10443,19 +10524,27 @@ var Join = class {
10443
10524
  };
10444
10525
  }
10445
10526
  };
10446
- function createPrimaryKeySetStorageKey(values) {
10527
+ function makeStorageKeyForValues(values) {
10447
10528
  const json = JSON.stringify(["pKeySet", ...values]);
10448
10529
  return json.substring(1, json.length - 1) + ",";
10449
10530
  }
10450
- function createPrimaryKeySetStorageKeyPrefix(value) {
10451
- return createPrimaryKeySetStorageKey([value]);
10531
+ function makeStorageKeyPrefix(row, key) {
10532
+ return makeStorageKeyForValues(key.map((k) => row[k]));
10452
10533
  }
10453
- function makeStorageKey(keyValue, primaryKey, row) {
10454
- const parentPrimaryKey = [keyValue];
10455
- for (const key of primaryKey) {
10456
- parentPrimaryKey.push(normalizeUndefined(row[key]));
10534
+ function makeStorageKey(key, primaryKey, row) {
10535
+ const values = key.map((k) => row[k]);
10536
+ for (const key2 of primaryKey) {
10537
+ values.push(row[key2]);
10457
10538
  }
10458
- return createPrimaryKeySetStorageKey(parentPrimaryKey);
10539
+ return makeStorageKeyForValues(values);
10540
+ }
10541
+ function rowEqualsForCompoundKey(a, b, key) {
10542
+ for (let i = 0; i < key.length; i++) {
10543
+ if (!valuesEqual(a[key[i]], b[key[i]])) {
10544
+ return false;
10545
+ }
10546
+ }
10547
+ return true;
10459
10548
  }
10460
10549
 
10461
10550
  // ../zql/src/ivm/skip.ts
@@ -10551,18 +10640,20 @@ var Take = class {
10551
10640
  #storage;
10552
10641
  #limit;
10553
10642
  #partitionKey;
10643
+ #partitionKeyComparator;
10554
10644
  #output = null;
10555
10645
  constructor(input, storage, limit, partitionKey) {
10556
- this.#input = input;
10557
- this.#storage = storage;
10558
- this.#limit = limit;
10559
- this.#partitionKey = partitionKey;
10560
10646
  assert(limit >= 0);
10561
10647
  assertOrderingIncludesPK(
10562
10648
  input.getSchema().sort,
10563
10649
  input.getSchema().primaryKey
10564
10650
  );
10565
10651
  input.setOutput(this);
10652
+ this.#input = input;
10653
+ this.#storage = storage;
10654
+ this.#limit = limit;
10655
+ this.#partitionKey = partitionKey;
10656
+ this.#partitionKeyComparator = partitionKey && makePartitionKeyComparator(partitionKey);
10566
10657
  }
10567
10658
  setOutput(output) {
10568
10659
  this.#output = output;
@@ -10571,9 +10662,8 @@ var Take = class {
10571
10662
  return this.#input.getSchema();
10572
10663
  }
10573
10664
  *fetch(req) {
10574
- if (this.#partitionKey === void 0 || req.constraint?.key === this.#partitionKey) {
10575
- const partitionValue = this.#partitionKey === void 0 ? void 0 : req.constraint?.value;
10576
- const takeStateKey = getTakeStateKey(partitionValue);
10665
+ if (!this.#partitionKey || req.constraint && constraintMatchesPartitionKey(req.constraint, this.#partitionKey)) {
10666
+ const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
10577
10667
  const takeState = this.#storage.get(takeStateKey);
10578
10668
  if (!takeState) {
10579
10669
  yield* this.#initialFetch(req);
@@ -10598,8 +10688,7 @@ var Take = class {
10598
10688
  if (this.getSchema().compareRows(inputNode.row, maxBound) > 0) {
10599
10689
  return;
10600
10690
  }
10601
- const partitionValue = inputNode.row[this.#partitionKey];
10602
- const takeStateKey = getTakeStateKey(partitionValue);
10691
+ const takeStateKey = getTakeStateKey(this.#partitionKey, inputNode.row);
10603
10692
  const takeState = this.#storage.get(takeStateKey);
10604
10693
  if (takeState?.bound !== void 0 && this.getSchema().compareRows(takeState.bound, inputNode.row) >= 0) {
10605
10694
  yield inputNode;
@@ -10609,13 +10698,13 @@ var Take = class {
10609
10698
  *#initialFetch(req) {
10610
10699
  assert(req.start === void 0);
10611
10700
  assert(
10612
- this.#partitionKey === void 0 || req.constraint !== void 0 && req.constraint.key === this.#partitionKey
10701
+ !this.#partitionKey || req.constraint && // TODO: Compound keys
10702
+ constraintMatchesPartitionKey(req.constraint, this.#partitionKey)
10613
10703
  );
10614
10704
  if (this.#limit === 0) {
10615
10705
  return;
10616
10706
  }
10617
- const partitionValue = this.#partitionKey === void 0 ? void 0 : req.constraint?.value;
10618
- const takeStateKey = getTakeStateKey(partitionValue);
10707
+ const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
10619
10708
  assert(this.#storage.get(takeStateKey) === void 0);
10620
10709
  let size = 0;
10621
10710
  let bound;
@@ -10646,14 +10735,17 @@ var Take = class {
10646
10735
  *cleanup(req) {
10647
10736
  assert(req.start === void 0);
10648
10737
  assert(
10649
- this.#partitionKey === void 0 || req.constraint !== void 0 && req.constraint.key === this.#partitionKey
10738
+ !this.#partitionKey || req.constraint && // TODO: Compound keys
10739
+ constraintMatchesPartitionKey(req.constraint, this.#partitionKey)
10650
10740
  );
10651
10741
  let takeState;
10652
10742
  if (this.#limit > 0) {
10653
- const partitionValue = this.#partitionKey === void 0 ? void 0 : req.constraint?.value;
10654
- const takeStateKey = getTakeStateKey(partitionValue);
10743
+ const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
10655
10744
  takeState = this.#storage.get(takeStateKey);
10656
- assert(takeState !== void 0);
10745
+ assert(
10746
+ takeState !== void 0,
10747
+ "takeStateKey was: " + takeStateKey + ", partitionKey was: " + this.#partitionKey + ", constraint was: " + JSON.stringify(req.constraint)
10748
+ );
10657
10749
  this.#storage.del(takeStateKey);
10658
10750
  }
10659
10751
  for (const inputNode of this.#input.cleanup(req)) {
@@ -10664,17 +10756,15 @@ var Take = class {
10664
10756
  }
10665
10757
  }
10666
10758
  #getStateAndConstraint(row) {
10667
- const partitionValue = this.#partitionKey === void 0 ? void 0 : row[this.#partitionKey];
10668
- const takeStateKey = getTakeStateKey(partitionValue);
10759
+ const takeStateKey = getTakeStateKey(this.#partitionKey, row);
10669
10760
  const takeState = this.#storage.get(takeStateKey);
10670
10761
  let maxBound;
10671
10762
  let constraint;
10672
10763
  if (takeState) {
10673
10764
  maxBound = this.#storage.get(MAX_BOUND_KEY);
10674
- constraint = this.#partitionKey ? {
10675
- key: this.#partitionKey,
10676
- value: partitionValue
10677
- } : void 0;
10765
+ constraint = this.#partitionKey && Object.fromEntries(
10766
+ this.#partitionKey.map((key) => [key, row[key]])
10767
+ );
10678
10768
  }
10679
10769
  return { takeState, takeStateKey, maxBound, constraint };
10680
10770
  }
@@ -10749,57 +10839,41 @@ var Take = class {
10749
10839
  if (compToBound > 0) {
10750
10840
  return;
10751
10841
  }
10752
- if (takeState.size === 1) {
10753
- this.#storage.set(takeStateKey, {
10754
- size: 0,
10755
- bound: void 0
10756
- });
10757
- this.#output.push(change);
10758
- return;
10759
- }
10760
- let beforeBoundNode;
10761
- let afterBoundNode;
10762
- if (compToBound === 0) {
10763
- [beforeBoundNode, afterBoundNode] = take(
10764
- this.#input.fetch({
10765
- start: {
10766
- row: takeState.bound,
10767
- basis: "before"
10768
- },
10769
- constraint
10770
- }),
10771
- 2
10772
- );
10773
- } else {
10774
- [beforeBoundNode, , afterBoundNode] = take(
10775
- this.#input.fetch({
10776
- start: {
10777
- row: takeState.bound,
10778
- basis: "before"
10779
- },
10780
- constraint
10781
- }),
10782
- 3
10783
- );
10842
+ let newBound;
10843
+ for (const node of this.#input.fetch({
10844
+ start: {
10845
+ row: takeState.bound,
10846
+ basis: "before"
10847
+ },
10848
+ constraint
10849
+ })) {
10850
+ const push2 = compareRows(node.row, takeState.bound) > 0;
10851
+ newBound = {
10852
+ node,
10853
+ push: push2
10854
+ };
10855
+ if (push2) {
10856
+ break;
10857
+ }
10784
10858
  }
10785
- if (afterBoundNode) {
10859
+ if (newBound?.push) {
10786
10860
  this.#setTakeState(
10787
10861
  takeStateKey,
10788
10862
  takeState.size,
10789
- afterBoundNode.row,
10863
+ newBound.node.row,
10790
10864
  maxBound
10791
10865
  );
10792
10866
  this.#output.push(change);
10793
10867
  this.#output.push({
10794
10868
  type: "add",
10795
- node: afterBoundNode
10869
+ node: newBound.node
10796
10870
  });
10797
10871
  return;
10798
10872
  }
10799
10873
  this.#setTakeState(
10800
10874
  takeStateKey,
10801
10875
  takeState.size - 1,
10802
- compToBound === 0 ? beforeBoundNode.row : takeState.bound,
10876
+ newBound?.node.row,
10803
10877
  maxBound
10804
10878
  );
10805
10879
  this.#output.push(change);
@@ -10811,33 +10885,32 @@ var Take = class {
10811
10885
  }
10812
10886
  #pushEditChange(change) {
10813
10887
  assert(this.#output, "Output not set");
10814
- if (this.#partitionKey !== void 0 && change.oldRow[this.#partitionKey] !== change.row[this.#partitionKey]) {
10888
+ if (this.#partitionKeyComparator && this.#partitionKeyComparator(change.oldNode.row, change.node.row) !== 0) {
10815
10889
  this.push({
10816
10890
  type: "remove",
10817
- node: {
10818
- row: change.oldRow,
10819
- relationships: {}
10820
- }
10891
+ node: change.oldNode
10821
10892
  });
10822
10893
  this.push({
10823
10894
  type: "add",
10824
- node: {
10825
- row: change.row,
10826
- relationships: {}
10827
- }
10895
+ node: change.node
10828
10896
  });
10829
10897
  return;
10830
10898
  }
10831
- const { takeState, takeStateKey, maxBound, constraint } = this.#getStateAndConstraint(change.oldRow);
10899
+ const { takeState, takeStateKey, maxBound, constraint } = this.#getStateAndConstraint(change.oldNode.row);
10832
10900
  if (!takeState) {
10833
10901
  return;
10834
10902
  }
10835
10903
  assert(takeState.bound, "Bound should be set");
10836
10904
  const { compareRows } = this.getSchema();
10837
- const oldCmp = compareRows(change.oldRow, takeState.bound);
10838
- const newCmp = compareRows(change.row, takeState.bound);
10905
+ const oldCmp = compareRows(change.oldNode.row, takeState.bound);
10906
+ const newCmp = compareRows(change.node.row, takeState.bound);
10839
10907
  const replaceBoundAndForwardChange = () => {
10840
- this.#setTakeState(takeStateKey, takeState.size, change.row, maxBound);
10908
+ this.#setTakeState(
10909
+ takeStateKey,
10910
+ takeState.size,
10911
+ change.node.row,
10912
+ maxBound
10913
+ );
10841
10914
  this.#output.push(change);
10842
10915
  };
10843
10916
  if (oldCmp === 0) {
@@ -10882,7 +10955,7 @@ var Take = class {
10882
10955
  })
10883
10956
  )
10884
10957
  );
10885
- if (compareRows(newBoundNode.row, change.row) === 0) {
10958
+ if (compareRows(newBoundNode.row, change.node.row) === 0) {
10886
10959
  replaceBoundAndForwardChange();
10887
10960
  return;
10888
10961
  }
@@ -10894,10 +10967,7 @@ var Take = class {
10894
10967
  );
10895
10968
  this.#output.push({
10896
10969
  type: "remove",
10897
- node: {
10898
- row: change.oldRow,
10899
- relationships: {}
10900
- }
10970
+ node: change.oldNode
10901
10971
  });
10902
10972
  this.#output.push({
10903
10973
  type: "add",
@@ -10933,10 +11003,7 @@ var Take = class {
10933
11003
  });
10934
11004
  this.#output.push({
10935
11005
  type: "add",
10936
- node: {
10937
- row: change.row,
10938
- relationships: {}
10939
- }
11006
+ node: change.node
10940
11007
  });
10941
11008
  return;
10942
11009
  }
@@ -10958,7 +11025,7 @@ var Take = class {
10958
11025
  })
10959
11026
  )
10960
11027
  );
10961
- if (compareRows(afterBoundNode.row, change.row) === 0) {
11028
+ if (compareRows(afterBoundNode.row, change.node.row) === 0) {
10962
11029
  replaceBoundAndForwardChange();
10963
11030
  return;
10964
11031
  }
@@ -10970,10 +11037,7 @@ var Take = class {
10970
11037
  );
10971
11038
  this.#output.push({
10972
11039
  type: "remove",
10973
- node: {
10974
- row: change.oldRow,
10975
- relationships: {}
10976
- }
11040
+ node: change.oldNode
10977
11041
  });
10978
11042
  this.#output.push({
10979
11043
  type: "add",
@@ -10996,8 +11060,33 @@ var Take = class {
10996
11060
  this.#input.destroy();
10997
11061
  }
10998
11062
  };
10999
- function getTakeStateKey(partitionValue) {
11000
- return JSON.stringify(["take", normalizeUndefined(partitionValue)]);
11063
+ function getTakeStateKey(partitionKey, rowOrConstraint) {
11064
+ const partitionValues = [];
11065
+ if (partitionKey && rowOrConstraint) {
11066
+ for (const key of partitionKey) {
11067
+ partitionValues.push(rowOrConstraint[key]);
11068
+ }
11069
+ }
11070
+ return JSON.stringify(["take", ...partitionValues]);
11071
+ }
11072
+ function constraintMatchesPartitionKey(constraint, partitionKey) {
11073
+ for (const key of partitionKey) {
11074
+ if (!hasOwn(constraint, key)) {
11075
+ return false;
11076
+ }
11077
+ }
11078
+ return true;
11079
+ }
11080
+ function makePartitionKeyComparator(partitionKey) {
11081
+ return (a, b) => {
11082
+ for (const key of partitionKey) {
11083
+ const cmp2 = compareValues(a[key], b[key]);
11084
+ if (cmp2 !== 0) {
11085
+ return cmp2;
11086
+ }
11087
+ }
11088
+ return 0;
11089
+ };
11001
11090
  }
11002
11091
 
11003
11092
  // ../zql/src/builder/like.ts
@@ -11050,6 +11139,24 @@ function patternToRegExp(source, flags = "") {
11050
11139
 
11051
11140
  // ../zql/src/builder/filter.ts
11052
11141
  function createPredicate(condition) {
11142
+ if (condition.type !== "simple") {
11143
+ const predicates = condition.conditions.map((c) => createPredicate(c));
11144
+ return condition.type === "and" ? (row) => {
11145
+ for (const predicate of predicates) {
11146
+ if (!predicate(row)) {
11147
+ return false;
11148
+ }
11149
+ }
11150
+ return true;
11151
+ } : (row) => {
11152
+ for (const predicate of predicates) {
11153
+ if (predicate(row)) {
11154
+ return true;
11155
+ }
11156
+ }
11157
+ return false;
11158
+ };
11159
+ }
11053
11160
  const { left } = condition;
11054
11161
  const { right } = condition;
11055
11162
  assert(
@@ -11115,11 +11222,11 @@ function createPredicateImpl(rhs, operator) {
11115
11222
  case "LIKE":
11116
11223
  return getLikePredicate(rhs, "");
11117
11224
  case "NOT LIKE":
11118
- return not(getLikePredicate(rhs, ""));
11225
+ return not2(getLikePredicate(rhs, ""));
11119
11226
  case "ILIKE":
11120
11227
  return getLikePredicate(rhs, "i");
11121
11228
  case "NOT ILIKE":
11122
- return not(getLikePredicate(rhs, "i"));
11229
+ return not2(getLikePredicate(rhs, "i"));
11123
11230
  case "IN": {
11124
11231
  assert(Array.isArray(rhs));
11125
11232
  const set = new Set(rhs);
@@ -11135,74 +11242,71 @@ function createPredicateImpl(rhs, operator) {
11135
11242
  throw new Error(`Unexpected operator: ${operator}`);
11136
11243
  }
11137
11244
  }
11138
- function not(f) {
11245
+ function not2(f) {
11139
11246
  return (lhs) => !f(lhs);
11140
11247
  }
11141
-
11142
- // ../zql/src/builder/builder.ts
11143
- function buildPipeline(ast, delegate, staticQueryParameters) {
11144
- return buildPipelineInternal(
11145
- bindStaticParameters(ast, staticQueryParameters),
11146
- delegate,
11147
- staticQueryParameters
11148
- );
11149
- }
11150
- function bindStaticParameters(ast, staticQueryParameters) {
11151
- const visit = (node) => {
11152
- if (node.where) {
11153
- return {
11154
- ...node,
11155
- where: bindCondition(node.where),
11156
- related: node.related?.map((sq) => ({
11157
- ...sq,
11158
- subquery: visit(sq.subquery)
11159
- }))
11160
- };
11161
- }
11162
- return node;
11163
- };
11164
- function bindCondition(condition) {
11165
- if (condition.type === "simple") {
11248
+ function transformFilters(filters) {
11249
+ if (!filters) {
11250
+ return { filters: void 0, conditionsRemoved: false };
11251
+ }
11252
+ switch (filters.type) {
11253
+ case "simple":
11254
+ return { filters, conditionsRemoved: false };
11255
+ case "correlatedSubquery":
11256
+ return { filters: void 0, conditionsRemoved: true };
11257
+ case "and": {
11258
+ const transformedConditions = [];
11259
+ for (const cond of filters.conditions) {
11260
+ assert(cond.type === "simple" || cond.type === "correlatedSubquery");
11261
+ if (cond.type === "simple") {
11262
+ transformedConditions.push(cond);
11263
+ }
11264
+ }
11265
+ const conditionsRemoved = transformedConditions.length !== filters.conditions.length;
11266
+ if (transformedConditions.length === 0) {
11267
+ return { filters: void 0, conditionsRemoved };
11268
+ }
11269
+ if (transformedConditions.length === 1) {
11270
+ return {
11271
+ filters: transformedConditions[0],
11272
+ conditionsRemoved
11273
+ };
11274
+ }
11166
11275
  return {
11167
- ...condition,
11168
- left: bindValue(condition.left),
11169
- right: bindValue(condition.right)
11276
+ filters: {
11277
+ type: "and",
11278
+ conditions: transformedConditions
11279
+ },
11280
+ conditionsRemoved
11170
11281
  };
11171
11282
  }
11172
- if (condition.type === "correlatedSubquery") {
11173
- return {
11174
- ...condition,
11175
- related: {
11176
- ...condition.related,
11177
- subquery: visit(condition.related.subquery)
11283
+ case "or": {
11284
+ const transformedConditions = [];
11285
+ let conditionsRemoved = false;
11286
+ for (const cond of filters.conditions) {
11287
+ assert(cond.type !== "or");
11288
+ const transformed = transformFilters(cond);
11289
+ if (transformed.filters === void 0) {
11290
+ return { filters: void 0, conditionsRemoved: true };
11178
11291
  }
11179
- };
11180
- }
11181
- return {
11182
- ...condition,
11183
- conditions: condition.conditions.map(bindCondition)
11184
- };
11185
- }
11186
- const bindValue = (value) => {
11187
- if (isParameter(value)) {
11188
- const anchor = must(
11189
- staticQueryParameters,
11190
- "Static query params do not exist"
11191
- )[value.anchor];
11192
- const resolvedValue = anchor?.[value.field] ?? null;
11292
+ conditionsRemoved = conditionsRemoved || transformed.conditionsRemoved;
11293
+ transformedConditions.push(transformed.filters);
11294
+ }
11193
11295
  return {
11194
- type: "literal",
11195
- value: resolvedValue
11296
+ filters: { type: "or", conditions: transformedConditions },
11297
+ conditionsRemoved
11196
11298
  };
11197
11299
  }
11198
- return value;
11199
- };
11200
- return visit(ast);
11300
+ default:
11301
+ unreachable(filters);
11302
+ }
11201
11303
  }
11202
- function isParameter(value) {
11203
- return value.type === "static";
11304
+
11305
+ // ../zql/src/builder/builder.ts
11306
+ function buildPipeline(ast, delegate) {
11307
+ return buildPipelineInternal(ast, delegate);
11204
11308
  }
11205
- function buildPipelineInternal(ast, delegate, staticQueryParameters, partitionKey) {
11309
+ function buildPipelineInternal(ast, delegate, partitionKey) {
11206
11310
  const source = delegate.getSource(ast.table);
11207
11311
  if (!source) {
11208
11312
  throw new Error(`Source not found: ${ast.table}`);
@@ -11215,7 +11319,7 @@ function buildPipelineInternal(ast, delegate, staticQueryParameters, partitionKe
11215
11319
  end = new Skip(end, ast.start);
11216
11320
  }
11217
11321
  for (const csq of gatherCorrelatedSubqueryQueriesFromCondition(ast.where)) {
11218
- end = applyCorrelatedSubQuery(csq, delegate, staticQueryParameters, end);
11322
+ end = applyCorrelatedSubQuery(csq, delegate, end);
11219
11323
  }
11220
11324
  if (ast.where) {
11221
11325
  end = applyWhere(end, ast.where, appliedFilters, delegate);
@@ -11225,7 +11329,7 @@ function buildPipelineInternal(ast, delegate, staticQueryParameters, partitionKe
11225
11329
  }
11226
11330
  if (ast.related) {
11227
11331
  for (const csq of ast.related) {
11228
- end = applyCorrelatedSubQuery(csq, delegate, staticQueryParameters, end);
11332
+ end = applyCorrelatedSubQuery(csq, delegate, end);
11229
11333
  }
11230
11334
  }
11231
11335
  return end;
@@ -11262,12 +11366,11 @@ function applySimpleCondition(input, condition, appliedFilters) {
11262
11366
  createPredicate(condition)
11263
11367
  );
11264
11368
  }
11265
- function applyCorrelatedSubQuery(sq, delegate, staticQueryParameters, end) {
11369
+ function applyCorrelatedSubQuery(sq, delegate, end) {
11266
11370
  assert(sq.subquery.alias, "Subquery must have an alias");
11267
11371
  const child = buildPipelineInternal(
11268
11372
  sq.subquery,
11269
11373
  delegate,
11270
- staticQueryParameters,
11271
11374
  sq.correlation.childField
11272
11375
  );
11273
11376
  end = new Join({
@@ -11409,199 +11512,47 @@ var ArrayView = class {
11409
11512
  get data() {
11410
11513
  return this.#root[""];
11411
11514
  }
11412
- addListener(listener) {
11413
- assert(!this.#listeners.has(listener), "Listener already registered");
11414
- this.#listeners.add(listener);
11415
- listener(this.data);
11416
- return () => {
11417
- this.#listeners.delete(listener);
11418
- };
11419
- }
11420
- #fireListeners() {
11421
- for (const listener of this.#listeners) {
11422
- listener(this.data);
11423
- }
11424
- }
11425
- destroy() {
11426
- this.onDestroy?.();
11427
- }
11428
- #hydrate() {
11429
- this.#dirty = true;
11430
- for (const node of this.#input.fetch({})) {
11431
- applyChange(
11432
- this.#root,
11433
- { type: "add", node },
11434
- this.#schema,
11435
- "",
11436
- this.#format
11437
- );
11438
- }
11439
- this.flush();
11440
- }
11441
- push(change) {
11442
- this.#dirty = true;
11443
- applyChange(this.#root, change, this.#schema, "", this.#format);
11444
- }
11445
- flush() {
11446
- if (!this.#dirty) {
11447
- return;
11448
- }
11449
- this.#dirty = false;
11450
- this.#fireListeners();
11451
- }
11452
- };
11453
-
11454
- // ../zql/src/query/expression.ts
11455
- var ExpressionBuilder = class {
11456
- #exists;
11457
- constructor(exists) {
11458
- this.#exists = exists;
11459
- this.exists = this.exists.bind(this);
11460
- }
11461
- get eb() {
11462
- return this;
11463
- }
11464
- cmp(field, opOrValue, value) {
11465
- return cmp(field, opOrValue, value);
11466
- }
11467
- cmpLit(left, op, right) {
11468
- return {
11469
- type: "simple",
11470
- left: isParameter2(left) ? left : { type: "literal", value: left },
11471
- right: isParameter2(right) ? right : { type: "literal", value: right },
11472
- op
11473
- };
11474
- }
11475
- and = and;
11476
- or = or;
11477
- not = not2;
11478
- exists(relationship, cb) {
11479
- return this.#exists(relationship, cb);
11480
- }
11481
- };
11482
- function and(...conditions) {
11483
- const expressions = filterTrue(filterUndefined(conditions));
11484
- if (expressions.length === 1) {
11485
- return expressions[0];
11486
- }
11487
- if (expressions.some(isAlwaysFalse)) {
11488
- return FALSE;
11515
+ addListener(listener) {
11516
+ assert(!this.#listeners.has(listener), "Listener already registered");
11517
+ this.#listeners.add(listener);
11518
+ listener(this.data);
11519
+ return () => {
11520
+ this.#listeners.delete(listener);
11521
+ };
11489
11522
  }
11490
- return { type: "and", conditions: expressions };
11491
- }
11492
- function or(...conditions) {
11493
- const expressions = filterFalse(filterUndefined(conditions));
11494
- if (expressions.length === 1) {
11495
- return expressions[0];
11523
+ #fireListeners() {
11524
+ for (const listener of this.#listeners) {
11525
+ listener(this.data);
11526
+ }
11496
11527
  }
11497
- if (expressions.some(isAlwaysTrue)) {
11498
- return TRUE;
11528
+ destroy() {
11529
+ this.onDestroy?.();
11499
11530
  }
11500
- return { type: "or", conditions: expressions };
11501
- }
11502
- function not2(expression) {
11503
- switch (expression.type) {
11504
- case "and":
11505
- return {
11506
- type: "or",
11507
- conditions: expression.conditions.map(not2)
11508
- };
11509
- case "or":
11510
- return {
11511
- type: "and",
11512
- conditions: expression.conditions.map(not2)
11513
- };
11514
- case "correlatedSubquery":
11515
- return {
11516
- type: "correlatedSubquery",
11517
- related: expression.related,
11518
- op: negateOperator(expression.op)
11519
- };
11520
- case "simple":
11521
- return {
11522
- type: "simple",
11523
- op: negateOperator(expression.op),
11524
- left: expression.left,
11525
- right: expression.right
11526
- };
11531
+ #hydrate() {
11532
+ this.#dirty = true;
11533
+ for (const node of this.#input.fetch({})) {
11534
+ applyChange(
11535
+ this.#root,
11536
+ { type: "add", node },
11537
+ this.#schema,
11538
+ "",
11539
+ this.#format
11540
+ );
11541
+ }
11542
+ this.flush();
11527
11543
  }
11528
- }
11529
- function cmp(field, opOrValue, value) {
11530
- let op;
11531
- if (value === void 0) {
11532
- value = opOrValue;
11533
- op = "=";
11534
- } else {
11535
- op = opOrValue;
11544
+ push(change) {
11545
+ this.#dirty = true;
11546
+ applyChange(this.#root, change, this.#schema, "", this.#format);
11536
11547
  }
11537
- return {
11538
- type: "simple",
11539
- left: { type: "column", name: field },
11540
- right: isParameter2(value) ? value : { type: "literal", value },
11541
- op
11542
- };
11543
- }
11544
- function isParameter2(value) {
11545
- return typeof value === "object" && value?.type === "static";
11546
- }
11547
- var TRUE = {
11548
- type: "and",
11549
- conditions: []
11550
- };
11551
- var FALSE = {
11552
- type: "or",
11553
- conditions: []
11554
- };
11555
- function isAlwaysTrue(condition) {
11556
- return condition.type === "and" && condition.conditions.length === 0;
11557
- }
11558
- function isAlwaysFalse(condition) {
11559
- return condition.type === "or" && condition.conditions.length === 0;
11560
- }
11561
- function flatten(type, conditions) {
11562
- const flattened2 = [];
11563
- for (const c of conditions) {
11564
- if (c.type === type) {
11565
- flattened2.push(...c.conditions);
11566
- } else {
11567
- flattened2.push(c);
11548
+ flush() {
11549
+ if (!this.#dirty) {
11550
+ return;
11568
11551
  }
11552
+ this.#dirty = false;
11553
+ this.#fireListeners();
11569
11554
  }
11570
- return flattened2;
11571
- }
11572
- var negateSimpleOperatorMap = {
11573
- ["="]: "!=",
11574
- ["!="]: "=",
11575
- ["<"]: ">=",
11576
- [">"]: "<=",
11577
- [">="]: "<",
11578
- ["<="]: ">",
11579
- ["IN"]: "NOT IN",
11580
- ["NOT IN"]: "IN",
11581
- ["LIKE"]: "NOT LIKE",
11582
- ["NOT LIKE"]: "LIKE",
11583
- ["ILIKE"]: "NOT ILIKE",
11584
- ["NOT ILIKE"]: "ILIKE",
11585
- ["IS"]: "IS NOT",
11586
- ["IS NOT"]: "IS"
11587
- };
11588
- var negateOperatorMap = {
11589
- ...negateSimpleOperatorMap,
11590
- ["EXISTS"]: "NOT EXISTS",
11591
- ["NOT EXISTS"]: "EXISTS"
11592
11555
  };
11593
- function negateOperator(op) {
11594
- return must(negateOperatorMap[op]);
11595
- }
11596
- function filterUndefined(array9) {
11597
- return array9.filter((e) => e !== void 0);
11598
- }
11599
- function filterTrue(conditions) {
11600
- return conditions.filter((c) => !isAlwaysTrue(c));
11601
- }
11602
- function filterFalse(conditions) {
11603
- return conditions.filter((c) => !isAlwaysFalse(c));
11604
- }
11605
11556
 
11606
11557
  // ../zql/src/query/dnf.ts
11607
11558
  function dnf(condition) {
@@ -11716,10 +11667,8 @@ var AbstractQuery = class {
11716
11667
  }
11717
11668
  const related = this.#schema.relationships[relationship];
11718
11669
  assert(related, "Invalid relationship");
11719
- const fieldRelationship = related;
11720
- const junctionRelationship = related;
11721
- if (isFieldRelationship(fieldRelationship)) {
11722
- const destSchema = fieldRelationship.dest.schema;
11670
+ if (isFieldRelationship(related)) {
11671
+ const { destSchema } = related;
11723
11672
  const sq = cb(
11724
11673
  this._newQuery(
11725
11674
  destSchema,
@@ -11738,9 +11687,8 @@ var AbstractQuery = class {
11738
11687
  ...this.#ast.related ?? [],
11739
11688
  {
11740
11689
  correlation: {
11741
- parentField: fieldRelationship.source,
11742
- childField: fieldRelationship.dest.field,
11743
- op: "="
11690
+ parentField: related.sourceField,
11691
+ childField: related.destField
11744
11692
  },
11745
11693
  subquery: addPrimaryKeysToAst(destSchema, sq.#ast)
11746
11694
  }
@@ -11755,9 +11703,11 @@ var AbstractQuery = class {
11755
11703
  }
11756
11704
  );
11757
11705
  }
11758
- if (isJunctionRelationship(junctionRelationship)) {
11759
- const destSchema = junctionRelationship.dest.schema;
11760
- const junctionSchema = junctionRelationship.junction.schema;
11706
+ if (isJunctionRelationship(related)) {
11707
+ assert(related.length === 2, "Invalid relationship");
11708
+ const [firstRelation, secondRelation] = related;
11709
+ const { destSchema } = secondRelation;
11710
+ const junctionSchema = firstRelation.destSchema;
11761
11711
  const sq = cb(
11762
11712
  this._newQuery(
11763
11713
  destSchema,
@@ -11776,9 +11726,8 @@ var AbstractQuery = class {
11776
11726
  ...this.#ast.related ?? [],
11777
11727
  {
11778
11728
  correlation: {
11779
- parentField: junctionRelationship.source,
11780
- childField: junctionRelationship.junction.sourceField,
11781
- op: "="
11729
+ parentField: firstRelation.sourceField,
11730
+ childField: firstRelation.destField
11782
11731
  },
11783
11732
  subquery: {
11784
11733
  table: junctionSchema.tableName,
@@ -11787,9 +11736,8 @@ var AbstractQuery = class {
11787
11736
  related: [
11788
11737
  {
11789
11738
  correlation: {
11790
- parentField: junctionRelationship.junction.destField,
11791
- childField: junctionRelationship.dest.field,
11792
- op: "="
11739
+ parentField: secondRelation.sourceField,
11740
+ childField: secondRelation.destField
11793
11741
  },
11794
11742
  hidden: true,
11795
11743
  subquery: addPrimaryKeysToAst(destSchema, sq.#ast)
@@ -11813,7 +11761,7 @@ var AbstractQuery = class {
11813
11761
  where(fieldOrExpressionFactory, opOrValue, value) {
11814
11762
  let cond;
11815
11763
  if (typeof fieldOrExpressionFactory === "function") {
11816
- cond = fieldOrExpressionFactory(new ExpressionBuilder(this.#exists));
11764
+ cond = fieldOrExpressionFactory(new ExpressionBuilder(this._exists));
11817
11765
  } else {
11818
11766
  assert(opOrValue !== void 0, "Invalid condition");
11819
11767
  cond = cmp(fieldOrExpressionFactory, opOrValue, value);
@@ -11870,13 +11818,11 @@ var AbstractQuery = class {
11870
11818
  this.#format
11871
11819
  );
11872
11820
  }
11873
- #exists = (relationship, cb = (q) => q) => {
11821
+ _exists = (relationship, cb = (q) => q) => {
11874
11822
  const related = this.#schema.relationships[relationship];
11875
11823
  assert(related, "Invalid relationship");
11876
- const fieldRelationship = related;
11877
- const junctionRelationship = related;
11878
- if (isFieldRelationship(fieldRelationship)) {
11879
- const destSchema = fieldRelationship.dest.schema;
11824
+ if (isFieldRelationship(related)) {
11825
+ const { destSchema } = related;
11880
11826
  const sq = cb(
11881
11827
  this._newQuery(
11882
11828
  destSchema,
@@ -11891,18 +11837,19 @@ var AbstractQuery = class {
11891
11837
  type: "correlatedSubquery",
11892
11838
  related: {
11893
11839
  correlation: {
11894
- parentField: fieldRelationship.source,
11895
- childField: fieldRelationship.dest.field,
11896
- op: "="
11840
+ parentField: related.sourceField,
11841
+ childField: related.destField
11897
11842
  },
11898
11843
  subquery: addPrimaryKeysToAst(destSchema, sq.#ast)
11899
11844
  },
11900
11845
  op: "EXISTS"
11901
11846
  };
11902
11847
  }
11903
- if (isJunctionRelationship(junctionRelationship)) {
11904
- const destSchema = junctionRelationship.dest.schema;
11905
- const junctionSchema = junctionRelationship.junction.schema;
11848
+ if (isJunctionRelationship(related)) {
11849
+ assert(related.length === 2, "Invalid relationship");
11850
+ const [firstRelation, secondRelation] = related;
11851
+ const { destSchema } = secondRelation;
11852
+ const junctionSchema = firstRelation.destSchema;
11906
11853
  const queryToDest = cb(
11907
11854
  this._newQuery(
11908
11855
  destSchema,
@@ -11917,9 +11864,8 @@ var AbstractQuery = class {
11917
11864
  type: "correlatedSubquery",
11918
11865
  related: {
11919
11866
  correlation: {
11920
- parentField: junctionRelationship.source,
11921
- childField: junctionRelationship.junction.sourceField,
11922
- op: "="
11867
+ parentField: firstRelation.sourceField,
11868
+ childField: firstRelation.destField
11923
11869
  },
11924
11870
  subquery: {
11925
11871
  table: junctionSchema.tableName,
@@ -11929,9 +11875,8 @@ var AbstractQuery = class {
11929
11875
  type: "correlatedSubquery",
11930
11876
  related: {
11931
11877
  correlation: {
11932
- parentField: junctionRelationship.junction.destField,
11933
- childField: junctionRelationship.dest.field,
11934
- op: "="
11878
+ parentField: secondRelation.sourceField,
11879
+ childField: secondRelation.destField
11935
11880
  },
11936
11881
  subquery: addPrimaryKeysToAst(destSchema, queryToDest.#ast)
11937
11882
  },
@@ -11973,6 +11918,7 @@ var AbstractQuery = class {
11973
11918
  }
11974
11919
  };
11975
11920
  var astForTestingSymbol = Symbol();
11921
+ var completedAstSymbol = Symbol();
11976
11922
  var QueryImpl = class extends AbstractQuery {
11977
11923
  #delegate;
11978
11924
  #ast;
@@ -11985,13 +11931,16 @@ var QueryImpl = class extends AbstractQuery {
11985
11931
  get [astForTestingSymbol]() {
11986
11932
  return this.#ast;
11987
11933
  }
11934
+ get [completedAstSymbol]() {
11935
+ return this._completeAst();
11936
+ }
11988
11937
  _newQuery(schema, ast, format) {
11989
11938
  return newQueryWithDetails(this.#delegate, schema, ast, format);
11990
11939
  }
11991
11940
  materialize(factory) {
11992
11941
  const ast = this._completeAst();
11993
11942
  const removeServerQuery = this.#delegate.addServerQuery(ast);
11994
- const input = buildPipeline(ast, this.#delegate, void 0);
11943
+ const input = buildPipeline(ast, this.#delegate);
11995
11944
  let removeCommitObserver;
11996
11945
  const onDestroy = () => {
11997
11946
  input.destroy();
@@ -12060,6 +12009,9 @@ var AuthQuery = class _AuthQuery extends AbstractQuery {
12060
12009
  constructor(schema, ast = { table: schema.tableName }, format) {
12061
12010
  super(schema, ast, format);
12062
12011
  }
12012
+ expressionBuilder() {
12013
+ return new ExpressionBuilder(this._exists);
12014
+ }
12063
12015
  _newQuery(schema, ast, format) {
12064
12016
  return new _AuthQuery(schema, ast, format);
12065
12017
  }
@@ -12077,65 +12029,77 @@ var AuthQuery = class _AuthQuery extends AbstractQuery {
12077
12029
  }
12078
12030
  };
12079
12031
 
12080
- // ../zero-schema/src/authorization.ts
12081
- async function defineAuthorization(schema, definer) {
12032
+ // ../zero-schema/src/permissions.ts
12033
+ async function definePermissions(schema, definer) {
12082
12034
  const normalizedSchema = normalizeSchema(schema);
12083
- const queries = {};
12035
+ const expressionBuilders = {};
12084
12036
  for (const [name, tableSchema] of Object.entries(normalizedSchema.tables)) {
12085
- queries[name] = new AuthQuery(tableSchema);
12037
+ expressionBuilders[name] = new AuthQuery(tableSchema).expressionBuilder();
12086
12038
  }
12087
- const config = await definer(queries);
12088
- return compileAuthorization(config);
12039
+ const config = await definer();
12040
+ return compilePermissions(config, expressionBuilders);
12089
12041
  }
12090
- function compileAuthorization(authz) {
12042
+ function compilePermissions(authz, expressionBuilders) {
12091
12043
  if (!authz) {
12092
12044
  return void 0;
12093
12045
  }
12094
12046
  const ret = {};
12095
12047
  for (const [tableName, tableConfig] of Object.entries(authz)) {
12096
12048
  ret[tableName] = {
12097
- row: compileRowConfig(tableConfig.row),
12098
- cell: compileCellConfig(tableConfig.cell)
12049
+ row: compileRowConfig(tableConfig.row, expressionBuilders[tableName]),
12050
+ cell: compileCellConfig(tableConfig.cell, expressionBuilders[tableName])
12099
12051
  };
12100
12052
  }
12101
12053
  return ret;
12102
12054
  }
12103
- function compileRowConfig(rowRules) {
12055
+ function compileRowConfig(rowRules, expressionBuilder) {
12104
12056
  if (!rowRules) {
12105
12057
  return void 0;
12106
12058
  }
12107
12059
  return {
12108
- select: compileRules(rowRules.select),
12109
- insert: compileRules(rowRules.insert),
12110
- update: compileRules(rowRules.update),
12111
- delete: compileRules(rowRules.delete)
12060
+ select: compileRules(rowRules.select, expressionBuilder),
12061
+ insert: compileRules(rowRules.insert, expressionBuilder),
12062
+ update: {
12063
+ preMutation: compileRules(
12064
+ rowRules.update?.preMutation,
12065
+ expressionBuilder
12066
+ ),
12067
+ postProposedMutation: compileRules(
12068
+ rowRules.update?.postProposedMutation,
12069
+ expressionBuilder
12070
+ )
12071
+ },
12072
+ delete: compileRules(rowRules.delete, expressionBuilder)
12112
12073
  };
12113
12074
  }
12114
- function compileRules(rules) {
12075
+ function compileRules(rules, expressionBuilder) {
12115
12076
  if (!rules) {
12116
12077
  return void 0;
12117
12078
  }
12118
12079
  return rules.map(
12119
12080
  (rule) => [
12120
12081
  "allow",
12121
- rule(
12122
- authDataRef,
12123
- preMutationRowRef
12124
- ).ast
12082
+ rule(authDataRef, expressionBuilder)
12125
12083
  ]
12126
12084
  );
12127
12085
  }
12128
- function compileCellConfig(cellRules) {
12086
+ function compileCellConfig(cellRules, expressionBuilder) {
12129
12087
  if (!cellRules) {
12130
12088
  return void 0;
12131
12089
  }
12132
12090
  const ret = {};
12133
12091
  for (const [columnName, rules] of Object.entries(cellRules)) {
12134
12092
  ret[columnName] = {
12135
- select: compileRules(rules.select),
12136
- insert: compileRules(rules.insert),
12137
- update: compileRules(rules.update),
12138
- delete: compileRules(rules.delete)
12093
+ select: compileRules(rules.select, expressionBuilder),
12094
+ insert: compileRules(rules.insert, expressionBuilder),
12095
+ update: {
12096
+ preMutation: compileRules(rules.update?.preMutation, expressionBuilder),
12097
+ postProposedMutation: compileRules(
12098
+ rules.update?.postProposedMutation,
12099
+ expressionBuilder
12100
+ )
12101
+ },
12102
+ delete: compileRules(rules.delete, expressionBuilder)
12139
12103
  };
12140
12104
  }
12141
12105
  return ret;
@@ -12168,7 +12132,7 @@ function escapeLike(val) {
12168
12132
  }
12169
12133
 
12170
12134
  // ../zero-client/src/client/zero.ts
12171
- import { LogContext as LogContext3 } from "@rocicorp/logger";
12135
+ import { LogContext as LogContext4 } from "@rocicorp/logger";
12172
12136
  import { resolver as resolver8 } from "@rocicorp/resolver";
12173
12137
 
12174
12138
  // ../zero-protocol/src/queries-patch.ts
@@ -12312,10 +12276,14 @@ var pokeStartBodySchema = valita_exports.object({
12312
12276
  // able to send a base cookie with value `null` to match that state.
12313
12277
  baseCookie: nullableVersionSchema,
12314
12278
  cookie: versionSchema,
12279
+ /**
12280
+ * This field is always set if the poke contains a `rowsPatch`.
12281
+ * It may be absent for patches that only update clients and queries.
12282
+ */
12315
12283
  schemaVersions: valita_exports.object({
12316
12284
  minSupportedVersion: valita_exports.number(),
12317
12285
  maxSupportedVersion: valita_exports.number()
12318
- }),
12286
+ }).optional(),
12319
12287
  timestamp: valita_exports.number().optional()
12320
12288
  });
12321
12289
  var pokePartBodySchema = valita_exports.object({
@@ -14117,6 +14085,29 @@ var EmptyBTree = (() => {
14117
14085
  return t2;
14118
14086
  })();
14119
14087
 
14088
+ // ../zql/src/ivm/constraint.ts
14089
+ function constraintMatchesRow(constraint, row) {
14090
+ for (const [key, value] of Object.entries(constraint)) {
14091
+ if (!valuesEqual(row[key], value)) {
14092
+ return false;
14093
+ }
14094
+ }
14095
+ return true;
14096
+ }
14097
+ function constraintMatchesPrimaryKey(constraint, primary) {
14098
+ const constraintKeys = Object.keys(constraint);
14099
+ if (constraintKeys.length !== primary.length) {
14100
+ return false;
14101
+ }
14102
+ constraintKeys.sort(stringCompare);
14103
+ for (let i = 0; i < constraintKeys.length; i++) {
14104
+ if (constraintKeys[i][0] !== primary[i]) {
14105
+ return false;
14106
+ }
14107
+ }
14108
+ return true;
14109
+ }
14110
+
14120
14111
  // ../zql/src/ivm/lookahead-iterator.ts
14121
14112
  var LookaheadIterator = class {
14122
14113
  #iter;
@@ -14200,8 +14191,7 @@ var MemorySource = class {
14200
14191
  };
14201
14192
  }
14202
14193
  connect(sort, optionalFilters) {
14203
- const filteredOptionalFilters = filterOptionalFilters(optionalFilters);
14204
- const predicates = filteredOptionalFilters.filters.map((c) => createPredicate(c));
14194
+ const transformedFilters = transformFilters(optionalFilters);
14205
14195
  const input = {
14206
14196
  getSchema: () => schema,
14207
14197
  fetch: (req) => this.#fetch(req, connection),
@@ -14212,14 +14202,17 @@ var MemorySource = class {
14212
14202
  destroy: () => {
14213
14203
  this.#disconnect(input);
14214
14204
  },
14215
- appliedFilters: filteredOptionalFilters.allApplied
14205
+ appliedFilters: !transformedFilters.conditionsRemoved
14216
14206
  };
14217
14207
  const connection = {
14218
14208
  input,
14219
14209
  output: void 0,
14220
14210
  sort,
14221
14211
  compareRows: makeComparator(sort),
14222
- optionalFilters: predicates
14212
+ filters: transformedFilters.filters ? {
14213
+ condition: transformedFilters.filters,
14214
+ predicate: createPredicate(transformedFilters.filters)
14215
+ } : void 0
14223
14216
  };
14224
14217
  const schema = this.#getSchema(connection);
14225
14218
  assertOrderingIncludesPK(sort, this.#primaryKey);
@@ -14275,9 +14268,11 @@ var MemorySource = class {
14275
14268
  const { sort: requestedSort } = conn;
14276
14269
  const indexSort = [];
14277
14270
  if (req.constraint) {
14278
- indexSort.push([req.constraint.key, "asc"]);
14271
+ for (const key of Object.keys(req.constraint)) {
14272
+ indexSort.push([key, "asc"]);
14273
+ }
14279
14274
  }
14280
- if (this.#primaryKey.length > 1 || req.constraint?.key !== this.#primaryKey[0]) {
14275
+ if (this.#primaryKey.length > 1 || !req.constraint || !constraintMatchesPrimaryKey(req.constraint, this.#primaryKey)) {
14281
14276
  indexSort.push(...requestedSort);
14282
14277
  }
14283
14278
  const index = this.#getOrCreateIndex(indexSort, from);
@@ -14287,20 +14282,10 @@ var MemorySource = class {
14287
14282
  overlay = this.#overlay;
14288
14283
  }
14289
14284
  }
14290
- const matchesConstraint = (row) => {
14291
- if (!req.constraint) {
14292
- return true;
14293
- }
14294
- const { key, value } = req.constraint;
14295
- return valuesEqual(row[key], value);
14296
- };
14297
- const matchesFilters = (row) => conn.optionalFilters.every((f) => f(row));
14298
- const matchesConstraintAndFilters = (row) => matchesConstraint(row) && matchesFilters(row);
14299
- if (overlay) {
14300
- if (!matchesConstraintAndFilters(overlay.change.row)) {
14301
- overlay = void 0;
14302
- }
14303
- }
14285
+ const { constraint } = req;
14286
+ const matchesConstraint = constraint ? (row) => constraintMatchesRow(constraint, row) : (_) => true;
14287
+ const predicate = conn.filters?.predicate;
14288
+ const matchesConstraintAndFilters = predicate ? (row) => matchesConstraint(row) && predicate(row) : matchesConstraint;
14304
14289
  const nextLowerKey = (row) => {
14305
14290
  if (!row) {
14306
14291
  return void 0;
@@ -14325,9 +14310,7 @@ var MemorySource = class {
14325
14310
  let startAt = req.start?.row;
14326
14311
  if (startAt) {
14327
14312
  if (req.constraint) {
14328
- if (!matchesConstraint(startAt)) {
14329
- assert(false, "Start row must match constraint");
14330
- }
14313
+ assert(matchesConstraint(startAt), "Start row must match constraint");
14331
14314
  }
14332
14315
  if (req.start.basis === "before") {
14333
14316
  startAt = nextLowerKey(startAt);
@@ -14337,8 +14320,8 @@ var MemorySource = class {
14337
14320
  if (req.constraint) {
14338
14321
  scanStart = {};
14339
14322
  for (const [key, dir] of indexSort) {
14340
- if (key === req.constraint.key) {
14341
- scanStart[key] = req.constraint.value;
14323
+ if (hasOwn(req.constraint, key)) {
14324
+ scanStart[key] = req.constraint[key];
14342
14325
  } else {
14343
14326
  scanStart[key] = dir === "asc" ? minValue : maxValue;
14344
14327
  }
@@ -14353,13 +14336,14 @@ var MemorySource = class {
14353
14336
  data.keys(scanStart),
14354
14337
  req.constraint,
14355
14338
  overlay,
14356
- comparator
14339
+ comparator,
14340
+ conn.filters?.predicate
14357
14341
  );
14358
14342
  const withConstraint = generateWithConstraint(
14359
14343
  generateWithStart(withOverlay, req, comparator),
14360
14344
  req.constraint
14361
14345
  );
14362
- yield* conn.optionalFilters.length ? generateWithFilter(withConstraint, matchesFilters) : withConstraint;
14346
+ yield* conn.filters ? generateWithFilter(withConstraint, conn.filters.predicate) : withConstraint;
14363
14347
  }
14364
14348
  #cleanup(req, connection) {
14365
14349
  return this.#fetch(req, connection);
@@ -14370,23 +14354,33 @@ var MemorySource = class {
14370
14354
  switch (change.type) {
14371
14355
  case "add":
14372
14356
  if (data.has(change.row)) {
14373
- throw new Error(`Row already exists: ` + JSON.stringify(change));
14357
+ throw new Error(`Row already exists ${JSON.stringify(change)}`);
14374
14358
  }
14375
14359
  break;
14376
14360
  case "remove":
14377
14361
  if (!data.has(change.row)) {
14378
- throw new Error(`Row not found: ` + JSON.stringify(change));
14362
+ throw new Error(`Row not found ${JSON.stringify(change)}`);
14379
14363
  }
14380
14364
  break;
14381
14365
  case "edit":
14382
14366
  if (!data.has(change.oldRow)) {
14383
- throw new Error(`Row not found: ` + JSON.stringify(change));
14367
+ throw new Error(`Row not found ${JSON.stringify(change)}`);
14384
14368
  }
14385
14369
  break;
14386
14370
  default:
14387
14371
  unreachable(change);
14388
14372
  }
14389
- const outputChange = change.type === "edit" ? change : {
14373
+ const outputChange = change.type === "edit" ? {
14374
+ type: change.type,
14375
+ oldNode: {
14376
+ row: change.oldRow,
14377
+ relationships: {}
14378
+ },
14379
+ node: {
14380
+ row: change.row,
14381
+ relationships: {}
14382
+ }
14383
+ } : {
14390
14384
  type: change.type,
14391
14385
  node: {
14392
14386
  row: change.row,
@@ -14426,7 +14420,7 @@ var MemorySource = class {
14426
14420
  };
14427
14421
  function* generateWithConstraint(it, constraint) {
14428
14422
  for (const node of it) {
14429
- if (constraint && !valuesEqual(node.row[constraint.key], constraint.value)) {
14423
+ if (constraint && !constraintMatchesRow(constraint, node.row)) {
14430
14424
  break;
14431
14425
  }
14432
14426
  yield node;
@@ -14464,11 +14458,17 @@ function* generateWithStart(it, req, compare) {
14464
14458
  }
14465
14459
  }
14466
14460
  }
14467
- function* generateWithOverlay(startAt, rows, constraint, overlay, compare) {
14468
- const overlays = computeOverlays(startAt, constraint, overlay, compare);
14461
+ function* generateWithOverlay(startAt, rows, constraint, overlay, compare, filterPredicate) {
14462
+ const overlays = computeOverlays(
14463
+ startAt,
14464
+ constraint,
14465
+ overlay,
14466
+ compare,
14467
+ filterPredicate
14468
+ );
14469
14469
  yield* generateWithOverlayInner(rows, overlays, compare);
14470
14470
  }
14471
- function computeOverlays(startAt, constraint, overlay, compare) {
14471
+ function computeOverlays(startAt, constraint, overlay, compare, filterPredicate) {
14472
14472
  let overlays = {
14473
14473
  add: void 0,
14474
14474
  remove: void 0
@@ -14499,6 +14499,9 @@ function computeOverlays(startAt, constraint, overlay, compare) {
14499
14499
  if (constraint) {
14500
14500
  overlays = overlaysForConstraint(overlays, constraint);
14501
14501
  }
14502
+ if (filterPredicate) {
14503
+ overlays = overlaysForFilterPredicate(overlays, filterPredicate);
14504
+ }
14502
14505
  return overlays;
14503
14506
  }
14504
14507
  function overlaysForStartAt({ add, remove }, startAt, compare) {
@@ -14509,12 +14512,19 @@ function overlaysForStartAt({ add, remove }, startAt, compare) {
14509
14512
  };
14510
14513
  }
14511
14514
  function overlaysForConstraint({ add, remove }, constraint) {
14512
- const undefinedIfDoesntMatchConstraint = (row) => row === void 0 || !valuesEqual(row[constraint.key], constraint.value) ? void 0 : row;
14515
+ const undefinedIfDoesntMatchConstraint = (row) => row === void 0 || !constraintMatchesRow(constraint, row) ? void 0 : row;
14513
14516
  return {
14514
14517
  add: undefinedIfDoesntMatchConstraint(add),
14515
14518
  remove: undefinedIfDoesntMatchConstraint(remove)
14516
14519
  };
14517
14520
  }
14521
+ function overlaysForFilterPredicate({ add, remove }, filterPredicate) {
14522
+ const undefinedIfDoesntMatchFilter = (row) => row === void 0 || !filterPredicate(row) ? void 0 : row;
14523
+ return {
14524
+ add: undefinedIfDoesntMatchFilter(add),
14525
+ remove: undefinedIfDoesntMatchFilter(remove)
14526
+ };
14527
+ }
14518
14528
  function* generateWithOverlayInner(rowIterator, overlays, compare) {
14519
14529
  let addOverlayYielded = false;
14520
14530
  let removeOverlaySkipped = false;
@@ -14571,33 +14581,6 @@ function compareBounds(a, b) {
14571
14581
  }
14572
14582
  return compareValues(a, b);
14573
14583
  }
14574
- function filterOptionalFilters(optionalFilters) {
14575
- if (optionalFilters) {
14576
- if (optionalFilters.type === "or" && optionalFilters.conditions.length === 1) {
14577
- optionalFilters = optionalFilters.conditions[0];
14578
- }
14579
- if (optionalFilters.type === "and") {
14580
- const filters = optionalFilters.conditions.filter(
14581
- (c) => c.type === "simple"
14582
- );
14583
- return {
14584
- filters,
14585
- allApplied: filters.length === optionalFilters.conditions.length
14586
- };
14587
- }
14588
- if (optionalFilters.type === "simple") {
14589
- return {
14590
- filters: [optionalFilters],
14591
- allApplied: true
14592
- };
14593
- }
14594
- return { filters: [], allApplied: false };
14595
- }
14596
- return {
14597
- filters: [],
14598
- allApplied: true
14599
- };
14600
- }
14601
14584
 
14602
14585
  // ../zql/src/ivm/memory-storage.ts
14603
14586
  var MemoryStorage = class {
@@ -15236,7 +15219,7 @@ function makeMessage(message, context, logLevel) {
15236
15219
  }
15237
15220
 
15238
15221
  // ../zero-client/src/client/version.ts
15239
- var version2 = "0.6.2024112102+391068";
15222
+ var version2 = "0.7.2024120100+3f2152";
15240
15223
 
15241
15224
  // ../zero-client/src/client/log-options.ts
15242
15225
  var LevelFilterLogSink = class {
@@ -15522,6 +15505,9 @@ var State = class {
15522
15505
  }
15523
15506
  };
15524
15507
 
15508
+ // ../zero-client/src/client/protocol-version.ts
15509
+ var PROTOCOL_VERSION = 1;
15510
+
15525
15511
  // ../zero-client/src/client/query-manager.ts
15526
15512
  var QueryManager = class {
15527
15513
  #clientID;
@@ -15660,24 +15646,90 @@ var QueryManager = class {
15660
15646
  };
15661
15647
 
15662
15648
  // ../zero-client/src/client/reload-error-handler.ts
15649
+ import "@rocicorp/logger";
15663
15650
  var RELOAD_REASON_STORAGE_KEY = "_zeroReloadReason";
15651
+ var RELOAD_BACKOFF_STATE_KEY = "_zeroReloadBackoffState";
15652
+ var backoffStateSchema = valita_exports.object({
15653
+ lastReloadTime: valita_exports.number().default(0),
15654
+ nextIntervalMs: valita_exports.number().default(0)
15655
+ });
15656
+ var MIN_RELOAD_INTERVAL_MS = 500;
15657
+ var MAX_RELOAD_INTERVAL_MS = 6e4;
15658
+ var FALLBACK_RELOAD_INTERVAL_MS = 1e4;
15659
+ var reloadTimer = null;
15664
15660
  function reloadWithReason(lc, reload2, reason) {
15665
- if (typeof localStorage === "undefined") {
15666
- lc.error?.("Zero reloaded the page.", reason);
15667
- } else {
15668
- localStorage[RELOAD_REASON_STORAGE_KEY] = reason;
15661
+ if (reloadTimer) {
15662
+ lc.warn?.("reload timer already scheduled");
15663
+ return;
15669
15664
  }
15670
- reload2();
15665
+ const now = Date.now();
15666
+ const backoff = nextBackoff(lc, now);
15667
+ if (typeof sessionStorage !== "undefined") {
15668
+ sessionStorage.setItem(RELOAD_BACKOFF_STATE_KEY, JSON.stringify(backoff));
15669
+ sessionStorage.setItem(RELOAD_REASON_STORAGE_KEY, reason);
15670
+ }
15671
+ const delay = backoff.lastReloadTime - now;
15672
+ lc.error?.(
15673
+ reason,
15674
+ "\n",
15675
+ "reloading",
15676
+ delay > 0 ? `in ${delay / 1e3} seconds` : ""
15677
+ );
15678
+ reloadTimer = setTimeout(() => {
15679
+ reloadTimer = null;
15680
+ reload2();
15681
+ }, delay);
15671
15682
  }
15672
15683
  function reportReloadReason(lc) {
15673
- if (typeof localStorage === "undefined") {
15674
- return;
15684
+ if (typeof sessionStorage !== "undefined") {
15685
+ const reason = sessionStorage.getItem(RELOAD_REASON_STORAGE_KEY);
15686
+ if (reason) {
15687
+ sessionStorage.removeItem(RELOAD_REASON_STORAGE_KEY);
15688
+ lc.error?.("Zero reloaded the page.", reason);
15689
+ }
15690
+ }
15691
+ }
15692
+ function reloadScheduled() {
15693
+ return reloadTimer !== null;
15694
+ }
15695
+ function resetBackoff() {
15696
+ if (typeof sessionStorage !== "undefined") {
15697
+ sessionStorage.removeItem(RELOAD_BACKOFF_STATE_KEY);
15698
+ }
15699
+ }
15700
+ function nextBackoff(lc, now) {
15701
+ if (typeof sessionStorage === "undefined") {
15702
+ lc.warn?.(
15703
+ `sessionStorage not supported. backing off in ${FALLBACK_RELOAD_INTERVAL_MS / 1e3} seconds`
15704
+ );
15705
+ return {
15706
+ lastReloadTime: now + FALLBACK_RELOAD_INTERVAL_MS,
15707
+ nextIntervalMs: MIN_RELOAD_INTERVAL_MS
15708
+ };
15675
15709
  }
15676
- const reason = localStorage[RELOAD_REASON_STORAGE_KEY];
15677
- if (reason) {
15678
- delete localStorage[RELOAD_REASON_STORAGE_KEY];
15679
- lc.error?.("Zero reloaded the page.", reason);
15710
+ const val = sessionStorage.getItem(RELOAD_BACKOFF_STATE_KEY);
15711
+ if (!val) {
15712
+ return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
15680
15713
  }
15714
+ let parsed;
15715
+ try {
15716
+ parsed = parse(JSON.parse(val), backoffStateSchema, "passthrough");
15717
+ } catch (e) {
15718
+ lc.warn?.("ignoring unparsable backoff state", val, e);
15719
+ return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
15720
+ }
15721
+ const { lastReloadTime, nextIntervalMs } = parsed;
15722
+ if (now - lastReloadTime > MAX_RELOAD_INTERVAL_MS * 2) {
15723
+ return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
15724
+ }
15725
+ if (now < lastReloadTime) {
15726
+ return parsed;
15727
+ }
15728
+ const nextReloadTime = Math.max(now, lastReloadTime + nextIntervalMs);
15729
+ return {
15730
+ lastReloadTime: nextReloadTime,
15731
+ nextIntervalMs: Math.min(nextIntervalMs * 2, MAX_RELOAD_INTERVAL_MS)
15732
+ };
15681
15733
  }
15682
15734
 
15683
15735
  // ../zero-client/src/client/server-error.ts
@@ -16028,9 +16080,6 @@ function rafFallback(callback) {
16028
16080
  setTimeout(callback, 0);
16029
16081
  }
16030
16082
 
16031
- // ../zero-client/src/client/protocol-version.ts
16032
- var PROTOCOL_VERSION = 1;
16033
-
16034
16083
  // ../zero-client/src/client/zero.ts
16035
16084
  var onSetConnectionStateSymbol = Symbol();
16036
16085
  var exposedToTestingSymbol = Symbol();
@@ -16097,14 +16146,9 @@ var Zero = class {
16097
16146
  #lastMutationIDSent = NULL_LAST_MUTATION_ID_SENT;
16098
16147
  #onPong = () => void 0;
16099
16148
  #online = false;
16100
- /**
16101
- * `onOnlineChange` is called when the Zero instance's online status
16102
- * changes.
16103
- */
16104
- onOnlineChange = null;
16105
- #onUpdateNeeded = null;
16106
- #onClientStateNotFound = null;
16107
- #jurisdiction;
16149
+ #onOnlineChange;
16150
+ #onUpdateNeeded;
16151
+ #onClientStateNotFound;
16108
16152
  // Last cookie used to initiate a connection
16109
16153
  #connectCookie = null;
16110
16154
  // Total number of sockets successfully connected by this client
@@ -16118,52 +16162,6 @@ var Zero = class {
16118
16162
  #abortPingTimeout = () => {
16119
16163
  };
16120
16164
  #zeroContext;
16121
- /**
16122
- * `onUpdateNeeded` is called when a code update is needed.
16123
- *
16124
- * A code update can be needed because:
16125
- * - the server no longer supports the protocol version of the current code,
16126
- * - a new Zero client has created a new client group, because its code
16127
- * has different mutators, indexes, schema version and/or format version
16128
- * from this Zero client. This is likely due to the new client having
16129
- * newer code. A code update is needed to be able to locally sync with this
16130
- * new Zero client (i.e. to sync while offline, the clients can can
16131
- * still sync with each other via the server).
16132
- *
16133
- * The default behavior is to reload the page (using `location.reload()`). Set
16134
- * this to `null` or provide your own function to prevent the page from
16135
- * reloading automatically. You may want to provide your own function to
16136
- * display a toast to inform the end user there is a new version of your app
16137
- * available and prompting them to refresh.
16138
- */
16139
- get onUpdateNeeded() {
16140
- return this.#onUpdateNeeded;
16141
- }
16142
- set onUpdateNeeded(callback) {
16143
- this.#onUpdateNeeded = callback;
16144
- this.#rep.onUpdateNeeded = callback && ((reason) => {
16145
- callback(convertOnUpdateNeededReason(reason));
16146
- });
16147
- }
16148
- /**
16149
- * `onClientStateNotFound` is called when this client will no longer be able
16150
- * to sync due to missing synchronization state. This can be because:
16151
- * - the local persistent synchronization state has been garbage collected.
16152
- * This can happen if the client has no pending mutations and has not been
16153
- * used for a while.
16154
- * - the zero-cache fails to find the synchronization state of this client.
16155
- *
16156
- * The default behavior is to reload the page (using `location.reload()`). Set
16157
- * this to `null` or provide your own function to prevent the page from
16158
- * reloading automatically.
16159
- */
16160
- get onClientStateNotFound() {
16161
- return this.#onClientStateNotFound;
16162
- }
16163
- set onClientStateNotFound(value) {
16164
- this.#onClientStateNotFound = value;
16165
- this.#rep.onClientStateNotFound = value;
16166
- }
16167
16165
  #connectResolver = resolver8();
16168
16166
  #pendingPullsByRequestID = /* @__PURE__ */ new Map();
16169
16167
  #lastMutationIDReceived = 0;
@@ -16214,7 +16212,8 @@ var Zero = class {
16214
16212
  const {
16215
16213
  userID,
16216
16214
  onOnlineChange,
16217
- jurisdiction,
16215
+ onUpdateNeeded,
16216
+ onClientStateNotFound,
16218
16217
  hiddenTabDisconnectDelay = DEFAULT_DISCONNECT_HIDDEN_DELAY_MS,
16219
16218
  kvStore = "idb",
16220
16219
  schema,
@@ -16229,15 +16228,12 @@ var Zero = class {
16229
16228
  false
16230
16229
  // Reenable analytics
16231
16230
  );
16232
- if (jurisdiction !== void 0 && jurisdiction !== "eu") {
16233
- throw new Error('ZeroOptions.jurisdiction must be "eu" if present.');
16234
- }
16235
16231
  if (hiddenTabDisconnectDelay < 0) {
16236
16232
  throw new Error(
16237
16233
  "ZeroOptions.hiddenTabDisconnectDelay must not be negative."
16238
16234
  );
16239
16235
  }
16240
- this.onOnlineChange = onOnlineChange;
16236
+ this.#onOnlineChange = onOnlineChange;
16241
16237
  this.#options = options;
16242
16238
  this.#logOptions = this.#createLogOptions({
16243
16239
  consoleLogLevel: options.logLevel ?? "error",
@@ -16267,36 +16263,41 @@ var Zero = class {
16267
16263
  kvStore
16268
16264
  };
16269
16265
  const replicacheImplOptions = {
16270
- enableClientGroupForking: false
16266
+ enableClientGroupForking: false,
16267
+ enableMutationRecovery: false
16271
16268
  };
16272
16269
  const rep = new ReplicacheImpl(replicacheOptions, replicacheImplOptions);
16273
16270
  this.#rep = rep;
16274
16271
  if (false) {
16275
16272
  internalReplicacheImplMap.set(this, rep);
16276
16273
  }
16277
- rep.getAuth = this.#getAuthToken;
16278
16274
  this.#server = server;
16279
16275
  this.userID = userID;
16280
- this.#jurisdiction = jurisdiction;
16281
- this.#lc = new LogContext3(
16276
+ this.#lc = new LogContext4(
16282
16277
  logOptions.logLevel,
16283
16278
  { clientID: rep.clientID },
16284
16279
  logOptions.logSink
16285
16280
  );
16286
- this.onUpdateNeeded = (reason, serverErrorMsg) => {
16281
+ const onUpdateNeededCallback = onUpdateNeeded ?? ((reason, serverErrorMsg) => {
16287
16282
  reloadWithReason(
16288
16283
  this.#lc,
16289
16284
  this.#reload,
16290
16285
  updateNeededReloadReason(reason, serverErrorMsg)
16291
16286
  );
16287
+ });
16288
+ this.#onUpdateNeeded = onUpdateNeededCallback;
16289
+ this.#rep.onUpdateNeeded = (reason) => {
16290
+ onUpdateNeededCallback(convertOnUpdateNeededReason(reason));
16292
16291
  };
16293
- this.onClientStateNotFound = (reason) => {
16292
+ const onClientStateNotFoundCallback = onClientStateNotFound ?? ((reason) => {
16294
16293
  reloadWithReason(
16295
16294
  this.#lc,
16296
16295
  this.#reload,
16297
16296
  reason ?? ON_CLIENT_STATE_NOT_FOUND_REASON_CLIENT
16298
16297
  );
16299
- };
16298
+ });
16299
+ this.#onClientStateNotFound = onClientStateNotFoundCallback;
16300
+ this.#rep.onClientStateNotFound = onClientStateNotFoundCallback;
16300
16301
  const { mutate, mutateBatch } = makeCRUDMutate(
16301
16302
  normalizedSchema,
16302
16303
  rep.mutate
@@ -16433,10 +16434,10 @@ var Zero = class {
16433
16434
  */
16434
16435
  mutateBatch;
16435
16436
  /**
16436
- * Whether this Zero instance has been closed. Once a Zero instance has
16437
- * been closed it no longer syncs and you can no longer read or write data out
16438
- * of it. After it has been closed it is pretty much useless and should not be
16439
- * used any more.
16437
+ * Whether this Zero instance has been closed.
16438
+ *
16439
+ * Once a Zero instance has been closed it no longer syncs, you can no
16440
+ * longer query or mutate data with it, and its query views stop updating.
16440
16441
  */
16441
16442
  get closed() {
16442
16443
  return this.#rep.closed;
@@ -16444,7 +16445,8 @@ var Zero = class {
16444
16445
  /**
16445
16446
  * Closes this Zero instance.
16446
16447
  *
16447
- * When closed all subscriptions end and no more read or writes are allowed.
16448
+ * Once a Zero instance has been closed it no longer syncs, you can no
16449
+ * longer query or mutate data with it, and its query views stop updating.
16448
16450
  */
16449
16451
  close() {
16450
16452
  const lc = this.#lc.withContext("close");
@@ -16681,7 +16683,6 @@ var Zero = class {
16681
16683
  this.#options.schema.version,
16682
16684
  this.userID,
16683
16685
  this.#rep.auth,
16684
- this.#jurisdiction,
16685
16686
  this.#lastMutationIDReceived,
16686
16687
  wsid,
16687
16688
  this.#options.logLevel === "debug",
@@ -16768,6 +16769,7 @@ var Zero = class {
16768
16769
  this.#pokeHandler.handleDisconnect();
16769
16770
  }
16770
16771
  async #handlePokeStart(_lc, pokeMessage) {
16772
+ resetBackoff();
16771
16773
  this.#abortPingTimeout();
16772
16774
  await this.#pokeHandler.handlePokeStart(pokeMessage[1]);
16773
16775
  }
@@ -16869,12 +16871,9 @@ var Zero = class {
16869
16871
  }
16870
16872
  };
16871
16873
  }
16872
- #getAuthToken = () => {
16873
- const { auth } = this.#options;
16874
- return typeof auth === "function" ? auth() : auth;
16875
- };
16876
- async #updateAuthToken(lc) {
16877
- const auth = await this.#getAuthToken();
16874
+ async #updateAuthToken(lc, error) {
16875
+ const { auth: authOption } = this.#options;
16876
+ const auth = await (typeof authOption === "function" ? authOption(error) : authOption);
16878
16877
  if (auth) {
16879
16878
  lc.debug?.("Got auth token");
16880
16879
  this.#rep.auth = auth;
@@ -16910,7 +16909,10 @@ var Zero = class {
16910
16909
  }
16911
16910
  await this.#visibilityWatcher.waitForVisible();
16912
16911
  if (needsReauth) {
16913
- await this.#updateAuthToken(lc);
16912
+ await this.#updateAuthToken(lc, "invalid-token");
16913
+ }
16914
+ if (reloadScheduled()) {
16915
+ break;
16914
16916
  }
16915
16917
  await this.#connect(lc);
16916
16918
  if (this.closed) {
@@ -17080,7 +17082,7 @@ var Zero = class {
17080
17082
  return;
17081
17083
  }
17082
17084
  this.#online = online;
17083
- this.onOnlineChange?.(online);
17085
+ this.#onOnlineChange?.(online);
17084
17086
  }
17085
17087
  /**
17086
17088
  * A rough heuristic for whether the client is currently online and
@@ -17138,7 +17140,7 @@ var Zero = class {
17138
17140
  return rv;
17139
17141
  }
17140
17142
  };
17141
- async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientID, clientGroupID, schemaVersion, userID, auth, jurisdiction, lmid, wsid, debugPerf, lc, maxHeaderLength = 1024 * 8) {
17143
+ async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientID, clientGroupID, schemaVersion, userID, auth, lmid, wsid, debugPerf, lc, maxHeaderLength = 1024 * 8) {
17142
17144
  const url = new URL(
17143
17145
  appendPath(socketOrigin, `/sync/v${PROTOCOL_VERSION}/connect`)
17144
17146
  );
@@ -17147,9 +17149,6 @@ async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientI
17147
17149
  searchParams.set("clientGroupID", clientGroupID);
17148
17150
  searchParams.set("schemaVersion", schemaVersion.toString());
17149
17151
  searchParams.set("userID", userID);
17150
- if (jurisdiction !== void 0) {
17151
- searchParams.set("jurisdiction", jurisdiction);
17152
- }
17153
17152
  searchParams.set("baseCookie", baseCookie === null ? "" : String(baseCookie));
17154
17153
  searchParams.set("ts", String(performance.now()));
17155
17154
  searchParams.set("lmid", String(lmid));
@@ -17205,9 +17204,9 @@ export {
17205
17204
  dropDatabase,
17206
17205
  dropAllDatabases,
17207
17206
  createTableSchema,
17208
- defineAuthorization,
17207
+ definePermissions,
17209
17208
  createSchema,
17210
17209
  escapeLike,
17211
17210
  Zero
17212
17211
  };
17213
- //# sourceMappingURL=chunk-QB7G63C6.js.map
17212
+ //# sourceMappingURL=chunk-4XX2NVJ7.js.map