@noy-db/hub 0.1.0-pre.9 → 0.2.0-pre.2

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 (288) hide show
  1. package/dist/aggregate/index.cjs +91 -36
  2. package/dist/aggregate/index.cjs.map +1 -1
  3. package/dist/aggregate/index.d.cts +2 -2
  4. package/dist/aggregate/index.d.ts +2 -2
  5. package/dist/aggregate/index.js +16 -9
  6. package/dist/aggregate/index.js.map +1 -1
  7. package/dist/attestation/index.cjs +305 -0
  8. package/dist/attestation/index.cjs.map +1 -0
  9. package/dist/attestation/index.d.cts +52 -0
  10. package/dist/attestation/index.d.ts +52 -0
  11. package/dist/attestation/index.js +36 -0
  12. package/dist/attestation/index.js.map +1 -0
  13. package/dist/blobs/index.cjs.map +1 -1
  14. package/dist/blobs/index.d.cts +7 -6
  15. package/dist/blobs/index.d.ts +7 -6
  16. package/dist/blobs/index.js +10 -8
  17. package/dist/blobs/index.js.map +1 -1
  18. package/dist/bundle/index.cjs +16923 -60
  19. package/dist/bundle/index.cjs.map +1 -1
  20. package/dist/bundle/index.d.cts +175 -6
  21. package/dist/bundle/index.d.ts +175 -6
  22. package/dist/bundle/index.js +543 -4
  23. package/dist/bundle/index.js.map +1 -1
  24. package/dist/{chunk-PTVMYYON.js → chunk-243PNUA6.js} +3 -3
  25. package/dist/{chunk-MR4424N3.js → chunk-2PAQNPE3.js} +2 -2
  26. package/dist/chunk-3QAKZ37R.js +83 -0
  27. package/dist/chunk-3QAKZ37R.js.map +1 -0
  28. package/dist/chunk-3S4BJX25.js +36 -0
  29. package/dist/chunk-3S4BJX25.js.map +1 -0
  30. package/dist/chunk-3XHOCQK4.js +118 -0
  31. package/dist/chunk-3XHOCQK4.js.map +1 -0
  32. package/dist/{chunk-AVVPZ4BC.js → chunk-3Y53S2SA.js} +4 -4
  33. package/dist/chunk-3Z2TPHC4.js +291 -0
  34. package/dist/chunk-3Z2TPHC4.js.map +1 -0
  35. package/dist/chunk-4HIL6AHQ.js +57 -0
  36. package/dist/chunk-4HIL6AHQ.js.map +1 -0
  37. package/dist/chunk-5ZGZ6HIZ.js +100 -0
  38. package/dist/chunk-5ZGZ6HIZ.js.map +1 -0
  39. package/dist/{chunk-ZFKD4QMV.js → chunk-7BRE6EUA.js} +3 -3
  40. package/dist/chunk-7BUTTVMR.js +34 -0
  41. package/dist/chunk-7BUTTVMR.js.map +1 -0
  42. package/dist/{chunk-VQBTTTUN.js → chunk-7Q5PLD5C.js} +4 -4
  43. package/dist/{chunk-VQBTTTUN.js.map → chunk-7Q5PLD5C.js.map} +1 -1
  44. package/dist/{chunk-QAVUREFT.js → chunk-7Z23ZFLV.js} +12 -6
  45. package/dist/chunk-7Z23ZFLV.js.map +1 -0
  46. package/dist/chunk-AHPFONIL.js +59 -0
  47. package/dist/chunk-AHPFONIL.js.map +1 -0
  48. package/dist/chunk-CXSCDO5T.js +51 -0
  49. package/dist/chunk-CXSCDO5T.js.map +1 -0
  50. package/dist/chunk-E535SAN4.js +8834 -0
  51. package/dist/chunk-E535SAN4.js.map +1 -0
  52. package/dist/chunk-EUYOGYGV.js +830 -0
  53. package/dist/chunk-EUYOGYGV.js.map +1 -0
  54. package/dist/chunk-FAQVNJD4.js +61 -0
  55. package/dist/chunk-FAQVNJD4.js.map +1 -0
  56. package/dist/{chunk-SCZXXXU4.js → chunk-G6FRSBKK.js} +7 -32
  57. package/dist/chunk-G6FRSBKK.js.map +1 -0
  58. package/dist/chunk-GIV6DWBG.js +79 -0
  59. package/dist/chunk-GIV6DWBG.js.map +1 -0
  60. package/dist/chunk-HXJXPZRE.js +73 -0
  61. package/dist/chunk-HXJXPZRE.js.map +1 -0
  62. package/dist/{chunk-GOUT6DND.js → chunk-J4KLMEUL.js} +173 -91
  63. package/dist/chunk-J4KLMEUL.js.map +1 -0
  64. package/dist/{chunk-2CSJGFCB.js → chunk-JYQTXEIO.js} +6 -229
  65. package/dist/chunk-JYQTXEIO.js.map +1 -0
  66. package/dist/{chunk-MDDTIZUO.js → chunk-LRAZDV5X.js} +7 -119
  67. package/dist/chunk-LRAZDV5X.js.map +1 -0
  68. package/dist/{chunk-M5INGEFC.js → chunk-MRIBLZL3.js} +3 -1
  69. package/dist/chunk-MRIBLZL3.js.map +1 -0
  70. package/dist/{chunk-USKYUS74.js → chunk-MUWOSVEP.js} +2 -2
  71. package/dist/{chunk-4PWAI7Q4.js → chunk-NWZ3I6R6.js} +5 -5
  72. package/dist/chunk-OVZDFEOR.js +124 -0
  73. package/dist/chunk-OVZDFEOR.js.map +1 -0
  74. package/dist/chunk-PEULZC6M.js +118 -0
  75. package/dist/chunk-PEULZC6M.js.map +1 -0
  76. package/dist/chunk-PFSNOPBQ.js +233 -0
  77. package/dist/chunk-PFSNOPBQ.js.map +1 -0
  78. package/dist/chunk-PLI5TV7N.js +53 -0
  79. package/dist/chunk-PLI5TV7N.js.map +1 -0
  80. package/dist/{chunk-WDM5XGGS.js → chunk-Q6W2CMEJ.js} +181 -11
  81. package/dist/chunk-Q6W2CMEJ.js.map +1 -0
  82. package/dist/{chunk-QGZRWRSL.js → chunk-QPEXPHJR.js} +4 -4
  83. package/dist/{chunk-R36SIKES.js → chunk-QXQRKXCU.js} +2 -2
  84. package/dist/chunk-RTZVQAJ7.js +82 -0
  85. package/dist/chunk-RTZVQAJ7.js.map +1 -0
  86. package/dist/chunk-TBKOGSYR.js +296 -0
  87. package/dist/chunk-TBKOGSYR.js.map +1 -0
  88. package/dist/chunk-UMLVJTYV.js +20 -0
  89. package/dist/chunk-UMLVJTYV.js.map +1 -0
  90. package/dist/chunk-UND4XIB6.js +251 -0
  91. package/dist/chunk-UND4XIB6.js.map +1 -0
  92. package/dist/chunk-VCGTOS2A.js +795 -0
  93. package/dist/chunk-VCGTOS2A.js.map +1 -0
  94. package/dist/chunk-VE6YVP32.js +19 -0
  95. package/dist/chunk-VE6YVP32.js.map +1 -0
  96. package/dist/{chunk-M62XNWRA.js → chunk-VK5EER6C.js} +2 -2
  97. package/dist/{chunk-NXFEYLVG.js → chunk-VPSUZLOJ.js} +4 -3
  98. package/dist/{chunk-NXFEYLVG.js.map → chunk-VPSUZLOJ.js.map} +1 -1
  99. package/dist/{chunk-TDR6T5CJ.js → chunk-VRBCTEKQ.js} +91 -132
  100. package/dist/chunk-VRBCTEKQ.js.map +1 -0
  101. package/dist/{chunk-ACLDOTNQ.js → chunk-W3XXT26A.js} +303 -3
  102. package/dist/chunk-W3XXT26A.js.map +1 -0
  103. package/dist/{chunk-CIMZBAZB.js → chunk-XG3PTSCD.js} +1 -1
  104. package/dist/chunk-XG3PTSCD.js.map +1 -0
  105. package/dist/chunk-Y2RKOPNC.js +145 -0
  106. package/dist/chunk-Y2RKOPNC.js.map +1 -0
  107. package/dist/{chunk-NPC4LFV5.js → chunk-YMYK7US4.js} +2 -2
  108. package/dist/{chunk-RKJ6OL7K.js → chunk-YS3POABP.js} +1 -1
  109. package/dist/chunk-YS3POABP.js.map +1 -0
  110. package/dist/chunk-YTXSFG3C.js +179 -0
  111. package/dist/chunk-YTXSFG3C.js.map +1 -0
  112. package/dist/consent/index.cjs.map +1 -1
  113. package/dist/consent/index.d.cts +7 -6
  114. package/dist/consent/index.d.ts +7 -6
  115. package/dist/consent/index.js +3 -3
  116. package/dist/{crypto-IVKU7YTT.js → crypto-5ZDIY3NG.js} +3 -3
  117. package/dist/{delegation-2DBS2EOH.js → delegation-QYXZW25W.js} +5 -4
  118. package/dist/derivations/index.cjs +351 -0
  119. package/dist/derivations/index.cjs.map +1 -0
  120. package/dist/derivations/index.d.cts +72 -0
  121. package/dist/derivations/index.d.ts +72 -0
  122. package/dist/derivations/index.js +27 -0
  123. package/dist/{dev-unlock-Da1B0TIK.d.cts → dev-unlock-DQCNDfFp.d.cts} +1 -1
  124. package/dist/{dev-unlock-BdPp68qn.d.ts → dev-unlock-utkybTKb.d.ts} +1 -1
  125. package/dist/executor-AS2IDHKZ.js +11 -0
  126. package/dist/executor-HLXFXNFM.js +8 -0
  127. package/dist/executor-HLXFXNFM.js.map +1 -0
  128. package/dist/executor-HN6YBHZ5.js +8 -0
  129. package/dist/executor-HN6YBHZ5.js.map +1 -0
  130. package/dist/fanout-sidecar-VJ52RIEY.js +51 -0
  131. package/dist/fanout-sidecar-VJ52RIEY.js.map +1 -0
  132. package/dist/guards/index.cjs +315 -0
  133. package/dist/guards/index.cjs.map +1 -0
  134. package/dist/guards/index.d.cts +31 -0
  135. package/dist/guards/index.d.ts +31 -0
  136. package/dist/guards/index.js +29 -0
  137. package/dist/guards/index.js.map +1 -0
  138. package/dist/{hash-lsoL3eEW.d.ts → hash-DcoYWfJ_.d.ts} +1 -1
  139. package/dist/{hash-BEfzPKwo.d.cts → hash-jDowCrK2.d.cts} +1 -1
  140. package/dist/history/index.cjs +8 -1
  141. package/dist/history/index.cjs.map +1 -1
  142. package/dist/history/index.d.cts +8 -7
  143. package/dist/history/index.d.ts +8 -7
  144. package/dist/history/index.js +6 -6
  145. package/dist/i18n/index.cjs +81 -0
  146. package/dist/i18n/index.cjs.map +1 -1
  147. package/dist/i18n/index.d.cts +7 -6
  148. package/dist/i18n/index.d.ts +7 -6
  149. package/dist/i18n/index.js +27 -12
  150. package/dist/i18n/index.js.map +1 -1
  151. package/dist/{index-6xNpPsxR.d.cts → index-BCKdioeh.d.ts} +331 -5
  152. package/dist/{index-DJTf9yxn.d.ts → index-BMjrzNZr.d.cts} +331 -5
  153. package/dist/index.cjs +6065 -959
  154. package/dist/index.cjs.map +1 -1
  155. package/dist/index.d.cts +208 -16
  156. package/dist/index.d.ts +208 -16
  157. package/dist/index.js +242 -7392
  158. package/dist/index.js.map +1 -1
  159. package/dist/indexing/index.cjs +2 -0
  160. package/dist/indexing/index.cjs.map +1 -1
  161. package/dist/indexing/index.d.cts +3 -3
  162. package/dist/indexing/index.d.ts +3 -3
  163. package/dist/indexing/index.js +4 -4
  164. package/dist/issue-ORP37MVW.js +12 -0
  165. package/dist/issue-ORP37MVW.js.map +1 -0
  166. package/dist/{lazy-builder-CZVLKh0Z.d.cts → lazy-builder-C-rPfWG0.d.cts} +1 -1
  167. package/dist/{lazy-builder-BwEoBQZ9.d.ts → lazy-builder-Rpd-V3jP.d.ts} +1 -1
  168. package/dist/{ledger-QZTTHQAQ.js → ledger-3IU5GMXA.js} +6 -6
  169. package/dist/ledger-3IU5GMXA.js.map +1 -0
  170. package/dist/materialized-views/index.cjs +837 -0
  171. package/dist/materialized-views/index.cjs.map +1 -0
  172. package/dist/materialized-views/index.d.cts +184 -0
  173. package/dist/materialized-views/index.d.ts +184 -0
  174. package/dist/materialized-views/index.js +45 -0
  175. package/dist/materialized-views/index.js.map +1 -0
  176. package/dist/noydb-5H3C24GG.js +34 -0
  177. package/dist/noydb-5H3C24GG.js.map +1 -0
  178. package/dist/overlay-views/index.cjs +359 -0
  179. package/dist/overlay-views/index.cjs.map +1 -0
  180. package/dist/overlay-views/index.d.cts +82 -0
  181. package/dist/overlay-views/index.d.ts +82 -0
  182. package/dist/overlay-views/index.js +25 -0
  183. package/dist/overlay-views/index.js.map +1 -0
  184. package/dist/periods/index.cjs +7 -1
  185. package/dist/periods/index.cjs.map +1 -1
  186. package/dist/periods/index.d.cts +7 -6
  187. package/dist/periods/index.d.ts +7 -6
  188. package/dist/periods/index.js +6 -6
  189. package/dist/{predicate-SBHmi6D0.d.cts → predicate-Dnu81tsS.d.cts} +25 -1
  190. package/dist/{predicate-SBHmi6D0.d.ts → predicate-Dnu81tsS.d.ts} +25 -1
  191. package/dist/{public-envelope-6JTACYJV.js → public-envelope-U3CMEOMV.js} +4 -4
  192. package/dist/public-envelope-U3CMEOMV.js.map +1 -0
  193. package/dist/query/index.cjs +302 -124
  194. package/dist/query/index.cjs.map +1 -1
  195. package/dist/query/index.d.cts +3 -3
  196. package/dist/query/index.d.ts +3 -3
  197. package/dist/query/index.js +26 -11
  198. package/dist/read-only-facade-ITU6L7BL.js +7 -0
  199. package/dist/read-only-facade-ITU6L7BL.js.map +1 -0
  200. package/dist/registry-3ALP62P6.js +10 -0
  201. package/dist/registry-3ALP62P6.js.map +1 -0
  202. package/dist/registry-7HE6VJGC.js +8 -0
  203. package/dist/registry-7HE6VJGC.js.map +1 -0
  204. package/dist/registry-PSIPG2QR.js +8 -0
  205. package/dist/registry-PSIPG2QR.js.map +1 -0
  206. package/dist/registry-RFGGMVNJ.js +7 -0
  207. package/dist/registry-RFGGMVNJ.js.map +1 -0
  208. package/dist/revoke-KY2GB4KP.js +17 -0
  209. package/dist/revoke-KY2GB4KP.js.map +1 -0
  210. package/dist/session/index.cjs +7 -1
  211. package/dist/session/index.cjs.map +1 -1
  212. package/dist/session/index.d.cts +8 -7
  213. package/dist/session/index.d.ts +8 -7
  214. package/dist/session/index.js +10 -3
  215. package/dist/session/index.js.map +1 -1
  216. package/dist/shadow/index.cjs.map +1 -1
  217. package/dist/shadow/index.d.cts +7 -6
  218. package/dist/shadow/index.d.ts +7 -6
  219. package/dist/shadow/index.js +2 -2
  220. package/dist/signer-GRI5TZKH.js +18 -0
  221. package/dist/signer-GRI5TZKH.js.map +1 -0
  222. package/dist/stale-OTOF3FH7.js +13 -0
  223. package/dist/stale-OTOF3FH7.js.map +1 -0
  224. package/dist/store/index.cjs +14 -0
  225. package/dist/store/index.cjs.map +1 -1
  226. package/dist/store/index.d.cts +7 -6
  227. package/dist/store/index.d.ts +7 -6
  228. package/dist/store/index.js +5 -2
  229. package/dist/{strategy-D-SrOLCl.d.cts → strategy-DSTrsZ8t.d.cts} +72 -19
  230. package/dist/{strategy-D-SrOLCl.d.ts → strategy-DSTrsZ8t.d.ts} +72 -19
  231. package/dist/sync/index.cjs.map +1 -1
  232. package/dist/sync/index.d.cts +6 -5
  233. package/dist/sync/index.d.ts +6 -5
  234. package/dist/sync/index.js +4 -4
  235. package/dist/team/index.cjs +1554 -2
  236. package/dist/team/index.cjs.map +1 -1
  237. package/dist/team/index.d.cts +7 -6
  238. package/dist/team/index.d.ts +7 -6
  239. package/dist/team/index.js +77 -8
  240. package/dist/tx/index.cjs +296 -44
  241. package/dist/tx/index.cjs.map +1 -1
  242. package/dist/tx/index.d.cts +7 -6
  243. package/dist/tx/index.d.ts +7 -6
  244. package/dist/tx/index.js +2 -2
  245. package/dist/{types-Bo7NSXJr.d.ts → types-BoFFiskX.d.ts} +2714 -321
  246. package/dist/{types-Bnb82f5R.d.cts → types-DJG8HG6F.d.cts} +2714 -321
  247. package/dist/{index-CywCC1qZ.d.cts → ulid-BmBgooGm.d.ts} +215 -26
  248. package/dist/{index-8QDuznDr.d.ts → ulid-C7ms9oli.d.cts} +215 -26
  249. package/dist/util/index.cjs.map +1 -1
  250. package/dist/util/index.js +1 -1
  251. package/dist/with-derivation-BKXXa8Vt.d.ts +13 -0
  252. package/dist/with-derivation-BjQ7q4NE.d.cts +13 -0
  253. package/dist/with-guard-C25yNjzd.d.ts +18 -0
  254. package/dist/with-guard-DQme5DKE.d.cts +18 -0
  255. package/dist/with-materialized-view-BbEPFIIJ.d.cts +27 -0
  256. package/dist/with-materialized-view-CqnRwI2S.d.ts +27 -0
  257. package/dist/with-overlayed-view-Ct1fSJt-.d.ts +13 -0
  258. package/dist/with-overlayed-view-bwlmmFjx.d.cts +13 -0
  259. package/package.json +65 -2
  260. package/dist/chunk-2CSJGFCB.js.map +0 -1
  261. package/dist/chunk-ACLDOTNQ.js.map +0 -1
  262. package/dist/chunk-BTDCBVJW.js +0 -160
  263. package/dist/chunk-BTDCBVJW.js.map +0 -1
  264. package/dist/chunk-CIMZBAZB.js.map +0 -1
  265. package/dist/chunk-EXHNQEV4.js +0 -392
  266. package/dist/chunk-EXHNQEV4.js.map +0 -1
  267. package/dist/chunk-GOUT6DND.js.map +0 -1
  268. package/dist/chunk-M5INGEFC.js.map +0 -1
  269. package/dist/chunk-MDDTIZUO.js.map +0 -1
  270. package/dist/chunk-QAVUREFT.js.map +0 -1
  271. package/dist/chunk-RKJ6OL7K.js.map +0 -1
  272. package/dist/chunk-SCZXXXU4.js.map +0 -1
  273. package/dist/chunk-TDR6T5CJ.js.map +0 -1
  274. package/dist/chunk-WDM5XGGS.js.map +0 -1
  275. /package/dist/{chunk-PTVMYYON.js.map → chunk-243PNUA6.js.map} +0 -0
  276. /package/dist/{chunk-MR4424N3.js.map → chunk-2PAQNPE3.js.map} +0 -0
  277. /package/dist/{chunk-AVVPZ4BC.js.map → chunk-3Y53S2SA.js.map} +0 -0
  278. /package/dist/{chunk-ZFKD4QMV.js.map → chunk-7BRE6EUA.js.map} +0 -0
  279. /package/dist/{chunk-USKYUS74.js.map → chunk-MUWOSVEP.js.map} +0 -0
  280. /package/dist/{chunk-4PWAI7Q4.js.map → chunk-NWZ3I6R6.js.map} +0 -0
  281. /package/dist/{chunk-QGZRWRSL.js.map → chunk-QPEXPHJR.js.map} +0 -0
  282. /package/dist/{chunk-R36SIKES.js.map → chunk-QXQRKXCU.js.map} +0 -0
  283. /package/dist/{chunk-M62XNWRA.js.map → chunk-VK5EER6C.js.map} +0 -0
  284. /package/dist/{chunk-NPC4LFV5.js.map → chunk-YMYK7US4.js.map} +0 -0
  285. /package/dist/{crypto-IVKU7YTT.js.map → crypto-5ZDIY3NG.js.map} +0 -0
  286. /package/dist/{delegation-2DBS2EOH.js.map → delegation-QYXZW25W.js.map} +0 -0
  287. /package/dist/{ledger-QZTTHQAQ.js.map → derivations/index.js.map} +0 -0
  288. /package/dist/{public-envelope-6JTACYJV.js.map → executor-AS2IDHKZ.js.map} +0 -0
@@ -23,10 +23,16 @@ __export(query_exports, {
23
23
  Aggregation: () => Aggregation,
24
24
  CollectionIndexes: () => CollectionIndexes,
25
25
  DEFAULT_JOIN_MAX_ROWS: () => DEFAULT_JOIN_MAX_ROWS,
26
+ DanglingReferenceError: () => DanglingReferenceError,
26
27
  GROUPBY_MAX_CARDINALITY: () => GROUPBY_MAX_CARDINALITY,
27
28
  GROUPBY_WARN_CARDINALITY: () => GROUPBY_WARN_CARDINALITY,
29
+ GroupCardinalityError: () => GroupCardinalityError,
28
30
  GroupedAggregation: () => GroupedAggregation,
29
31
  GroupedQuery: () => GroupedQuery,
32
+ GroupedQueryN: () => GroupedQueryN,
33
+ IndexRequiredError: () => IndexRequiredError,
34
+ IndexWriteFailureError: () => IndexWriteFailureError,
35
+ JoinTooLargeError: () => JoinTooLargeError,
30
36
  Query: () => Query,
31
37
  ScanBuilder: () => ScanBuilder,
32
38
  applyJoins: () => applyJoins,
@@ -111,6 +117,8 @@ function evaluateClause(record, clause) {
111
117
  return evaluateFieldClause(record, clause);
112
118
  case "filter":
113
119
  return clause.fn(record);
120
+ case "wherePredicate":
121
+ return clause.fn(record, clause.ctx);
114
122
  case "group":
115
123
  if (clause.op === "and") {
116
124
  for (const child of clause.clauses) {
@@ -154,6 +162,38 @@ var GroupCardinalityError = class extends NoydbError {
154
162
  this.maxGroups = maxGroups;
155
163
  }
156
164
  };
165
+ var IndexRequiredError = class extends NoydbError {
166
+ collection;
167
+ touchedFields;
168
+ missingFields;
169
+ constructor(args) {
170
+ super(
171
+ "INDEX_REQUIRED",
172
+ `Collection "${args.collection}": query references unindexed fields in lazy mode (missing: ${args.missingFields.join(", ")}). Declare an index on each field, or use collection.scan() for non-indexed iteration.`
173
+ );
174
+ this.name = "IndexRequiredError";
175
+ this.collection = args.collection;
176
+ this.touchedFields = [...args.touchedFields];
177
+ this.missingFields = [...args.missingFields];
178
+ }
179
+ };
180
+ var IndexWriteFailureError = class extends NoydbError {
181
+ recordId;
182
+ field;
183
+ op;
184
+ cause;
185
+ constructor(args) {
186
+ super(
187
+ "INDEX_WRITE_FAILURE",
188
+ `Index side-car ${args.op} failed for field "${args.field}" on record "${args.recordId}"`
189
+ );
190
+ this.name = "IndexWriteFailureError";
191
+ this.recordId = args.recordId;
192
+ this.field = args.field;
193
+ this.op = args.op;
194
+ this.cause = args.cause;
195
+ }
196
+ };
157
197
  var JoinTooLargeError = class extends NoydbError {
158
198
  leftRows;
159
199
  rightRows;
@@ -418,6 +458,9 @@ var NO_AGGREGATE = {
418
458
  groupBy() {
419
459
  throw NOT_ENABLED;
420
460
  },
461
+ groupByN() {
462
+ throw NOT_ENABLED;
463
+ },
421
464
  scanAggregate() {
422
465
  throw NOT_ENABLED;
423
466
  }
@@ -436,11 +479,83 @@ var Query = class _Query {
436
479
  plan;
437
480
  joinContext;
438
481
  aggregateStrategy;
439
- constructor(source, plan = EMPTY_PLAN, joinContext, aggregateStrategy = NO_AGGREGATE) {
482
+ predicates;
483
+ constructor(source, plan = EMPTY_PLAN, joinContext, aggregateStrategy = NO_AGGREGATE, predicates) {
440
484
  this.source = source;
441
485
  this.plan = plan;
442
486
  this.joinContext = joinContext;
443
487
  this.aggregateStrategy = aggregateStrategy;
488
+ this.predicates = predicates;
489
+ }
490
+ /**
491
+ * @internal — accessor for the materialized-view dependency
492
+ * analyzer. Not part of the public API; consumers should use the
493
+ * builder methods, not inspect the plan directly.
494
+ */
495
+ _plan() {
496
+ return this.plan;
497
+ }
498
+ /**
499
+ * @internal — accessor for the materialized-view dependency
500
+ * analyzer. Returns the join resolution context (or `undefined` for
501
+ * queries constructed without a Collection backing).
502
+ */
503
+ _joinContext() {
504
+ return this.joinContext;
505
+ }
506
+ /**
507
+ * @internal — clone this Query with a declared-predicate map
508
+ * attached. Used by the materialized-view registry to enable
509
+ * `.wherePredicate(name, ctx?)` for the MV's query callback (#153).
510
+ * Consumers don't call this directly.
511
+ */
512
+ _withPredicates(predicates) {
513
+ return new _Query(
514
+ this.source,
515
+ this.plan,
516
+ this.joinContext,
517
+ this.aggregateStrategy,
518
+ predicates
519
+ );
520
+ }
521
+ /**
522
+ * Filter by a registered deterministic predicate (#153). Requires
523
+ * the Query to have been augmented with a predicates map (typically
524
+ * via the materialized-view registry — bare Queries constructed
525
+ * outside an MV throw on `.wherePredicate()`).
526
+ *
527
+ * `ctx` is an optional opaque value passed verbatim to the predicate
528
+ * function. Both `predicateHash` (from the registration) and a
529
+ * canonical-JSON hash of `ctx` fold into the MV's `queryHash`, so
530
+ * either changing forces refresh on next visit.
531
+ */
532
+ wherePredicate(name, ctx) {
533
+ if (!this.predicates) {
534
+ throw new Error(
535
+ `.wherePredicate("${name}"): no predicates registered on this Query. Function-based predicates require the Query to be obtained from inside a materialized-view query() callback whose strategy declares \`predicates: { ${name}: { hash, fn } }\`.`
536
+ );
537
+ }
538
+ const decl = this.predicates.get(name);
539
+ if (!decl) {
540
+ throw new Error(
541
+ `.wherePredicate("${name}"): predicate not registered. Available: ${[...this.predicates.keys()].join(", ") || "(none)"}.`
542
+ );
543
+ }
544
+ const clause = {
545
+ type: "wherePredicate",
546
+ name,
547
+ ctx,
548
+ predicateHash: decl.hash,
549
+ ctxHash: canonicalCtxHash(ctx),
550
+ fn: decl.fn
551
+ };
552
+ return new _Query(
553
+ this.source,
554
+ { ...this.plan, clauses: [...this.plan.clauses, clause] },
555
+ this.joinContext,
556
+ this.aggregateStrategy,
557
+ this.predicates
558
+ );
444
559
  }
445
560
  /** Add a field comparison. Multiple where() calls are AND-combined. */
446
561
  where(field, op, value) {
@@ -449,7 +564,8 @@ var Query = class _Query {
449
564
  this.source,
450
565
  { ...this.plan, clauses: [...this.plan.clauses, clause] },
451
566
  this.joinContext,
452
- this.aggregateStrategy
567
+ this.aggregateStrategy,
568
+ this.predicates
453
569
  );
454
570
  }
455
571
  /**
@@ -459,7 +575,7 @@ var Query = class _Query {
459
575
  */
460
576
  or(builder) {
461
577
  const sub = builder(
462
- new _Query(this.source, EMPTY_PLAN, this.joinContext, this.aggregateStrategy)
578
+ new _Query(this.source, EMPTY_PLAN, this.joinContext, this.aggregateStrategy, this.predicates)
463
579
  );
464
580
  const group = {
465
581
  type: "group",
@@ -470,7 +586,8 @@ var Query = class _Query {
470
586
  this.source,
471
587
  { ...this.plan, clauses: [...this.plan.clauses, group] },
472
588
  this.joinContext,
473
- this.aggregateStrategy
589
+ this.aggregateStrategy,
590
+ this.predicates
474
591
  );
475
592
  }
476
593
  /**
@@ -479,7 +596,7 @@ var Query = class _Query {
479
596
  */
480
597
  and(builder) {
481
598
  const sub = builder(
482
- new _Query(this.source, EMPTY_PLAN, this.joinContext, this.aggregateStrategy)
599
+ new _Query(this.source, EMPTY_PLAN, this.joinContext, this.aggregateStrategy, this.predicates)
483
600
  );
484
601
  const group = {
485
602
  type: "group",
@@ -490,7 +607,8 @@ var Query = class _Query {
490
607
  this.source,
491
608
  { ...this.plan, clauses: [...this.plan.clauses, group] },
492
609
  this.joinContext,
493
- this.aggregateStrategy
610
+ this.aggregateStrategy,
611
+ this.predicates
494
612
  );
495
613
  }
496
614
  /** Escape hatch: add an arbitrary predicate function. Not serializable. */
@@ -503,7 +621,8 @@ var Query = class _Query {
503
621
  this.source,
504
622
  { ...this.plan, clauses: [...this.plan.clauses, clause] },
505
623
  this.joinContext,
506
- this.aggregateStrategy
624
+ this.aggregateStrategy,
625
+ this.predicates
507
626
  );
508
627
  }
509
628
  /** Sort by a field. Subsequent calls are tie-breakers. */
@@ -512,7 +631,8 @@ var Query = class _Query {
512
631
  this.source,
513
632
  { ...this.plan, orderBy: [...this.plan.orderBy, { field, direction }] },
514
633
  this.joinContext,
515
- this.aggregateStrategy
634
+ this.aggregateStrategy,
635
+ this.predicates
516
636
  );
517
637
  }
518
638
  /** Cap the result size. */
@@ -521,7 +641,8 @@ var Query = class _Query {
521
641
  this.source,
522
642
  { ...this.plan, limit: n },
523
643
  this.joinContext,
524
- this.aggregateStrategy
644
+ this.aggregateStrategy,
645
+ this.predicates
525
646
  );
526
647
  }
527
648
  /** Skip the first N matching records (after ordering). */
@@ -530,7 +651,8 @@ var Query = class _Query {
530
651
  this.source,
531
652
  { ...this.plan, offset: n },
532
653
  this.joinContext,
533
- this.aggregateStrategy
654
+ this.aggregateStrategy,
655
+ this.predicates
534
656
  );
535
657
  }
536
658
  /**
@@ -629,7 +751,8 @@ var Query = class _Query {
629
751
  this.source,
630
752
  { ...this.plan, joins: [...this.plan.joins, leg] },
631
753
  this.joinContext,
632
- this.aggregateStrategy
754
+ this.aggregateStrategy,
755
+ this.predicates
633
756
  );
634
757
  }
635
758
  /**
@@ -721,53 +844,10 @@ var Query = class _Query {
721
844
  }
722
845
  return this.aggregateStrategy.aggregate(executeRecords, spec, upstreams);
723
846
  }
724
- /**
725
- * Partition matching records into buckets keyed by a field, then
726
- * terminate with `.aggregate(spec)` to compute per-bucket
727
- * reducers..
728
- *
729
- * ```ts
730
- * const byClient = invoices.query()
731
- * .where('status', '==', 'open')
732
- * .groupBy('clientId')
733
- * .aggregate({ total: sum('amount'), n: count() })
734
- * .run()
735
- * // → [ { clientId: 'c1', total: 5250, n: 3 }, … ]
736
- * ```
737
- *
738
- * Result rows carry the group key value under the grouping field
739
- * name plus every reducer output from the spec. Buckets are
740
- * emitted in first-seen order — consumers who want a specific
741
- * ordering should `.sort()` downstream.
742
- *
743
- * **Cardinality caps:** a one-shot warning fires at 10_000
744
- * distinct groups; `GroupCardinalityError` throws at 100_000.
745
- * Grouping on a high-uniqueness field like `id` or `createdAt` is
746
- * almost always a query mistake — the error message names the
747
- * field and observed cardinality and suggests narrowing with
748
- * `.where()` first.
749
- *
750
- * **Null / undefined keys:** records with a missing or explicitly
751
- * `null` group field get their own buckets. `Map`-based
752
- * partitioning distinguishes `undefined` from `null`, so the two
753
- * cases do NOT merge. Consumers who want them merged should
754
- * coalesce upstream with `.filter()`.
755
- *
756
- * **Joins are not applied** — same rationale as `.count()` and
757
- * `.aggregate()`. Joined fields in are projection-only, so
758
- * running a join inside a grouping pipeline would be wasteful and
759
- * could trigger `DanglingReferenceError` in strict mode for a
760
- * call whose intent is purely to bucket-and-reduce. Grouping by
761
- * a joined field is explicitly out of scope for — file an
762
- * issue if a real consumer needs it.
763
- *
764
- * **Filter clauses (`.filter(fn)`):** grouped queries still
765
- * support filter clauses in the underlying plan — they run in
766
- * the same candidate/filter pipeline that `.aggregate()` uses.
767
- * The performance caveat is the same: filter clauses cost O(N)
768
- * per record and can't be index-accelerated.
769
- */
770
- groupBy(field) {
847
+ groupBy(...fields) {
848
+ if (fields.length === 0) {
849
+ throw new Error(".groupBy() requires at least one field");
850
+ }
771
851
  const source = this.source;
772
852
  const clauses = this.plan.clauses;
773
853
  const executeRecords = () => {
@@ -779,36 +859,21 @@ var Query = class _Query {
779
859
  const subscribe = source.subscribe.bind(source);
780
860
  upstreams.push({ subscribe: (cb) => subscribe(cb) });
781
861
  }
782
- const joinCtx = this.joinContext;
783
- const dictLabelResolver = joinCtx?.resolveDictSource ? (() => {
784
- const dictSource = joinCtx.resolveDictSource(field);
785
- if (!dictSource) return void 0;
786
- const snapshot = dictSource.snapshot();
787
- const dictMap = /* @__PURE__ */ new Map();
788
- for (const entry of snapshot) {
789
- const k = entry["key"];
790
- const labels = entry["labels"];
791
- if (typeof k === "string" && labels && typeof labels === "object") {
792
- dictMap.set(k, labels);
793
- }
794
- }
795
- return async (key, locale, fallback) => {
796
- const labels = dictMap.get(key);
797
- if (!labels) return void 0;
798
- if (labels[locale] !== void 0) return labels[locale];
799
- const chain = Array.isArray(fallback) ? fallback : fallback ? [fallback] : [];
800
- for (const fb of chain) {
801
- if (fb === "any") {
802
- const any = Object.values(labels)[0];
803
- if (any !== void 0) return any;
804
- } else if (labels[fb] !== void 0) {
805
- return labels[fb];
806
- }
807
- }
808
- return void 0;
809
- };
810
- })() : void 0;
811
- return this.aggregateStrategy.groupBy(executeRecords, field, upstreams, dictLabelResolver);
862
+ if (fields.length === 1) {
863
+ const field = fields[0];
864
+ const dictLabelResolver = buildDictLabelResolver(this.joinContext, field);
865
+ return this.aggregateStrategy.groupBy(
866
+ executeRecords,
867
+ field,
868
+ upstreams,
869
+ dictLabelResolver
870
+ );
871
+ }
872
+ return this.aggregateStrategy.groupByN(
873
+ executeRecords,
874
+ fields,
875
+ upstreams
876
+ );
812
877
  }
813
878
  /**
814
879
  * Re-run the query whenever the source notifies of changes.
@@ -1034,6 +1099,16 @@ function serializeClause(clause) {
1034
1099
  if (clause.type === "filter") {
1035
1100
  return { type: "filter", fn: "[function]" };
1036
1101
  }
1102
+ if (clause.type === "wherePredicate") {
1103
+ return {
1104
+ type: "wherePredicate",
1105
+ name: clause.name,
1106
+ ctx: clause.ctx,
1107
+ predicateHash: clause.predicateHash,
1108
+ ctxHash: clause.ctxHash,
1109
+ fn: "[function]"
1110
+ };
1111
+ }
1037
1112
  if (clause.type === "group") {
1038
1113
  return {
1039
1114
  type: "group",
@@ -1043,6 +1118,53 @@ function serializeClause(clause) {
1043
1118
  }
1044
1119
  return clause;
1045
1120
  }
1121
+ function canonicalCtxHash(ctx) {
1122
+ if (ctx === void 0) return "";
1123
+ const canonical = JSON.stringify(ctx, (_key, value) => {
1124
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1125
+ const sorted = {};
1126
+ for (const k of Object.keys(value).sort()) {
1127
+ sorted[k] = value[k];
1128
+ }
1129
+ return sorted;
1130
+ }
1131
+ return value;
1132
+ });
1133
+ let h = 5381;
1134
+ for (let i = 0; i < canonical.length; i++) {
1135
+ h = (h << 5) + h ^ canonical.charCodeAt(i);
1136
+ }
1137
+ return (h >>> 0).toString(16).padStart(8, "0");
1138
+ }
1139
+ function buildDictLabelResolver(joinCtx, field) {
1140
+ if (!joinCtx?.resolveDictSource) return void 0;
1141
+ const dictSource = joinCtx.resolveDictSource(field);
1142
+ if (!dictSource) return void 0;
1143
+ const snapshot = dictSource.snapshot();
1144
+ const dictMap = /* @__PURE__ */ new Map();
1145
+ for (const entry of snapshot) {
1146
+ const k = entry["key"];
1147
+ const labels = entry["labels"];
1148
+ if (typeof k === "string" && labels && typeof labels === "object") {
1149
+ dictMap.set(k, labels);
1150
+ }
1151
+ }
1152
+ return async (key, locale, fallback) => {
1153
+ const labels = dictMap.get(key);
1154
+ if (!labels) return void 0;
1155
+ if (labels[locale] !== void 0) return labels[locale];
1156
+ const chain = Array.isArray(fallback) ? fallback : fallback ? [fallback] : [];
1157
+ for (const fb of chain) {
1158
+ if (fb === "any") {
1159
+ const any = Object.values(labels)[0];
1160
+ if (any !== void 0) return any;
1161
+ } else if (labels[fb] !== void 0) {
1162
+ return labels[fb];
1163
+ }
1164
+ }
1165
+ return void 0;
1166
+ };
1167
+ }
1046
1168
 
1047
1169
  // src/indexing/eager-indexes.ts
1048
1170
  var CollectionIndexes = class {
@@ -1379,31 +1501,53 @@ function buildLiveAggregation(recompute, upstreams) {
1379
1501
  return new LiveAggregationImpl(recompute, upstreams);
1380
1502
  }
1381
1503
 
1504
+ // src/aggregate/canonical-key.ts
1505
+ function canonicalGroupKey(fields, row) {
1506
+ const sorted = [...fields].sort();
1507
+ const parts = [];
1508
+ for (const name of sorted) {
1509
+ const v = row[name];
1510
+ const serialised = v === void 0 ? "undefined" : JSON.stringify(v);
1511
+ parts.push(`${name}=${serialised}`);
1512
+ }
1513
+ return parts.join("|");
1514
+ }
1515
+
1382
1516
  // src/aggregate/groupby.ts
1383
1517
  var GROUPBY_WARN_CARDINALITY = 1e4;
1384
1518
  var GROUPBY_MAX_CARDINALITY = 1e5;
1385
1519
  var warnedCardinalityFields = /* @__PURE__ */ new Set();
1386
- function warnCardinalityApproaching(field, observed) {
1387
- if (warnedCardinalityFields.has(field)) return;
1388
- warnedCardinalityFields.add(field);
1520
+ function warnCardinalityApproaching(fields, observed) {
1521
+ const key = JSON.stringify([...fields].sort());
1522
+ if (warnedCardinalityFields.has(key)) return;
1523
+ warnedCardinalityFields.add(key);
1524
+ const label = `[${fields.join(", ")}]`;
1389
1525
  console.warn(
1390
- `[noy-db] .groupBy("${field}") produced ${observed} distinct groups, ${Math.round(observed / GROUPBY_MAX_CARDINALITY * 100)}% of the ${GROUPBY_MAX_CARDINALITY}-group ceiling. Narrow the query with .where() before grouping, or switch to a lower-cardinality field.`
1526
+ `[noy-db] .groupBy(${label}) produced ${observed} distinct groups, ${Math.round(observed / GROUPBY_MAX_CARDINALITY * 100)}% of the ${GROUPBY_MAX_CARDINALITY}-group ceiling. Narrow the query with .where() before grouping, or switch to a lower-cardinality field.`
1391
1527
  );
1392
1528
  }
1393
1529
  function resetGroupByWarnings() {
1394
1530
  warnedCardinalityFields.clear();
1395
1531
  }
1396
- var GroupedQuery = class {
1397
- constructor(executeRecords, field, upstreams, dictLabelResolver) {
1532
+ var GroupedQueryBase = class {
1533
+ constructor(executeRecords, fieldOrFields, upstreams, dictLabelResolver) {
1398
1534
  this.executeRecords = executeRecords;
1399
- this.field = field;
1400
1535
  this.upstreams = upstreams;
1401
1536
  this.dictLabelResolver = dictLabelResolver;
1537
+ this.fields = typeof fieldOrFields === "string" ? [fieldOrFields] : [...fieldOrFields];
1402
1538
  }
1403
1539
  executeRecords;
1404
- field;
1405
1540
  upstreams;
1406
1541
  dictLabelResolver;
1542
+ /**
1543
+ * Field set this grouped query buckets on. Stored in declaration
1544
+ * order — the same order is preserved on every result row by
1545
+ * `groupAndReduce`. For the single-field constructor, this is
1546
+ * `[field]`.
1547
+ */
1548
+ fields;
1549
+ };
1550
+ var GroupedQuery = class extends GroupedQueryBase {
1407
1551
  /**
1408
1552
  * Build a grouped aggregation. Returns a `GroupedAggregation`
1409
1553
  * with `.run()`, `.runAsync()`, and `.live()` terminals — same shape
@@ -1413,70 +1557,93 @@ var GroupedQuery = class {
1413
1557
  aggregate(spec) {
1414
1558
  return new GroupedAggregation(
1415
1559
  this.executeRecords,
1416
- this.field,
1560
+ this.fields,
1561
+ spec,
1562
+ this.upstreams,
1563
+ this.dictLabelResolver
1564
+ );
1565
+ }
1566
+ };
1567
+ var GroupedQueryN = class extends GroupedQueryBase {
1568
+ aggregate(spec) {
1569
+ return new GroupedAggregation(
1570
+ this.executeRecords,
1571
+ this.fields,
1417
1572
  spec,
1418
1573
  this.upstreams,
1419
1574
  this.dictLabelResolver
1420
1575
  );
1421
1576
  }
1422
1577
  };
1423
- function groupAndReduce(records, field, spec) {
1578
+ function groupAndReduce(records, fieldOrFields, spec) {
1579
+ const fields = typeof fieldOrFields === "string" ? [fieldOrFields] : fieldOrFields;
1580
+ if (fields.length === 0) {
1581
+ throw new Error(".groupBy() requires at least one field");
1582
+ }
1424
1583
  const buckets = /* @__PURE__ */ new Map();
1584
+ const fieldLabel = fields.length === 1 ? fields[0] : `[${fields.join(", ")}]`;
1425
1585
  for (const record of records) {
1426
- const key = readPath(record, field);
1427
- let bucket = buckets.get(key);
1586
+ const keyValues = {};
1587
+ for (const f of fields) {
1588
+ keyValues[f] = readPath(record, f);
1589
+ }
1590
+ const dedupKey = canonicalGroupKey(fields, keyValues);
1591
+ let bucket = buckets.get(dedupKey);
1428
1592
  if (bucket === void 0) {
1429
1593
  if (buckets.size >= GROUPBY_MAX_CARDINALITY) {
1430
1594
  throw new GroupCardinalityError(
1431
- field,
1595
+ fieldLabel,
1432
1596
  buckets.size + 1,
1433
1597
  GROUPBY_MAX_CARDINALITY
1434
1598
  );
1435
1599
  }
1436
- bucket = [];
1437
- buckets.set(key, bucket);
1600
+ bucket = { keyValues, records: [] };
1601
+ buckets.set(dedupKey, bucket);
1438
1602
  }
1439
- bucket.push(record);
1603
+ bucket.records.push(record);
1440
1604
  }
1441
1605
  if (buckets.size >= GROUPBY_WARN_CARDINALITY) {
1442
- warnCardinalityApproaching(field, buckets.size);
1606
+ warnCardinalityApproaching(fields, buckets.size);
1443
1607
  }
1444
- const keys = Object.keys(spec);
1608
+ const reducerKeys = Object.keys(spec);
1445
1609
  const out = [];
1446
- for (const [groupKey, bucketRecords] of buckets) {
1610
+ for (const bucket of buckets.values()) {
1447
1611
  const state = {};
1448
- for (const key of keys) {
1449
- state[key] = spec[key].init();
1612
+ for (const rk of reducerKeys) {
1613
+ state[rk] = spec[rk].init();
1450
1614
  }
1451
- for (const record of bucketRecords) {
1452
- for (const key of keys) {
1453
- state[key] = spec[key].step(state[key], record);
1615
+ for (const record of bucket.records) {
1616
+ for (const rk of reducerKeys) {
1617
+ state[rk] = spec[rk].step(state[rk], record);
1454
1618
  }
1455
1619
  }
1456
- const row = { [field]: groupKey };
1457
- for (const key of keys) {
1458
- row[key] = spec[key].finalize(state[key]);
1620
+ const row = {};
1621
+ for (const f of fields) {
1622
+ row[f] = bucket.keyValues[f];
1623
+ }
1624
+ for (const rk of reducerKeys) {
1625
+ row[rk] = spec[rk].finalize(state[rk]);
1459
1626
  }
1460
1627
  out.push(row);
1461
1628
  }
1462
1629
  return out;
1463
1630
  }
1464
1631
  var GroupedAggregation = class {
1465
- constructor(executeRecords, field, spec, upstreams, dictLabelResolver) {
1632
+ constructor(executeRecords, fields, spec, upstreams, dictLabelResolver) {
1466
1633
  this.executeRecords = executeRecords;
1467
- this.field = field;
1468
1634
  this.spec = spec;
1469
1635
  this.upstreams = upstreams;
1470
1636
  this.dictLabelResolver = dictLabelResolver;
1637
+ this.fields = typeof fields === "string" ? [fields] : [...fields];
1471
1638
  }
1472
1639
  executeRecords;
1473
- field;
1474
1640
  spec;
1475
1641
  upstreams;
1476
1642
  dictLabelResolver;
1643
+ fields;
1477
1644
  /** Execute the query, group, reduce, and return an array of rows. */
1478
1645
  run() {
1479
- return groupAndReduce(this.executeRecords(), this.field, this.spec);
1646
+ return groupAndReduce(this.executeRecords(), this.fields, this.spec);
1480
1647
  }
1481
1648
  /**
1482
1649
  * Execute the query, group, reduce, and resolve `<field>Label` for
@@ -1486,17 +1653,22 @@ var GroupedAggregation = class {
1486
1653
  *
1487
1654
  * The `<field>Label` field is appended to each row. Rows whose group
1488
1655
  * key has no dictionary entry get `<field>Label: undefined`.
1656
+ *
1657
+ * Dict-label resolution is single-field only — multi-key groupings
1658
+ * do not produce a `<field>Label`. The resolver is only attached
1659
+ * by the builder when `fields.length === 1`.
1489
1660
  */
1490
1661
  async runAsync(opts) {
1491
- const rows = groupAndReduce(this.executeRecords(), this.field, this.spec);
1492
- if (!opts?.locale || !this.dictLabelResolver) return rows;
1662
+ const rows = groupAndReduce(this.executeRecords(), this.fields, this.spec);
1663
+ if (!opts?.locale || !this.dictLabelResolver || this.fields.length !== 1) return rows;
1493
1664
  const resolve = this.dictLabelResolver;
1494
1665
  const locale = opts.locale;
1495
1666
  const fallback = opts.fallback;
1496
- const labelKey = `${this.field}Label`;
1667
+ const field = this.fields[0];
1668
+ const labelKey = `${field}Label`;
1497
1669
  return Promise.all(
1498
1670
  rows.map(async (row) => {
1499
- const key = row[this.field];
1671
+ const key = row[field];
1500
1672
  if (typeof key !== "string") return row;
1501
1673
  const label = await resolve(key, locale, fallback);
1502
1674
  return { ...row, [labelKey]: label };
@@ -1520,7 +1692,7 @@ var GroupedAggregation = class {
1520
1692
  * Always call `live.stop()` when finished.
1521
1693
  */
1522
1694
  live() {
1523
- const recompute = () => groupAndReduce(this.executeRecords(), this.field, this.spec);
1695
+ const recompute = () => groupAndReduce(this.executeRecords(), this.fields, this.spec);
1524
1696
  return buildLiveAggregation(recompute, this.upstreams);
1525
1697
  }
1526
1698
  };
@@ -1931,10 +2103,16 @@ function coerceRefKey2(value) {
1931
2103
  Aggregation,
1932
2104
  CollectionIndexes,
1933
2105
  DEFAULT_JOIN_MAX_ROWS,
2106
+ DanglingReferenceError,
1934
2107
  GROUPBY_MAX_CARDINALITY,
1935
2108
  GROUPBY_WARN_CARDINALITY,
2109
+ GroupCardinalityError,
1936
2110
  GroupedAggregation,
1937
2111
  GroupedQuery,
2112
+ GroupedQueryN,
2113
+ IndexRequiredError,
2114
+ IndexWriteFailureError,
2115
+ JoinTooLargeError,
1938
2116
  Query,
1939
2117
  ScanBuilder,
1940
2118
  applyJoins,