@noy-db/hub 0.2.0-pre.14 → 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 +3 -3
- package/dist/attestation/index.d.cts +5 -5
- package/dist/attestation/index.d.ts +5 -5
- package/dist/blobs/index.d.cts +6 -6
- package/dist/blobs/index.d.ts +6 -6
- package/dist/bundle/index.cjs +426 -68
- 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 +1 -1
- package/dist/{chunk-3EWA37FV.js → chunk-3EWXMOK3.js} +7 -266
- package/dist/chunk-3EWXMOK3.js.map +1 -0
- package/dist/{chunk-ACKFRSAH.js → chunk-7EFFHEN5.js} +26 -19
- package/dist/chunk-7EFFHEN5.js.map +1 -0
- package/dist/{chunk-UWNYBOOO.js → chunk-C5T5AFWN.js} +2 -2
- package/dist/chunk-CJORTUJ2.js +524 -0
- package/dist/chunk-CJORTUJ2.js.map +1 -0
- package/dist/{chunk-YNTBADIY.js → chunk-CZI2A4MQ.js} +2 -2
- package/dist/{chunk-KGCORI4L.js → chunk-EYVQHAGH.js} +266 -66
- package/dist/chunk-EYVQHAGH.js.map +1 -0
- package/dist/{chunk-NP6EZT44.js → chunk-IQLVUT37.js} +2 -2
- package/dist/{chunk-4PEFEETV.js → chunk-KIP6JLTF.js} +2 -2
- package/dist/{chunk-ZWTNWAO4.js → chunk-NU6Q3FOR.js} +3 -3
- package/dist/chunk-NU6Q3FOR.js.map +1 -0
- package/dist/{chunk-WIBHRONM.js → chunk-XWH4MXIU.js} +2 -2
- package/dist/consent/index.d.cts +6 -6
- package/dist/consent/index.d.ts +6 -6
- package/dist/derivations/index.d.cts +7 -7
- package/dist/derivations/index.d.ts +7 -7
- package/dist/{dev-unlock-DV7ujTCI.d.ts → dev-unlock-iAS8z9jc.d.ts} +1 -1
- package/dist/{dev-unlock-BF4OSxRv.d.cts → dev-unlock-nVkuRLLe.d.cts} +1 -1
- package/dist/{executor-723ZP6TH.js → executor-HSSRXDOB.js} +4 -4
- package/dist/guards/index.d.cts +7 -7
- package/dist/guards/index.d.ts +7 -7
- package/dist/{hash-BcF5WQXl.d.cts → hash-Cv6byZs7.d.cts} +1 -1
- package/dist/{hash-DswxkLtW.d.ts → hash-DHOnRarj.d.ts} +1 -1
- package/dist/history/index.d.cts +7 -7
- package/dist/history/index.d.ts +7 -7
- package/dist/i18n/index.d.cts +6 -6
- package/dist/i18n/index.d.ts +6 -6
- package/dist/{immutable-guard-C8IYdzfu.d.ts → immutable-guard-BehB1YGB.d.ts} +1 -1
- package/dist/{immutable-guard-7KqslW2K.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 +567 -70
- 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 +132 -16
- 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 +3 -3
- 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/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 +5 -5
- package/dist/{noydb-VZ4JVW55.js → noydb-GZGFBA4E.js} +8 -8
- package/dist/overlay-views/index.d.cts +7 -7
- package/dist/overlay-views/index.d.ts +7 -7
- package/dist/periods/index.d.cts +6 -6
- package/dist/periods/index.d.ts +6 -6
- 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/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 +5 -5
- package/dist/session/index.d.cts +7 -7
- package/dist/session/index.d.ts +7 -7
- package/dist/shadow/index.d.cts +6 -6
- package/dist/shadow/index.d.ts +6 -6
- package/dist/snapshots/index.d.cts +6 -6
- package/dist/snapshots/index.d.ts +6 -6
- package/dist/{stale-7FRJVHN6.js → stale-JH67FU57.js} +2 -2
- package/dist/store/index.d.cts +6 -6
- package/dist/store/index.d.ts +6 -6
- 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.d.cts +5 -5
- package/dist/sync/index.d.ts +5 -5
- package/dist/team/index.d.cts +6 -6
- package/dist/team/index.d.ts +6 -6
- package/dist/tx/index.d.cts +6 -6
- package/dist/tx/index.d.ts +6 -6
- package/dist/{types-BFHQUjdy.d.ts → types-4t1-tWS4.d.ts} +22 -7
- package/dist/{types-V5R2-pd4.d.cts → types-BpPV5uyy.d.cts} +22 -7
- package/dist/{ulid-CwNf9e6-.d.cts → ulid-CiPrpGqm.d.cts} +1 -1
- package/dist/{ulid-p2nKiiKg.d.ts → ulid-DAfenvFd.d.ts} +1 -1
- package/dist/{vault-group-W7QC4UYW.js → vault-group-KOM7QRJG.js} +3 -3
- package/dist/{with-derivation-C9K43BOB.d.cts → with-derivation-DBqJB3dQ.d.cts} +1 -1
- package/dist/{with-derivation-Ds9yZgCj.d.ts → with-derivation-OK9M2sJE.d.ts} +1 -1
- package/dist/{with-materialized-view-DwR4jkV5.d.ts → with-materialized-view-Dt-ufPWQ.d.ts} +1 -1
- package/dist/{with-materialized-view-DgQcAjYv.d.cts → with-materialized-view-NzuxYPDF.d.cts} +1 -1
- package/dist/{with-overlayed-view-7-rUB3vD.d.cts → with-overlayed-view-CC0_ocy-.d.cts} +1 -1
- package/dist/{with-overlayed-view-ByyhHdVr.d.ts → with-overlayed-view-eDvMs6LO.d.ts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-3EWA37FV.js.map +0 -1
- package/dist/chunk-ACKFRSAH.js.map +0 -1
- package/dist/chunk-KGCORI4L.js.map +0 -1
- package/dist/chunk-TV3YZ35S.js +0 -90
- package/dist/chunk-TV3YZ35S.js.map +0 -1
- package/dist/chunk-ZWTNWAO4.js.map +0 -1
- /package/dist/{chunk-UWNYBOOO.js.map → chunk-C5T5AFWN.js.map} +0 -0
- /package/dist/{chunk-YNTBADIY.js.map → chunk-CZI2A4MQ.js.map} +0 -0
- /package/dist/{chunk-NP6EZT44.js.map → chunk-IQLVUT37.js.map} +0 -0
- /package/dist/{chunk-4PEFEETV.js.map → chunk-KIP6JLTF.js.map} +0 -0
- /package/dist/{chunk-WIBHRONM.js.map → chunk-XWH4MXIU.js.map} +0 -0
- /package/dist/{executor-723ZP6TH.js.map → executor-HSSRXDOB.js.map} +0 -0
- /package/dist/{noydb-VZ4JVW55.js.map → noydb-GZGFBA4E.js.map} +0 -0
- /package/dist/{stale-7FRJVHN6.js.map → stale-JH67FU57.js.map} +0 -0
- /package/dist/{vault-group-W7QC4UYW.js.map → vault-group-KOM7QRJG.js.map} +0 -0
package/dist/bundle/index.cjs
CHANGED
|
@@ -3894,6 +3894,115 @@ var init_descriptor = __esm({
|
|
|
3894
3894
|
}
|
|
3895
3895
|
});
|
|
3896
3896
|
|
|
3897
|
+
// src/money/paths.ts
|
|
3898
|
+
function parseMoneyPath(path) {
|
|
3899
|
+
const cached = parseCache.get(path);
|
|
3900
|
+
if (cached) return cached;
|
|
3901
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
3902
|
+
throw new ValidationError("moneyFields: path must be a non-empty string");
|
|
3903
|
+
}
|
|
3904
|
+
const segments = [];
|
|
3905
|
+
for (const part of path.split(".")) {
|
|
3906
|
+
const m = SEGMENT_RE.exec(part);
|
|
3907
|
+
if (!m) {
|
|
3908
|
+
throw new ValidationError(
|
|
3909
|
+
`moneyFields: invalid path "${path}" \u2014 segment "${part}" must be a key, "key[]", "*", or "*[]"`
|
|
3910
|
+
);
|
|
3911
|
+
}
|
|
3912
|
+
const array = m[2] === "[]";
|
|
3913
|
+
segments.push(
|
|
3914
|
+
m[1] === "*" ? { kind: "wildcard", array } : { kind: "key", key: m[1], array }
|
|
3915
|
+
);
|
|
3916
|
+
}
|
|
3917
|
+
parseCache.set(path, segments);
|
|
3918
|
+
return segments;
|
|
3919
|
+
}
|
|
3920
|
+
function isSimpleMoneyPath(path) {
|
|
3921
|
+
return !path.includes(".") && !path.includes("[") && !path.includes("*");
|
|
3922
|
+
}
|
|
3923
|
+
function validateMoneyFieldPaths(moneyFields) {
|
|
3924
|
+
for (const path of Object.keys(moneyFields)) parseMoneyPath(path);
|
|
3925
|
+
}
|
|
3926
|
+
function transformAtMoneyPath(node, path, segments, index, visit, lenient) {
|
|
3927
|
+
if (node === null || node === void 0) return node;
|
|
3928
|
+
const seg = segments[index];
|
|
3929
|
+
const last = index === segments.length - 1;
|
|
3930
|
+
if (seg.kind === "key") {
|
|
3931
|
+
if (typeof node !== "object" || Array.isArray(node)) {
|
|
3932
|
+
if (lenient) return node;
|
|
3933
|
+
throw new ValidationError(
|
|
3934
|
+
`moneyFields: path "${path}" expected an object at segment "${seg.key}", got ${Array.isArray(node) ? "an array" : typeof node}`
|
|
3935
|
+
);
|
|
3936
|
+
}
|
|
3937
|
+
const obj2 = node;
|
|
3938
|
+
if (!(seg.key in obj2) || obj2[seg.key] === null || obj2[seg.key] === void 0) return node;
|
|
3939
|
+
if (seg.array) {
|
|
3940
|
+
const arr = obj2[seg.key];
|
|
3941
|
+
if (!Array.isArray(arr)) {
|
|
3942
|
+
if (lenient) return node;
|
|
3943
|
+
throw new ValidationError(
|
|
3944
|
+
`moneyFields: path "${path}" declares "${seg.key}[]" but the value is not an array`
|
|
3945
|
+
);
|
|
3946
|
+
}
|
|
3947
|
+
const cloned = [...arr];
|
|
3948
|
+
if (last) {
|
|
3949
|
+
for (let i = 0; i < cloned.length; i++) visit(cloned, i);
|
|
3950
|
+
} else {
|
|
3951
|
+
for (let i = 0; i < cloned.length; i++) {
|
|
3952
|
+
cloned[i] = transformAtMoneyPath(cloned[i], path, segments, index + 1, visit, lenient);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
return { ...obj2, [seg.key]: cloned };
|
|
3956
|
+
}
|
|
3957
|
+
const clone3 = { ...obj2 };
|
|
3958
|
+
if (last) {
|
|
3959
|
+
visit(clone3, seg.key);
|
|
3960
|
+
} else {
|
|
3961
|
+
clone3[seg.key] = transformAtMoneyPath(clone3[seg.key], path, segments, index + 1, visit, lenient);
|
|
3962
|
+
}
|
|
3963
|
+
return clone3;
|
|
3964
|
+
}
|
|
3965
|
+
if (seg.array) {
|
|
3966
|
+
if (!Array.isArray(node)) {
|
|
3967
|
+
if (lenient) return node;
|
|
3968
|
+
throw new ValidationError(`moneyFields: path "${path}" declares "*[]" but the value is not an array`);
|
|
3969
|
+
}
|
|
3970
|
+
const cloned = [...node];
|
|
3971
|
+
if (last) {
|
|
3972
|
+
for (let i = 0; i < cloned.length; i++) visit(cloned, i);
|
|
3973
|
+
} else {
|
|
3974
|
+
for (let i = 0; i < cloned.length; i++) {
|
|
3975
|
+
cloned[i] = transformAtMoneyPath(cloned[i], path, segments, index + 1, visit, lenient);
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
return cloned;
|
|
3979
|
+
}
|
|
3980
|
+
if (typeof node !== "object" || Array.isArray(node)) {
|
|
3981
|
+
if (lenient) return node;
|
|
3982
|
+
throw new ValidationError(
|
|
3983
|
+
`moneyFields: path "${path}" applies "*" to a non-object (${Array.isArray(node) ? 'array \u2014 use "*[]"' : typeof node})`
|
|
3984
|
+
);
|
|
3985
|
+
}
|
|
3986
|
+
const obj = node;
|
|
3987
|
+
const clone2 = { ...obj };
|
|
3988
|
+
for (const key of Object.keys(obj)) {
|
|
3989
|
+
const v = clone2[key];
|
|
3990
|
+
if (v === null || v === void 0) continue;
|
|
3991
|
+
if (last) visit(clone2, key);
|
|
3992
|
+
else clone2[key] = transformAtMoneyPath(v, path, segments, index + 1, visit, lenient);
|
|
3993
|
+
}
|
|
3994
|
+
return clone2;
|
|
3995
|
+
}
|
|
3996
|
+
var SEGMENT_RE, parseCache;
|
|
3997
|
+
var init_paths = __esm({
|
|
3998
|
+
"src/money/paths.ts"() {
|
|
3999
|
+
"use strict";
|
|
4000
|
+
init_errors();
|
|
4001
|
+
SEGMENT_RE = /^(\*|[^.[\]*]+)(\[\])?$/;
|
|
4002
|
+
parseCache = /* @__PURE__ */ new Map();
|
|
4003
|
+
}
|
|
4004
|
+
});
|
|
4005
|
+
|
|
3897
4006
|
// src/money/normalize.ts
|
|
3898
4007
|
function isMoneyValueObject(v) {
|
|
3899
4008
|
return typeof v === "object" && v !== null && "currency" in v;
|
|
@@ -3906,33 +4015,68 @@ function quantizeAmount(field, input, scale, rounding) {
|
|
|
3906
4015
|
}
|
|
3907
4016
|
return r.value.toString();
|
|
3908
4017
|
}
|
|
4018
|
+
function canonicalizeStoredMoney(record, moneyFields) {
|
|
4019
|
+
if (record === null || record === void 0) return record;
|
|
4020
|
+
if (!moneyFields || Object.keys(moneyFields).length === 0) return record;
|
|
4021
|
+
return decodeMoneyFields(record, moneyFields, "raw");
|
|
4022
|
+
}
|
|
4023
|
+
function canonicalizeIncomingMoney(record, moneyFields) {
|
|
4024
|
+
if (!moneyFields || Object.keys(moneyFields).length === 0) return record;
|
|
4025
|
+
try {
|
|
4026
|
+
return decodeMoneyFields(
|
|
4027
|
+
quantizeMoneyFields(record, moneyFields),
|
|
4028
|
+
moneyFields,
|
|
4029
|
+
"raw"
|
|
4030
|
+
);
|
|
4031
|
+
} catch {
|
|
4032
|
+
return record;
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
function quantizeValue(field, raw, desc) {
|
|
4036
|
+
if (desc.mode === "fixed") {
|
|
4037
|
+
const currency2 = desc.fixedCurrency;
|
|
4038
|
+
return quantizeAmount(field, raw, desc.scaleFor(currency2), desc.rounding);
|
|
4039
|
+
}
|
|
4040
|
+
let amount;
|
|
4041
|
+
let currency;
|
|
4042
|
+
if (isMoneyValueObject(raw)) {
|
|
4043
|
+
currency = String(raw.currency);
|
|
4044
|
+
amount = raw.amount;
|
|
4045
|
+
} else {
|
|
4046
|
+
const sole = desc.soleCurrency();
|
|
4047
|
+
if (sole === void 0) {
|
|
4048
|
+
throw new TypeError(
|
|
4049
|
+
`money: field "${field}" is multi-currency \u2014 write { amount, currency }, not a bare amount`
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4052
|
+
currency = sole;
|
|
4053
|
+
amount = raw;
|
|
4054
|
+
}
|
|
4055
|
+
const scale = desc.scaleFor(currency);
|
|
4056
|
+
return { amount: quantizeAmount(field, amount, scale, desc.rounding), currency };
|
|
4057
|
+
}
|
|
3909
4058
|
function quantizeMoneyFields(record, moneyFields) {
|
|
3910
|
-
|
|
3911
|
-
for (const [
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
out[field] = quantizeAmount(field, raw, desc.scaleFor(currency2), desc.rounding);
|
|
4059
|
+
let out = { ...record };
|
|
4060
|
+
for (const [path, desc] of Object.entries(moneyFields)) {
|
|
4061
|
+
if (isSimpleMoneyPath(path)) {
|
|
4062
|
+
const raw = out[path];
|
|
4063
|
+
if (raw === null || raw === void 0) continue;
|
|
4064
|
+
out[path] = quantizeValue(path, raw, desc);
|
|
3917
4065
|
continue;
|
|
3918
4066
|
}
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
amount = raw;
|
|
3933
|
-
}
|
|
3934
|
-
const scale = desc.scaleFor(currency);
|
|
3935
|
-
out[field] = { amount: quantizeAmount(field, amount, scale, desc.rounding), currency };
|
|
4067
|
+
out = transformAtMoneyPath(
|
|
4068
|
+
out,
|
|
4069
|
+
path,
|
|
4070
|
+
parseMoneyPath(path),
|
|
4071
|
+
0,
|
|
4072
|
+
(container, key) => {
|
|
4073
|
+
const raw = container[key];
|
|
4074
|
+
if (raw === null || raw === void 0) return;
|
|
4075
|
+
container[key] = quantizeValue(path, raw, desc);
|
|
4076
|
+
},
|
|
4077
|
+
/* lenient */
|
|
4078
|
+
false
|
|
4079
|
+
);
|
|
3936
4080
|
}
|
|
3937
4081
|
return out;
|
|
3938
4082
|
}
|
|
@@ -3945,33 +4089,70 @@ function formatCurrency(decimal, currency, scale, locale) {
|
|
|
3945
4089
|
});
|
|
3946
4090
|
return fmt.format(decimal);
|
|
3947
4091
|
}
|
|
4092
|
+
function decodeValue(stored, desc) {
|
|
4093
|
+
let currency;
|
|
4094
|
+
let scaledIntString;
|
|
4095
|
+
if (desc.mode === "fixed") {
|
|
4096
|
+
if (typeof stored !== "string" && typeof stored !== "number") return null;
|
|
4097
|
+
currency = desc.fixedCurrency;
|
|
4098
|
+
scaledIntString = String(stored);
|
|
4099
|
+
} else {
|
|
4100
|
+
if (!isMoneyValueObject(stored)) return null;
|
|
4101
|
+
const amount = stored.amount;
|
|
4102
|
+
if (typeof stored.currency !== "string" || typeof amount !== "string" && typeof amount !== "number") return null;
|
|
4103
|
+
currency = stored.currency;
|
|
4104
|
+
scaledIntString = String(amount);
|
|
4105
|
+
}
|
|
4106
|
+
const scale = desc.scaleFor(currency);
|
|
4107
|
+
let decimal;
|
|
4108
|
+
try {
|
|
4109
|
+
decimal = formatScaledInt(BigInt(scaledIntString), scale);
|
|
4110
|
+
} catch {
|
|
4111
|
+
return null;
|
|
4112
|
+
}
|
|
4113
|
+
return {
|
|
4114
|
+
decoded: desc.mode === "fixed" ? decimal : { amount: decimal, currency },
|
|
4115
|
+
decimal,
|
|
4116
|
+
currency,
|
|
4117
|
+
scale
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
3948
4120
|
function decodeMoneyFields(record, moneyFields, locale) {
|
|
3949
|
-
|
|
4121
|
+
let out = { ...record };
|
|
3950
4122
|
const format = locale !== "raw";
|
|
3951
4123
|
const fmtLocale = typeof locale === "string" && locale !== "raw" ? locale : "en-US";
|
|
3952
|
-
for (const [
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
if (typeof stored.currency !== "string" || typeof amount !== "string" && typeof amount !== "number") continue;
|
|
3965
|
-
currency = stored.currency;
|
|
3966
|
-
scaledIntString = String(amount);
|
|
3967
|
-
}
|
|
3968
|
-
const scale = desc.scaleFor(currency);
|
|
3969
|
-
const decimal = formatScaledInt(BigInt(scaledIntString), scale);
|
|
3970
|
-
out[field] = desc.mode === "fixed" ? decimal : { amount: decimal, currency };
|
|
3971
|
-
if (format) {
|
|
3972
|
-
out[`${field}Formatted`] = formatCurrency(decimal, currency, scale, fmtLocale);
|
|
3973
|
-
out[`${field}Number`] = Number(decimal);
|
|
4124
|
+
for (const [path, desc] of Object.entries(moneyFields)) {
|
|
4125
|
+
if (isSimpleMoneyPath(path)) {
|
|
4126
|
+
const stored = out[path];
|
|
4127
|
+
if (stored === null || stored === void 0) continue;
|
|
4128
|
+
const r = decodeValue(stored, desc);
|
|
4129
|
+
if (r === null) continue;
|
|
4130
|
+
out[path] = r.decoded;
|
|
4131
|
+
if (format) {
|
|
4132
|
+
out[`${path}Formatted`] = formatCurrency(r.decimal, r.currency, r.scale, fmtLocale);
|
|
4133
|
+
out[`${path}Number`] = Number(r.decimal);
|
|
4134
|
+
}
|
|
4135
|
+
continue;
|
|
3974
4136
|
}
|
|
4137
|
+
out = transformAtMoneyPath(
|
|
4138
|
+
out,
|
|
4139
|
+
path,
|
|
4140
|
+
parseMoneyPath(path),
|
|
4141
|
+
0,
|
|
4142
|
+
(container, key) => {
|
|
4143
|
+
const stored = container[key];
|
|
4144
|
+
if (stored === null || stored === void 0) return;
|
|
4145
|
+
const r = decodeValue(stored, desc);
|
|
4146
|
+
if (r === null) return;
|
|
4147
|
+
container[key] = r.decoded;
|
|
4148
|
+
if (format && typeof key === "string" && !Array.isArray(container)) {
|
|
4149
|
+
container[`${key}Formatted`] = formatCurrency(r.decimal, r.currency, r.scale, fmtLocale);
|
|
4150
|
+
container[`${key}Number`] = Number(r.decimal);
|
|
4151
|
+
}
|
|
4152
|
+
},
|
|
4153
|
+
/* lenient */
|
|
4154
|
+
true
|
|
4155
|
+
);
|
|
3975
4156
|
}
|
|
3976
4157
|
return out;
|
|
3977
4158
|
}
|
|
@@ -3980,6 +4161,7 @@ var init_normalize = __esm({
|
|
|
3980
4161
|
"use strict";
|
|
3981
4162
|
init_fixed_point();
|
|
3982
4163
|
init_descriptor();
|
|
4164
|
+
init_paths();
|
|
3983
4165
|
}
|
|
3984
4166
|
});
|
|
3985
4167
|
|
|
@@ -4152,6 +4334,146 @@ var init_strategy3 = __esm({
|
|
|
4152
4334
|
}
|
|
4153
4335
|
});
|
|
4154
4336
|
|
|
4337
|
+
// src/money/where.ts
|
|
4338
|
+
function isMoneyValueObject2(v) {
|
|
4339
|
+
return typeof v === "object" && v !== null && "currency" in v;
|
|
4340
|
+
}
|
|
4341
|
+
function parseOperand(field, raw, desc) {
|
|
4342
|
+
let amount;
|
|
4343
|
+
let currency;
|
|
4344
|
+
if (desc.mode === "fixed") {
|
|
4345
|
+
currency = desc.fixedCurrency;
|
|
4346
|
+
amount = raw;
|
|
4347
|
+
} else if (isMoneyValueObject2(raw)) {
|
|
4348
|
+
currency = String(raw.currency);
|
|
4349
|
+
amount = raw.amount;
|
|
4350
|
+
} else {
|
|
4351
|
+
const sole = desc.soleCurrency();
|
|
4352
|
+
if (sole === void 0) {
|
|
4353
|
+
throw new MoneyUnsupportedError(
|
|
4354
|
+
`where("${field}"): field is multi-currency \u2014 compare against { amount, currency }, not a bare amount`
|
|
4355
|
+
);
|
|
4356
|
+
}
|
|
4357
|
+
currency = sole;
|
|
4358
|
+
amount = raw;
|
|
4359
|
+
}
|
|
4360
|
+
if (typeof amount !== "number" && typeof amount !== "string") {
|
|
4361
|
+
throw new MoneyUnsupportedError(
|
|
4362
|
+
`where("${field}"): operand ${JSON.stringify(raw)} is not a money amount`
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
const r = parseToScaledInt(amount, desc.scaleFor(currency), desc.rounding);
|
|
4366
|
+
if (!r.ok) {
|
|
4367
|
+
throw new MoneyUnsupportedError(
|
|
4368
|
+
`where("${field}"): operand ${JSON.stringify(amount)} is not a finite decimal`
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
return { scaled: r.value.toString(), currency };
|
|
4372
|
+
}
|
|
4373
|
+
function moneyFieldClause(field, op, value, desc) {
|
|
4374
|
+
switch (op) {
|
|
4375
|
+
case "==":
|
|
4376
|
+
case "!=":
|
|
4377
|
+
case "<":
|
|
4378
|
+
case "<=":
|
|
4379
|
+
case ">":
|
|
4380
|
+
case ">=": {
|
|
4381
|
+
const e = parseOperand(field, value, desc);
|
|
4382
|
+
return withMoney(field, op, value, desc, [e]);
|
|
4383
|
+
}
|
|
4384
|
+
case "between": {
|
|
4385
|
+
if (!Array.isArray(value) || value.length !== 2) {
|
|
4386
|
+
throw new MoneyUnsupportedError(`where("${field}"): 'between' needs a [lo, hi] tuple`);
|
|
4387
|
+
}
|
|
4388
|
+
const lo = parseOperand(field, value[0], desc);
|
|
4389
|
+
const hi = parseOperand(field, value[1], desc);
|
|
4390
|
+
if (lo.currency !== hi.currency) {
|
|
4391
|
+
throw new MoneyUnsupportedError(
|
|
4392
|
+
`where("${field}"): 'between' bounds mix currencies (${lo.currency} vs ${hi.currency})`
|
|
4393
|
+
);
|
|
4394
|
+
}
|
|
4395
|
+
return withMoney(field, op, value, desc, [lo, hi]);
|
|
4396
|
+
}
|
|
4397
|
+
case "in": {
|
|
4398
|
+
if (!Array.isArray(value)) {
|
|
4399
|
+
throw new MoneyUnsupportedError(`where("${field}"): 'in' needs an array of amounts`);
|
|
4400
|
+
}
|
|
4401
|
+
return withMoney(field, op, value, desc, value.map((v) => parseOperand(field, v, desc)));
|
|
4402
|
+
}
|
|
4403
|
+
default:
|
|
4404
|
+
throw new MoneyUnsupportedError(
|
|
4405
|
+
`where("${field}"): operator '${op}' is not supported on a money field`
|
|
4406
|
+
);
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4409
|
+
function withMoney(field, op, originalValue, desc, entries) {
|
|
4410
|
+
const money = { mode: desc.mode, entries };
|
|
4411
|
+
const value = desc.mode !== "fixed" ? originalValue : entries.length === 1 && op !== "in" && op !== "between" ? entries[0].scaled : entries.map((e) => e.scaled);
|
|
4412
|
+
return { type: "field", field, op, value, money };
|
|
4413
|
+
}
|
|
4414
|
+
function readStored(actual, operand) {
|
|
4415
|
+
let amount;
|
|
4416
|
+
let currency;
|
|
4417
|
+
if (operand.mode === "fixed") {
|
|
4418
|
+
if (typeof actual !== "string" && typeof actual !== "number") return null;
|
|
4419
|
+
amount = actual;
|
|
4420
|
+
currency = operand.entries[0]?.currency ?? "";
|
|
4421
|
+
} else {
|
|
4422
|
+
if (!isMoneyValueObject2(actual)) return null;
|
|
4423
|
+
if (typeof actual.currency !== "string") return null;
|
|
4424
|
+
amount = actual.amount;
|
|
4425
|
+
currency = actual.currency;
|
|
4426
|
+
}
|
|
4427
|
+
if (typeof amount !== "string" && typeof amount !== "number") return null;
|
|
4428
|
+
try {
|
|
4429
|
+
return { scaled: BigInt(amount).toString(), currency };
|
|
4430
|
+
} catch {
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
function evaluateMoneyClause(actual, op, operand) {
|
|
4435
|
+
const stored = readStored(actual, operand);
|
|
4436
|
+
if (stored === null) return op === "!=";
|
|
4437
|
+
const a = BigInt(stored.scaled);
|
|
4438
|
+
if (op === "in") {
|
|
4439
|
+
return operand.entries.some(
|
|
4440
|
+
(e2) => e2.currency === stored.currency && BigInt(e2.scaled) === a
|
|
4441
|
+
);
|
|
4442
|
+
}
|
|
4443
|
+
if (op === "between") {
|
|
4444
|
+
const [lo, hi] = operand.entries;
|
|
4445
|
+
if (!lo || !hi || lo.currency !== stored.currency) return false;
|
|
4446
|
+
return a >= BigInt(lo.scaled) && a <= BigInt(hi.scaled);
|
|
4447
|
+
}
|
|
4448
|
+
const e = operand.entries[0];
|
|
4449
|
+
if (!e) return false;
|
|
4450
|
+
if (e.currency !== stored.currency) return op === "!=";
|
|
4451
|
+
const b = BigInt(e.scaled);
|
|
4452
|
+
switch (op) {
|
|
4453
|
+
case "==":
|
|
4454
|
+
return a === b;
|
|
4455
|
+
case "!=":
|
|
4456
|
+
return a !== b;
|
|
4457
|
+
case "<":
|
|
4458
|
+
return a < b;
|
|
4459
|
+
case "<=":
|
|
4460
|
+
return a <= b;
|
|
4461
|
+
case ">":
|
|
4462
|
+
return a > b;
|
|
4463
|
+
case ">=":
|
|
4464
|
+
return a >= b;
|
|
4465
|
+
default:
|
|
4466
|
+
return false;
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
var init_where = __esm({
|
|
4470
|
+
"src/money/where.ts"() {
|
|
4471
|
+
"use strict";
|
|
4472
|
+
init_fixed_point();
|
|
4473
|
+
init_descriptor();
|
|
4474
|
+
}
|
|
4475
|
+
});
|
|
4476
|
+
|
|
4155
4477
|
// src/query/predicate.ts
|
|
4156
4478
|
function readPath(record, path) {
|
|
4157
4479
|
if (record === null || record === void 0) return void 0;
|
|
@@ -4169,6 +4491,7 @@ function readPath(record, path) {
|
|
|
4169
4491
|
function evaluateFieldClause(record, clause) {
|
|
4170
4492
|
const actual = readPath(record, clause.field);
|
|
4171
4493
|
const { op, value } = clause;
|
|
4494
|
+
if (clause.money) return evaluateMoneyClause(actual, op, clause.money);
|
|
4172
4495
|
switch (op) {
|
|
4173
4496
|
case "==":
|
|
4174
4497
|
return actual === value;
|
|
@@ -4209,14 +4532,14 @@ function isComparable(a, b) {
|
|
|
4209
4532
|
if (a instanceof Date && b instanceof Date) return true;
|
|
4210
4533
|
return false;
|
|
4211
4534
|
}
|
|
4212
|
-
function evaluateClause(record, clause) {
|
|
4535
|
+
function evaluateClause(record, clause, fnRecord) {
|
|
4213
4536
|
switch (clause.type) {
|
|
4214
4537
|
case "field":
|
|
4215
4538
|
return evaluateFieldClause(record, clause);
|
|
4216
4539
|
case "filter":
|
|
4217
|
-
return clause.fn(record);
|
|
4540
|
+
return clause.fn(fnRecord !== void 0 ? fnRecord : record);
|
|
4218
4541
|
case "wherePredicate":
|
|
4219
|
-
return clause.fn(record, clause.ctx);
|
|
4542
|
+
return clause.fn(fnRecord !== void 0 ? fnRecord : record, clause.ctx);
|
|
4220
4543
|
case "crossJoin":
|
|
4221
4544
|
throw new Error(
|
|
4222
4545
|
`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.`
|
|
@@ -4224,20 +4547,28 @@ function evaluateClause(record, clause) {
|
|
|
4224
4547
|
case "group":
|
|
4225
4548
|
if (clause.op === "and") {
|
|
4226
4549
|
for (const child of clause.clauses) {
|
|
4227
|
-
if (!evaluateClause(record, child)) return false;
|
|
4550
|
+
if (!evaluateClause(record, child, fnRecord)) return false;
|
|
4228
4551
|
}
|
|
4229
4552
|
return true;
|
|
4230
4553
|
} else {
|
|
4231
4554
|
for (const child of clause.clauses) {
|
|
4232
|
-
if (evaluateClause(record, child)) return true;
|
|
4555
|
+
if (evaluateClause(record, child, fnRecord)) return true;
|
|
4233
4556
|
}
|
|
4234
4557
|
return false;
|
|
4235
4558
|
}
|
|
4236
4559
|
}
|
|
4237
4560
|
}
|
|
4561
|
+
function hasFnClause(clauses) {
|
|
4562
|
+
for (const c of clauses) {
|
|
4563
|
+
if (c.type === "filter" || c.type === "wherePredicate") return true;
|
|
4564
|
+
if (c.type === "group" && hasFnClause(c.clauses)) return true;
|
|
4565
|
+
}
|
|
4566
|
+
return false;
|
|
4567
|
+
}
|
|
4238
4568
|
var init_predicate = __esm({
|
|
4239
4569
|
"src/query/predicate.ts"() {
|
|
4240
4570
|
"use strict";
|
|
4571
|
+
init_where();
|
|
4241
4572
|
}
|
|
4242
4573
|
});
|
|
4243
4574
|
|
|
@@ -4698,7 +5029,7 @@ function executePlanWithSource(source, plan, joinContext) {
|
|
|
4698
5029
|
result = executeClausePipeline(source, plan.clauses, joinContext);
|
|
4699
5030
|
} else {
|
|
4700
5031
|
const { candidates, remainingClauses } = candidateRecords(source, plan.clauses);
|
|
4701
|
-
result = remainingClauses.length === 0 ? [...candidates] : filterRecords(candidates, remainingClauses);
|
|
5032
|
+
result = remainingClauses.length === 0 ? [...candidates] : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
4702
5033
|
}
|
|
4703
5034
|
if (plan.orderBy.length > 0) {
|
|
4704
5035
|
result = sortRecords(result, plan.orderBy);
|
|
@@ -4721,6 +5052,7 @@ function candidateRecords(source, clauses) {
|
|
|
4721
5052
|
const clause = clauses[i];
|
|
4722
5053
|
if (clause.type !== "field") continue;
|
|
4723
5054
|
if (!indexes.has(clause.field)) continue;
|
|
5055
|
+
if (clause.money?.mode === "multi") continue;
|
|
4724
5056
|
let ids = null;
|
|
4725
5057
|
if (clause.op === "==") {
|
|
4726
5058
|
ids = indexes.lookupEqual(clause.field, clause.value);
|
|
@@ -4748,13 +5080,20 @@ function materializeIds(ids, lookupById) {
|
|
|
4748
5080
|
}
|
|
4749
5081
|
return out;
|
|
4750
5082
|
}
|
|
4751
|
-
function
|
|
5083
|
+
function fnViewDecoder(source) {
|
|
5084
|
+
const mf = source.moneyFields;
|
|
5085
|
+
if (!mf || Object.keys(mf).length === 0) return void 0;
|
|
5086
|
+
return (r) => decodeMoneyFields(r, mf, "raw");
|
|
5087
|
+
}
|
|
5088
|
+
function filterRecords(records, clauses, decodeForFns) {
|
|
4752
5089
|
if (clauses.length === 0) return [...records];
|
|
5090
|
+
const needsFnView = decodeForFns !== void 0 && hasFnClause(clauses);
|
|
4753
5091
|
const out = [];
|
|
4754
5092
|
for (const r of records) {
|
|
5093
|
+
const fnView = needsFnView ? decodeForFns(r) : void 0;
|
|
4755
5094
|
let matches = true;
|
|
4756
5095
|
for (const clause of clauses) {
|
|
4757
|
-
if (!evaluateClause(r, clause)) {
|
|
5096
|
+
if (!evaluateClause(r, clause, fnView)) {
|
|
4758
5097
|
matches = false;
|
|
4759
5098
|
break;
|
|
4760
5099
|
}
|
|
@@ -4766,10 +5105,11 @@ function filterRecords(records, clauses) {
|
|
|
4766
5105
|
function executeClausePipeline(source, clauses, joinContext) {
|
|
4767
5106
|
let rel = [...source.snapshot()];
|
|
4768
5107
|
let filterBatch = [];
|
|
5108
|
+
const decodeForFns = fnViewDecoder(source);
|
|
4769
5109
|
for (const clause of clauses) {
|
|
4770
5110
|
if (clause.type === "crossJoin") {
|
|
4771
5111
|
if (filterBatch.length > 0) {
|
|
4772
|
-
rel = filterRecords(rel, filterBatch);
|
|
5112
|
+
rel = filterRecords(rel, filterBatch, decodeForFns);
|
|
4773
5113
|
filterBatch = [];
|
|
4774
5114
|
}
|
|
4775
5115
|
const rightSource = joinContext.resolveSource(clause.target);
|
|
@@ -4782,7 +5122,7 @@ function executeClausePipeline(source, clauses, joinContext) {
|
|
|
4782
5122
|
}
|
|
4783
5123
|
}
|
|
4784
5124
|
if (filterBatch.length > 0) {
|
|
4785
|
-
rel = filterRecords(rel, filterBatch);
|
|
5125
|
+
rel = filterRecords(rel, filterBatch, decodeForFns);
|
|
4786
5126
|
}
|
|
4787
5127
|
return rel;
|
|
4788
5128
|
}
|
|
@@ -4963,6 +5303,7 @@ var init_builder = __esm({
|
|
|
4963
5303
|
init_strategy4();
|
|
4964
5304
|
init_money_reducer();
|
|
4965
5305
|
init_normalize();
|
|
5306
|
+
init_where();
|
|
4966
5307
|
EMPTY_PLAN = {
|
|
4967
5308
|
clauses: [],
|
|
4968
5309
|
orderBy: [],
|
|
@@ -5054,9 +5395,18 @@ var init_builder = __esm({
|
|
|
5054
5395
|
this.predicates
|
|
5055
5396
|
);
|
|
5056
5397
|
}
|
|
5057
|
-
/**
|
|
5398
|
+
/**
|
|
5399
|
+
* Add a field comparison. Multiple where() calls are AND-combined.
|
|
5400
|
+
*
|
|
5401
|
+
* A declared money field compares in MAJOR units (#336): the operand
|
|
5402
|
+
* (`10000`, `'10000.00'`, or `{ amount, currency }` in multi mode) is
|
|
5403
|
+
* quantized into stored scaled-int space at build time and evaluated
|
|
5404
|
+
* BigInt-exact per record. A malformed operand or a string operator
|
|
5405
|
+
* (`contains`/`startsWith`) throws here, at the call site.
|
|
5406
|
+
*/
|
|
5058
5407
|
where(field, op, value) {
|
|
5059
|
-
const
|
|
5408
|
+
const desc = this.source.moneyFields?.[field];
|
|
5409
|
+
const clause = desc ? moneyFieldClause(field, op, value, desc) : { type: "field", field, op, value };
|
|
5060
5410
|
return new _Query(
|
|
5061
5411
|
this.source,
|
|
5062
5412
|
{ ...this.plan, clauses: [...this.plan.clauses, clause] },
|
|
@@ -5382,7 +5732,7 @@ var init_builder = __esm({
|
|
|
5382
5732
|
}
|
|
5383
5733
|
const { candidates, remainingClauses } = candidateRecords(this.source, this.plan.clauses);
|
|
5384
5734
|
if (remainingClauses.length === 0) return candidates.length;
|
|
5385
|
-
return filterRecords(candidates, remainingClauses).length;
|
|
5735
|
+
return filterRecords(candidates, remainingClauses, fnViewDecoder(this.source)).length;
|
|
5386
5736
|
}
|
|
5387
5737
|
/**
|
|
5388
5738
|
* Reduce the matching records through a named set of reducers.
|
|
@@ -5439,7 +5789,7 @@ var init_builder = __esm({
|
|
|
5439
5789
|
return executeClausePipeline(source, clauses, joinCtx);
|
|
5440
5790
|
}
|
|
5441
5791
|
const { candidates, remainingClauses } = candidateRecords(source, clauses);
|
|
5442
|
-
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses);
|
|
5792
|
+
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
5443
5793
|
};
|
|
5444
5794
|
const upstreams = [];
|
|
5445
5795
|
if (source.subscribe) {
|
|
@@ -5462,7 +5812,7 @@ var init_builder = __esm({
|
|
|
5462
5812
|
return executeClausePipeline(source, clauses, joinCtx);
|
|
5463
5813
|
}
|
|
5464
5814
|
const { candidates, remainingClauses } = candidateRecords(source, clauses);
|
|
5465
|
-
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses);
|
|
5815
|
+
return remainingClauses.length === 0 ? candidates : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
|
|
5466
5816
|
};
|
|
5467
5817
|
const upstreams = [];
|
|
5468
5818
|
if (source.subscribe) {
|
|
@@ -5735,6 +6085,7 @@ var init_scan_builder = __esm({
|
|
|
5735
6085
|
init_predicate();
|
|
5736
6086
|
init_errors();
|
|
5737
6087
|
init_normalize();
|
|
6088
|
+
init_where();
|
|
5738
6089
|
DEFAULT_SCAN_PAGE_SIZE = 100;
|
|
5739
6090
|
ScanBuilder = class _ScanBuilder {
|
|
5740
6091
|
pageProvider;
|
|
@@ -5798,7 +6149,8 @@ var init_scan_builder = __esm({
|
|
|
5798
6149
|
* evaluates clauses per record in O(1) per clause.
|
|
5799
6150
|
*/
|
|
5800
6151
|
where(field, op, value) {
|
|
5801
|
-
const
|
|
6152
|
+
const desc = this.moneyFields?.[field];
|
|
6153
|
+
const clause = desc ? moneyFieldClause(field, op, value, desc) : { type: "field", field, op, value };
|
|
5802
6154
|
return new _ScanBuilder(
|
|
5803
6155
|
this.pageProvider,
|
|
5804
6156
|
this.pageSize,
|
|
@@ -6144,8 +6496,9 @@ var init_scan_builder = __esm({
|
|
|
6144
6496
|
*/
|
|
6145
6497
|
recordMatches(record) {
|
|
6146
6498
|
if (this.clauses.length === 0) return true;
|
|
6499
|
+
const fnView = this.moneyFields && Object.keys(this.moneyFields).length > 0 && hasFnClause(this.clauses) ? this.decodeMoney(record) : void 0;
|
|
6147
6500
|
for (const clause of this.clauses) {
|
|
6148
|
-
if (!evaluateClause(record, clause)) return false;
|
|
6501
|
+
if (!evaluateClause(record, clause, fnView)) return false;
|
|
6149
6502
|
}
|
|
6150
6503
|
return true;
|
|
6151
6504
|
}
|
|
@@ -7686,6 +8039,7 @@ var init_collection = __esm({
|
|
|
7686
8039
|
init_strategy();
|
|
7687
8040
|
init_core();
|
|
7688
8041
|
init_normalize();
|
|
8042
|
+
init_paths();
|
|
7689
8043
|
init_computed();
|
|
7690
8044
|
init_strategy2();
|
|
7691
8045
|
init_policy();
|
|
@@ -8008,6 +8362,7 @@ var init_collection = __esm({
|
|
|
8008
8362
|
this.joinResolver = opts.joinResolver;
|
|
8009
8363
|
this.i18nFields = opts.i18nFields;
|
|
8010
8364
|
this.dictKeyFields = opts.dictKeyFields;
|
|
8365
|
+
if (opts.moneyFields) validateMoneyFieldPaths(opts.moneyFields);
|
|
8011
8366
|
this.moneyFields = opts.moneyFields;
|
|
8012
8367
|
this.computed = opts.computed;
|
|
8013
8368
|
this.dictLabelResolver = opts.dictLabelResolver;
|
|
@@ -8141,7 +8496,9 @@ var init_collection = __esm({
|
|
|
8141
8496
|
* declaration; this reconciles that ordering. First-wins. Not public.
|
|
8142
8497
|
*/
|
|
8143
8498
|
_applyMoneyFields(moneyFields) {
|
|
8144
|
-
if (this.moneyFields
|
|
8499
|
+
if (this.moneyFields !== void 0) return;
|
|
8500
|
+
validateMoneyFieldPaths(moneyFields);
|
|
8501
|
+
this.moneyFields = moneyFields;
|
|
8145
8502
|
}
|
|
8146
8503
|
/** @internal — attach computed fields post-construction. See {@link _applyMoneyFields}. */
|
|
8147
8504
|
_applyComputed(computed) {
|
|
@@ -8308,6 +8665,7 @@ var init_collection = __esm({
|
|
|
8308
8665
|
if (!hasWritePermission(this.keyring, this.name)) {
|
|
8309
8666
|
throw new ReadOnlyError();
|
|
8310
8667
|
}
|
|
8668
|
+
record = canonicalizeIncomingMoney(record, this.moneyFields);
|
|
8311
8669
|
if (this.subsystemBus?.hasGateHandlers("beforePut")) {
|
|
8312
8670
|
const existingEnv = await this.adapter.get(this.vault, this.name, id);
|
|
8313
8671
|
let existingRecord = null;
|
|
@@ -8324,7 +8682,7 @@ var init_collection = __esm({
|
|
|
8324
8682
|
collection: this.name,
|
|
8325
8683
|
docId: id,
|
|
8326
8684
|
incoming: record,
|
|
8327
|
-
existing: existingRecord,
|
|
8685
|
+
existing: canonicalizeStoredMoney(existingRecord, this.moneyFields),
|
|
8328
8686
|
existingVersion: existingEnv?._v ?? 0,
|
|
8329
8687
|
existingTs: existingEnv?._ts,
|
|
8330
8688
|
userId: this.keyring.userId,
|
|
@@ -8593,7 +8951,7 @@ var init_collection = __esm({
|
|
|
8593
8951
|
*/
|
|
8594
8952
|
async dispatchDerivations(id, record, version) {
|
|
8595
8953
|
if (this.derivationSource === void 0) return;
|
|
8596
|
-
const incoming = record;
|
|
8954
|
+
const incoming = canonicalizeStoredMoney(record, this.moneyFields);
|
|
8597
8955
|
if (incoming && typeof incoming === "object" && "_derivedFrom" in incoming) return;
|
|
8598
8956
|
const registry = this.derivationSource.registry();
|
|
8599
8957
|
const strategies = registry.strategiesForSource(this.name);
|
|
@@ -8826,7 +9184,7 @@ var init_collection = __esm({
|
|
|
8826
9184
|
vault: this.vault,
|
|
8827
9185
|
collection: this.name,
|
|
8828
9186
|
docId: id,
|
|
8829
|
-
existing: existingRecord,
|
|
9187
|
+
existing: canonicalizeStoredMoney(existingRecord, this.moneyFields),
|
|
8830
9188
|
existingVersion: existingEnv._v,
|
|
8831
9189
|
existingTs: existingEnv._ts,
|
|
8832
9190
|
internal,
|