@noy-db/hub 0.2.0-pre.13 → 0.2.0-pre.15
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 +56 -56
- 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 +4 -4
- package/dist/attestation/index.cjs.map +1 -1
- package/dist/attestation/index.d.cts +5 -5
- package/dist/attestation/index.d.ts +5 -5
- package/dist/attestation/index.js +5 -5
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +6 -6
- package/dist/blobs/index.d.ts +6 -6
- package/dist/blobs/index.js +4 -4
- package/dist/bundle/index.cjs +559 -76
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +7 -7
- package/dist/bundle/index.d.ts +7 -7
- package/dist/bundle/index.js +8 -8
- package/dist/{chunk-YWBHS25M.js → chunk-3EWXMOK3.js} +8 -267
- package/dist/chunk-3EWXMOK3.js.map +1 -0
- package/dist/{chunk-SJ24GHID.js → chunk-4TBBMHVC.js} +2 -2
- package/dist/{chunk-NKGY3C53.js → chunk-535SSHBS.js} +8 -1
- package/dist/{chunk-NKGY3C53.js.map → chunk-535SSHBS.js.map} +1 -1
- package/dist/{chunk-HQXOEWLZ.js → chunk-56DJ7JVK.js} +3 -3
- package/dist/{chunk-KKB42D3Q.js → chunk-5LQG6ZO2.js} +2 -2
- package/dist/{chunk-TDECYU4Y.js → chunk-6AJBSQU4.js} +2 -2
- package/dist/{chunk-O2JW656W.js → chunk-6RR3MNMG.js} +3 -3
- package/dist/{chunk-P5MW7BG2.js → chunk-7EFFHEN5.js} +57 -50
- package/dist/chunk-7EFFHEN5.js.map +1 -0
- package/dist/{chunk-7TEI2K2A.js → chunk-7HT2MEZ5.js} +4 -4
- package/dist/{chunk-WQKZIQIL.js → chunk-7PS7EOCF.js} +3 -3
- package/dist/{chunk-C3WRKABE.js → chunk-A5ZOOZFB.js} +3 -3
- package/dist/{chunk-5NISHSBO.js → chunk-AAVWKNZW.js} +2 -2
- package/dist/{chunk-SOU42FGB.js → chunk-BIYRQQV6.js} +4 -4
- package/dist/{chunk-ILWQGTNH.js → chunk-BQ65SS5A.js} +2 -2
- package/dist/{chunk-CWFQTAD4.js → chunk-C5T5AFWN.js} +4 -4
- package/dist/chunk-CJORTUJ2.js +524 -0
- package/dist/chunk-CJORTUJ2.js.map +1 -0
- package/dist/{chunk-SYSKC237.js → chunk-COFPAMX6.js} +5 -5
- package/dist/{chunk-D5Y3HIC6.js → chunk-CZI2A4MQ.js} +3 -3
- package/dist/{chunk-KJF7EPUE.js → chunk-DKO2QFSA.js} +2 -2
- package/dist/{chunk-QFYVGJLI.js → chunk-DQU36Q7I.js} +2 -2
- package/dist/{chunk-NIUXQDWD.js → chunk-EGD5DXFT.js} +2 -2
- package/dist/{chunk-NJMKHRQI.js → chunk-EYVQHAGH.js} +267 -67
- package/dist/chunk-EYVQHAGH.js.map +1 -0
- package/dist/{chunk-KHQ3N5AB.js → chunk-F4OJZIWQ.js} +4 -4
- package/dist/{chunk-3OUCWHV6.js → chunk-FWPKCXTN.js} +2 -2
- package/dist/{chunk-QIVFGU2M.js → chunk-HOR4R722.js} +3 -3
- package/dist/{chunk-NP6EZT44.js → chunk-IQLVUT37.js} +2 -2
- package/dist/{chunk-4VCQH32J.js → chunk-JD3OZAI4.js} +2 -2
- package/dist/{chunk-J67BP5EP.js → chunk-KI6HAJWL.js} +3 -3
- package/dist/{chunk-AYNF7PVX.js → chunk-KIP6JLTF.js} +2 -2
- package/dist/{chunk-PW26DAXS.js → chunk-L2FE64BU.js} +3 -3
- package/dist/{chunk-QAWCVWCX.js → chunk-LX3CB26H.js} +4 -4
- package/dist/{chunk-VAK6NQAK.js → chunk-NSCVNK5K.js} +4 -4
- package/dist/{chunk-4YDZ7JPZ.js → chunk-NU6Q3FOR.js} +4 -4
- package/dist/chunk-NU6Q3FOR.js.map +1 -0
- package/dist/{chunk-3XZRRBFW.js → chunk-OHVFWCJP.js} +2 -2
- package/dist/{chunk-TEQGXA7L.js → chunk-PE4AQGFH.js} +4 -4
- package/dist/{chunk-UNQEWORI.js → chunk-TS26M2SB.js} +2 -2
- package/dist/{chunk-FNVFT4HZ.js → chunk-VU7SWWT5.js} +2 -2
- package/dist/{chunk-GZJ5JBED.js → chunk-WBAYSNUQ.js} +3 -3
- package/dist/{chunk-HHZ77DHM.js → chunk-WGHU7BLI.js} +2 -2
- package/dist/{chunk-GL3Z7LH7.js → chunk-X73VS74Y.js} +2 -2
- package/dist/{chunk-WIBHRONM.js → chunk-XWH4MXIU.js} +2 -2
- package/dist/{chunk-M6KXHRIA.js → chunk-YHPM5D7Y.js} +3 -3
- package/dist/{chunk-E3DIBDKA.js → chunk-YULZKK4F.js} +2 -2
- package/dist/{chunk-JWFNOD2T.js → chunk-Z4DO7YSI.js} +2 -2
- package/dist/{chunk-JPOQMXGT.js → chunk-ZNQYHJXX.js} +2 -2
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +6 -6
- package/dist/consent/index.d.ts +6 -6
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-YXH6SAOW.js → crypto-QXQOHMHF.js} +3 -3
- package/dist/{delegation-K5ERUH6A.js → delegation-NIQ43IPU.js} +5 -5
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +7 -7
- package/dist/derivations/index.d.ts +7 -7
- package/dist/derivations/index.js +4 -4
- package/dist/{dev-unlock-BW0GNBEV.d.ts → dev-unlock-iAS8z9jc.d.ts} +1 -1
- package/dist/{dev-unlock-a7SOtaV0.d.cts → dev-unlock-nVkuRLLe.d.cts} +1 -1
- package/dist/executor-6ZDSDZ6V.js +8 -0
- package/dist/executor-HSSRXDOB.js +11 -0
- package/dist/executor-IDZDAFNH.js +8 -0
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +7 -7
- package/dist/guards/index.d.ts +7 -7
- package/dist/guards/index.js +3 -3
- package/dist/{hash-B0cLQcq_.d.cts → hash-Cv6byZs7.d.cts} +1 -1
- package/dist/{hash-uMNIAAW8.d.ts → hash-DHOnRarj.d.ts} +1 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +7 -7
- package/dist/history/index.d.ts +7 -7
- package/dist/history/index.js +4 -4
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +6 -6
- package/dist/i18n/index.d.ts +6 -6
- package/dist/i18n/index.js +5 -5
- package/dist/{immutable-guard-B0h-ipLz.d.ts → immutable-guard-BehB1YGB.d.ts} +1 -1
- package/dist/{immutable-guard-BZIcYhYX.d.cts → immutable-guard-yBEOYmif.d.cts} +1 -1
- package/dist/{index-CUVOMtgg.d.cts → index-D95VK1Qy.d.cts} +11 -3
- package/dist/{index-Cqzp4tt9.d.ts → index-XNB2r6bX.d.ts} +11 -3
- package/dist/index.cjs +700 -78
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -15
- package/dist/index.d.ts +145 -15
- package/dist/index.js +164 -48
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs +92 -31
- package/dist/indexing/index.cjs.map +1 -1
- package/dist/indexing/index.d.cts +3 -3
- package/dist/indexing/index.d.ts +3 -3
- package/dist/indexing/index.js +4 -4
- package/dist/issue-ADVS4OVP.js +12 -0
- package/dist/{lazy-builder-D5GU14TS.d.ts → lazy-builder-ChSqcF5t.d.ts} +1 -1
- package/dist/{lazy-builder-Ci5_YG73.d.cts → lazy-builder-eYZzLEL1.d.cts} +1 -1
- package/dist/{ledger-64TTQMRS.js → ledger-CWSE3BLF.js} +4 -4
- package/dist/materialized-views/index.cjs +2 -2
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +7 -7
- package/dist/materialized-views/index.d.ts +7 -7
- package/dist/materialized-views/index.js +7 -7
- package/dist/noydb-GZGFBA4E.js +35 -0
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +7 -7
- package/dist/overlay-views/index.d.ts +7 -7
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +6 -6
- package/dist/periods/index.d.ts +6 -6
- package/dist/periods/index.js +4 -4
- package/dist/{predicate-Bt5ft-9c.d.cts → predicate-BmhBSPCH.d.cts} +59 -2
- package/dist/{predicate-Bt5ft-9c.d.ts → predicate-BmhBSPCH.d.ts} +59 -2
- package/dist/{public-envelope-MHG6YVXW.js → public-envelope-SYHEYQ3X.js} +3 -3
- package/dist/query/index.cjs +580 -195
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +3 -3
- package/dist/query/index.d.ts +3 -3
- package/dist/query/index.js +6 -6
- package/dist/{registry-PV4G3OPA.js → registry-DK5YWAAA.js} +3 -3
- package/dist/registry-IUZQVVBB.js +8 -0
- package/dist/registry-XGLNADIE.js +8 -0
- package/dist/{revoke-5BOLVJ3N.js → revoke-ZDFKMR5E.js} +5 -5
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +7 -7
- package/dist/session/index.d.ts +7 -7
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +6 -6
- package/dist/shadow/index.d.ts +6 -6
- package/dist/shadow/index.js +2 -2
- package/dist/{signer-GRIYBA22.js → signer-P5D7Y72U.js} +4 -4
- package/dist/snapshots/index.cjs.map +1 -1
- package/dist/snapshots/index.d.cts +6 -6
- package/dist/snapshots/index.d.ts +6 -6
- package/dist/snapshots/index.js +3 -3
- package/dist/{stale-LZYMMDDS.js → stale-JH67FU57.js} +2 -2
- package/dist/{state-vault-QFJWU23A.js → state-vault-TMXZRTY5.js} +3 -3
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +6 -6
- package/dist/store/index.d.ts +6 -6
- package/dist/store/index.js +2 -2
- package/dist/{strategy-CrS7PnbE.d.ts → strategy-CbneC7bS.d.cts} +1 -1
- package/dist/{strategy-CrS7PnbE.d.cts → strategy-CbneC7bS.d.ts} +1 -1
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +5 -5
- package/dist/sync/index.d.ts +5 -5
- package/dist/sync/index.js +3 -3
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +6 -6
- package/dist/team/index.d.ts +6 -6
- package/dist/team/index.js +7 -7
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +6 -6
- package/dist/tx/index.d.ts +6 -6
- package/dist/tx/index.js +3 -3
- package/dist/{types-pax34sec.d.ts → types-4t1-tWS4.d.ts} +77 -9
- package/dist/{types-CDwSSXiI.d.cts → types-BpPV5uyy.d.cts} +77 -9
- package/dist/{ulid-7bCSgIgb.d.cts → ulid-CiPrpGqm.d.cts} +1 -1
- package/dist/{ulid-C_t4hL3d.d.ts → ulid-DAfenvFd.d.ts} +1 -1
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.js +1 -1
- package/dist/{vault-group-UO4YUZOG.js → vault-group-KOM7QRJG.js} +125 -11
- package/dist/vault-group-KOM7QRJG.js.map +1 -0
- package/dist/{with-derivation-D8wFlb6V.d.cts → with-derivation-DBqJB3dQ.d.cts} +1 -1
- package/dist/{with-derivation-BjdOxUBn.d.ts → with-derivation-OK9M2sJE.d.ts} +1 -1
- package/dist/{with-materialized-view-DJb-HO65.d.ts → with-materialized-view-Dt-ufPWQ.d.ts} +1 -1
- package/dist/{with-materialized-view-5QMF1rS_.d.cts → with-materialized-view-NzuxYPDF.d.cts} +1 -1
- package/dist/{with-overlayed-view-DDNflPvC.d.cts → with-overlayed-view-CC0_ocy-.d.cts} +1 -1
- package/dist/{with-overlayed-view-CkqTefbz.d.ts → with-overlayed-view-eDvMs6LO.d.ts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-4YDZ7JPZ.js.map +0 -1
- package/dist/chunk-NJMKHRQI.js.map +0 -1
- package/dist/chunk-P5MW7BG2.js.map +0 -1
- package/dist/chunk-TV3YZ35S.js +0 -90
- package/dist/chunk-TV3YZ35S.js.map +0 -1
- package/dist/chunk-YWBHS25M.js.map +0 -1
- package/dist/executor-AVJ7UEWA.js +0 -8
- package/dist/executor-IQO3KGXQ.js +0 -11
- package/dist/executor-VT7TKGE4.js +0 -8
- package/dist/issue-ZH27C23Y.js +0 -12
- package/dist/noydb-O76SKBST.js +0 -35
- package/dist/registry-2PKBQDCH.js +0 -8
- package/dist/registry-4VXFKCBJ.js +0 -8
- package/dist/vault-group-UO4YUZOG.js.map +0 -1
- /package/dist/{chunk-SJ24GHID.js.map → chunk-4TBBMHVC.js.map} +0 -0
- /package/dist/{chunk-HQXOEWLZ.js.map → chunk-56DJ7JVK.js.map} +0 -0
- /package/dist/{chunk-KKB42D3Q.js.map → chunk-5LQG6ZO2.js.map} +0 -0
- /package/dist/{chunk-TDECYU4Y.js.map → chunk-6AJBSQU4.js.map} +0 -0
- /package/dist/{chunk-O2JW656W.js.map → chunk-6RR3MNMG.js.map} +0 -0
- /package/dist/{chunk-7TEI2K2A.js.map → chunk-7HT2MEZ5.js.map} +0 -0
- /package/dist/{chunk-WQKZIQIL.js.map → chunk-7PS7EOCF.js.map} +0 -0
- /package/dist/{chunk-C3WRKABE.js.map → chunk-A5ZOOZFB.js.map} +0 -0
- /package/dist/{chunk-5NISHSBO.js.map → chunk-AAVWKNZW.js.map} +0 -0
- /package/dist/{chunk-SOU42FGB.js.map → chunk-BIYRQQV6.js.map} +0 -0
- /package/dist/{chunk-ILWQGTNH.js.map → chunk-BQ65SS5A.js.map} +0 -0
- /package/dist/{chunk-CWFQTAD4.js.map → chunk-C5T5AFWN.js.map} +0 -0
- /package/dist/{chunk-SYSKC237.js.map → chunk-COFPAMX6.js.map} +0 -0
- /package/dist/{chunk-D5Y3HIC6.js.map → chunk-CZI2A4MQ.js.map} +0 -0
- /package/dist/{chunk-KJF7EPUE.js.map → chunk-DKO2QFSA.js.map} +0 -0
- /package/dist/{chunk-QFYVGJLI.js.map → chunk-DQU36Q7I.js.map} +0 -0
- /package/dist/{chunk-NIUXQDWD.js.map → chunk-EGD5DXFT.js.map} +0 -0
- /package/dist/{chunk-KHQ3N5AB.js.map → chunk-F4OJZIWQ.js.map} +0 -0
- /package/dist/{chunk-3OUCWHV6.js.map → chunk-FWPKCXTN.js.map} +0 -0
- /package/dist/{chunk-QIVFGU2M.js.map → chunk-HOR4R722.js.map} +0 -0
- /package/dist/{chunk-NP6EZT44.js.map → chunk-IQLVUT37.js.map} +0 -0
- /package/dist/{chunk-4VCQH32J.js.map → chunk-JD3OZAI4.js.map} +0 -0
- /package/dist/{chunk-J67BP5EP.js.map → chunk-KI6HAJWL.js.map} +0 -0
- /package/dist/{chunk-AYNF7PVX.js.map → chunk-KIP6JLTF.js.map} +0 -0
- /package/dist/{chunk-PW26DAXS.js.map → chunk-L2FE64BU.js.map} +0 -0
- /package/dist/{chunk-QAWCVWCX.js.map → chunk-LX3CB26H.js.map} +0 -0
- /package/dist/{chunk-VAK6NQAK.js.map → chunk-NSCVNK5K.js.map} +0 -0
- /package/dist/{chunk-3XZRRBFW.js.map → chunk-OHVFWCJP.js.map} +0 -0
- /package/dist/{chunk-TEQGXA7L.js.map → chunk-PE4AQGFH.js.map} +0 -0
- /package/dist/{chunk-UNQEWORI.js.map → chunk-TS26M2SB.js.map} +0 -0
- /package/dist/{chunk-FNVFT4HZ.js.map → chunk-VU7SWWT5.js.map} +0 -0
- /package/dist/{chunk-GZJ5JBED.js.map → chunk-WBAYSNUQ.js.map} +0 -0
- /package/dist/{chunk-HHZ77DHM.js.map → chunk-WGHU7BLI.js.map} +0 -0
- /package/dist/{chunk-GL3Z7LH7.js.map → chunk-X73VS74Y.js.map} +0 -0
- /package/dist/{chunk-WIBHRONM.js.map → chunk-XWH4MXIU.js.map} +0 -0
- /package/dist/{chunk-M6KXHRIA.js.map → chunk-YHPM5D7Y.js.map} +0 -0
- /package/dist/{chunk-E3DIBDKA.js.map → chunk-YULZKK4F.js.map} +0 -0
- /package/dist/{chunk-JWFNOD2T.js.map → chunk-Z4DO7YSI.js.map} +0 -0
- /package/dist/{chunk-JPOQMXGT.js.map → chunk-ZNQYHJXX.js.map} +0 -0
- /package/dist/{crypto-YXH6SAOW.js.map → crypto-QXQOHMHF.js.map} +0 -0
- /package/dist/{delegation-K5ERUH6A.js.map → delegation-NIQ43IPU.js.map} +0 -0
- /package/dist/{executor-AVJ7UEWA.js.map → executor-6ZDSDZ6V.js.map} +0 -0
- /package/dist/{executor-IQO3KGXQ.js.map → executor-HSSRXDOB.js.map} +0 -0
- /package/dist/{executor-VT7TKGE4.js.map → executor-IDZDAFNH.js.map} +0 -0
- /package/dist/{issue-ZH27C23Y.js.map → issue-ADVS4OVP.js.map} +0 -0
- /package/dist/{ledger-64TTQMRS.js.map → ledger-CWSE3BLF.js.map} +0 -0
- /package/dist/{noydb-O76SKBST.js.map → noydb-GZGFBA4E.js.map} +0 -0
- /package/dist/{public-envelope-MHG6YVXW.js.map → public-envelope-SYHEYQ3X.js.map} +0 -0
- /package/dist/{registry-2PKBQDCH.js.map → registry-DK5YWAAA.js.map} +0 -0
- /package/dist/{registry-4VXFKCBJ.js.map → registry-IUZQVVBB.js.map} +0 -0
- /package/dist/{registry-PV4G3OPA.js.map → registry-XGLNADIE.js.map} +0 -0
- /package/dist/{revoke-5BOLVJ3N.js.map → revoke-ZDFKMR5E.js.map} +0 -0
- /package/dist/{signer-GRIYBA22.js.map → signer-P5D7Y72U.js.map} +0 -0
- /package/dist/{stale-LZYMMDDS.js.map → stale-JH67FU57.js.map} +0 -0
- /package/dist/{state-vault-QFJWU23A.js.map → state-vault-TMXZRTY5.js.map} +0 -0
package/dist/query/index.cjs
CHANGED
|
@@ -57,88 +57,156 @@ __export(query_exports, {
|
|
|
57
57
|
});
|
|
58
58
|
module.exports = __toCommonJS(query_exports);
|
|
59
59
|
|
|
60
|
-
// src/
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
if (!
|
|
64
|
-
|
|
60
|
+
// src/money/fixed-point.ts
|
|
61
|
+
function expandExponent(s) {
|
|
62
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
|
|
63
|
+
if (!m) return s;
|
|
64
|
+
const sign = m[1] === "-" ? "-" : "";
|
|
65
|
+
const intp = m[2];
|
|
66
|
+
const frac = m[3] ?? "";
|
|
67
|
+
const exp = Number(m[4]);
|
|
68
|
+
const digits = intp + frac;
|
|
69
|
+
const pointPos = intp.length + exp;
|
|
70
|
+
let body;
|
|
71
|
+
if (pointPos <= 0) {
|
|
72
|
+
body = "0." + "0".repeat(-pointPos) + digits;
|
|
73
|
+
} else if (pointPos >= digits.length) {
|
|
74
|
+
body = digits + "0".repeat(pointPos - digits.length);
|
|
75
|
+
} else {
|
|
76
|
+
body = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
|
|
65
77
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
return sign + body;
|
|
79
|
+
}
|
|
80
|
+
function toCanonicalDecimalString(input) {
|
|
81
|
+
let s;
|
|
82
|
+
if (typeof input === "number") {
|
|
83
|
+
if (!Number.isFinite(input)) return null;
|
|
84
|
+
s = String(input);
|
|
85
|
+
} else {
|
|
86
|
+
s = input.trim();
|
|
71
87
|
}
|
|
72
|
-
|
|
88
|
+
s = expandExponent(s);
|
|
89
|
+
if (s.startsWith("+")) s = s.slice(1);
|
|
90
|
+
if (!/^-?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null;
|
|
91
|
+
return s;
|
|
73
92
|
}
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
case "
|
|
79
|
-
return actual === value;
|
|
80
|
-
case "!=":
|
|
81
|
-
return actual !== value;
|
|
82
|
-
case "<":
|
|
83
|
-
return isComparable(actual, value) && actual < value;
|
|
84
|
-
case "<=":
|
|
85
|
-
return isComparable(actual, value) && actual <= value;
|
|
86
|
-
case ">":
|
|
87
|
-
return isComparable(actual, value) && actual > value;
|
|
88
|
-
case ">=":
|
|
89
|
-
return isComparable(actual, value) && actual >= value;
|
|
90
|
-
case "in":
|
|
91
|
-
return Array.isArray(value) && value.includes(actual);
|
|
92
|
-
case "contains":
|
|
93
|
-
if (typeof actual === "string") return typeof value === "string" && actual.includes(value);
|
|
94
|
-
if (Array.isArray(actual)) return actual.includes(value);
|
|
95
|
-
return false;
|
|
96
|
-
case "startsWith":
|
|
97
|
-
return typeof actual === "string" && typeof value === "string" && actual.startsWith(value);
|
|
98
|
-
case "between": {
|
|
99
|
-
if (!Array.isArray(value) || value.length !== 2) return false;
|
|
100
|
-
const [lo, hi] = value;
|
|
101
|
-
if (!isComparable(actual, lo) || !isComparable(actual, hi)) return false;
|
|
102
|
-
return actual >= lo && actual <= hi;
|
|
103
|
-
}
|
|
104
|
-
default: {
|
|
105
|
-
const _exhaustive = op;
|
|
106
|
-
void _exhaustive;
|
|
93
|
+
function shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, mode) {
|
|
94
|
+
switch (mode) {
|
|
95
|
+
case "up":
|
|
96
|
+
return true;
|
|
97
|
+
case "down":
|
|
107
98
|
return false;
|
|
108
|
-
|
|
99
|
+
case "ceil":
|
|
100
|
+
return !negative;
|
|
101
|
+
case "floor":
|
|
102
|
+
return negative;
|
|
103
|
+
case "half-up":
|
|
104
|
+
return firstDiscarded >= 5;
|
|
105
|
+
case "half-down":
|
|
106
|
+
return firstDiscarded > 5 || firstDiscarded === 5 && hasMoreNonZeroAfterFirst;
|
|
107
|
+
case "half-even":
|
|
108
|
+
if (firstDiscarded > 5) return true;
|
|
109
|
+
if (firstDiscarded < 5) return false;
|
|
110
|
+
return hasMoreNonZeroAfterFirst || lastKeptDigit % 2 === 1;
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
function parseToScaledInt(input, scale, rounding) {
|
|
114
|
+
const canonical = toCanonicalDecimalString(input);
|
|
115
|
+
if (canonical === null) return { ok: false, reason: "nonfinite" };
|
|
116
|
+
const negative = canonical.startsWith("-");
|
|
117
|
+
const unsigned = negative ? canonical.slice(1) : canonical;
|
|
118
|
+
const dot = unsigned.indexOf(".");
|
|
119
|
+
const intPart = dot === -1 ? unsigned : unsigned.slice(0, dot);
|
|
120
|
+
const fracPart = dot === -1 ? "" : unsigned.slice(dot + 1);
|
|
121
|
+
const intDigits = intPart === "" ? "0" : intPart;
|
|
122
|
+
if (fracPart.length <= scale) {
|
|
123
|
+
const keep2 = fracPart.padEnd(scale, "0");
|
|
124
|
+
const magnitude2 = BigInt(intDigits + keep2);
|
|
125
|
+
return { ok: true, value: negative && magnitude2 !== 0n ? -magnitude2 : magnitude2 };
|
|
126
|
+
}
|
|
127
|
+
const keep = fracPart.slice(0, scale);
|
|
128
|
+
const tail = fracPart.slice(scale);
|
|
129
|
+
const magnitudeDigits = intDigits + keep;
|
|
130
|
+
let magnitude = BigInt(magnitudeDigits);
|
|
131
|
+
if (/^0+$/.test(tail)) {
|
|
132
|
+
return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
|
|
133
|
+
}
|
|
134
|
+
if (rounding === void 0) return { ok: false, reason: "precision" };
|
|
135
|
+
const lastKeptDigit = Number(magnitudeDigits[magnitudeDigits.length - 1]);
|
|
136
|
+
const firstDiscarded = Number(tail[0]);
|
|
137
|
+
const hasMoreNonZeroAfterFirst = /[1-9]/.test(tail.slice(1));
|
|
138
|
+
if (shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, rounding)) {
|
|
139
|
+
magnitude += 1n;
|
|
140
|
+
}
|
|
141
|
+
return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
|
|
116
142
|
}
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
function formatScaledInt(value, scale) {
|
|
144
|
+
const negative = value < 0n;
|
|
145
|
+
const abs = (negative ? -value : value).toString();
|
|
146
|
+
if (scale === 0) return (negative ? "-" : "") + abs;
|
|
147
|
+
const padded = abs.padStart(scale + 1, "0");
|
|
148
|
+
const cut = padded.length - scale;
|
|
149
|
+
const intPart = padded.slice(0, cut);
|
|
150
|
+
const fracPart = padded.slice(cut);
|
|
151
|
+
return (negative ? "-" : "") + intPart + "." + fracPart;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/money/iso4217.ts
|
|
155
|
+
var MINOR_UNITS = {
|
|
156
|
+
// 2-decimal majors
|
|
157
|
+
EUR: 2,
|
|
158
|
+
USD: 2,
|
|
159
|
+
GBP: 2,
|
|
160
|
+
CHF: 2,
|
|
161
|
+
CAD: 2,
|
|
162
|
+
AUD: 2,
|
|
163
|
+
NZD: 2,
|
|
164
|
+
SGD: 2,
|
|
165
|
+
HKD: 2,
|
|
166
|
+
CNY: 2,
|
|
167
|
+
INR: 2,
|
|
168
|
+
BRL: 2,
|
|
169
|
+
MXN: 2,
|
|
170
|
+
ZAR: 2,
|
|
171
|
+
RUB: 2,
|
|
172
|
+
TRY: 2,
|
|
173
|
+
PLN: 2,
|
|
174
|
+
SEK: 2,
|
|
175
|
+
NOK: 2,
|
|
176
|
+
DKK: 2,
|
|
177
|
+
CZK: 2,
|
|
178
|
+
HUF: 2,
|
|
179
|
+
RON: 2,
|
|
180
|
+
ILS: 2,
|
|
181
|
+
THB: 2,
|
|
182
|
+
PHP: 2,
|
|
183
|
+
MYR: 2,
|
|
184
|
+
IDR: 2,
|
|
185
|
+
AED: 2,
|
|
186
|
+
SAR: 2,
|
|
187
|
+
QAR: 2,
|
|
188
|
+
EGP: 2,
|
|
189
|
+
// 0-decimal
|
|
190
|
+
JPY: 0,
|
|
191
|
+
KRW: 0,
|
|
192
|
+
ISK: 0,
|
|
193
|
+
CLP: 0,
|
|
194
|
+
VND: 0,
|
|
195
|
+
XOF: 0,
|
|
196
|
+
XAF: 0,
|
|
197
|
+
PYG: 0,
|
|
198
|
+
// 3-decimal
|
|
199
|
+
BHD: 3,
|
|
200
|
+
KWD: 3,
|
|
201
|
+
OMR: 3,
|
|
202
|
+
TND: 3,
|
|
203
|
+
JOD: 3,
|
|
204
|
+
IQD: 3,
|
|
205
|
+
LYD: 3
|
|
206
|
+
};
|
|
207
|
+
function scaleForCurrency(code) {
|
|
208
|
+
const v = MINOR_UNITS[code];
|
|
209
|
+
return v === void 0 ? null : v;
|
|
142
210
|
}
|
|
143
211
|
|
|
144
212
|
// src/errors.ts
|
|
@@ -151,6 +219,12 @@ var NoydbError = class extends Error {
|
|
|
151
219
|
this.code = code;
|
|
152
220
|
}
|
|
153
221
|
};
|
|
222
|
+
var ValidationError = class extends NoydbError {
|
|
223
|
+
constructor(message = "Validation error") {
|
|
224
|
+
super("VALIDATION_ERROR", message);
|
|
225
|
+
this.name = "ValidationError";
|
|
226
|
+
}
|
|
227
|
+
};
|
|
154
228
|
var GroupCardinalityError = class extends NoydbError {
|
|
155
229
|
/** The field being grouped on. */
|
|
156
230
|
field;
|
|
@@ -256,6 +330,244 @@ var DanglingReferenceError = class extends NoydbError {
|
|
|
256
330
|
}
|
|
257
331
|
};
|
|
258
332
|
|
|
333
|
+
// src/money/descriptor.ts
|
|
334
|
+
var MoneyUnsupportedError = class extends NoydbError {
|
|
335
|
+
constructor(field, message) {
|
|
336
|
+
super(
|
|
337
|
+
"MONEY_UNSUPPORTED",
|
|
338
|
+
message ?? `money: operation is not supported on field "${field}" \u2014 use sum() and count() and divide at the boundary`
|
|
339
|
+
);
|
|
340
|
+
this.field = field;
|
|
341
|
+
this.name = "MoneyUnsupportedError";
|
|
342
|
+
}
|
|
343
|
+
field;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/money/where.ts
|
|
347
|
+
function isMoneyValueObject(v) {
|
|
348
|
+
return typeof v === "object" && v !== null && "currency" in v;
|
|
349
|
+
}
|
|
350
|
+
function parseOperand(field, raw, desc) {
|
|
351
|
+
let amount;
|
|
352
|
+
let currency;
|
|
353
|
+
if (desc.mode === "fixed") {
|
|
354
|
+
currency = desc.fixedCurrency;
|
|
355
|
+
amount = raw;
|
|
356
|
+
} else if (isMoneyValueObject(raw)) {
|
|
357
|
+
currency = String(raw.currency);
|
|
358
|
+
amount = raw.amount;
|
|
359
|
+
} else {
|
|
360
|
+
const sole = desc.soleCurrency();
|
|
361
|
+
if (sole === void 0) {
|
|
362
|
+
throw new MoneyUnsupportedError(
|
|
363
|
+
`where("${field}"): field is multi-currency \u2014 compare against { amount, currency }, not a bare amount`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
currency = sole;
|
|
367
|
+
amount = raw;
|
|
368
|
+
}
|
|
369
|
+
if (typeof amount !== "number" && typeof amount !== "string") {
|
|
370
|
+
throw new MoneyUnsupportedError(
|
|
371
|
+
`where("${field}"): operand ${JSON.stringify(raw)} is not a money amount`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
const r = parseToScaledInt(amount, desc.scaleFor(currency), desc.rounding);
|
|
375
|
+
if (!r.ok) {
|
|
376
|
+
throw new MoneyUnsupportedError(
|
|
377
|
+
`where("${field}"): operand ${JSON.stringify(amount)} is not a finite decimal`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return { scaled: r.value.toString(), currency };
|
|
381
|
+
}
|
|
382
|
+
function moneyFieldClause(field, op, value, desc) {
|
|
383
|
+
switch (op) {
|
|
384
|
+
case "==":
|
|
385
|
+
case "!=":
|
|
386
|
+
case "<":
|
|
387
|
+
case "<=":
|
|
388
|
+
case ">":
|
|
389
|
+
case ">=": {
|
|
390
|
+
const e = parseOperand(field, value, desc);
|
|
391
|
+
return withMoney(field, op, value, desc, [e]);
|
|
392
|
+
}
|
|
393
|
+
case "between": {
|
|
394
|
+
if (!Array.isArray(value) || value.length !== 2) {
|
|
395
|
+
throw new MoneyUnsupportedError(`where("${field}"): 'between' needs a [lo, hi] tuple`);
|
|
396
|
+
}
|
|
397
|
+
const lo = parseOperand(field, value[0], desc);
|
|
398
|
+
const hi = parseOperand(field, value[1], desc);
|
|
399
|
+
if (lo.currency !== hi.currency) {
|
|
400
|
+
throw new MoneyUnsupportedError(
|
|
401
|
+
`where("${field}"): 'between' bounds mix currencies (${lo.currency} vs ${hi.currency})`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return withMoney(field, op, value, desc, [lo, hi]);
|
|
405
|
+
}
|
|
406
|
+
case "in": {
|
|
407
|
+
if (!Array.isArray(value)) {
|
|
408
|
+
throw new MoneyUnsupportedError(`where("${field}"): 'in' needs an array of amounts`);
|
|
409
|
+
}
|
|
410
|
+
return withMoney(field, op, value, desc, value.map((v) => parseOperand(field, v, desc)));
|
|
411
|
+
}
|
|
412
|
+
default:
|
|
413
|
+
throw new MoneyUnsupportedError(
|
|
414
|
+
`where("${field}"): operator '${op}' is not supported on a money field`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function withMoney(field, op, originalValue, desc, entries) {
|
|
419
|
+
const money = { mode: desc.mode, entries };
|
|
420
|
+
const value = desc.mode !== "fixed" ? originalValue : entries.length === 1 && op !== "in" && op !== "between" ? entries[0].scaled : entries.map((e) => e.scaled);
|
|
421
|
+
return { type: "field", field, op, value, money };
|
|
422
|
+
}
|
|
423
|
+
function readStored(actual, operand) {
|
|
424
|
+
let amount;
|
|
425
|
+
let currency;
|
|
426
|
+
if (operand.mode === "fixed") {
|
|
427
|
+
if (typeof actual !== "string" && typeof actual !== "number") return null;
|
|
428
|
+
amount = actual;
|
|
429
|
+
currency = operand.entries[0]?.currency ?? "";
|
|
430
|
+
} else {
|
|
431
|
+
if (!isMoneyValueObject(actual)) return null;
|
|
432
|
+
if (typeof actual.currency !== "string") return null;
|
|
433
|
+
amount = actual.amount;
|
|
434
|
+
currency = actual.currency;
|
|
435
|
+
}
|
|
436
|
+
if (typeof amount !== "string" && typeof amount !== "number") return null;
|
|
437
|
+
try {
|
|
438
|
+
return { scaled: BigInt(amount).toString(), currency };
|
|
439
|
+
} catch {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function evaluateMoneyClause(actual, op, operand) {
|
|
444
|
+
const stored = readStored(actual, operand);
|
|
445
|
+
if (stored === null) return op === "!=";
|
|
446
|
+
const a = BigInt(stored.scaled);
|
|
447
|
+
if (op === "in") {
|
|
448
|
+
return operand.entries.some(
|
|
449
|
+
(e2) => e2.currency === stored.currency && BigInt(e2.scaled) === a
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (op === "between") {
|
|
453
|
+
const [lo, hi] = operand.entries;
|
|
454
|
+
if (!lo || !hi || lo.currency !== stored.currency) return false;
|
|
455
|
+
return a >= BigInt(lo.scaled) && a <= BigInt(hi.scaled);
|
|
456
|
+
}
|
|
457
|
+
const e = operand.entries[0];
|
|
458
|
+
if (!e) return false;
|
|
459
|
+
if (e.currency !== stored.currency) return op === "!=";
|
|
460
|
+
const b = BigInt(e.scaled);
|
|
461
|
+
switch (op) {
|
|
462
|
+
case "==":
|
|
463
|
+
return a === b;
|
|
464
|
+
case "!=":
|
|
465
|
+
return a !== b;
|
|
466
|
+
case "<":
|
|
467
|
+
return a < b;
|
|
468
|
+
case "<=":
|
|
469
|
+
return a <= b;
|
|
470
|
+
case ">":
|
|
471
|
+
return a > b;
|
|
472
|
+
case ">=":
|
|
473
|
+
return a >= b;
|
|
474
|
+
default:
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/query/predicate.ts
|
|
480
|
+
function readPath(record, path) {
|
|
481
|
+
if (record === null || record === void 0) return void 0;
|
|
482
|
+
if (!path.includes(".")) {
|
|
483
|
+
return record[path];
|
|
484
|
+
}
|
|
485
|
+
const segments = path.split(".");
|
|
486
|
+
let cursor = record;
|
|
487
|
+
for (const segment of segments) {
|
|
488
|
+
if (cursor === null || cursor === void 0) return void 0;
|
|
489
|
+
cursor = cursor[segment];
|
|
490
|
+
}
|
|
491
|
+
return cursor;
|
|
492
|
+
}
|
|
493
|
+
function evaluateFieldClause(record, clause) {
|
|
494
|
+
const actual = readPath(record, clause.field);
|
|
495
|
+
const { op, value } = clause;
|
|
496
|
+
if (clause.money) return evaluateMoneyClause(actual, op, clause.money);
|
|
497
|
+
switch (op) {
|
|
498
|
+
case "==":
|
|
499
|
+
return actual === value;
|
|
500
|
+
case "!=":
|
|
501
|
+
return actual !== value;
|
|
502
|
+
case "<":
|
|
503
|
+
return isComparable(actual, value) && actual < value;
|
|
504
|
+
case "<=":
|
|
505
|
+
return isComparable(actual, value) && actual <= value;
|
|
506
|
+
case ">":
|
|
507
|
+
return isComparable(actual, value) && actual > value;
|
|
508
|
+
case ">=":
|
|
509
|
+
return isComparable(actual, value) && actual >= value;
|
|
510
|
+
case "in":
|
|
511
|
+
return Array.isArray(value) && value.includes(actual);
|
|
512
|
+
case "contains":
|
|
513
|
+
if (typeof actual === "string") return typeof value === "string" && actual.includes(value);
|
|
514
|
+
if (Array.isArray(actual)) return actual.includes(value);
|
|
515
|
+
return false;
|
|
516
|
+
case "startsWith":
|
|
517
|
+
return typeof actual === "string" && typeof value === "string" && actual.startsWith(value);
|
|
518
|
+
case "between": {
|
|
519
|
+
if (!Array.isArray(value) || value.length !== 2) return false;
|
|
520
|
+
const [lo, hi] = value;
|
|
521
|
+
if (!isComparable(actual, lo) || !isComparable(actual, hi)) return false;
|
|
522
|
+
return actual >= lo && actual <= hi;
|
|
523
|
+
}
|
|
524
|
+
default: {
|
|
525
|
+
const _exhaustive = op;
|
|
526
|
+
void _exhaustive;
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function isComparable(a, b) {
|
|
532
|
+
if (typeof a === "number" && typeof b === "number") return true;
|
|
533
|
+
if (typeof a === "string" && typeof b === "string") return true;
|
|
534
|
+
if (a instanceof Date && b instanceof Date) return true;
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
function evaluateClause(record, clause, fnRecord) {
|
|
538
|
+
switch (clause.type) {
|
|
539
|
+
case "field":
|
|
540
|
+
return evaluateFieldClause(record, clause);
|
|
541
|
+
case "filter":
|
|
542
|
+
return clause.fn(fnRecord !== void 0 ? fnRecord : record);
|
|
543
|
+
case "wherePredicate":
|
|
544
|
+
return clause.fn(fnRecord !== void 0 ? fnRecord : record, clause.ctx);
|
|
545
|
+
case "crossJoin":
|
|
546
|
+
throw new Error(
|
|
547
|
+
`evaluateClause: 'crossJoin' clauses are expansion primitives and are not evaluated per-record. This is a query planner routing error \u2014 crossJoin clauses must be extracted from the clause list before calling evaluateClause or filterRecords.`
|
|
548
|
+
);
|
|
549
|
+
case "group":
|
|
550
|
+
if (clause.op === "and") {
|
|
551
|
+
for (const child of clause.clauses) {
|
|
552
|
+
if (!evaluateClause(record, child, fnRecord)) return false;
|
|
553
|
+
}
|
|
554
|
+
return true;
|
|
555
|
+
} else {
|
|
556
|
+
for (const child of clause.clauses) {
|
|
557
|
+
if (evaluateClause(record, child, fnRecord)) return true;
|
|
558
|
+
}
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function hasFnClause(clauses) {
|
|
564
|
+
for (const c of clauses) {
|
|
565
|
+
if (c.type === "filter" || c.type === "wherePredicate") return true;
|
|
566
|
+
if (c.type === "group" && hasFnClause(c.clauses)) return true;
|
|
567
|
+
}
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
|
|
259
571
|
// src/query/join.ts
|
|
260
572
|
var DEFAULT_JOIN_MAX_ROWS = 5e4;
|
|
261
573
|
var JOIN_WARN_FRACTION = 0.8;
|
|
@@ -501,89 +813,6 @@ var NO_AGGREGATE = {
|
|
|
501
813
|
}
|
|
502
814
|
};
|
|
503
815
|
|
|
504
|
-
// src/money/fixed-point.ts
|
|
505
|
-
function formatScaledInt(value, scale) {
|
|
506
|
-
const negative = value < 0n;
|
|
507
|
-
const abs = (negative ? -value : value).toString();
|
|
508
|
-
if (scale === 0) return (negative ? "-" : "") + abs;
|
|
509
|
-
const padded = abs.padStart(scale + 1, "0");
|
|
510
|
-
const cut = padded.length - scale;
|
|
511
|
-
const intPart = padded.slice(0, cut);
|
|
512
|
-
const fracPart = padded.slice(cut);
|
|
513
|
-
return (negative ? "-" : "") + intPart + "." + fracPart;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// src/money/iso4217.ts
|
|
517
|
-
var MINOR_UNITS = {
|
|
518
|
-
// 2-decimal majors
|
|
519
|
-
EUR: 2,
|
|
520
|
-
USD: 2,
|
|
521
|
-
GBP: 2,
|
|
522
|
-
CHF: 2,
|
|
523
|
-
CAD: 2,
|
|
524
|
-
AUD: 2,
|
|
525
|
-
NZD: 2,
|
|
526
|
-
SGD: 2,
|
|
527
|
-
HKD: 2,
|
|
528
|
-
CNY: 2,
|
|
529
|
-
INR: 2,
|
|
530
|
-
BRL: 2,
|
|
531
|
-
MXN: 2,
|
|
532
|
-
ZAR: 2,
|
|
533
|
-
RUB: 2,
|
|
534
|
-
TRY: 2,
|
|
535
|
-
PLN: 2,
|
|
536
|
-
SEK: 2,
|
|
537
|
-
NOK: 2,
|
|
538
|
-
DKK: 2,
|
|
539
|
-
CZK: 2,
|
|
540
|
-
HUF: 2,
|
|
541
|
-
RON: 2,
|
|
542
|
-
ILS: 2,
|
|
543
|
-
THB: 2,
|
|
544
|
-
PHP: 2,
|
|
545
|
-
MYR: 2,
|
|
546
|
-
IDR: 2,
|
|
547
|
-
AED: 2,
|
|
548
|
-
SAR: 2,
|
|
549
|
-
QAR: 2,
|
|
550
|
-
EGP: 2,
|
|
551
|
-
// 0-decimal
|
|
552
|
-
JPY: 0,
|
|
553
|
-
KRW: 0,
|
|
554
|
-
ISK: 0,
|
|
555
|
-
CLP: 0,
|
|
556
|
-
VND: 0,
|
|
557
|
-
XOF: 0,
|
|
558
|
-
XAF: 0,
|
|
559
|
-
PYG: 0,
|
|
560
|
-
// 3-decimal
|
|
561
|
-
BHD: 3,
|
|
562
|
-
KWD: 3,
|
|
563
|
-
OMR: 3,
|
|
564
|
-
TND: 3,
|
|
565
|
-
JOD: 3,
|
|
566
|
-
IQD: 3,
|
|
567
|
-
LYD: 3
|
|
568
|
-
};
|
|
569
|
-
function scaleForCurrency(code) {
|
|
570
|
-
const v = MINOR_UNITS[code];
|
|
571
|
-
return v === void 0 ? null : v;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// src/money/descriptor.ts
|
|
575
|
-
var MoneyUnsupportedError = class extends NoydbError {
|
|
576
|
-
constructor(field, message) {
|
|
577
|
-
super(
|
|
578
|
-
"MONEY_UNSUPPORTED",
|
|
579
|
-
message ?? `money: operation is not supported on field "${field}" \u2014 use sum() and count() and divide at the boundary`
|
|
580
|
-
);
|
|
581
|
-
this.field = field;
|
|
582
|
-
this.name = "MoneyUnsupportedError";
|
|
583
|
-
}
|
|
584
|
-
field;
|
|
585
|
-
};
|
|
586
|
-
|
|
587
816
|
// src/money/money-reducer.ts
|
|
588
817
|
function toScaledInt(v) {
|
|
589
818
|
if (typeof v === "string" || typeof v === "number" || typeof v === "bigint") {
|
|
@@ -758,8 +987,107 @@ function wrapMoneyReducers(spec, moneyFields) {
|
|
|
758
987
|
return changed ? out : spec;
|
|
759
988
|
}
|
|
760
989
|
|
|
990
|
+
// src/money/paths.ts
|
|
991
|
+
var SEGMENT_RE = /^(\*|[^.[\]*]+)(\[\])?$/;
|
|
992
|
+
var parseCache = /* @__PURE__ */ new Map();
|
|
993
|
+
function parseMoneyPath(path) {
|
|
994
|
+
const cached = parseCache.get(path);
|
|
995
|
+
if (cached) return cached;
|
|
996
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
997
|
+
throw new ValidationError("moneyFields: path must be a non-empty string");
|
|
998
|
+
}
|
|
999
|
+
const segments = [];
|
|
1000
|
+
for (const part of path.split(".")) {
|
|
1001
|
+
const m = SEGMENT_RE.exec(part);
|
|
1002
|
+
if (!m) {
|
|
1003
|
+
throw new ValidationError(
|
|
1004
|
+
`moneyFields: invalid path "${path}" \u2014 segment "${part}" must be a key, "key[]", "*", or "*[]"`
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
const array = m[2] === "[]";
|
|
1008
|
+
segments.push(
|
|
1009
|
+
m[1] === "*" ? { kind: "wildcard", array } : { kind: "key", key: m[1], array }
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
parseCache.set(path, segments);
|
|
1013
|
+
return segments;
|
|
1014
|
+
}
|
|
1015
|
+
function isSimpleMoneyPath(path) {
|
|
1016
|
+
return !path.includes(".") && !path.includes("[") && !path.includes("*");
|
|
1017
|
+
}
|
|
1018
|
+
function transformAtMoneyPath(node, path, segments, index, visit, lenient) {
|
|
1019
|
+
if (node === null || node === void 0) return node;
|
|
1020
|
+
const seg = segments[index];
|
|
1021
|
+
const last = index === segments.length - 1;
|
|
1022
|
+
if (seg.kind === "key") {
|
|
1023
|
+
if (typeof node !== "object" || Array.isArray(node)) {
|
|
1024
|
+
if (lenient) return node;
|
|
1025
|
+
throw new ValidationError(
|
|
1026
|
+
`moneyFields: path "${path}" expected an object at segment "${seg.key}", got ${Array.isArray(node) ? "an array" : typeof node}`
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
const obj2 = node;
|
|
1030
|
+
if (!(seg.key in obj2) || obj2[seg.key] === null || obj2[seg.key] === void 0) return node;
|
|
1031
|
+
if (seg.array) {
|
|
1032
|
+
const arr = obj2[seg.key];
|
|
1033
|
+
if (!Array.isArray(arr)) {
|
|
1034
|
+
if (lenient) return node;
|
|
1035
|
+
throw new ValidationError(
|
|
1036
|
+
`moneyFields: path "${path}" declares "${seg.key}[]" but the value is not an array`
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
const cloned = [...arr];
|
|
1040
|
+
if (last) {
|
|
1041
|
+
for (let i = 0; i < cloned.length; i++) visit(cloned, i);
|
|
1042
|
+
} else {
|
|
1043
|
+
for (let i = 0; i < cloned.length; i++) {
|
|
1044
|
+
cloned[i] = transformAtMoneyPath(cloned[i], path, segments, index + 1, visit, lenient);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return { ...obj2, [seg.key]: cloned };
|
|
1048
|
+
}
|
|
1049
|
+
const clone2 = { ...obj2 };
|
|
1050
|
+
if (last) {
|
|
1051
|
+
visit(clone2, seg.key);
|
|
1052
|
+
} else {
|
|
1053
|
+
clone2[seg.key] = transformAtMoneyPath(clone2[seg.key], path, segments, index + 1, visit, lenient);
|
|
1054
|
+
}
|
|
1055
|
+
return clone2;
|
|
1056
|
+
}
|
|
1057
|
+
if (seg.array) {
|
|
1058
|
+
if (!Array.isArray(node)) {
|
|
1059
|
+
if (lenient) return node;
|
|
1060
|
+
throw new ValidationError(`moneyFields: path "${path}" declares "*[]" but the value is not an array`);
|
|
1061
|
+
}
|
|
1062
|
+
const cloned = [...node];
|
|
1063
|
+
if (last) {
|
|
1064
|
+
for (let i = 0; i < cloned.length; i++) visit(cloned, i);
|
|
1065
|
+
} else {
|
|
1066
|
+
for (let i = 0; i < cloned.length; i++) {
|
|
1067
|
+
cloned[i] = transformAtMoneyPath(cloned[i], path, segments, index + 1, visit, lenient);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
return cloned;
|
|
1071
|
+
}
|
|
1072
|
+
if (typeof node !== "object" || Array.isArray(node)) {
|
|
1073
|
+
if (lenient) return node;
|
|
1074
|
+
throw new ValidationError(
|
|
1075
|
+
`moneyFields: path "${path}" applies "*" to a non-object (${Array.isArray(node) ? 'array \u2014 use "*[]"' : typeof node})`
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
const obj = node;
|
|
1079
|
+
const clone = { ...obj };
|
|
1080
|
+
for (const key of Object.keys(obj)) {
|
|
1081
|
+
const v = clone[key];
|
|
1082
|
+
if (v === null || v === void 0) continue;
|
|
1083
|
+
if (last) visit(clone, key);
|
|
1084
|
+
else clone[key] = transformAtMoneyPath(v, path, segments, index + 1, visit, lenient);
|
|
1085
|
+
}
|
|
1086
|
+
return clone;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
761
1089
|
// src/money/normalize.ts
|
|
762
|
-
function
|
|
1090
|
+
function isMoneyValueObject2(v) {
|
|
763
1091
|
return typeof v === "object" && v !== null && "currency" in v;
|
|
764
1092
|
}
|
|
765
1093
|
function formatCurrency(decimal, currency, scale, locale) {
|
|
@@ -771,33 +1099,70 @@ function formatCurrency(decimal, currency, scale, locale) {
|
|
|
771
1099
|
});
|
|
772
1100
|
return fmt.format(decimal);
|
|
773
1101
|
}
|
|
1102
|
+
function decodeValue(stored, desc) {
|
|
1103
|
+
let currency;
|
|
1104
|
+
let scaledIntString;
|
|
1105
|
+
if (desc.mode === "fixed") {
|
|
1106
|
+
if (typeof stored !== "string" && typeof stored !== "number") return null;
|
|
1107
|
+
currency = desc.fixedCurrency;
|
|
1108
|
+
scaledIntString = String(stored);
|
|
1109
|
+
} else {
|
|
1110
|
+
if (!isMoneyValueObject2(stored)) return null;
|
|
1111
|
+
const amount = stored.amount;
|
|
1112
|
+
if (typeof stored.currency !== "string" || typeof amount !== "string" && typeof amount !== "number") return null;
|
|
1113
|
+
currency = stored.currency;
|
|
1114
|
+
scaledIntString = String(amount);
|
|
1115
|
+
}
|
|
1116
|
+
const scale = desc.scaleFor(currency);
|
|
1117
|
+
let decimal;
|
|
1118
|
+
try {
|
|
1119
|
+
decimal = formatScaledInt(BigInt(scaledIntString), scale);
|
|
1120
|
+
} catch {
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
return {
|
|
1124
|
+
decoded: desc.mode === "fixed" ? decimal : { amount: decimal, currency },
|
|
1125
|
+
decimal,
|
|
1126
|
+
currency,
|
|
1127
|
+
scale
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
774
1130
|
function decodeMoneyFields(record, moneyFields, locale) {
|
|
775
|
-
|
|
1131
|
+
let out = { ...record };
|
|
776
1132
|
const format = locale !== "raw";
|
|
777
1133
|
const fmtLocale = typeof locale === "string" && locale !== "raw" ? locale : "en-US";
|
|
778
|
-
for (const [
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1134
|
+
for (const [path, desc] of Object.entries(moneyFields)) {
|
|
1135
|
+
if (isSimpleMoneyPath(path)) {
|
|
1136
|
+
const stored = out[path];
|
|
1137
|
+
if (stored === null || stored === void 0) continue;
|
|
1138
|
+
const r = decodeValue(stored, desc);
|
|
1139
|
+
if (r === null) continue;
|
|
1140
|
+
out[path] = r.decoded;
|
|
1141
|
+
if (format) {
|
|
1142
|
+
out[`${path}Formatted`] = formatCurrency(r.decimal, r.currency, r.scale, fmtLocale);
|
|
1143
|
+
out[`${path}Number`] = Number(r.decimal);
|
|
1144
|
+
}
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
out = transformAtMoneyPath(
|
|
1148
|
+
out,
|
|
1149
|
+
path,
|
|
1150
|
+
parseMoneyPath(path),
|
|
1151
|
+
0,
|
|
1152
|
+
(container, key) => {
|
|
1153
|
+
const stored = container[key];
|
|
1154
|
+
if (stored === null || stored === void 0) return;
|
|
1155
|
+
const r = decodeValue(stored, desc);
|
|
1156
|
+
if (r === null) return;
|
|
1157
|
+
container[key] = r.decoded;
|
|
1158
|
+
if (format && typeof key === "string" && !Array.isArray(container)) {
|
|
1159
|
+
container[`${key}Formatted`] = formatCurrency(r.decimal, r.currency, r.scale, fmtLocale);
|
|
1160
|
+
container[`${key}Number`] = Number(r.decimal);
|
|
1161
|
+
}
|
|
1162
|
+
},
|
|
1163
|
+
/* lenient */
|
|
1164
|
+
true
|
|
1165
|
+
);
|
|
801
1166
|
}
|
|
802
1167
|
return out;
|
|
803
1168
|
}
|
|
@@ -894,9 +1259,18 @@ var Query = class _Query {
|
|
|
894
1259
|
this.predicates
|
|
895
1260
|
);
|
|
896
1261
|
}
|
|
897
|
-
/**
|
|
1262
|
+
/**
|
|
1263
|
+
* Add a field comparison. Multiple where() calls are AND-combined.
|
|
1264
|
+
*
|
|
1265
|
+
* A declared money field compares in MAJOR units (#336): the operand
|
|
1266
|
+
* (`10000`, `'10000.00'`, or `{ amount, currency }` in multi mode) is
|
|
1267
|
+
* quantized into stored scaled-int space at build time and evaluated
|
|
1268
|
+
* BigInt-exact per record. A malformed operand or a string operator
|
|
1269
|
+
* (`contains`/`startsWith`) throws here, at the call site.
|
|
1270
|
+
*/
|
|
898
1271
|
where(field, op, value) {
|
|
899
|
-
const
|
|
1272
|
+
const desc = this.source.moneyFields?.[field];
|
|
1273
|
+
const clause = desc ? moneyFieldClause(field, op, value, desc) : { type: "field", field, op, value };
|
|
900
1274
|
return new _Query(
|
|
901
1275
|
this.source,
|
|
902
1276
|
{ ...this.plan, clauses: [...this.plan.clauses, clause] },
|
|
@@ -1222,7 +1596,7 @@ var Query = class _Query {
|
|
|
1222
1596
|
}
|
|
1223
1597
|
const { candidates, remainingClauses } = candidateRecords(this.source, this.plan.clauses);
|
|
1224
1598
|
if (remainingClauses.length === 0) return candidates.length;
|
|
1225
|
-
return filterRecords(candidates, remainingClauses).length;
|
|
1599
|
+
return filterRecords(candidates, remainingClauses, fnViewDecoder(this.source)).length;
|
|
1226
1600
|
}
|
|
1227
1601
|
/**
|
|
1228
1602
|
* Reduce the matching records through a named set of reducers.
|
|
@@ -1279,7 +1653,7 @@ var Query = class _Query {
|
|
|
1279
1653
|
return executeClausePipeline(source, clauses, joinCtx);
|
|
1280
1654
|
}
|
|
1281
1655
|
const { candidates, remainingClauses } = candidateRecords(source, clauses);
|
|
1282
|
-
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses);
|
|
1656
|
+
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
1283
1657
|
};
|
|
1284
1658
|
const upstreams = [];
|
|
1285
1659
|
if (source.subscribe) {
|
|
@@ -1302,7 +1676,7 @@ var Query = class _Query {
|
|
|
1302
1676
|
return executeClausePipeline(source, clauses, joinCtx);
|
|
1303
1677
|
}
|
|
1304
1678
|
const { candidates, remainingClauses } = candidateRecords(source, clauses);
|
|
1305
|
-
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses);
|
|
1679
|
+
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
1306
1680
|
};
|
|
1307
1681
|
const upstreams = [];
|
|
1308
1682
|
if (source.subscribe) {
|
|
@@ -1454,7 +1828,7 @@ function executePlanWithSource(source, plan, joinContext) {
|
|
|
1454
1828
|
result = executeClausePipeline(source, plan.clauses, joinContext);
|
|
1455
1829
|
} else {
|
|
1456
1830
|
const { candidates, remainingClauses } = candidateRecords(source, plan.clauses);
|
|
1457
|
-
result = remainingClauses.length === 0 ? [...candidates] : filterRecords(candidates, remainingClauses);
|
|
1831
|
+
result = remainingClauses.length === 0 ? [...candidates] : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
1458
1832
|
}
|
|
1459
1833
|
if (plan.orderBy.length > 0) {
|
|
1460
1834
|
result = sortRecords(result, plan.orderBy);
|
|
@@ -1477,6 +1851,7 @@ function candidateRecords(source, clauses) {
|
|
|
1477
1851
|
const clause = clauses[i];
|
|
1478
1852
|
if (clause.type !== "field") continue;
|
|
1479
1853
|
if (!indexes.has(clause.field)) continue;
|
|
1854
|
+
if (clause.money?.mode === "multi") continue;
|
|
1480
1855
|
let ids = null;
|
|
1481
1856
|
if (clause.op === "==") {
|
|
1482
1857
|
ids = indexes.lookupEqual(clause.field, clause.value);
|
|
@@ -1522,13 +1897,20 @@ function executePlan(records, plan) {
|
|
|
1522
1897
|
}
|
|
1523
1898
|
return result;
|
|
1524
1899
|
}
|
|
1525
|
-
function
|
|
1900
|
+
function fnViewDecoder(source) {
|
|
1901
|
+
const mf = source.moneyFields;
|
|
1902
|
+
if (!mf || Object.keys(mf).length === 0) return void 0;
|
|
1903
|
+
return (r) => decodeMoneyFields(r, mf, "raw");
|
|
1904
|
+
}
|
|
1905
|
+
function filterRecords(records, clauses, decodeForFns) {
|
|
1526
1906
|
if (clauses.length === 0) return [...records];
|
|
1907
|
+
const needsFnView = decodeForFns !== void 0 && hasFnClause(clauses);
|
|
1527
1908
|
const out = [];
|
|
1528
1909
|
for (const r of records) {
|
|
1910
|
+
const fnView = needsFnView ? decodeForFns(r) : void 0;
|
|
1529
1911
|
let matches = true;
|
|
1530
1912
|
for (const clause of clauses) {
|
|
1531
|
-
if (!evaluateClause(r, clause)) {
|
|
1913
|
+
if (!evaluateClause(r, clause, fnView)) {
|
|
1532
1914
|
matches = false;
|
|
1533
1915
|
break;
|
|
1534
1916
|
}
|
|
@@ -1540,10 +1922,11 @@ function filterRecords(records, clauses) {
|
|
|
1540
1922
|
function executeClausePipeline(source, clauses, joinContext) {
|
|
1541
1923
|
let rel = [...source.snapshot()];
|
|
1542
1924
|
let filterBatch = [];
|
|
1925
|
+
const decodeForFns = fnViewDecoder(source);
|
|
1543
1926
|
for (const clause of clauses) {
|
|
1544
1927
|
if (clause.type === "crossJoin") {
|
|
1545
1928
|
if (filterBatch.length > 0) {
|
|
1546
|
-
rel = filterRecords(rel, filterBatch);
|
|
1929
|
+
rel = filterRecords(rel, filterBatch, decodeForFns);
|
|
1547
1930
|
filterBatch = [];
|
|
1548
1931
|
}
|
|
1549
1932
|
const rightSource = joinContext.resolveSource(clause.target);
|
|
@@ -1556,7 +1939,7 @@ function executeClausePipeline(source, clauses, joinContext) {
|
|
|
1556
1939
|
}
|
|
1557
1940
|
}
|
|
1558
1941
|
if (filterBatch.length > 0) {
|
|
1559
|
-
rel = filterRecords(rel, filterBatch);
|
|
1942
|
+
rel = filterRecords(rel, filterBatch, decodeForFns);
|
|
1560
1943
|
}
|
|
1561
1944
|
return rel;
|
|
1562
1945
|
}
|
|
@@ -2351,7 +2734,8 @@ var ScanBuilder = class _ScanBuilder {
|
|
|
2351
2734
|
* evaluates clauses per record in O(1) per clause.
|
|
2352
2735
|
*/
|
|
2353
2736
|
where(field, op, value) {
|
|
2354
|
-
const
|
|
2737
|
+
const desc = this.moneyFields?.[field];
|
|
2738
|
+
const clause = desc ? moneyFieldClause(field, op, value, desc) : { type: "field", field, op, value };
|
|
2355
2739
|
return new _ScanBuilder(
|
|
2356
2740
|
this.pageProvider,
|
|
2357
2741
|
this.pageSize,
|
|
@@ -2697,8 +3081,9 @@ var ScanBuilder = class _ScanBuilder {
|
|
|
2697
3081
|
*/
|
|
2698
3082
|
recordMatches(record) {
|
|
2699
3083
|
if (this.clauses.length === 0) return true;
|
|
3084
|
+
const fnView = this.moneyFields && Object.keys(this.moneyFields).length > 0 && hasFnClause(this.clauses) ? this.decodeMoney(record) : void 0;
|
|
2700
3085
|
for (const clause of this.clauses) {
|
|
2701
|
-
if (!evaluateClause(record, clause)) return false;
|
|
3086
|
+
if (!evaluateClause(record, clause, fnView)) return false;
|
|
2702
3087
|
}
|
|
2703
3088
|
return true;
|
|
2704
3089
|
}
|