quetch 0.30.0 → 0.31.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/dist/tools/comparatorFieldValues.d.ts +8 -0
- package/dist/tools/comparatorFieldValues.js +26 -0
- package/dist/tools/comparatorFieldValues.js.map +1 -0
- package/dist/tools/filterChildren.d.ts +2 -1
- package/dist/tools/filterChildren.js +3 -2
- package/dist/tools/filterChildren.js.map +1 -1
- package/dist/tools/get.d.ts +4 -4
- package/dist/tools/get.js +6 -2
- package/dist/tools/get.js.map +1 -1
- package/dist/tools/querySettings.d.ts +8 -0
- package/dist/tools/querySettings.js +16 -0
- package/dist/tools/querySettings.js.map +1 -0
- package/dist/tools/sortItemList.d.ts +4 -4
- package/dist/tools/sortItemList.js +17 -24
- package/dist/tools/sortItemList.js.map +1 -1
- package/dist/tools/testFilter.js +1 -2
- package/dist/tools/testFilter.js.map +1 -1
- package/dist/tools/transformerFilterChildren.d.ts +2 -22
- package/dist/tools/transformerFilterChildren.js +2 -5
- package/dist/tools/transformerFilterChildren.js.map +1 -1
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +2 -0
- package/dist/tools.js.map +1 -1
- package/dist/types/CombineUnion.d.ts +1 -1
- package/dist/types/Decrement.d.ts +4 -0
- package/dist/types/Decrement.js +1 -0
- package/dist/types/Decrement.js.map +1 -0
- package/dist/types/DepthLimit.d.ts +1 -0
- package/dist/types/DepthLimit.js +1 -0
- package/dist/types/DepthLimit.js.map +1 -0
- package/dist/types/FieldKey.d.ts +2 -1
- package/dist/types/Get.d.ts +3 -1
- package/dist/types/KeyFiltered.d.ts +1 -1
- package/dist/types/NormalizedPathFieldSettings.d.ts +24 -0
- package/dist/types/NormalizedPathFieldSettings.js +1 -0
- package/dist/types/NormalizedPathFieldSettings.js.map +1 -0
- package/dist/types/Path.d.ts +4 -3
- package/dist/types/PathFiltered.d.ts +4 -3
- package/dist/types/QuerySettings.d.ts +12 -17
- package/dist/types.d.ts +3 -1
- package/doc/README.md +5 -1
- package/doc/classes/RequestError.md +5 -5
- package/doc/functions/aggregate.md +1 -1
- package/doc/functions/branch.md +1 -1
- package/doc/functions/cache.md +1 -1
- package/doc/functions/combine.md +1 -1
- package/doc/functions/comparatorFieldValues.md +33 -0
- package/doc/functions/cork.md +1 -1
- package/doc/functions/defineCheckQuery.md +1 -1
- package/doc/functions/defineCustomFetch.md +1 -1
- package/doc/functions/defineGenericFetch.md +1 -1
- package/doc/functions/escapeRegex.md +1 -1
- package/doc/functions/fetchExternal.md +1 -1
- package/doc/functions/fetchLocal.md +1 -1
- package/doc/functions/fieldListFromFilter.md +1 -1
- package/doc/functions/filterChildren.md +8 -2
- package/doc/functions/filterFromValue.md +1 -1
- package/doc/functions/get.md +2 -2
- package/doc/functions/groupFilters.md +1 -1
- package/doc/functions/identity.md +1 -1
- package/doc/functions/intrinsicFilter.md +1 -1
- package/doc/functions/isFilterGroup.md +1 -1
- package/doc/functions/log.md +1 -1
- package/doc/functions/normalizeOrder.md +1 -1
- package/doc/functions/queryItemList.md +1 -1
- package/doc/functions/querySettings.md +33 -0
- package/doc/functions/retry.md +1 -1
- package/doc/functions/reverseOrder.md +1 -1
- package/doc/functions/sameField.md +1 -1
- package/doc/functions/sortItemList.md +2 -2
- package/doc/functions/splitPath.md +2 -2
- package/doc/functions/testFilter.md +1 -1
- package/doc/functions/transformerFilterChildren.md +2 -2
- package/doc/interfaces/CustomFetch.md +1 -1
- package/doc/type-aliases/AggregateFunction.md +1 -1
- package/doc/type-aliases/AggregateFunctionOperator.md +1 -1
- package/doc/type-aliases/CombineUnion.md +2 -2
- package/doc/type-aliases/Context.md +1 -1
- package/doc/type-aliases/CustomFieldAggregateMap.md +1 -1
- package/doc/type-aliases/CustomFieldMap.md +1 -1
- package/doc/type-aliases/Decrement.md +17 -0
- package/doc/type-aliases/DepthLimit.md +13 -0
- package/doc/type-aliases/Field.md +1 -1
- package/doc/type-aliases/FieldFiltered.md +1 -1
- package/doc/type-aliases/FieldFunction.md +1 -1
- package/doc/type-aliases/FieldFunctionCustom.md +1 -1
- package/doc/type-aliases/FieldFunctionFormatDate.md +1 -1
- package/doc/type-aliases/FieldFunctionReturn.md +1 -1
- package/doc/type-aliases/FieldKey.md +2 -2
- package/doc/type-aliases/FieldMap.md +1 -1
- package/doc/type-aliases/Filter.md +1 -1
- package/doc/type-aliases/FilterArray.md +1 -1
- package/doc/type-aliases/FilterBoolean.md +1 -1
- package/doc/type-aliases/FilterChildren.md +1 -1
- package/doc/type-aliases/FilterCustom.md +1 -1
- package/doc/type-aliases/FilterField.md +1 -1
- package/doc/type-aliases/FilterGroup.md +1 -1
- package/doc/type-aliases/FilterNumber.md +1 -1
- package/doc/type-aliases/FilterOperator.md +1 -1
- package/doc/type-aliases/FilterString.md +1 -1
- package/doc/type-aliases/FilterStringIntersect.md +1 -1
- package/doc/type-aliases/FilterStringMatch.md +1 -1
- package/doc/type-aliases/Get.md +5 -3
- package/doc/type-aliases/Group.md +1 -1
- package/doc/type-aliases/Handler.md +1 -1
- package/doc/type-aliases/Immutable.md +1 -1
- package/doc/type-aliases/InjectCustomFields.md +1 -1
- package/doc/type-aliases/IntersectUnion.md +1 -1
- package/doc/type-aliases/IntrinsicFilter.md +1 -1
- package/doc/type-aliases/Item.md +1 -1
- package/doc/type-aliases/Join.md +1 -1
- package/doc/type-aliases/Key.md +1 -1
- package/doc/type-aliases/KeyFiltered.md +2 -2
- package/doc/type-aliases/KeyFromUnion.md +1 -1
- package/doc/type-aliases/Locale.md +1 -1
- package/doc/type-aliases/NextHandler.md +1 -1
- package/doc/type-aliases/NormalizedPathFieldSettings.md +57 -0
- package/doc/type-aliases/Order.md +1 -1
- package/doc/type-aliases/OrderNormalized.md +1 -1
- package/doc/type-aliases/Parameters.md +1 -1
- package/doc/type-aliases/Path.md +3 -3
- package/doc/type-aliases/PathFiltered.md +3 -3
- package/doc/type-aliases/Primitive.md +1 -1
- package/doc/type-aliases/PrimitiveObject.md +1 -1
- package/doc/type-aliases/Query.md +1 -1
- package/doc/type-aliases/QueryAggregate.md +1 -1
- package/doc/type-aliases/QueryCreate.md +1 -1
- package/doc/type-aliases/QueryCreateMultiple.md +1 -1
- package/doc/type-aliases/QueryDelete.md +1 -1
- package/doc/type-aliases/QueryDeleteMultiple.md +1 -1
- package/doc/type-aliases/QueryMethod.md +1 -1
- package/doc/type-aliases/QueryRead.md +1 -1
- package/doc/type-aliases/QueryReadMultiple.md +1 -1
- package/doc/type-aliases/QuerySettings.md +36 -30
- package/doc/type-aliases/QueryUpdate.md +1 -1
- package/doc/type-aliases/QueryUpdateMultiple.md +1 -1
- package/doc/type-aliases/Result.md +1 -1
- package/doc/type-aliases/Store.md +1 -1
- package/doc/type-aliases/Value.md +1 -1
- package/doc/type-aliases/ValueMap.md +1 -1
- package/doc/variables/CACHE.md +1 -1
- package/doc/variables/FILTER_ANY.md +1 -1
- package/doc/variables/FILTER_NONE.md +1 -1
- package/doc/variables/SELF.md +1 -1
- package/lib/tools/comparatorFieldValues.ts +46 -0
- package/lib/tools/filterChildren.ts +3 -1
- package/lib/tools/get.ts +9 -4
- package/lib/tools/querySettings.ts +20 -0
- package/lib/tools/sortItemList.test.ts +31 -8
- package/lib/tools/sortItemList.ts +21 -41
- package/lib/tools/testFilter.test.ts +35 -12
- package/lib/tools/testFilter.ts +1 -2
- package/lib/tools/transformerFilterChildren.ts +4 -26
- package/lib/tools.ts +2 -0
- package/lib/types/CombineUnion.ts +12 -10
- package/lib/types/Decrement.ts +5 -0
- package/lib/types/DepthLimit.ts +1 -0
- package/lib/types/FieldKey.ts +6 -1
- package/lib/types/Get.ts +17 -9
- package/lib/types/KeyFiltered.ts +14 -10
- package/lib/types/NormalizedPathFieldSettings.ts +25 -0
- package/lib/types/Path.ts +18 -15
- package/lib/types/PathFiltered.ts +20 -17
- package/lib/types/QuerySettings.ts +16 -17
- package/lib/types.ts +3 -1
- package/package.json +2 -2
- package/dist/types/Increment.d.ts +0 -4
- package/dist/types/Increment.js +0 -1
- package/dist/types/Increment.js.map +0 -1
- package/doc/type-aliases/Increment.md +0 -17
- package/lib/types/Increment.ts +0 -5
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EMPTY_OBJECT } from "unchangeable";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
FieldFiltered,
|
|
5
|
+
NormalizedPathFieldSettings,
|
|
6
|
+
QuerySettings,
|
|
7
|
+
} from "../types";
|
|
8
|
+
|
|
9
|
+
import { escapeRegex } from "./escapeRegex.js";
|
|
10
|
+
import { sameField } from "./sameField.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Returns a function that transforms a `FilterChildren` into a `FilterStringMatch`.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Options for the transformer.
|
|
16
|
+
* @returns A function that takes a `FilterChildren` and returns a `FilterStringMatch` that matches the paths of the children of the item specified in the `FilterChildren`.
|
|
17
|
+
*/
|
|
18
|
+
export function comparatorFieldValues<T>({
|
|
19
|
+
pathField = "path" as FieldFiltered<T, string>,
|
|
20
|
+
pathFieldSeparator = "/",
|
|
21
|
+
pathFieldSeparatorEscape = "\\",
|
|
22
|
+
}: NormalizedPathFieldSettings<T> = EMPTY_OBJECT): QuerySettings<T>["compareFieldValues"] {
|
|
23
|
+
const fieldSeparatorRegexp = new RegExp(
|
|
24
|
+
!pathFieldSeparatorEscape
|
|
25
|
+
? escapeRegex(pathFieldSeparator)
|
|
26
|
+
: `(?<!${escapeRegex(pathFieldSeparatorEscape)})${escapeRegex(pathFieldSeparator)}`,
|
|
27
|
+
"g",
|
|
28
|
+
);
|
|
29
|
+
return (field, a, b) => {
|
|
30
|
+
if (!sameField(field, pathField)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const normalizedA = (a as string).replaceAll?.(
|
|
34
|
+
fieldSeparatorRegexp,
|
|
35
|
+
"\x00",
|
|
36
|
+
);
|
|
37
|
+
const normalizedB = (b as string).replaceAll?.(
|
|
38
|
+
fieldSeparatorRegexp,
|
|
39
|
+
"\x00",
|
|
40
|
+
);
|
|
41
|
+
if (normalizedA > normalizedB) {
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
return -1;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -10,6 +10,7 @@ import { escapeRegex } from "./escapeRegex.js";
|
|
|
10
10
|
* @param minDepth - The minimum depth of the child items relative to the parent.
|
|
11
11
|
* @param maxDepth - The maximum depth of the child items relative to the parent.
|
|
12
12
|
* @param pathSeparator - The character used to separate path segments.
|
|
13
|
+
* @param not - If true, generates a filter that matches items that are not children of the given parent path.
|
|
13
14
|
* @returns A filter that can be used to match child items.
|
|
14
15
|
*/
|
|
15
16
|
export function filterChildren<T>(
|
|
@@ -18,6 +19,7 @@ export function filterChildren<T>(
|
|
|
18
19
|
minDepth = 1,
|
|
19
20
|
maxDepth = Infinity,
|
|
20
21
|
pathSeparator = "/",
|
|
22
|
+
not = false,
|
|
21
23
|
): FilterStringMatch<T> {
|
|
22
24
|
const escapedSeparator = escapeRegex(pathSeparator);
|
|
23
25
|
const segment = `${escapedSeparator}[^${escapedSeparator}]+`;
|
|
@@ -27,7 +29,7 @@ export function filterChildren<T>(
|
|
|
27
29
|
: `{${minDepth},${maxDepth === Infinity ? "" : maxDepth}}`;
|
|
28
30
|
return {
|
|
29
31
|
field: pathFieldKey,
|
|
30
|
-
operator: "match",
|
|
32
|
+
operator: not ? "notMatch" : "match",
|
|
31
33
|
value: `^${escapeRegex(parentPath)}(?:${segment})${quantifier}$`,
|
|
32
34
|
};
|
|
33
35
|
}
|
package/lib/tools/get.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { SELF } from "../constants/SELF.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Field, Get } from "../types";
|
|
3
|
+
|
|
4
|
+
const { isArray } = Array;
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Gets the property value of the given `value` at the specified `path` (an array of object property names or array indexes).
|
|
@@ -7,11 +9,11 @@ import type { Get, Path } from "../types";
|
|
|
7
9
|
* If the `path` is a string, it is considered as a path with one item.
|
|
8
10
|
* If the `path` leads to an unknown property, returns `undefined`.
|
|
9
11
|
*
|
|
10
|
-
* @param value The value from which to get the property value.
|
|
11
|
-
* @param path The path leading to the property value or a property name or `undefined`.
|
|
12
|
+
* @param value - The value from which to get the property value.
|
|
13
|
+
* @param path - The path leading to the property value or a property name or `undefined`.
|
|
12
14
|
* @returns The property value found at the given path, or `undefined` if it cannot be found.
|
|
13
15
|
*/
|
|
14
|
-
export function get<const T, const P extends
|
|
16
|
+
export function get<const T, const P extends Field<T>>(
|
|
15
17
|
value: T,
|
|
16
18
|
path?: P,
|
|
17
19
|
): Get<T, P> {
|
|
@@ -24,6 +26,9 @@ export function get<const T, const P extends Path<T> | keyof T>(
|
|
|
24
26
|
case "symbol":
|
|
25
27
|
return (value as any)?.[path];
|
|
26
28
|
default: {
|
|
29
|
+
if (!isArray(path)) {
|
|
30
|
+
return value as any;
|
|
31
|
+
}
|
|
27
32
|
switch (path.length as number) {
|
|
28
33
|
case 0:
|
|
29
34
|
return value as any;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EMPTY_OBJECT } from "unchangeable";
|
|
2
|
+
|
|
3
|
+
import type { NormalizedPathFieldSettings, QuerySettings } from "../types";
|
|
4
|
+
|
|
5
|
+
import { comparatorFieldValues } from "./comparatorFieldValues.js";
|
|
6
|
+
import { transformerFilterChildren } from "./transformerFilterChildren.js";
|
|
7
|
+
/**
|
|
8
|
+
* Returns query settings for path fields.
|
|
9
|
+
*
|
|
10
|
+
* @param settings - Settings for normalizing path fields.
|
|
11
|
+
* @returns Query settings for path fields.
|
|
12
|
+
*/
|
|
13
|
+
export function querySettings<T>(
|
|
14
|
+
settings: NormalizedPathFieldSettings<T> = EMPTY_OBJECT,
|
|
15
|
+
): QuerySettings<T> {
|
|
16
|
+
return {
|
|
17
|
+
compareFieldValues: comparatorFieldValues(settings),
|
|
18
|
+
transformFilterChildren: transformerFilterChildren(settings),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect, test } from "vitest";
|
|
2
2
|
|
|
3
|
+
import { querySettings } from "./querySettings.js";
|
|
3
4
|
import { sortItemList } from "./sortItemList.js";
|
|
4
5
|
|
|
5
6
|
test("sorts items", () => {
|
|
@@ -76,10 +77,7 @@ test("sorts items with separator setting", () => {
|
|
|
76
77
|
{ path: "a\\/b.c" },
|
|
77
78
|
{ path: "a.b/c" },
|
|
78
79
|
],
|
|
79
|
-
|
|
80
|
-
pathField: "path",
|
|
81
|
-
pathFieldSeparator: "/",
|
|
82
|
-
},
|
|
80
|
+
querySettings(),
|
|
83
81
|
),
|
|
84
82
|
).toEqual([
|
|
85
83
|
{ path: "a" },
|
|
@@ -104,10 +102,7 @@ test("sorts items with separator setting", () => {
|
|
|
104
102
|
{ path: "a\\/b.c" },
|
|
105
103
|
{ path: "a.b/c" },
|
|
106
104
|
],
|
|
107
|
-
|
|
108
|
-
pathField: "path",
|
|
109
|
-
pathFieldSeparator: "/",
|
|
110
|
-
},
|
|
105
|
+
querySettings(),
|
|
111
106
|
),
|
|
112
107
|
).toEqual([
|
|
113
108
|
{ path: "a" },
|
|
@@ -119,4 +114,32 @@ test("sorts items with separator setting", () => {
|
|
|
119
114
|
{ path: "a.b.c" },
|
|
120
115
|
{ path: "a\\/b.c" },
|
|
121
116
|
]);
|
|
117
|
+
|
|
118
|
+
expect(
|
|
119
|
+
sortItemList(
|
|
120
|
+
[{ descending: false, field: "path" }],
|
|
121
|
+
[
|
|
122
|
+
{ path: "a" },
|
|
123
|
+
{ path: "a/b" },
|
|
124
|
+
{ path: "a.b" },
|
|
125
|
+
{ path: "a/b/c" },
|
|
126
|
+
{ path: "a.b.c" },
|
|
127
|
+
{ path: "a/b.c" },
|
|
128
|
+
{ path: "a\\.b.c" },
|
|
129
|
+
{ path: "a.b/c" },
|
|
130
|
+
],
|
|
131
|
+
querySettings({
|
|
132
|
+
pathFieldSeparator: ".",
|
|
133
|
+
}),
|
|
134
|
+
),
|
|
135
|
+
).toEqual([
|
|
136
|
+
{ path: "a" },
|
|
137
|
+
{ path: "a.b" },
|
|
138
|
+
{ path: "a.b.c" },
|
|
139
|
+
{ path: "a.b/c" },
|
|
140
|
+
{ path: "a/b" },
|
|
141
|
+
{ path: "a/b.c" },
|
|
142
|
+
{ path: "a/b/c" },
|
|
143
|
+
{ path: "a\\.b.c" },
|
|
144
|
+
]);
|
|
122
145
|
});
|
|
@@ -1,73 +1,53 @@
|
|
|
1
|
+
import { EMPTY_OBJECT } from "unchangeable";
|
|
2
|
+
|
|
1
3
|
import type { Order, QuerySettings } from "../types";
|
|
2
4
|
|
|
3
|
-
import { escapeRegex } from "./escapeRegex.js";
|
|
4
5
|
import { get } from "./get.js";
|
|
5
6
|
import { normalizeOrder } from "./normalizeOrder.js";
|
|
6
|
-
import { sameField } from "./sameField.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Sorts provided `value` array according to the `orderList`.
|
|
10
10
|
*
|
|
11
|
-
* @param orderList The order to use for sorting.
|
|
12
|
-
* @param value The array to sort.
|
|
13
|
-
* @param settings Optional query settings.
|
|
11
|
+
* @param orderList - The order to use for sorting.
|
|
12
|
+
* @param value - The array to sort.
|
|
13
|
+
* @param settings - Optional query settings.
|
|
14
14
|
* @returns A new sorted array.
|
|
15
15
|
*/
|
|
16
16
|
export function sortItemList<T>(
|
|
17
|
-
orderList: readonly Order<T>[] | undefined,
|
|
17
|
+
orderList: NoInfer<readonly Order<T>[]> | undefined,
|
|
18
18
|
value: readonly T[],
|
|
19
19
|
settings?: QuerySettings<T>,
|
|
20
20
|
) {
|
|
21
|
-
const {
|
|
22
|
-
pathField,
|
|
23
|
-
pathFieldSeparator = "/",
|
|
24
|
-
pathFieldSeparatorEscape,
|
|
25
|
-
} = settings ?? {};
|
|
26
21
|
if (orderList === undefined || orderList.length === 0) {
|
|
27
22
|
return value;
|
|
28
23
|
}
|
|
24
|
+
const { compareFieldValues } = settings ?? EMPTY_OBJECT;
|
|
29
25
|
const normalizedOrder = orderList.map(normalizeOrder);
|
|
30
|
-
const fieldSeparatorRegexp =
|
|
31
|
-
pathField == null || pathFieldSeparator == null
|
|
32
|
-
? null
|
|
33
|
-
: new RegExp(
|
|
34
|
-
!pathFieldSeparatorEscape
|
|
35
|
-
? escapeRegex(pathFieldSeparator)
|
|
36
|
-
: `(?<!${escapeRegex(pathFieldSeparatorEscape)})${escapeRegex(pathFieldSeparator)}`,
|
|
37
|
-
"g",
|
|
38
|
-
);
|
|
39
26
|
return value.toSorted((a, b) => {
|
|
40
27
|
for (let index = 0; index < normalizedOrder.length; index++) {
|
|
41
28
|
const { field, descending } = normalizedOrder[index]!;
|
|
42
|
-
const valueA = get(a, field
|
|
43
|
-
const valueB = get(b, field
|
|
29
|
+
const valueA = get(a, field);
|
|
30
|
+
const valueB = get(b, field);
|
|
44
31
|
if (valueA === valueB) {
|
|
45
32
|
continue;
|
|
46
33
|
}
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"\x00",
|
|
57
|
-
);
|
|
58
|
-
const normalizedB = (valueB as string).replaceAll(
|
|
59
|
-
fieldSeparatorRegexp,
|
|
60
|
-
"\x00",
|
|
61
|
-
);
|
|
62
|
-
if (normalizedA > normalizedB) {
|
|
34
|
+
if (valueA == null) {
|
|
35
|
+
return valueB == null ? 0 : descending ? 1 : -1;
|
|
36
|
+
}
|
|
37
|
+
if (valueB == null) {
|
|
38
|
+
return descending ? -1 : 1;
|
|
39
|
+
}
|
|
40
|
+
const comparison = compareFieldValues?.(field, valueA, valueB);
|
|
41
|
+
if (comparison === undefined) {
|
|
42
|
+
if (valueA > valueB) {
|
|
63
43
|
return descending ? -1 : 1;
|
|
64
44
|
}
|
|
65
45
|
return descending ? 1 : -1;
|
|
66
46
|
}
|
|
67
|
-
if (
|
|
68
|
-
|
|
47
|
+
if (comparison === 0) {
|
|
48
|
+
continue;
|
|
69
49
|
}
|
|
70
|
-
return descending ?
|
|
50
|
+
return descending ? -comparison : comparison;
|
|
71
51
|
}
|
|
72
52
|
return 0;
|
|
73
53
|
});
|
|
@@ -5,6 +5,7 @@ import { SELF } from "../constants.js";
|
|
|
5
5
|
import type { FilterChildren } from "../types.js";
|
|
6
6
|
|
|
7
7
|
import { filterFromValue } from "./filterFromValue.js";
|
|
8
|
+
import { querySettings } from "./querySettings.js";
|
|
8
9
|
import { testFilter } from "./testFilter.js";
|
|
9
10
|
|
|
10
11
|
test("tests filter lists", () => {
|
|
@@ -360,27 +361,37 @@ test("tests filter with children predicates", () => {
|
|
|
360
361
|
{ id: "a" },
|
|
361
362
|
),
|
|
362
363
|
).toBe(true);
|
|
364
|
+
|
|
365
|
+
// Always true if `transformFilterChildren` is not provided, to avoid false negatives
|
|
363
366
|
expect(
|
|
364
367
|
testFilter({ operator: "notChildren", value: { id: "a" } }, { id: "a/b" }),
|
|
368
|
+
).toBe(true);
|
|
369
|
+
expect(
|
|
370
|
+
testFilter(
|
|
371
|
+
{ operator: "notChildren", value: { id: "a" } },
|
|
372
|
+
{ id: "a/b" },
|
|
373
|
+
querySettings({ pathField: "id" }),
|
|
374
|
+
),
|
|
365
375
|
).toBe(false);
|
|
376
|
+
|
|
366
377
|
expect(
|
|
367
378
|
testFilter(
|
|
368
379
|
{ operator: "children", value: { path: ".a" } },
|
|
369
380
|
{ path: ".a.b" },
|
|
370
|
-
{
|
|
381
|
+
querySettings({
|
|
371
382
|
pathField: "path",
|
|
372
383
|
pathFieldSeparator: ".",
|
|
373
|
-
},
|
|
384
|
+
}),
|
|
374
385
|
),
|
|
375
386
|
).toBe(true);
|
|
376
387
|
expect(
|
|
377
388
|
testFilter(
|
|
378
389
|
{ operator: "notChildren", value: { path: ".a" } },
|
|
379
390
|
{ path: ".a.b" },
|
|
380
|
-
{
|
|
391
|
+
querySettings({
|
|
381
392
|
pathField: "path",
|
|
382
393
|
pathFieldSeparator: ".",
|
|
383
|
-
},
|
|
394
|
+
}),
|
|
384
395
|
),
|
|
385
396
|
).toBe(false);
|
|
386
397
|
const filterChildren: FilterChildren<{ path: string }> = {
|
|
@@ -397,7 +408,7 @@ test("tests filter with children predicates", () => {
|
|
|
397
408
|
field: "path",
|
|
398
409
|
operator: "startWith",
|
|
399
410
|
value: `.${filter.value?.path}.`,
|
|
400
|
-
};
|
|
411
|
+
} as const;
|
|
401
412
|
},
|
|
402
413
|
},
|
|
403
414
|
),
|
|
@@ -415,36 +426,48 @@ test("tests filter with children predicates", () => {
|
|
|
415
426
|
field: "path",
|
|
416
427
|
operator: "startWith",
|
|
417
428
|
value: `.${filter.value?.path}.`,
|
|
418
|
-
};
|
|
429
|
+
} as const;
|
|
419
430
|
},
|
|
420
431
|
},
|
|
421
432
|
),
|
|
422
433
|
).toBe(true);
|
|
423
434
|
expect(filterChildren[CACHE]).toBeDefined();
|
|
424
435
|
expect(
|
|
425
|
-
testFilter(
|
|
436
|
+
testFilter(
|
|
437
|
+
{ operator: "children", value: { id: "b" } },
|
|
438
|
+
{ id: "a/b" },
|
|
439
|
+
querySettings({
|
|
440
|
+
pathField: "id",
|
|
441
|
+
}),
|
|
442
|
+
),
|
|
426
443
|
).toBe(false);
|
|
427
444
|
expect(
|
|
428
|
-
testFilter(
|
|
445
|
+
testFilter(
|
|
446
|
+
{ operator: "notChildren", value: { id: "b" } },
|
|
447
|
+
{ id: "a/b" },
|
|
448
|
+
querySettings({
|
|
449
|
+
pathField: "id",
|
|
450
|
+
}),
|
|
451
|
+
),
|
|
429
452
|
).toBe(true);
|
|
430
453
|
expect(
|
|
431
454
|
testFilter(
|
|
432
455
|
{ operator: "children", value: { path: "ba" } },
|
|
433
456
|
{ path: ".a.b" },
|
|
434
|
-
{
|
|
457
|
+
querySettings({
|
|
435
458
|
pathField: "path",
|
|
436
459
|
pathFieldSeparator: ".",
|
|
437
|
-
},
|
|
460
|
+
}),
|
|
438
461
|
),
|
|
439
462
|
).toBe(false);
|
|
440
463
|
expect(
|
|
441
464
|
testFilter(
|
|
442
465
|
{ operator: "notChildren", value: { path: "ba" } },
|
|
443
466
|
{ path: ".a.b" },
|
|
444
|
-
{
|
|
467
|
+
querySettings({
|
|
445
468
|
pathField: "path",
|
|
446
469
|
pathFieldSeparator: ".",
|
|
447
|
-
},
|
|
470
|
+
}),
|
|
448
471
|
),
|
|
449
472
|
).toBe(true);
|
|
450
473
|
});
|
package/lib/tools/testFilter.ts
CHANGED
|
@@ -121,7 +121,6 @@ export function testFilter<T>(
|
|
|
121
121
|
}
|
|
122
122
|
case "children":
|
|
123
123
|
case "notChildren": {
|
|
124
|
-
const not = filter.operator[0] === "n";
|
|
125
124
|
if (filter[CACHE] === undefined) {
|
|
126
125
|
switch (true) {
|
|
127
126
|
case settings?.transformFilterChildren !== undefined:
|
|
@@ -133,7 +132,7 @@ export function testFilter<T>(
|
|
|
133
132
|
}
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
|
-
return
|
|
135
|
+
return testFilter(filter[CACHE], value, settings);
|
|
137
136
|
}
|
|
138
137
|
case "custom": {
|
|
139
138
|
return filter.value(value);
|
|
@@ -4,32 +4,12 @@ import type {
|
|
|
4
4
|
FieldFiltered,
|
|
5
5
|
FilterChildren,
|
|
6
6
|
FilterStringMatch,
|
|
7
|
+
NormalizedPathFieldSettings,
|
|
7
8
|
} from "../types";
|
|
8
9
|
|
|
9
10
|
import { filterChildren } from "./filterChildren.js";
|
|
10
11
|
import { get } from "./get.js";
|
|
11
12
|
|
|
12
|
-
export type TransformerFilterChildrenOptions<T> = {
|
|
13
|
-
/**
|
|
14
|
-
* Path to the field that contains the path value of an item, used for displaying items in a tree.
|
|
15
|
-
*
|
|
16
|
-
* @default "path"
|
|
17
|
-
*/
|
|
18
|
-
pathField?: FieldFiltered<T, string>;
|
|
19
|
-
/**
|
|
20
|
-
* String used to escape the separator.
|
|
21
|
-
*
|
|
22
|
-
* @default "\\"
|
|
23
|
-
*/
|
|
24
|
-
pathFieldSeparatorEscape?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Maps path fields to a string used to separate the path nodes of a field value.
|
|
27
|
-
*
|
|
28
|
-
* @default "/"
|
|
29
|
-
*/
|
|
30
|
-
pathFieldSeparator?: string;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
13
|
/**
|
|
34
14
|
* Returns a function that transforms a `FilterChildren` into a `FilterStringMatch`.
|
|
35
15
|
*
|
|
@@ -39,19 +19,17 @@ export type TransformerFilterChildrenOptions<T> = {
|
|
|
39
19
|
export function transformerFilterChildren<T>({
|
|
40
20
|
pathField = "path" as FieldFiltered<T, string>,
|
|
41
21
|
pathFieldSeparator = "/",
|
|
42
|
-
}:
|
|
22
|
+
}: NormalizedPathFieldSettings<T> = EMPTY_OBJECT) {
|
|
43
23
|
return (filter: FilterChildren<T>): FilterStringMatch<T> => {
|
|
44
24
|
const { value, minDepth = 1, maxDepth = Infinity } = filter;
|
|
45
|
-
|
|
46
|
-
throw new Error("FilterChildren must have a value");
|
|
47
|
-
}
|
|
48
|
-
const parentPath = get(value, pathField as any) as string;
|
|
25
|
+
const parentPath = (get(value, pathField as any) ?? "") as string;
|
|
49
26
|
return filterChildren(
|
|
50
27
|
parentPath,
|
|
51
28
|
pathField,
|
|
52
29
|
minDepth,
|
|
53
30
|
maxDepth,
|
|
54
31
|
pathFieldSeparator,
|
|
32
|
+
filter.operator[0] === "n",
|
|
55
33
|
);
|
|
56
34
|
};
|
|
57
35
|
}
|
package/lib/tools.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// File automatically generated by `vite-plugin-module-list`
|
|
2
|
+
export { comparatorFieldValues } from "./tools/comparatorFieldValues.js";
|
|
2
3
|
export { cork } from "./tools/cork.js";
|
|
3
4
|
export { defineCheckQuery } from "./tools/defineCheckQuery.js";
|
|
4
5
|
export { defineCustomFetch } from "./tools/defineCustomFetch.js";
|
|
@@ -13,6 +14,7 @@ export { intrinsicFilter } from "./tools/intrinsicFilter.js";
|
|
|
13
14
|
export { isFilterGroup } from "./tools/isFilterGroup.js";
|
|
14
15
|
export { normalizeOrder } from "./tools/normalizeOrder.js";
|
|
15
16
|
export { queryItemList } from "./tools/queryItemList.js";
|
|
17
|
+
export { querySettings } from "./tools/querySettings.js";
|
|
16
18
|
export { reverseOrder } from "./tools/reverseOrder.js";
|
|
17
19
|
export { sameField } from "./tools/sameField.js";
|
|
18
20
|
export { sortItemList } from "./tools/sortItemList.js";
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import type { KeyFromUnion } from "./KeyFromUnion";
|
|
2
2
|
import type { Primitive } from "./Primitive";
|
|
3
3
|
|
|
4
|
-
export type CombineUnion<U> = [
|
|
5
|
-
?
|
|
6
|
-
: [
|
|
7
|
-
?
|
|
8
|
-
: [U] extends [
|
|
9
|
-
?
|
|
10
|
-
: [U] extends
|
|
4
|
+
export type CombineUnion<U> = [unknown] extends [U]
|
|
5
|
+
? unknown
|
|
6
|
+
: [0] extends [1 & U]
|
|
7
|
+
? any
|
|
8
|
+
: [U] extends [Function | readonly Function[]]
|
|
9
|
+
? undefined
|
|
10
|
+
: [U] extends [Primitive]
|
|
11
11
|
? U
|
|
12
|
-
:
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
: [U] extends readonly [Array<any>]
|
|
13
|
+
? U
|
|
14
|
+
: {
|
|
15
|
+
[K in KeyFromUnion<U>]: Continue<Combine<U, K>>;
|
|
16
|
+
};
|
|
15
17
|
|
|
16
18
|
type Combine<U, K extends string | number | symbol> = Exclude<
|
|
17
19
|
Extract<U, { [k in K]?: any }>[K],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type DepthLimit = 4;
|
package/lib/types/FieldKey.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { SELF } from "../constants/SELF.ts";
|
|
2
2
|
|
|
3
|
+
import type { Key } from "./Key.ts";
|
|
3
4
|
import type { Primitive } from "./Primitive";
|
|
4
5
|
|
|
5
|
-
export type FieldKey<T> = T extends Primitive
|
|
6
|
+
export type FieldKey<T> = T extends Primitive
|
|
7
|
+
? typeof SELF
|
|
8
|
+
: [unknown] extends [T]
|
|
9
|
+
? Key
|
|
10
|
+
: keyof T;
|
package/lib/types/Get.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
import type { Decrement } from "./Decrement";
|
|
2
|
+
import type { DepthLimit } from "./DepthLimit";
|
|
1
3
|
import type { Path } from "./Path";
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Returns the type of the property at the specified `P` path.
|
|
5
7
|
*/
|
|
6
|
-
export type Get<T, P> = [
|
|
7
|
-
?
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
export type Get<T, P, D = DepthLimit> = [unknown] extends [T]
|
|
9
|
+
? unknown
|
|
10
|
+
: [0] extends [1 & T]
|
|
11
|
+
? any
|
|
12
|
+
: D extends -1
|
|
13
|
+
? any
|
|
14
|
+
: [P] extends [readonly [infer K, ...infer R]]
|
|
15
|
+
? K extends keyof T
|
|
16
|
+
? R extends Path<T[K]>
|
|
17
|
+
? Get<T[K], R, Decrement<D>>
|
|
18
|
+
: T[K]
|
|
19
|
+
: never
|
|
20
|
+
: [P] extends [keyof T]
|
|
21
|
+
? T[P]
|
|
22
|
+
: T;
|
package/lib/types/KeyFiltered.ts
CHANGED
|
@@ -7,14 +7,18 @@ type SymbolSelf = typeof SELF;
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns union of keys whose mapped value extend the provided `P` type.
|
|
9
9
|
*/
|
|
10
|
-
export type KeyFiltered<T, P> = [
|
|
10
|
+
export type KeyFiltered<T, P> = [unknown] extends [T]
|
|
11
11
|
? Key | SymbolSelf
|
|
12
|
-
:
|
|
13
|
-
?
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
: [0] extends [1 & T]
|
|
13
|
+
? Key | SymbolSelf
|
|
14
|
+
: T extends string | number | boolean | bigint | symbol
|
|
15
|
+
? T extends P
|
|
16
|
+
? SymbolSelf
|
|
17
|
+
: never
|
|
18
|
+
: T extends object
|
|
19
|
+
? keyof {
|
|
20
|
+
[K in keyof T as Extract<T[K], P> extends never
|
|
21
|
+
? never
|
|
22
|
+
: K]-?: T[K];
|
|
23
|
+
}
|
|
24
|
+
: never;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FieldFiltered } from "./FieldFiltered";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Settings for fields that contain path values of items, used for displaying items in a tree.
|
|
5
|
+
*/
|
|
6
|
+
export type NormalizedPathFieldSettings<T> = {
|
|
7
|
+
/**
|
|
8
|
+
* Path to the field that contains the path value of an item, used for displaying items in a tree.
|
|
9
|
+
*
|
|
10
|
+
* @default "path"
|
|
11
|
+
*/
|
|
12
|
+
pathField?: FieldFiltered<T, string>;
|
|
13
|
+
/**
|
|
14
|
+
* String used to escape the separator.
|
|
15
|
+
*
|
|
16
|
+
* @default "\\"
|
|
17
|
+
*/
|
|
18
|
+
pathFieldSeparatorEscape?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Maps path fields to a string used to separate the path nodes of a field value.
|
|
21
|
+
*
|
|
22
|
+
* @default "/"
|
|
23
|
+
*/
|
|
24
|
+
pathFieldSeparator?: string;
|
|
25
|
+
};
|
package/lib/types/Path.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Decrement } from "./Decrement";
|
|
2
|
+
import type { DepthLimit } from "./DepthLimit";
|
|
2
3
|
import type { Key } from "./Key";
|
|
3
4
|
import type { Primitive } from "./Primitive";
|
|
4
5
|
|
|
5
|
-
export type Path<T, D =
|
|
6
|
+
export type Path<T, D = DepthLimit> = [unknown] extends [T]
|
|
6
7
|
? readonly (Key | never)[]
|
|
7
|
-
:
|
|
8
|
-
? never
|
|
9
|
-
:
|
|
10
|
-
?
|
|
11
|
-
: T extends
|
|
12
|
-
? readonly [
|
|
13
|
-
: T extends
|
|
14
|
-
?
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
: [0] extends [1 & T]
|
|
9
|
+
? readonly (Key | never)[]
|
|
10
|
+
: D extends -1
|
|
11
|
+
? never
|
|
12
|
+
: T extends Primitive
|
|
13
|
+
? readonly never[]
|
|
14
|
+
: T extends Array<infer P>
|
|
15
|
+
? readonly [number] | readonly [number, ...Path<P, Decrement<D>>]
|
|
16
|
+
: T extends object
|
|
17
|
+
? {
|
|
18
|
+
[K in keyof T]:
|
|
19
|
+
| readonly [K]
|
|
20
|
+
| readonly [K, ...Path<T[K], Decrement<D>>];
|
|
21
|
+
}[keyof T]
|
|
22
|
+
: never;
|