@noy-db/hub 0.2.0-pre.15 → 0.2.0-pre.16
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.
- package/dist/aggregate/index.cjs +106 -10
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +2 -2
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/aggregate/index.js +1 -1
- package/dist/attestation/index.cjs.map +1 -1
- package/dist/attestation/index.d.cts +3 -3
- package/dist/attestation/index.d.ts +3 -3
- package/dist/attestation/index.js +4 -4
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +4 -4
- package/dist/blobs/index.d.ts +4 -4
- package/dist/blobs/index.js +3 -3
- package/dist/bundle/index.cjs +181 -46
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +5 -5
- package/dist/bundle/index.d.ts +5 -5
- package/dist/bundle/index.js +7 -7
- package/dist/{chunk-BIYRQQV6.js → chunk-3YWP3WBP.js} +3 -3
- package/dist/{chunk-VU7SWWT5.js → chunk-42FEUPZQ.js} +10 -6
- package/dist/chunk-42FEUPZQ.js.map +1 -0
- package/dist/{chunk-7EFFHEN5.js → chunk-667MB6AH.js} +118 -47
- package/dist/chunk-667MB6AH.js.map +1 -0
- package/dist/{chunk-A5ZOOZFB.js → chunk-6H2ZUNR7.js} +2 -2
- package/dist/{chunk-7HT2MEZ5.js → chunk-7BQ4QWYX.js} +3 -3
- package/dist/{chunk-DQU36Q7I.js → chunk-7Z7KSVA5.js} +13 -4
- package/dist/chunk-7Z7KSVA5.js.map +1 -0
- package/dist/{chunk-WBAYSNUQ.js → chunk-BI6ETQPF.js} +2 -2
- package/dist/{chunk-56DJ7JVK.js → chunk-BR3AMFGS.js} +2 -2
- package/dist/{chunk-COFPAMX6.js → chunk-DLZ2ONOD.js} +3 -3
- package/dist/{chunk-EYVQHAGH.js → chunk-DUREQF5W.js} +2 -2
- package/dist/{chunk-PE4AQGFH.js → chunk-E2CDVKMH.js} +3 -3
- package/dist/{chunk-GC4V7RU7.js → chunk-F3BPIPLS.js} +1 -1
- package/dist/{chunk-GC4V7RU7.js.map → chunk-F3BPIPLS.js.map} +1 -1
- package/dist/{chunk-L2FE64BU.js → chunk-FFXM3ZIF.js} +2 -2
- package/dist/{chunk-5LQG6ZO2.js → chunk-G4SCICH5.js} +8 -3
- package/dist/chunk-G4SCICH5.js.map +1 -0
- package/dist/{chunk-WGHU7BLI.js → chunk-GNI5STXQ.js} +2 -2
- package/dist/{chunk-C5T5AFWN.js → chunk-HBXJ37ZY.js} +11 -5
- package/dist/chunk-HBXJ37ZY.js.map +1 -0
- package/dist/{chunk-7PS7EOCF.js → chunk-IXBIFDEW.js} +2 -2
- package/dist/{chunk-LX3CB26H.js → chunk-KABJXG2F.js} +2 -2
- package/dist/{chunk-3EWXMOK3.js → chunk-L2BNJ6HM.js} +26 -11
- package/dist/chunk-L2BNJ6HM.js.map +1 -0
- package/dist/{chunk-DKO2QFSA.js → chunk-OB2ZJQ2D.js} +2 -2
- package/dist/{chunk-KIP6JLTF.js → chunk-OMAMZKKD.js} +2 -2
- package/dist/{chunk-EGD5DXFT.js → chunk-OQSRJG6A.js} +13 -1
- package/dist/chunk-OQSRJG6A.js.map +1 -0
- package/dist/{chunk-KI6HAJWL.js → chunk-QSUK7YWK.js} +2 -2
- package/dist/{chunk-YHPM5D7Y.js → chunk-QVIEAYTP.js} +61 -2
- package/dist/chunk-QVIEAYTP.js.map +1 -0
- package/dist/{chunk-NSCVNK5K.js → chunk-SCJPI4Z5.js} +3 -3
- package/dist/{chunk-NU6Q3FOR.js → chunk-TKIY625R.js} +11 -1
- package/dist/{chunk-NU6Q3FOR.js.map → chunk-TKIY625R.js.map} +1 -1
- package/dist/{chunk-OHVFWCJP.js → chunk-VLMPU56Q.js} +48 -18
- package/dist/chunk-VLMPU56Q.js.map +1 -0
- package/dist/{chunk-6AJBSQU4.js → chunk-XL35NSEN.js} +2 -2
- package/dist/consent/index.d.cts +4 -4
- package/dist/consent/index.d.ts +4 -4
- package/dist/derivations/index.cjs +24 -3
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +5 -5
- package/dist/derivations/index.d.ts +5 -5
- package/dist/derivations/index.js +2 -2
- package/dist/{dev-unlock-nVkuRLLe.d.cts → dev-unlock-8XzcD2Z4.d.cts} +1 -1
- package/dist/{dev-unlock-iAS8z9jc.d.ts → dev-unlock-DR3upLd1.d.ts} +1 -1
- package/dist/{executor-HSSRXDOB.js → executor-AZLS3KBK.js} +4 -4
- package/dist/{fanout-sidecar-N6OJX6QR.js → fanout-sidecar-67CMI3UT.js} +2 -2
- package/dist/guards/index.cjs +9 -5
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +5 -5
- package/dist/guards/index.d.ts +5 -5
- package/dist/guards/index.js +1 -1
- package/dist/{hash-DHOnRarj.d.ts → hash-CDjye9KV.d.ts} +1 -1
- package/dist/{hash-Cv6byZs7.d.cts → hash-DuQ88_5W.d.cts} +1 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +5 -5
- package/dist/history/index.d.ts +5 -5
- package/dist/history/index.js +2 -2
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +4 -4
- package/dist/i18n/index.d.ts +4 -4
- package/dist/i18n/index.js +3 -3
- package/dist/{immutable-guard-yBEOYmif.d.cts → immutable-guard-CRPvu24K.d.cts} +16 -1
- package/dist/{immutable-guard-BehB1YGB.d.ts → immutable-guard-Dov3WvwF.d.ts} +16 -1
- package/dist/{index-D95VK1Qy.d.cts → index-C8Bk3-VF.d.cts} +1 -1
- package/dist/{index-XNB2r6bX.d.ts → index-nP99bXLg.d.ts} +1 -1
- package/dist/index.cjs +273 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -12
- package/dist/index.d.ts +13 -12
- package/dist/index.js +27 -25
- package/dist/index.js.map +1 -1
- package/dist/{issue-ADVS4OVP.js → issue-RZP3VI6O.js} +4 -4
- package/dist/{ledger-CWSE3BLF.js → ledger-A3LL253R.js} +3 -3
- package/dist/materialized-views/index.cjs +407 -5
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +5 -5
- package/dist/materialized-views/index.d.ts +5 -5
- package/dist/materialized-views/index.js +5 -5
- package/dist/noydb-WCMY2ZOW.js +35 -0
- package/dist/overlay-views/index.cjs +47 -17
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +26 -8
- package/dist/overlay-views/index.d.ts +26 -8
- package/dist/overlay-views/index.js +1 -1
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +4 -4
- package/dist/periods/index.d.ts +4 -4
- package/dist/periods/index.js +3 -3
- package/dist/{public-envelope-SYHEYQ3X.js → public-envelope-YP2UWMLG.js} +3 -3
- package/dist/query/index.cjs +24 -10
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{registry-XGLNADIE.js → registry-EB6SISTA.js} +2 -2
- package/dist/{registry-DK5YWAAA.js → registry-UTA4CLQS.js} +2 -2
- package/dist/{revoke-ZDFKMR5E.js → revoke-HNMQZSCL.js} +4 -4
- package/dist/session/index.d.cts +5 -5
- package/dist/session/index.d.ts +5 -5
- package/dist/shadow/index.d.cts +4 -4
- package/dist/shadow/index.d.ts +4 -4
- package/dist/{signer-P5D7Y72U.js → signer-DCMNKXSF.js} +3 -3
- package/dist/snapshots/index.d.cts +4 -4
- package/dist/snapshots/index.d.ts +4 -4
- package/dist/snapshots/index.js +3 -3
- package/dist/{stale-JH67FU57.js → stale-W5PQTRYH.js} +2 -2
- package/dist/store/index.d.cts +4 -4
- package/dist/store/index.d.ts +4 -4
- package/dist/{strategy-CbneC7bS.d.ts → strategy-BtW8fAjz.d.cts} +1 -1
- package/dist/{strategy-CbneC7bS.d.cts → strategy-BtW8fAjz.d.ts} +1 -1
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +3 -3
- package/dist/sync/index.d.ts +3 -3
- package/dist/sync/index.js +2 -2
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +4 -4
- package/dist/team/index.d.ts +4 -4
- package/dist/team/index.js +5 -5
- package/dist/tx/index.cjs +66 -3
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +22 -6
- package/dist/tx/index.d.ts +22 -6
- package/dist/tx/index.js +7 -3
- package/dist/tx/index.js.map +1 -1
- package/dist/{types-BpPV5uyy.d.cts → types-Bze6vkwm.d.cts} +371 -139
- package/dist/{types-4t1-tWS4.d.ts → types-DrmBTscX.d.ts} +371 -139
- package/dist/{ulid-DAfenvFd.d.ts → ulid-DbBVrNSt.d.ts} +1 -1
- package/dist/{ulid-CiPrpGqm.d.cts → ulid-DfZlAh0u.d.cts} +1 -1
- package/dist/{vault-group-KOM7QRJG.js → vault-group-DX2HFQMX.js} +2 -2
- package/dist/{with-derivation-DBqJB3dQ.d.cts → with-derivation-CCqAchD5.d.cts} +1 -1
- package/dist/{with-derivation-OK9M2sJE.d.ts → with-derivation-_lySGdlm.d.ts} +1 -1
- package/dist/{with-materialized-view-NzuxYPDF.d.cts → with-materialized-view--4PsvMDu.d.cts} +1 -1
- package/dist/{with-materialized-view-Dt-ufPWQ.d.ts → with-materialized-view-QT1Tp7NO.d.ts} +1 -1
- package/dist/{with-overlayed-view-eDvMs6LO.d.ts → with-overlayed-view-BEXfpzSb.d.ts} +1 -1
- package/dist/{with-overlayed-view-CC0_ocy-.d.cts → with-overlayed-view-DlH5qmeB.d.cts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-3EWXMOK3.js.map +0 -1
- package/dist/chunk-5LQG6ZO2.js.map +0 -1
- package/dist/chunk-7EFFHEN5.js.map +0 -1
- package/dist/chunk-C5T5AFWN.js.map +0 -1
- package/dist/chunk-DQU36Q7I.js.map +0 -1
- package/dist/chunk-EGD5DXFT.js.map +0 -1
- package/dist/chunk-OHVFWCJP.js.map +0 -1
- package/dist/chunk-VU7SWWT5.js.map +0 -1
- package/dist/chunk-YHPM5D7Y.js.map +0 -1
- package/dist/noydb-GZGFBA4E.js +0 -35
- /package/dist/{chunk-BIYRQQV6.js.map → chunk-3YWP3WBP.js.map} +0 -0
- /package/dist/{chunk-A5ZOOZFB.js.map → chunk-6H2ZUNR7.js.map} +0 -0
- /package/dist/{chunk-7HT2MEZ5.js.map → chunk-7BQ4QWYX.js.map} +0 -0
- /package/dist/{chunk-WBAYSNUQ.js.map → chunk-BI6ETQPF.js.map} +0 -0
- /package/dist/{chunk-56DJ7JVK.js.map → chunk-BR3AMFGS.js.map} +0 -0
- /package/dist/{chunk-COFPAMX6.js.map → chunk-DLZ2ONOD.js.map} +0 -0
- /package/dist/{chunk-EYVQHAGH.js.map → chunk-DUREQF5W.js.map} +0 -0
- /package/dist/{chunk-PE4AQGFH.js.map → chunk-E2CDVKMH.js.map} +0 -0
- /package/dist/{chunk-L2FE64BU.js.map → chunk-FFXM3ZIF.js.map} +0 -0
- /package/dist/{chunk-WGHU7BLI.js.map → chunk-GNI5STXQ.js.map} +0 -0
- /package/dist/{chunk-7PS7EOCF.js.map → chunk-IXBIFDEW.js.map} +0 -0
- /package/dist/{chunk-LX3CB26H.js.map → chunk-KABJXG2F.js.map} +0 -0
- /package/dist/{chunk-DKO2QFSA.js.map → chunk-OB2ZJQ2D.js.map} +0 -0
- /package/dist/{chunk-KIP6JLTF.js.map → chunk-OMAMZKKD.js.map} +0 -0
- /package/dist/{chunk-KI6HAJWL.js.map → chunk-QSUK7YWK.js.map} +0 -0
- /package/dist/{chunk-NSCVNK5K.js.map → chunk-SCJPI4Z5.js.map} +0 -0
- /package/dist/{chunk-6AJBSQU4.js.map → chunk-XL35NSEN.js.map} +0 -0
- /package/dist/{executor-HSSRXDOB.js.map → executor-AZLS3KBK.js.map} +0 -0
- /package/dist/{fanout-sidecar-N6OJX6QR.js.map → fanout-sidecar-67CMI3UT.js.map} +0 -0
- /package/dist/{issue-ADVS4OVP.js.map → issue-RZP3VI6O.js.map} +0 -0
- /package/dist/{ledger-CWSE3BLF.js.map → ledger-A3LL253R.js.map} +0 -0
- /package/dist/{noydb-GZGFBA4E.js.map → noydb-WCMY2ZOW.js.map} +0 -0
- /package/dist/{public-envelope-SYHEYQ3X.js.map → public-envelope-YP2UWMLG.js.map} +0 -0
- /package/dist/{registry-DK5YWAAA.js.map → registry-EB6SISTA.js.map} +0 -0
- /package/dist/{registry-XGLNADIE.js.map → registry-UTA4CLQS.js.map} +0 -0
- /package/dist/{revoke-ZDFKMR5E.js.map → revoke-HNMQZSCL.js.map} +0 -0
- /package/dist/{signer-P5D7Y72U.js.map → signer-DCMNKXSF.js.map} +0 -0
- /package/dist/{stale-JH67FU57.js.map → stale-W5PQTRYH.js.map} +0 -0
- /package/dist/{vault-group-KOM7QRJG.js.map → vault-group-DX2HFQMX.js.map} +0 -0
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
LedgerStore,
|
|
6
6
|
applyPatch,
|
|
7
7
|
computePatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BR3AMFGS.js";
|
|
9
9
|
import {
|
|
10
10
|
canonicalJson,
|
|
11
11
|
envelopePayloadHash,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
parseIndex,
|
|
15
15
|
sha256Hex
|
|
16
16
|
} from "./chunk-Z6FNBOTC.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-F3BPIPLS.js";
|
|
18
18
|
import "./chunk-YULZKK4F.js";
|
|
19
19
|
import "./chunk-535SSHBS.js";
|
|
20
20
|
export {
|
|
@@ -30,4 +30,4 @@ export {
|
|
|
30
30
|
parseIndex,
|
|
31
31
|
sha256Hex
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=ledger-
|
|
33
|
+
//# sourceMappingURL=ledger-A3LL253R.js.map
|
|
@@ -160,10 +160,14 @@ function summarizeQueryPlan(query) {
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
function summarizeUnionPlan(spec) {
|
|
163
|
-
const arms = (spec.unionSources ?? []).map((s) =>
|
|
163
|
+
const arms = (spec.unionSources ?? []).map((s) => {
|
|
164
|
+
const joins = s.join?.length ? `[${s.join.map((j) => `${j.field}\u2192${j.as}`).join(";")}]` : "";
|
|
165
|
+
return `${s.collection}${joins}`;
|
|
166
|
+
}).join(",");
|
|
164
167
|
const groupBy = Array.isArray(spec.groupBy) ? [...spec.groupBy].sort().join(",") : typeof spec.groupBy === "string" ? spec.groupBy : "";
|
|
165
168
|
const aggKeys = spec.aggregate ? Object.keys(spec.aggregate).sort().join(",") : "";
|
|
166
|
-
|
|
169
|
+
const moneyKeys = spec.moneyFields ? Object.keys(spec.moneyFields).sort().join(",") : "";
|
|
170
|
+
return `union(${arms})|groupBy(${groupBy})|aggregate(${aggKeys})|money(${moneyKeys})`;
|
|
167
171
|
}
|
|
168
172
|
var init_dependency_analyzer = __esm({
|
|
169
173
|
"src/materialized-views/dependency-analyzer.ts"() {
|
|
@@ -297,6 +301,7 @@ var init_registry = __esm({
|
|
|
297
301
|
let isQuery = false;
|
|
298
302
|
if (spec.unionSources) {
|
|
299
303
|
dependencies = new Set(spec.unionSources.map((s) => s.collection));
|
|
304
|
+
if (spec.sources) for (const s of spec.sources) dependencies.add(s);
|
|
300
305
|
queryPlanSummary = summarizeUnionPlan(spec);
|
|
301
306
|
} else {
|
|
302
307
|
const q = spec.query(dbForQuery);
|
|
@@ -427,6 +432,189 @@ var init_registry = __esm({
|
|
|
427
432
|
}
|
|
428
433
|
});
|
|
429
434
|
|
|
435
|
+
// src/money/fixed-point.ts
|
|
436
|
+
function expandExponent(s) {
|
|
437
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
|
|
438
|
+
if (!m) return s;
|
|
439
|
+
const sign = m[1] === "-" ? "-" : "";
|
|
440
|
+
const intp = m[2];
|
|
441
|
+
const frac = m[3] ?? "";
|
|
442
|
+
const exp = Number(m[4]);
|
|
443
|
+
const digits = intp + frac;
|
|
444
|
+
const pointPos = intp.length + exp;
|
|
445
|
+
let body;
|
|
446
|
+
if (pointPos <= 0) {
|
|
447
|
+
body = "0." + "0".repeat(-pointPos) + digits;
|
|
448
|
+
} else if (pointPos >= digits.length) {
|
|
449
|
+
body = digits + "0".repeat(pointPos - digits.length);
|
|
450
|
+
} else {
|
|
451
|
+
body = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
|
|
452
|
+
}
|
|
453
|
+
return sign + body;
|
|
454
|
+
}
|
|
455
|
+
function toCanonicalDecimalString(input) {
|
|
456
|
+
let s;
|
|
457
|
+
if (typeof input === "number") {
|
|
458
|
+
if (!Number.isFinite(input)) return null;
|
|
459
|
+
s = String(input);
|
|
460
|
+
} else {
|
|
461
|
+
s = input.trim();
|
|
462
|
+
}
|
|
463
|
+
s = expandExponent(s);
|
|
464
|
+
if (s.startsWith("+")) s = s.slice(1);
|
|
465
|
+
if (!/^-?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null;
|
|
466
|
+
return s;
|
|
467
|
+
}
|
|
468
|
+
function shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, mode) {
|
|
469
|
+
switch (mode) {
|
|
470
|
+
case "up":
|
|
471
|
+
return true;
|
|
472
|
+
case "down":
|
|
473
|
+
return false;
|
|
474
|
+
case "ceil":
|
|
475
|
+
return !negative;
|
|
476
|
+
case "floor":
|
|
477
|
+
return negative;
|
|
478
|
+
case "half-up":
|
|
479
|
+
return firstDiscarded >= 5;
|
|
480
|
+
case "half-down":
|
|
481
|
+
return firstDiscarded > 5 || firstDiscarded === 5 && hasMoreNonZeroAfterFirst;
|
|
482
|
+
case "half-even":
|
|
483
|
+
if (firstDiscarded > 5) return true;
|
|
484
|
+
if (firstDiscarded < 5) return false;
|
|
485
|
+
return hasMoreNonZeroAfterFirst || lastKeptDigit % 2 === 1;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function parseToScaledInt(input, scale, rounding) {
|
|
489
|
+
const canonical = toCanonicalDecimalString(input);
|
|
490
|
+
if (canonical === null) return { ok: false, reason: "nonfinite" };
|
|
491
|
+
const negative = canonical.startsWith("-");
|
|
492
|
+
const unsigned = negative ? canonical.slice(1) : canonical;
|
|
493
|
+
const dot = unsigned.indexOf(".");
|
|
494
|
+
const intPart = dot === -1 ? unsigned : unsigned.slice(0, dot);
|
|
495
|
+
const fracPart = dot === -1 ? "" : unsigned.slice(dot + 1);
|
|
496
|
+
const intDigits = intPart === "" ? "0" : intPart;
|
|
497
|
+
if (fracPart.length <= scale) {
|
|
498
|
+
const keep2 = fracPart.padEnd(scale, "0");
|
|
499
|
+
const magnitude2 = BigInt(intDigits + keep2);
|
|
500
|
+
return { ok: true, value: negative && magnitude2 !== 0n ? -magnitude2 : magnitude2 };
|
|
501
|
+
}
|
|
502
|
+
const keep = fracPart.slice(0, scale);
|
|
503
|
+
const tail = fracPart.slice(scale);
|
|
504
|
+
const magnitudeDigits = intDigits + keep;
|
|
505
|
+
let magnitude = BigInt(magnitudeDigits);
|
|
506
|
+
if (/^0+$/.test(tail)) {
|
|
507
|
+
return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
|
|
508
|
+
}
|
|
509
|
+
if (rounding === void 0) return { ok: false, reason: "precision" };
|
|
510
|
+
const lastKeptDigit = Number(magnitudeDigits[magnitudeDigits.length - 1]);
|
|
511
|
+
const firstDiscarded = Number(tail[0]);
|
|
512
|
+
const hasMoreNonZeroAfterFirst = /[1-9]/.test(tail.slice(1));
|
|
513
|
+
if (shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, rounding)) {
|
|
514
|
+
magnitude += 1n;
|
|
515
|
+
}
|
|
516
|
+
return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
|
|
517
|
+
}
|
|
518
|
+
function formatScaledInt(value, scale) {
|
|
519
|
+
const negative = value < 0n;
|
|
520
|
+
const abs = (negative ? -value : value).toString();
|
|
521
|
+
if (scale === 0) return (negative ? "-" : "") + abs;
|
|
522
|
+
const padded = abs.padStart(scale + 1, "0");
|
|
523
|
+
const cut = padded.length - scale;
|
|
524
|
+
const intPart = padded.slice(0, cut);
|
|
525
|
+
const fracPart = padded.slice(cut);
|
|
526
|
+
return (negative ? "-" : "") + intPart + "." + fracPart;
|
|
527
|
+
}
|
|
528
|
+
var init_fixed_point = __esm({
|
|
529
|
+
"src/money/fixed-point.ts"() {
|
|
530
|
+
"use strict";
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// src/money/iso4217.ts
|
|
535
|
+
function scaleForCurrency(code) {
|
|
536
|
+
const v = MINOR_UNITS[code];
|
|
537
|
+
return v === void 0 ? null : v;
|
|
538
|
+
}
|
|
539
|
+
var MINOR_UNITS;
|
|
540
|
+
var init_iso4217 = __esm({
|
|
541
|
+
"src/money/iso4217.ts"() {
|
|
542
|
+
"use strict";
|
|
543
|
+
MINOR_UNITS = {
|
|
544
|
+
// 2-decimal majors
|
|
545
|
+
EUR: 2,
|
|
546
|
+
USD: 2,
|
|
547
|
+
GBP: 2,
|
|
548
|
+
CHF: 2,
|
|
549
|
+
CAD: 2,
|
|
550
|
+
AUD: 2,
|
|
551
|
+
NZD: 2,
|
|
552
|
+
SGD: 2,
|
|
553
|
+
HKD: 2,
|
|
554
|
+
CNY: 2,
|
|
555
|
+
INR: 2,
|
|
556
|
+
BRL: 2,
|
|
557
|
+
MXN: 2,
|
|
558
|
+
ZAR: 2,
|
|
559
|
+
RUB: 2,
|
|
560
|
+
TRY: 2,
|
|
561
|
+
PLN: 2,
|
|
562
|
+
SEK: 2,
|
|
563
|
+
NOK: 2,
|
|
564
|
+
DKK: 2,
|
|
565
|
+
CZK: 2,
|
|
566
|
+
HUF: 2,
|
|
567
|
+
RON: 2,
|
|
568
|
+
ILS: 2,
|
|
569
|
+
THB: 2,
|
|
570
|
+
PHP: 2,
|
|
571
|
+
MYR: 2,
|
|
572
|
+
IDR: 2,
|
|
573
|
+
AED: 2,
|
|
574
|
+
SAR: 2,
|
|
575
|
+
QAR: 2,
|
|
576
|
+
EGP: 2,
|
|
577
|
+
// 0-decimal
|
|
578
|
+
JPY: 0,
|
|
579
|
+
KRW: 0,
|
|
580
|
+
ISK: 0,
|
|
581
|
+
CLP: 0,
|
|
582
|
+
VND: 0,
|
|
583
|
+
XOF: 0,
|
|
584
|
+
XAF: 0,
|
|
585
|
+
PYG: 0,
|
|
586
|
+
// 3-decimal
|
|
587
|
+
BHD: 3,
|
|
588
|
+
KWD: 3,
|
|
589
|
+
OMR: 3,
|
|
590
|
+
TND: 3,
|
|
591
|
+
JOD: 3,
|
|
592
|
+
IQD: 3,
|
|
593
|
+
LYD: 3
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// src/money/descriptor.ts
|
|
599
|
+
var MoneyUnsupportedError;
|
|
600
|
+
var init_descriptor = __esm({
|
|
601
|
+
"src/money/descriptor.ts"() {
|
|
602
|
+
"use strict";
|
|
603
|
+
init_errors();
|
|
604
|
+
MoneyUnsupportedError = class extends NoydbError {
|
|
605
|
+
constructor(field, message) {
|
|
606
|
+
super(
|
|
607
|
+
"MONEY_UNSUPPORTED",
|
|
608
|
+
message ?? `money: operation is not supported on field "${field}" \u2014 use sum() and count() and divide at the boundary`
|
|
609
|
+
);
|
|
610
|
+
this.field = field;
|
|
611
|
+
this.name = "MoneyUnsupportedError";
|
|
612
|
+
}
|
|
613
|
+
field;
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
|
|
430
618
|
// src/query/predicate.ts
|
|
431
619
|
function readPath(record, path) {
|
|
432
620
|
if (record === null || record === void 0) return void 0;
|
|
@@ -464,6 +652,200 @@ var init_canonical_key = __esm({
|
|
|
464
652
|
}
|
|
465
653
|
});
|
|
466
654
|
|
|
655
|
+
// src/money/money-reducer.ts
|
|
656
|
+
function toScaledIntFromAny(v, scale) {
|
|
657
|
+
if (typeof v === "bigint") return v;
|
|
658
|
+
if (typeof v === "number") {
|
|
659
|
+
const r = parseToScaledInt(v, scale);
|
|
660
|
+
return r.ok ? r.value : null;
|
|
661
|
+
}
|
|
662
|
+
if (typeof v === "string") {
|
|
663
|
+
if (!v.includes(".")) {
|
|
664
|
+
try {
|
|
665
|
+
return BigInt(v);
|
|
666
|
+
} catch {
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const r = parseToScaledInt(v, scale);
|
|
671
|
+
return r.ok ? r.value : null;
|
|
672
|
+
}
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
function readMoney(record, field, desc) {
|
|
676
|
+
const raw = readPath(record, field);
|
|
677
|
+
if (raw === null || raw === void 0) return null;
|
|
678
|
+
if (desc.mode === "fixed") {
|
|
679
|
+
const cur = desc.fixedCurrency;
|
|
680
|
+
const value2 = toScaledIntFromAny(raw, desc.scaleFor(cur));
|
|
681
|
+
return value2 === null ? null : { currency: cur, value: value2 };
|
|
682
|
+
}
|
|
683
|
+
if (typeof raw !== "object") return null;
|
|
684
|
+
const o = raw;
|
|
685
|
+
if (typeof o.currency !== "string") return null;
|
|
686
|
+
const scale = desc.allows(o.currency) ? desc.scaleFor(o.currency) : 0;
|
|
687
|
+
const value = toScaledIntFromAny(o.amount, scale);
|
|
688
|
+
return value === null ? null : { currency: o.currency, value };
|
|
689
|
+
}
|
|
690
|
+
function targetScaleFor(desc, currency) {
|
|
691
|
+
if (desc.allows(currency)) return desc.scaleFor(currency);
|
|
692
|
+
const s = scaleForCurrency(currency);
|
|
693
|
+
if (s === null) {
|
|
694
|
+
throw new Error(`money: cannot determine scale for conversion target "${currency}"`);
|
|
695
|
+
}
|
|
696
|
+
return s;
|
|
697
|
+
}
|
|
698
|
+
function parseRate(rate) {
|
|
699
|
+
const s = String(rate).trim();
|
|
700
|
+
const neg = s.startsWith("-");
|
|
701
|
+
const body = neg ? s.slice(1) : s;
|
|
702
|
+
const dot = body.indexOf(".");
|
|
703
|
+
const intPart = dot === -1 ? body : body.slice(0, dot);
|
|
704
|
+
const fracPart = dot === -1 ? "" : body.slice(dot + 1);
|
|
705
|
+
const int = BigInt((intPart === "" ? "0" : intPart) + fracPart);
|
|
706
|
+
return { int: neg ? -int : int, scale: fracPart.length };
|
|
707
|
+
}
|
|
708
|
+
function divRoundHalfEven(n, d) {
|
|
709
|
+
const q = n / d;
|
|
710
|
+
const r = n % d;
|
|
711
|
+
const twiceR = (r < 0n ? -r : r) * 2n;
|
|
712
|
+
if (twiceR < d) return q;
|
|
713
|
+
if (twiceR > d) return q + (n < 0n ? -1n : 1n);
|
|
714
|
+
return q % 2n === 0n ? q : q + (n < 0n ? -1n : 1n);
|
|
715
|
+
}
|
|
716
|
+
function convertScaled(value, srcScale, rate, targetScale) {
|
|
717
|
+
const { int: rateInt, scale: rateScale } = parseRate(rate);
|
|
718
|
+
const product = value * rateInt;
|
|
719
|
+
const curScale = srcScale + rateScale;
|
|
720
|
+
if (curScale === targetScale) return product;
|
|
721
|
+
if (curScale < targetScale) return product * 10n ** BigInt(targetScale - curScale);
|
|
722
|
+
return divRoundHalfEven(product, 10n ** BigInt(curScale - targetScale));
|
|
723
|
+
}
|
|
724
|
+
function finalizeSum(state, desc, convertTo, fx) {
|
|
725
|
+
if (convertTo !== void 0) {
|
|
726
|
+
if (fx === void 0) {
|
|
727
|
+
throw new Error(`money: sum convertTo "${convertTo}" requires an fx rate map`);
|
|
728
|
+
}
|
|
729
|
+
const targetScale = targetScaleFor(desc, convertTo);
|
|
730
|
+
let total = 0n;
|
|
731
|
+
for (const [cur, v] of state) {
|
|
732
|
+
if (cur === convertTo) {
|
|
733
|
+
total += convertScaled(v, desc.scaleFor(cur), 1, targetScale);
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
const rate = fx[`${cur}->${convertTo}`];
|
|
737
|
+
if (rate === void 0) {
|
|
738
|
+
throw new Error(`money: no fx rate for "${cur}->${convertTo}"`);
|
|
739
|
+
}
|
|
740
|
+
total += convertScaled(v, desc.scaleFor(cur), rate, targetScale);
|
|
741
|
+
}
|
|
742
|
+
return formatScaledInt(total, targetScale);
|
|
743
|
+
}
|
|
744
|
+
if (desc.mode === "fixed") {
|
|
745
|
+
const cur = desc.fixedCurrency;
|
|
746
|
+
return formatScaledInt(state.get(cur) ?? 0n, desc.scaleFor(cur));
|
|
747
|
+
}
|
|
748
|
+
const out = {};
|
|
749
|
+
for (const [cur, v] of state) out[cur] = formatScaledInt(v, desc.scaleFor(cur));
|
|
750
|
+
return out;
|
|
751
|
+
}
|
|
752
|
+
function moneySumReducer(field, desc, convertTo, fx) {
|
|
753
|
+
return {
|
|
754
|
+
op: "sum",
|
|
755
|
+
field,
|
|
756
|
+
init: () => /* @__PURE__ */ new Map(),
|
|
757
|
+
step: (state, record) => {
|
|
758
|
+
const m = readMoney(record, field, desc);
|
|
759
|
+
if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) + m.value);
|
|
760
|
+
return state;
|
|
761
|
+
},
|
|
762
|
+
remove: (state, record) => {
|
|
763
|
+
const m = readMoney(record, field, desc);
|
|
764
|
+
if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) - m.value);
|
|
765
|
+
return state;
|
|
766
|
+
},
|
|
767
|
+
finalize: (state) => finalizeSum(state, desc, convertTo, fx)
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function extremum(values, op) {
|
|
771
|
+
let out = values[0];
|
|
772
|
+
for (let i = 1; i < values.length; i++) {
|
|
773
|
+
const v = values[i];
|
|
774
|
+
if (op === "min" ? v < out : v > out) out = v;
|
|
775
|
+
}
|
|
776
|
+
return out;
|
|
777
|
+
}
|
|
778
|
+
function moneyMinMaxReducer(op, field, desc) {
|
|
779
|
+
return {
|
|
780
|
+
op,
|
|
781
|
+
field,
|
|
782
|
+
init: () => /* @__PURE__ */ new Map(),
|
|
783
|
+
step: (state, record) => {
|
|
784
|
+
const m = readMoney(record, field, desc);
|
|
785
|
+
if (m) {
|
|
786
|
+
const arr = state.get(m.currency);
|
|
787
|
+
if (arr) arr.push(m.value);
|
|
788
|
+
else state.set(m.currency, [m.value]);
|
|
789
|
+
}
|
|
790
|
+
return state;
|
|
791
|
+
},
|
|
792
|
+
remove: (state, record) => {
|
|
793
|
+
const m = readMoney(record, field, desc);
|
|
794
|
+
if (m) {
|
|
795
|
+
const arr = state.get(m.currency);
|
|
796
|
+
if (arr) {
|
|
797
|
+
const idx = arr.indexOf(m.value);
|
|
798
|
+
if (idx >= 0) arr.splice(idx, 1);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return state;
|
|
802
|
+
},
|
|
803
|
+
finalize: (state) => {
|
|
804
|
+
if (desc.mode === "fixed") {
|
|
805
|
+
const cur = desc.fixedCurrency;
|
|
806
|
+
const arr = state.get(cur);
|
|
807
|
+
if (!arr || arr.length === 0) return null;
|
|
808
|
+
return formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
|
|
809
|
+
}
|
|
810
|
+
const out = {};
|
|
811
|
+
for (const [cur, arr] of state) {
|
|
812
|
+
if (arr.length > 0) out[cur] = formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
|
|
813
|
+
}
|
|
814
|
+
return out;
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
function wrapMoneyReducers(spec, moneyFields) {
|
|
819
|
+
let changed = false;
|
|
820
|
+
const out = {};
|
|
821
|
+
for (const [key, reducer] of Object.entries(spec)) {
|
|
822
|
+
const field = reducer.field;
|
|
823
|
+
const desc = field ? moneyFields[field] : void 0;
|
|
824
|
+
if (desc && reducer.op === "avg") {
|
|
825
|
+
throw new MoneyUnsupportedError(
|
|
826
|
+
field,
|
|
827
|
+
`avg() is not supported on money field "${field}" in v1 \u2014 use sum() and count() and divide at the boundary.`
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
if (desc && (reducer.op === "sum" || reducer.op === "min" || reducer.op === "max")) {
|
|
831
|
+
changed = true;
|
|
832
|
+
out[key] = reducer.op === "sum" ? moneySumReducer(field, desc, reducer.convertTo, reducer.fx) : moneyMinMaxReducer(reducer.op, field, desc);
|
|
833
|
+
} else {
|
|
834
|
+
out[key] = reducer;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return changed ? out : spec;
|
|
838
|
+
}
|
|
839
|
+
var init_money_reducer = __esm({
|
|
840
|
+
"src/money/money-reducer.ts"() {
|
|
841
|
+
"use strict";
|
|
842
|
+
init_predicate();
|
|
843
|
+
init_fixed_point();
|
|
844
|
+
init_iso4217();
|
|
845
|
+
init_descriptor();
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
|
|
467
849
|
// src/aggregate/groupby.ts
|
|
468
850
|
function warnCardinalityApproaching(fields, observed) {
|
|
469
851
|
const key = JSON.stringify([...fields].sort());
|
|
@@ -474,11 +856,14 @@ function warnCardinalityApproaching(fields, observed) {
|
|
|
474
856
|
`[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.`
|
|
475
857
|
);
|
|
476
858
|
}
|
|
477
|
-
function groupAndReduce(records, fieldOrFields, spec) {
|
|
859
|
+
function groupAndReduce(records, fieldOrFields, spec, moneyFields) {
|
|
478
860
|
const fields = typeof fieldOrFields === "string" ? [fieldOrFields] : fieldOrFields;
|
|
479
861
|
if (fields.length === 0) {
|
|
480
862
|
throw new Error(".groupBy() requires at least one field");
|
|
481
863
|
}
|
|
864
|
+
if (moneyFields) {
|
|
865
|
+
spec = wrapMoneyReducers(spec, moneyFields);
|
|
866
|
+
}
|
|
482
867
|
const buckets = /* @__PURE__ */ new Map();
|
|
483
868
|
const fieldLabel = fields.length === 1 ? fields[0] : `[${fields.join(", ")}]`;
|
|
484
869
|
for (const record of records) {
|
|
@@ -534,6 +919,7 @@ var init_groupby = __esm({
|
|
|
534
919
|
init_predicate();
|
|
535
920
|
init_canonical_key();
|
|
536
921
|
init_errors();
|
|
922
|
+
init_money_reducer();
|
|
537
923
|
GROUPBY_WARN_CARDINALITY = 1e4;
|
|
538
924
|
GROUPBY_MAX_CARDINALITY = 1e5;
|
|
539
925
|
warnedCardinalityFields = /* @__PURE__ */ new Set();
|
|
@@ -564,7 +950,13 @@ async function materializeUnionResult(spec, db) {
|
|
|
564
950
|
const unified = [];
|
|
565
951
|
for (const arm of spec.unionSources) {
|
|
566
952
|
const coll = db.collection(arm.collection);
|
|
567
|
-
|
|
953
|
+
let q = coll.query();
|
|
954
|
+
if (arm.join?.length) {
|
|
955
|
+
for (const leg of arm.join) {
|
|
956
|
+
q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
const sourceRows = q.toArray();
|
|
568
960
|
for (const r of sourceRows) {
|
|
569
961
|
const mapped = arm.map(r);
|
|
570
962
|
if (mapped == null) continue;
|
|
@@ -581,7 +973,7 @@ async function materializeUnionResult(spec, db) {
|
|
|
581
973
|
}
|
|
582
974
|
return [...seen.values()];
|
|
583
975
|
}
|
|
584
|
-
return groupAndReduce(unified, groupFields, spec.aggregate);
|
|
976
|
+
return groupAndReduce(unified, groupFields, spec.aggregate, spec.moneyFields);
|
|
585
977
|
}
|
|
586
978
|
async function listOutputIds(outputColl) {
|
|
587
979
|
const cAny = outputColl;
|
|
@@ -761,6 +1153,16 @@ function withMaterializedView(spec) {
|
|
|
761
1153
|
`withMaterializedView "${spec.name}": UNION strategy with aggregate requires groupBy \u2014 use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`
|
|
762
1154
|
);
|
|
763
1155
|
}
|
|
1156
|
+
if (spec.moneyFields && !spec.aggregate) {
|
|
1157
|
+
throw new MaterializedViewConfigError(
|
|
1158
|
+
`withMaterializedView "${spec.name}": moneyFields requires aggregate \u2014 moneyFields rewrites sum/min/max reducers over money output fields, so it is meaningless without an aggregate spec`
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
if (spec.unionSources.some((s) => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {
|
|
1162
|
+
throw new MaterializedViewConfigError(
|
|
1163
|
+
`withMaterializedView "${spec.name}": a unionSources arm declares join(s) but no \`sources\` are listed \u2014 declare sources: [...] with the right-side (join-target) collection names so writes to them trigger MV refresh`
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
764
1166
|
if (spec.predicates) {
|
|
765
1167
|
throw new MaterializedViewConfigError(
|
|
766
1168
|
`withMaterializedView "${spec.name}": predicates are not supported on UNION strategies \u2014 UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. Use the query() form, or open an issue if per-arm predicates are needed`
|