@vuu-ui/vuu-utils 3.5.16 → 3.5.18-beta.1
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/package.json +6 -6
- package/src/ScaledDecimal.js +0 -1
- package/src/filters/filterAsQuery.js +12 -3
- package/src/filters/index.js +1 -0
- package/src/filters/scaled-decimal-filter.js +130 -0
- package/src/form-utils.js +10 -4
- package/src/round-decimal.js +31 -5
- package/types/filters/filterAsQuery.d.ts +3 -2
- package/types/filters/index.d.ts +1 -0
- package/types/filters/scaled-decimal-filter.d.ts +58 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.5.
|
|
2
|
+
"version": "3.5.18-beta.1",
|
|
3
3
|
"author": "heswell",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@dnd-kit/react": "^0.1.21",
|
|
18
|
-
"@vuu-ui/vuu-data-types": "3.5.
|
|
19
|
-
"@vuu-ui/vuu-table-types": "3.5.
|
|
20
|
-
"@vuu-ui/vuu-filter-types": "3.5.
|
|
21
|
-
"@vuu-ui/vuu-protocol-types": "3.5.
|
|
18
|
+
"@vuu-ui/vuu-data-types": "3.5.18-beta.1",
|
|
19
|
+
"@vuu-ui/vuu-table-types": "3.5.18-beta.1",
|
|
20
|
+
"@vuu-ui/vuu-filter-types": "3.5.18-beta.1",
|
|
21
|
+
"@vuu-ui/vuu-protocol-types": "3.5.18-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"@internationalized/date": "^3.0.0",
|
|
25
|
-
"@vuu-ui/vuu-filter-parser": "3.5.
|
|
25
|
+
"@vuu-ui/vuu-filter-parser": "3.5.18-beta.1",
|
|
26
26
|
"clsx": "^2.0.0",
|
|
27
27
|
"react": "^19.2.3",
|
|
28
28
|
"react-dom": "^19.2.3"
|
package/src/ScaledDecimal.js
CHANGED
|
@@ -4,6 +4,7 @@ import { isStartOfDay, startOfDay, startOfNextDay, timeOfDayToEpochMillis } from
|
|
|
4
4
|
import { stringIsValidLong } from "../data-utils.js";
|
|
5
5
|
import { isMultiClauseFilter, isMultiValueFilter, isSerializableFilter } from "./filter-utils.js";
|
|
6
6
|
import { ScaledDecimal } from "../ScaledDecimal.js";
|
|
7
|
+
import { getScaledDecimalScale, isScaledDecimalFilterOptions, scaledDecimalFilterAsQuery } from "./scaled-decimal-filter.js";
|
|
7
8
|
const filterValue = (value, columnType)=>{
|
|
8
9
|
if ("string" == typeof value) {
|
|
9
10
|
if (void 0 !== columnType) {
|
|
@@ -12,7 +13,11 @@ const filterValue = (value, columnType)=>{
|
|
|
12
13
|
"long",
|
|
13
14
|
"double",
|
|
14
15
|
"epochtimestamp",
|
|
15
|
-
"epochtimestampnano"
|
|
16
|
+
"epochtimestampnano",
|
|
17
|
+
"scaleddecimal2",
|
|
18
|
+
"scaleddecimal4",
|
|
19
|
+
"scaleddecimal6",
|
|
20
|
+
"scaleddecimal8"
|
|
16
21
|
].includes(columnType);
|
|
17
22
|
return isNumericType ? value : `"${value}"`;
|
|
18
23
|
}
|
|
@@ -43,6 +48,7 @@ const filterAsQueryCore = (f, opts)=>{
|
|
|
43
48
|
function singleValueFilterAsQuery(f, opts) {
|
|
44
49
|
if (isSerializableFilter(f)) return f.asQuery();
|
|
45
50
|
{
|
|
51
|
+
if (isScaledDecimalFilterOptions(f.extendedOptions)) return scaledDecimalFilterAsQuery(f, f.extendedOptions);
|
|
46
52
|
const column = opts?.columnsByName?.[f.column];
|
|
47
53
|
const temporalInfo = getTemporalInfo(column);
|
|
48
54
|
if (temporalInfo) return temporalFilterAsQuery(f, temporalInfo);
|
|
@@ -143,7 +149,10 @@ const getColumnsByNameForFilter = (tableSchema, columnsByName)=>{
|
|
|
143
149
|
};
|
|
144
150
|
const filterRequiresResolution = (filter, columnsByName)=>{
|
|
145
151
|
if (isMultiClauseFilter(filter)) return filter.filters.some((f)=>filterRequiresResolution(f, columnsByName));
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
{
|
|
153
|
+
if (isSerializableFilter(filter) || isScaledDecimalFilterOptions(filter.extendedOptions)) return true;
|
|
154
|
+
const column = columnsByName?.[filter.column];
|
|
155
|
+
return void 0 !== getTemporalInfo(column) || void 0 !== getScaledDecimalScale(column?.serverDataType);
|
|
156
|
+
}
|
|
148
157
|
};
|
|
149
158
|
export { ONE_DAY_IN_MILLIS, dateFilterAsQuery, filterAsQuery, filterRequiresResolution, getColumnsByName, getColumnsByNameForFilter, temporalFilterAsQuery };
|
package/src/filters/index.js
CHANGED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { isTypeDescriptor } from "../column-utils.js";
|
|
2
|
+
import { roundScaledDecimal } from "../round-decimal.js";
|
|
3
|
+
const DEFAULT_DISPLAY_DECIMALS = 4;
|
|
4
|
+
const scales = {
|
|
5
|
+
scaleddecimal2: 2,
|
|
6
|
+
scaleddecimal4: 4,
|
|
7
|
+
scaleddecimal6: 6,
|
|
8
|
+
scaleddecimal8: 8
|
|
9
|
+
};
|
|
10
|
+
const getScaledDecimalScale = (serverDataType)=>void 0 === serverDataType ? void 0 : scales[serverDataType];
|
|
11
|
+
const decimalPattern = /^-?(\d+(\.\d*)?|\.\d+)$/;
|
|
12
|
+
const isValidDecimalString = (value)=>decimalPattern.test(value);
|
|
13
|
+
const isScaledDecimalFilterOptions = (options)=>options?.type === "ScaledDecimal";
|
|
14
|
+
const toDecimalString = (value, scale)=>{
|
|
15
|
+
if ("number" == typeof value) {
|
|
16
|
+
const text = `${value}`;
|
|
17
|
+
return /e/i.test(text) ? value.toFixed(scale) : text;
|
|
18
|
+
}
|
|
19
|
+
return `${value}`;
|
|
20
|
+
};
|
|
21
|
+
const toScaledInteger = (value, scale)=>{
|
|
22
|
+
if (!isValidDecimalString(value)) throw Error(`[scaled-decimal-filter] invalid decimal value '${value}'`);
|
|
23
|
+
const negative = value.startsWith("-");
|
|
24
|
+
const [integral, fraction = ""] = (negative ? value.slice(1) : value).split(".");
|
|
25
|
+
const magnitude = BigInt((integral || "0") + fraction.slice(0, scale).padEnd(scale, "0"));
|
|
26
|
+
return negative ? -magnitude : magnitude;
|
|
27
|
+
};
|
|
28
|
+
const fromScaledInteger = (value, scale)=>{
|
|
29
|
+
const negative = value < 0n;
|
|
30
|
+
const digits = (negative ? -value : value).toString().padStart(scale + 1, "0");
|
|
31
|
+
const literal = `${digits.slice(0, -scale)}.${digits.slice(-scale)}`;
|
|
32
|
+
return negative ? `-${literal}` : literal;
|
|
33
|
+
};
|
|
34
|
+
const getScaledDecimalFilterOptions = (column)=>{
|
|
35
|
+
const scale = getScaledDecimalScale(column.serverDataType);
|
|
36
|
+
if (void 0 === scale) return;
|
|
37
|
+
if (isTypeDescriptor(column.type)) {
|
|
38
|
+
const { decimals = DEFAULT_DISPLAY_DECIMALS, roundingRule = "round" } = column.type.formatting ?? {};
|
|
39
|
+
return decimals < scale ? {
|
|
40
|
+
type: "ScaledDecimal",
|
|
41
|
+
scale,
|
|
42
|
+
decimals,
|
|
43
|
+
roundingRule
|
|
44
|
+
} : {
|
|
45
|
+
type: "ScaledDecimal",
|
|
46
|
+
scale
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
type: "ScaledDecimal",
|
|
51
|
+
scale
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
const countDecimals = (value)=>value.split(".")[1]?.length ?? 0;
|
|
55
|
+
const getScaledDecimalMatchRange = (value, { scale, decimals, roundingRule = "round" })=>{
|
|
56
|
+
const scaledValue = toScaledInteger(value, scale);
|
|
57
|
+
const precision = void 0 === decimals ? scale : Math.max(decimals, countDecimals(value));
|
|
58
|
+
if (precision >= scale) return [
|
|
59
|
+
scaledValue,
|
|
60
|
+
scaledValue
|
|
61
|
+
];
|
|
62
|
+
const step = 10n ** BigInt(scale - precision);
|
|
63
|
+
if ("truncate" === roundingRule) if (scaledValue > 0n) return [
|
|
64
|
+
scaledValue,
|
|
65
|
+
scaledValue + step - 1n
|
|
66
|
+
];
|
|
67
|
+
else if (scaledValue < 0n) return [
|
|
68
|
+
scaledValue - step + 1n,
|
|
69
|
+
scaledValue
|
|
70
|
+
];
|
|
71
|
+
else return [
|
|
72
|
+
-step + 1n,
|
|
73
|
+
step - 1n
|
|
74
|
+
];
|
|
75
|
+
{
|
|
76
|
+
const half = step / 2n;
|
|
77
|
+
if (scaledValue > 0n) return [
|
|
78
|
+
scaledValue - half,
|
|
79
|
+
scaledValue + half - 1n
|
|
80
|
+
];
|
|
81
|
+
if (scaledValue < 0n) return [
|
|
82
|
+
scaledValue - half + 1n,
|
|
83
|
+
scaledValue + half
|
|
84
|
+
];
|
|
85
|
+
return [
|
|
86
|
+
-half + 1n,
|
|
87
|
+
half - 1n
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const scaledDecimalFilterAsQuery = ({ column, op, value }, options)=>{
|
|
92
|
+
const { scale } = options;
|
|
93
|
+
const [from, to] = getScaledDecimalMatchRange(toDecimalString(value, scale), options);
|
|
94
|
+
const lo = fromScaledInteger(from, scale);
|
|
95
|
+
const hi = fromScaledInteger(to, scale);
|
|
96
|
+
if (from === to) return `${column} ${op} ${lo}`;
|
|
97
|
+
switch(op){
|
|
98
|
+
case "=":
|
|
99
|
+
return `(${column} >= ${lo} and ${column} <= ${hi})`;
|
|
100
|
+
case "!=":
|
|
101
|
+
return `(${column} < ${lo} or ${column} > ${hi})`;
|
|
102
|
+
case ">":
|
|
103
|
+
return `${column} > ${hi}`;
|
|
104
|
+
case ">=":
|
|
105
|
+
return `${column} >= ${lo}`;
|
|
106
|
+
case "<":
|
|
107
|
+
return `${column} < ${lo}`;
|
|
108
|
+
case "<=":
|
|
109
|
+
return `${column} <= ${hi}`;
|
|
110
|
+
default:
|
|
111
|
+
throw Error(`[scaled-decimal-filter] operator ${op} is not supported for scaled decimals`);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const getScaledDecimalCellFilter = (column, value)=>{
|
|
115
|
+
const options = getScaledDecimalFilterOptions(column);
|
|
116
|
+
if (void 0 === options || "string" != typeof value || "" === value) return;
|
|
117
|
+
const { decimals, roundingRule } = options;
|
|
118
|
+
if (void 0 === decimals) return {
|
|
119
|
+
label: value,
|
|
120
|
+
op: "=",
|
|
121
|
+
value
|
|
122
|
+
};
|
|
123
|
+
const display = (useLocaleString)=>roundScaledDecimal(value, void 0, decimals, true, false, useLocaleString, roundingRule);
|
|
124
|
+
return {
|
|
125
|
+
label: display(true),
|
|
126
|
+
op: "=",
|
|
127
|
+
value: display(false)
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
export { fromScaledInteger, getScaledDecimalCellFilter, getScaledDecimalFilterOptions, getScaledDecimalMatchRange, getScaledDecimalScale, isScaledDecimalFilterOptions, isValidDecimalString, scaledDecimalFilterAsQuery, toDecimalString, toScaledInteger };
|
package/src/form-utils.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getTemporalInfo, parseTemporalInput } from "./date/temporal.js";
|
|
|
4
4
|
import { getDefaultTimeZone } from "./date/time-zone.js";
|
|
5
5
|
import { isTypeDescriptor } from "./column-utils.js";
|
|
6
6
|
import { queryClosest } from "./html-utils.js";
|
|
7
|
+
import { isValidDecimalString } from "./filters/scaled-decimal-filter.js";
|
|
7
8
|
import { ScaledDecimal2, ScaledDecimal4, ScaledDecimal6, ScaledDecimal8 } from "./ScaledDecimal.js";
|
|
8
9
|
class DataValidationError extends Error {
|
|
9
10
|
actualType;
|
|
@@ -33,6 +34,12 @@ function getTypedRange([value1, value2], dataType, options) {
|
|
|
33
34
|
getTypedValue(value2, dataType, false, options)
|
|
34
35
|
];
|
|
35
36
|
}
|
|
37
|
+
const ScaledDecimalFactory = {
|
|
38
|
+
scaleddecimal2: ScaledDecimal2,
|
|
39
|
+
scaleddecimal4: ScaledDecimal4,
|
|
40
|
+
scaleddecimal6: ScaledDecimal6,
|
|
41
|
+
scaleddecimal8: ScaledDecimal8
|
|
42
|
+
};
|
|
36
43
|
const getActualType = (value)=>{
|
|
37
44
|
if ("boolean" == typeof value) return "boolean";
|
|
38
45
|
if ("number" == typeof value) return "number";
|
|
@@ -53,13 +60,12 @@ function getTypedValue(value, type, throwIfInvalid = false, options) {
|
|
|
53
60
|
if (!throwIfInvalid) return;
|
|
54
61
|
throw new DataValidationError(`value ${value} is not a valid ${type}`, "single character", getActualType(value));
|
|
55
62
|
case "scaleddecimal2":
|
|
56
|
-
return ScaledDecimal2(value);
|
|
57
63
|
case "scaleddecimal4":
|
|
58
|
-
return ScaledDecimal4(value);
|
|
59
64
|
case "scaleddecimal6":
|
|
60
|
-
return ScaledDecimal6(value);
|
|
61
65
|
case "scaleddecimal8":
|
|
62
|
-
return
|
|
66
|
+
if ("" === value || isValidDecimalString(value)) return ScaledDecimalFactory[type](value);
|
|
67
|
+
if (!throwIfInvalid) return;
|
|
68
|
+
throw new DataValidationError(`value ${value} is not a valid ${type}`, "decimal", getActualType(value));
|
|
63
69
|
case "double":
|
|
64
70
|
case "number":
|
|
65
71
|
if (stringIsValidDecimal(value)) return parseFloat(value);
|
package/src/round-decimal.js
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
const PUNCTUATION_STR = String.fromCharCode(8200);
|
|
2
2
|
const DIGIT_STR = String.fromCharCode(8199);
|
|
3
3
|
const DECIMALS_AUTO = -1;
|
|
4
|
+
const integerFormat = new Intl.NumberFormat();
|
|
4
5
|
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER.toString();
|
|
5
6
|
const MAX_INTEGER_DIGITS = MAX_SAFE_INTEGER.length;
|
|
6
7
|
const exceedsMaxSafeInteger = (value)=>value.length > MAX_INTEGER_DIGITS || value.length === MAX_INTEGER_DIGITS && value > MAX_SAFE_INTEGER;
|
|
7
|
-
const
|
|
8
|
+
const roundFraction = (fraction, decimals)=>{
|
|
9
|
+
const kept = fraction.slice(0, decimals);
|
|
10
|
+
if (fraction.length <= decimals || fraction[decimals] < "5") return [
|
|
11
|
+
kept,
|
|
12
|
+
false
|
|
13
|
+
];
|
|
14
|
+
if (0 === decimals) return [
|
|
15
|
+
"",
|
|
16
|
+
true
|
|
17
|
+
];
|
|
18
|
+
const rounded = (BigInt(kept) + 1n).toString().padStart(decimals, "0");
|
|
19
|
+
return rounded.length > decimals ? [
|
|
20
|
+
rounded.slice(1),
|
|
21
|
+
true
|
|
22
|
+
] : [
|
|
23
|
+
rounded,
|
|
24
|
+
false
|
|
25
|
+
];
|
|
26
|
+
};
|
|
27
|
+
const carriesIntoIntegral = (fraction, decimals, roundingRule)=>"round" === roundingRule && decimals !== DECIMALS_AUTO && fraction.length > decimals && roundFraction(fraction, decimals)[1];
|
|
8
28
|
const incrementIntegral = (integral)=>{
|
|
9
29
|
const negative = integral.startsWith("-");
|
|
10
30
|
const magnitude = BigInt(negative ? integral.slice(1) : integral) + 1n;
|
|
@@ -70,9 +90,12 @@ function roundDecimal(value, align = Align.Right, decimals = 4, zeroPad, alignOn
|
|
|
70
90
|
const [whole, part2 = ""] = value.toString().split(".");
|
|
71
91
|
const part1 = carriesIntoIntegral(part2, decimals, roundingRule) ? incrementIntegral(whole) : whole;
|
|
72
92
|
const actualDecimals = part2.length;
|
|
73
|
-
integral = "-0" === part1 ? "-0" : useLocaleString ? parseFloat(part1)
|
|
93
|
+
integral = "-0" === part1 ? "-0" : useLocaleString ? integerFormat.format(parseFloat(part1)) : parseFloat(part1).toString();
|
|
74
94
|
if (align === Align.Left && alignOnDecimals) integral = padLeft(integral);
|
|
75
|
-
|
|
95
|
+
if (decimals === DECIMALS_AUTO || actualDecimals === decimals) fraction = part2;
|
|
96
|
+
else if (actualDecimals > decimals) if ("round" === roundingRule) [fraction] = roundFraction(part2, decimals);
|
|
97
|
+
else fraction = part2.slice(0, decimals);
|
|
98
|
+
else fraction = (Pad = zeroPad ? Zero : alignOnDecimals && align !== Align.Left ? Space : null) ? 0 === actualDecimals ? Pad.FULL_PADDING[decimals] ?? "" : pad(part2, decimals, Pad) : part2;
|
|
76
99
|
return integral + (fraction ? "." + fraction : "");
|
|
77
100
|
}
|
|
78
101
|
function roundScaledDecimal(value, align = Align.Right, decimals = 4, zeroPad, alignOnDecimals, useLocaleString = true, roundingRule = "round") {
|
|
@@ -83,9 +106,12 @@ function roundScaledDecimal(value, align = Align.Right, decimals = 4, zeroPad, a
|
|
|
83
106
|
const [whole, part2 = ""] = value.split(".");
|
|
84
107
|
const part1 = carriesIntoIntegral(part2, decimals, roundingRule) ? incrementIntegral(whole) : whole;
|
|
85
108
|
const actualDecimals = part2.length;
|
|
86
|
-
integral = "" === part1 ? "0" : "-0" === part1 ? "-0" : useLocaleString ? exceedsMaxSafeInteger(value) ? BigInt(part1)
|
|
109
|
+
integral = "" === part1 ? "0" : "-0" === part1 ? "-0" : useLocaleString ? exceedsMaxSafeInteger(value) ? integerFormat.format(BigInt(part1)) : integerFormat.format(parseFloat(part1)) : part1;
|
|
87
110
|
if (align === Align.Left && alignOnDecimals) integral = padLeft(integral);
|
|
88
|
-
|
|
111
|
+
if (decimals === DECIMALS_AUTO || actualDecimals === decimals) fraction = part2;
|
|
112
|
+
else if (actualDecimals > decimals) if ("round" === roundingRule) [fraction] = roundFraction(part2, decimals);
|
|
113
|
+
else fraction = part2.slice(0, decimals);
|
|
114
|
+
else fraction = (Pad = zeroPad ? Zero : alignOnDecimals && align !== Align.Left ? Space : null) ? 0 === actualDecimals ? Pad.FULL_PADDING[decimals] ?? "" : pad(part2, decimals, Pad) : part2;
|
|
89
115
|
return integral + (fraction ? "." + fraction : "");
|
|
90
116
|
}
|
|
91
117
|
export { exceedsMaxSafeInteger, roundDecimal, roundScaledDecimal };
|
|
@@ -43,7 +43,8 @@ export declare const getColumnsByName: (columns: readonly ColumnDescriptor[]) =>
|
|
|
43
43
|
export declare const getColumnsByNameForFilter: (tableSchema?: Pick<TableSchema, "columns">, columnsByName?: ColumnDescriptorsByName) => ColumnDescriptorsByName | undefined;
|
|
44
44
|
/**
|
|
45
45
|
* Returns true if the filter includes clauses whose meaning depends on the
|
|
46
|
-
* column type (temporal columns) or which serialize
|
|
47
|
-
* must be resolved (see resolveFilterQuery) before
|
|
46
|
+
* column type (temporal and scaled decimal columns) or which serialize
|
|
47
|
+
* themselves. Such filters must be resolved (see resolveFilterQuery) before
|
|
48
|
+
* they can be evaluated locally.
|
|
48
49
|
*/
|
|
49
50
|
export declare const filterRequiresResolution: (filter: Filter, columnsByName?: ColumnDescriptorsByName) => boolean;
|
package/types/filters/index.d.ts
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ExtendedFilterOptions, ScaledDecimalFilterOptions, SingleValueFilterClause } from "@vuu-ui/vuu-filter-types";
|
|
2
|
+
import type { DataValueDescriptor } from "@vuu-ui/vuu-data-types";
|
|
3
|
+
export type ScaledDecimalScale = ScaledDecimalFilterOptions["scale"];
|
|
4
|
+
export declare const getScaledDecimalScale: (serverDataType?: string) => ScaledDecimalScale | undefined;
|
|
5
|
+
export declare const isValidDecimalString: (value: string) => boolean;
|
|
6
|
+
export declare const isScaledDecimalFilterOptions: (options?: ExtendedFilterOptions) => options is ScaledDecimalFilterOptions;
|
|
7
|
+
/**
|
|
8
|
+
* A decimal (not exponential) string representation of a filter value.
|
|
9
|
+
*/
|
|
10
|
+
export declare const toDecimalString: (value: unknown, scale: ScaledDecimalScale) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Convert a decimal string to its scaled integer representation. Digits beyond
|
|
13
|
+
* the scale are truncated, as the Vuu server does.
|
|
14
|
+
*/
|
|
15
|
+
export declare const toScaledInteger: (value: string, scale: ScaledDecimalScale) => bigint;
|
|
16
|
+
/**
|
|
17
|
+
* Convert a scaled integer to a decimal string with 'scale' decimal places,
|
|
18
|
+
* the literal form in which scaled decimals are expressed in a filter query.
|
|
19
|
+
*/
|
|
20
|
+
export declare const fromScaledInteger: (value: bigint, scale: ScaledDecimalScale) => string;
|
|
21
|
+
/**
|
|
22
|
+
* The filter options for a clause on a scaled decimal column, describing the
|
|
23
|
+
* precision with which the column displays values. These mirror the formatting
|
|
24
|
+
* rules of numericFormatter: a column with no type descriptor displays the full
|
|
25
|
+
* value, a type descriptor with no decimals displays 4 decimal places.
|
|
26
|
+
*/
|
|
27
|
+
export declare const getScaledDecimalFilterOptions: (column: Pick<DataValueDescriptor, "serverDataType" | "type">) => ScaledDecimalFilterOptions | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The range of scaled integer values, inclusive at both ends, matched by a
|
|
30
|
+
* filter value. A value with no more decimal places than are displayed matches
|
|
31
|
+
* every value that displays as that value, e.g 1.23, displayed with 2 decimals,
|
|
32
|
+
* rounded, matches [1.225, 1.235). Display rounding applies to the magnitude,
|
|
33
|
+
* so -1.23 matches (-1.235, -1.225]. A value with more decimal places than are
|
|
34
|
+
* displayed is matched at its own precision, by the same rounding rule, e.g
|
|
35
|
+
* 1.234 matches [1.2335, 1.2345). A value with as many decimal places as the
|
|
36
|
+
* column holds, or any value where every decimal is displayed, is matched exactly.
|
|
37
|
+
*/
|
|
38
|
+
export declare const getScaledDecimalMatchRange: (value: string, { scale, decimals, roundingRule }: ScaledDecimalFilterOptions) => [bigint, bigint];
|
|
39
|
+
/**
|
|
40
|
+
* Serialize a filter clause on a scaled decimal column. Where the value matches
|
|
41
|
+
* a range of values (see getScaledDecimalMatchRange), each operator applies to
|
|
42
|
+
* that range, e.g '>' matches values greater than every value in the range.
|
|
43
|
+
* Note: '!=' on a range is expressed as '< from or > to', which, unlike an
|
|
44
|
+
* exact '!=', does not match a null value.
|
|
45
|
+
*/
|
|
46
|
+
export declare const scaledDecimalFilterAsQuery: ({ column, op, value, }: Pick<SingleValueFilterClause, "column" | "op" | "value">, options: ScaledDecimalFilterOptions) => string;
|
|
47
|
+
export interface ScaledDecimalCellFilter {
|
|
48
|
+
/** The value as displayed */
|
|
49
|
+
label: string;
|
|
50
|
+
op: "=";
|
|
51
|
+
value: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The filter for a cell value on a scaled decimal column, matching the value as
|
|
55
|
+
* displayed, e.g a cell displaying 1.23 (underlying value 1.234567) creates a
|
|
56
|
+
* filter matching every value that displays as 1.23.
|
|
57
|
+
*/
|
|
58
|
+
export declare const getScaledDecimalCellFilter: (column: Pick<DataValueDescriptor, "serverDataType" | "type">, value: unknown) => ScaledDecimalCellFilter | undefined;
|