quetch 0.20.0 → 0.22.0

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.
Files changed (138) hide show
  1. package/dist/tools/queryItemList.js +2 -2
  2. package/dist/tools/queryItemList.js.map +1 -1
  3. package/dist/tools/sameField.d.ts +2 -0
  4. package/dist/tools/sameField.js +13 -0
  5. package/dist/tools/sameField.js.map +1 -0
  6. package/dist/tools/sortItemList.d.ts +3 -2
  7. package/dist/tools/sortItemList.js +25 -2
  8. package/dist/tools/sortItemList.js.map +1 -1
  9. package/dist/tools/splitPath.d.ts +21 -0
  10. package/dist/tools/splitPath.js +19 -0
  11. package/dist/tools/splitPath.js.map +1 -0
  12. package/dist/tools/testFilter.js +3 -2
  13. package/dist/tools/testFilter.js.map +1 -1
  14. package/dist/tools.d.ts +2 -0
  15. package/dist/tools.js +2 -0
  16. package/dist/tools.js.map +1 -1
  17. package/dist/types/Field.d.ts +2 -3
  18. package/dist/types/FieldKey.d.ts +3 -0
  19. package/dist/types/FieldKey.js +1 -0
  20. package/dist/types/FieldKey.js.map +1 -0
  21. package/dist/types/FieldMap.d.ts +5 -0
  22. package/dist/types/FieldMap.js +1 -0
  23. package/dist/types/FieldMap.js.map +1 -0
  24. package/dist/types/QuerySettings.d.ts +13 -5
  25. package/dist/types/ValueMap.d.ts +7 -0
  26. package/dist/types/ValueMap.js +1 -0
  27. package/dist/types/ValueMap.js.map +1 -0
  28. package/dist/types.d.ts +3 -0
  29. package/doc/README.md +5 -0
  30. package/doc/classes/RequestError.md +5 -5
  31. package/doc/functions/aggregate.md +1 -1
  32. package/doc/functions/branch.md +1 -1
  33. package/doc/functions/cache.md +1 -1
  34. package/doc/functions/combine.md +1 -1
  35. package/doc/functions/cork.md +1 -1
  36. package/doc/functions/defineCheckQuery.md +1 -1
  37. package/doc/functions/defineCustomFetch.md +1 -1
  38. package/doc/functions/defineGenericFetch.md +1 -1
  39. package/doc/functions/escapeRegex.md +1 -1
  40. package/doc/functions/fetchExternal.md +1 -1
  41. package/doc/functions/fetchLocal.md +1 -1
  42. package/doc/functions/fieldListFromFilter.md +1 -1
  43. package/doc/functions/filterChildren.md +1 -1
  44. package/doc/functions/filterFromContext.md +1 -1
  45. package/doc/functions/get.md +1 -1
  46. package/doc/functions/identity.md +1 -1
  47. package/doc/functions/isFilterGroup.md +1 -1
  48. package/doc/functions/log.md +1 -1
  49. package/doc/functions/normalizeOrder.md +1 -1
  50. package/doc/functions/queryItemList.md +1 -1
  51. package/doc/functions/retry.md +1 -1
  52. package/doc/functions/reverseOrder.md +1 -1
  53. package/doc/functions/sameField.md +27 -0
  54. package/doc/functions/sortItemList.md +8 -2
  55. package/doc/functions/splitPath.md +73 -0
  56. package/doc/functions/testFilter.md +1 -1
  57. package/doc/interfaces/CustomFetch.md +1 -1
  58. package/doc/type-aliases/AggregateFunction.md +1 -1
  59. package/doc/type-aliases/AggregateFunctionOperator.md +1 -1
  60. package/doc/type-aliases/CombineUnion.md +1 -1
  61. package/doc/type-aliases/Context.md +1 -1
  62. package/doc/type-aliases/CustomFieldAggregateMap.md +1 -1
  63. package/doc/type-aliases/CustomFieldMap.md +1 -1
  64. package/doc/type-aliases/Field.md +1 -1
  65. package/doc/type-aliases/FieldFiltered.md +1 -1
  66. package/doc/type-aliases/FieldFunction.md +1 -1
  67. package/doc/type-aliases/FieldFunctionCustom.md +1 -1
  68. package/doc/type-aliases/FieldFunctionFormatDate.md +1 -1
  69. package/doc/type-aliases/FieldFunctionReturn.md +1 -1
  70. package/doc/type-aliases/FieldKey.md +17 -0
  71. package/doc/type-aliases/FieldMap.md +21 -0
  72. package/doc/type-aliases/Filter.md +1 -1
  73. package/doc/type-aliases/FilterArray.md +2 -2
  74. package/doc/type-aliases/FilterBoolean.md +1 -1
  75. package/doc/type-aliases/FilterChildren.md +2 -2
  76. package/doc/type-aliases/FilterCustom.md +1 -1
  77. package/doc/type-aliases/FilterField.md +2 -2
  78. package/doc/type-aliases/FilterGroup.md +1 -1
  79. package/doc/type-aliases/FilterNumber.md +2 -2
  80. package/doc/type-aliases/FilterOperator.md +1 -1
  81. package/doc/type-aliases/FilterString.md +2 -2
  82. package/doc/type-aliases/FilterStringIntersect.md +2 -2
  83. package/doc/type-aliases/FilterStringMatch.md +2 -2
  84. package/doc/type-aliases/Get.md +1 -1
  85. package/doc/type-aliases/Group.md +1 -1
  86. package/doc/type-aliases/Handler.md +1 -1
  87. package/doc/type-aliases/Immutable.md +1 -1
  88. package/doc/type-aliases/Increment.md +1 -1
  89. package/doc/type-aliases/InjectCustomFields.md +1 -1
  90. package/doc/type-aliases/IntersectUnion.md +1 -1
  91. package/doc/type-aliases/Item.md +1 -1
  92. package/doc/type-aliases/Join.md +1 -1
  93. package/doc/type-aliases/Key.md +1 -1
  94. package/doc/type-aliases/KeyFiltered.md +1 -1
  95. package/doc/type-aliases/KeyFromUnion.md +1 -1
  96. package/doc/type-aliases/Locale.md +1 -1
  97. package/doc/type-aliases/NextHandler.md +1 -1
  98. package/doc/type-aliases/Order.md +1 -1
  99. package/doc/type-aliases/OrderNormalized.md +1 -1
  100. package/doc/type-aliases/Parameters.md +1 -1
  101. package/doc/type-aliases/Path.md +1 -1
  102. package/doc/type-aliases/PathFiltered.md +1 -1
  103. package/doc/type-aliases/Primitive.md +1 -1
  104. package/doc/type-aliases/PrimitiveObject.md +1 -1
  105. package/doc/type-aliases/Query.md +1 -1
  106. package/doc/type-aliases/QueryAggregate.md +1 -1
  107. package/doc/type-aliases/QueryCreate.md +1 -1
  108. package/doc/type-aliases/QueryCreateMultiple.md +1 -1
  109. package/doc/type-aliases/QueryDelete.md +1 -1
  110. package/doc/type-aliases/QueryDeleteMultiple.md +1 -1
  111. package/doc/type-aliases/QueryMethod.md +1 -1
  112. package/doc/type-aliases/QueryRead.md +1 -1
  113. package/doc/type-aliases/QueryReadMultiple.md +1 -1
  114. package/doc/type-aliases/QuerySettings.md +23 -5
  115. package/doc/type-aliases/QueryUpdate.md +1 -1
  116. package/doc/type-aliases/QueryUpdateMultiple.md +1 -1
  117. package/doc/type-aliases/Result.md +1 -1
  118. package/doc/type-aliases/Store.md +1 -1
  119. package/doc/type-aliases/Value.md +1 -1
  120. package/doc/type-aliases/ValueMap.md +21 -0
  121. package/doc/variables/CACHE.md +1 -1
  122. package/doc/variables/SELF.md +1 -1
  123. package/lib/tools/queryItemList.ts +2 -2
  124. package/lib/tools/sameField.ts +15 -0
  125. package/lib/tools/sortItemList.test.ts +59 -0
  126. package/lib/tools/sortItemList.ts +40 -2
  127. package/lib/tools/splitPath.test.ts +17 -0
  128. package/lib/tools/splitPath.ts +54 -0
  129. package/lib/tools/testFilter.test.ts +4 -4
  130. package/lib/tools/testFilter.ts +6 -4
  131. package/lib/tools.ts +2 -0
  132. package/lib/types/Field.ts +2 -4
  133. package/lib/types/FieldKey.ts +5 -0
  134. package/lib/types/FieldMap.ts +6 -0
  135. package/lib/types/QuerySettings.ts +13 -6
  136. package/lib/types/ValueMap.ts +14 -0
  137. package/lib/types.ts +3 -0
  138. package/package.json +1 -1
@@ -48,4 +48,4 @@ Query settings.
48
48
 
49
49
  ## Defined in
50
50
 
51
- [lib/types/QueryDelete.ts:9](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryDelete.ts#L9)
51
+ [lib/types/QueryDelete.ts:9](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryDelete.ts#L9)
@@ -48,4 +48,4 @@ Query settings.
48
48
 
49
49
  ## Defined in
50
50
 
51
- [lib/types/QueryDeleteMultiple.ts:9](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryDeleteMultiple.ts#L9)
51
+ [lib/types/QueryDeleteMultiple.ts:9](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryDeleteMultiple.ts#L9)
@@ -12,4 +12,4 @@ Available query methods.
12
12
 
13
13
  ## Defined in
14
14
 
15
- [lib/types/QueryMethod.ts:6](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryMethod.ts#L6)
15
+ [lib/types/QueryMethod.ts:6](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryMethod.ts#L6)
@@ -76,4 +76,4 @@ Query settings.
76
76
 
77
77
  ## Defined in
78
78
 
79
- [lib/types/QueryRead.ts:10](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryRead.ts#L10)
79
+ [lib/types/QueryRead.ts:10](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryRead.ts#L10)
@@ -80,4 +80,4 @@ Query settings.
80
80
 
81
81
  ## Defined in
82
82
 
83
- [lib/types/QueryReadMultiple.ts:11](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryReadMultiple.ts#L11)
83
+ [lib/types/QueryReadMultiple.ts:11](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryReadMultiple.ts#L11)
@@ -22,17 +22,35 @@ Settings to use when doing a query.
22
22
 
23
23
  Abort controller to abort the query.
24
24
 
25
- ### pathFieldKey?
25
+ ### pathField?
26
26
 
27
- > `optional` **pathFieldKey**: [`FieldFiltered`](FieldFiltered.md)\<`T`, `string`\>
27
+ > `optional` **pathField**: [`FieldFiltered`](FieldFiltered.md)\<`T`, `string`\>
28
28
 
29
- Field key to that contains the path value of an item.
29
+ Path to the field that contains the path value of an item, used for displaying items in a tree.
30
30
 
31
31
  ### pathFieldSeparator?
32
32
 
33
33
  > `optional` **pathFieldSeparator**: `string`
34
34
 
35
- String used to separate the path nodes of an item.
35
+ Maps path fields to a string used to separate the path nodes of a field value.
36
+
37
+ #### Default
38
+
39
+ ```ts
40
+ "/"
41
+ ```
42
+
43
+ ### pathFieldSeparatorEscape?
44
+
45
+ > `optional` **pathFieldSeparatorEscape**: `string`
46
+
47
+ String used to escape the separator.
48
+
49
+ #### Default
50
+
51
+ ```ts
52
+ "\\"
53
+ ```
36
54
 
37
55
  ### signal?
38
56
 
@@ -62,4 +80,4 @@ A filter that captures the items expressed by the provided `FilterChildren`.
62
80
 
63
81
  ## Defined in
64
82
 
65
- [lib/types/QuerySettings.ts:8](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QuerySettings.ts#L8)
83
+ [lib/types/QuerySettings.ts:8](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QuerySettings.ts#L8)
@@ -68,4 +68,4 @@ Partial property values to update.
68
68
 
69
69
  ## Defined in
70
70
 
71
- [lib/types/QueryUpdate.ts:9](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryUpdate.ts#L9)
71
+ [lib/types/QueryUpdate.ts:9](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryUpdate.ts#L9)
@@ -72,4 +72,4 @@ Partial property values to update.
72
72
 
73
73
  ## Defined in
74
74
 
75
- [lib/types/QueryUpdateMultiple.ts:10](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/QueryUpdateMultiple.ts#L10)
75
+ [lib/types/QueryUpdateMultiple.ts:10](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/QueryUpdateMultiple.ts#L10)
@@ -16,4 +16,4 @@
16
16
 
17
17
  ## Defined in
18
18
 
19
- [lib/types/Result.ts:20](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/Result.ts#L20)
19
+ [lib/types/Result.ts:20](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/Result.ts#L20)
@@ -68,4 +68,4 @@
68
68
 
69
69
  ## Defined in
70
70
 
71
- [lib/types/Store.ts:2](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/Store.ts#L2)
71
+ [lib/types/Store.ts:2](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/Store.ts#L2)
@@ -36,4 +36,4 @@ Path leading to the value.
36
36
 
37
37
  ## Defined in
38
38
 
39
- [lib/types/Value.ts:6](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/types/Value.ts#L6)
39
+ [lib/types/Value.ts:6](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/Value.ts#L6)
@@ -0,0 +1,21 @@
1
+ [**quetch**](../README.md)
2
+
3
+ ***
4
+
5
+ [quetch](../README.md) / ValueMap
6
+
7
+ # Type Alias: ValueMap\<T, V\>
8
+
9
+ > **ValueMap**\<`T`, `V`\>: `T` *extends* [`Primitive`](Primitive.md) ? `V` : `T` *extends* infer P[] ? `Record`\<`number`, [`ValueMap`](ValueMap.md)\<`P`, `V`\>\> : `T` *extends* `object` ? `{ [K in keyof T]?: ValueMap<T[K], V> }` : `never`
10
+
11
+ Maps the properties of the provided value `T` to a specific value `V`.
12
+
13
+ ## Type Parameters
14
+
15
+ • **T**
16
+
17
+ • **V**
18
+
19
+ ## Defined in
20
+
21
+ [lib/types/ValueMap.ts:6](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/types/ValueMap.ts#L6)
@@ -10,4 +10,4 @@
10
10
 
11
11
  ## Defined in
12
12
 
13
- [lib/constants/CACHE.ts:1](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/constants/CACHE.ts#L1)
13
+ [lib/constants/CACHE.ts:1](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/constants/CACHE.ts#L1)
@@ -10,4 +10,4 @@
10
10
 
11
11
  ## Defined in
12
12
 
13
- [lib/constants/SELF.ts:1](https://github.com/nevoland/quetch/blob/74684cd5cd1bd7a08980d4ce305ecc4be0c3e8b8/lib/constants/SELF.ts#L1)
13
+ [lib/constants/SELF.ts:1](https://github.com/nevoland/quetch/blob/5d54d23c7450a0f85309e15fdf3a25ea832b3452/lib/constants/SELF.ts#L1)
@@ -83,7 +83,7 @@ export function queryItemList<T, const Q extends Query<T>>(
83
83
  );
84
84
  }
85
85
  // Sort
86
- result = sortItemList(order, result);
86
+ result = sortItemList(order, result, query.settings);
87
87
  // Slice
88
88
  if (offset !== 0 || limit !== Infinity) {
89
89
  result = result.slice(offset, offset + limit);
@@ -125,7 +125,7 @@ export function queryItemList<T, const Q extends Query<T>>(
125
125
  );
126
126
  }
127
127
  // Sort
128
- result = sortItemList(order, result);
128
+ result = sortItemList(order, result, query.settings);
129
129
  // Slice
130
130
  if (offset !== 0 || limit !== Infinity) {
131
131
  result = result.slice(offset, offset + limit);
@@ -0,0 +1,15 @@
1
+ import type { Field } from "../types";
2
+
3
+ const { isArray } = Array;
4
+
5
+ export function sameField(a: Field<any>, b: Field<any>): boolean {
6
+ if (a === b) {
7
+ return true;
8
+ }
9
+ const aNormalized = isArray(a) ? a : [a];
10
+ const bNormalized = isArray(b) ? b : [b];
11
+ if (aNormalized.length !== bNormalized.length) {
12
+ return false;
13
+ }
14
+ return aNormalized.every((value, index) => value === bNormalized[index]);
15
+ }
@@ -61,3 +61,62 @@ test("sorts items", () => {
61
61
  { a: 3, c: "b" },
62
62
  ]);
63
63
  });
64
+
65
+ test("sorts items with separator setting", () => {
66
+ expect(
67
+ sortItemList(
68
+ [{ descending: false, field: "path" }],
69
+ [
70
+ { path: "a" },
71
+ { path: "a/b" },
72
+ { path: "a.b" },
73
+ { path: "a/b/c" },
74
+ { path: "a.b.c" },
75
+ { path: "a/b.c" },
76
+ { path: "a\\/b.c" },
77
+ { path: "a.b/c" },
78
+ ],
79
+ {
80
+ pathField: "path",
81
+ pathFieldSeparator: "/",
82
+ },
83
+ ),
84
+ ).toEqual([
85
+ { path: "a" },
86
+ { path: "a/b" },
87
+ { path: "a/b/c" },
88
+ { path: "a/b.c" },
89
+ { path: "a.b" },
90
+ { path: "a.b/c" },
91
+ { path: "a.b.c" },
92
+ { path: "a\\/b.c" },
93
+ ]);
94
+ expect(
95
+ sortItemList(
96
+ [{ descending: false, field: "path" }],
97
+ [
98
+ { path: "a" },
99
+ { path: "a/b" },
100
+ { path: "a.b" },
101
+ { path: "a/b/c" },
102
+ { path: "a.b.c" },
103
+ { path: "a/b.c" },
104
+ { path: "a\\/b.c" },
105
+ { path: "a.b/c" },
106
+ ],
107
+ {
108
+ pathField: "path",
109
+ pathFieldSeparator: "/",
110
+ },
111
+ ),
112
+ ).toEqual([
113
+ { path: "a" },
114
+ { path: "a/b" },
115
+ { path: "a/b/c" },
116
+ { path: "a/b.c" },
117
+ { path: "a.b" },
118
+ { path: "a.b/c" },
119
+ { path: "a.b.c" },
120
+ { path: "a\\/b.c" },
121
+ ]);
122
+ });
@@ -1,24 +1,42 @@
1
- import type { Order } from "../types";
1
+ import type { Order, QuerySettings } from "../types";
2
2
 
3
+ import { escapeRegex } from "./escapeRegex.js";
3
4
  import { get } from "./get.js";
4
5
  import { normalizeOrder } from "./normalizeOrder.js";
6
+ import { sameField } from "./sameField.js";
5
7
 
6
8
  /**
7
9
  * Sorts provided `value` array according to the `orderList`.
8
10
  *
9
11
  * @param orderList The order to use for sorting.
10
12
  * @param value The array to sort.
13
+ * @param settings Optional query settings.
11
14
  * @returns A new sorted array.
12
15
  */
13
16
  export function sortItemList<T>(
14
17
  orderList: readonly Order<T>[] | undefined,
15
18
  value: readonly T[],
19
+ settings?: QuerySettings<T>,
16
20
  ) {
21
+ const {
22
+ pathField,
23
+ pathFieldSeparator = "/",
24
+ pathFieldSeparatorEscape,
25
+ } = settings ?? {};
17
26
  if (orderList === undefined || orderList.length === 0) {
18
27
  return value;
19
28
  }
20
29
  const normalizedOrder = orderList.map(normalizeOrder);
21
- return [...value].sort((a, b) => {
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
+ return value.toSorted((a, b) => {
22
40
  for (let index = 0; index < normalizedOrder.length; index++) {
23
41
  const { field, descending } = normalizedOrder[index]!;
24
42
  const valueA = get(a, field as any);
@@ -26,6 +44,26 @@ export function sortItemList<T>(
26
44
  if (valueA === valueB) {
27
45
  continue;
28
46
  }
47
+ if (fieldSeparatorRegexp != null && sameField(field, pathField!)) {
48
+ if (valueA == null) {
49
+ return valueB == null ? 0 : descending ? 1 : -1;
50
+ }
51
+ if (valueB == null) {
52
+ return descending ? -1 : 1;
53
+ }
54
+ const normalizedA = (valueA as string).replaceAll(
55
+ fieldSeparatorRegexp,
56
+ "\x00",
57
+ );
58
+ const normalizedB = (valueB as string).replaceAll(
59
+ fieldSeparatorRegexp,
60
+ "\x00",
61
+ );
62
+ if (normalizedA > normalizedB) {
63
+ return descending ? -1 : 1;
64
+ }
65
+ return descending ? 1 : -1;
66
+ }
29
67
  if (valueA > valueB) {
30
68
  return descending ? -1 : 1;
31
69
  }
@@ -0,0 +1,17 @@
1
+ import { expect, test } from "vitest";
2
+
3
+ import { splitPath } from "./splitPath.js";
4
+
5
+ test("splits paths", () => {
6
+ expect(splitPath("/", "\\", "/a/b")).toEqual(["", "a", "b"]);
7
+ expect(splitPath("/", "\\", "/a\\/b")).toEqual(["", "a\\/b"]);
8
+ expect(splitPath("/", "", "/a\\/b")).toEqual(["", "a\\", "b"]);
9
+ expect(splitPath("", "", "/a/b")).toEqual(["/a/b"]);
10
+ });
11
+
12
+ test("returns path splitter", () => {
13
+ expect(splitPath("/", "\\")("/a/b")).toEqual(["", "a", "b"]);
14
+ expect(splitPath("/", "\\")("/a\\/b")).toEqual(["", "a\\/b"]);
15
+ expect(splitPath("/", "")("/a\\/b")).toEqual(["", "a\\", "b"]);
16
+ expect(splitPath("", "")("/a/b")).toEqual(["/a/b"]);
17
+ });
@@ -0,0 +1,54 @@
1
+ import { escapeRegex } from "./escapeRegex.js";
2
+
3
+ type PathSplitter =
4
+ /**
5
+ * Takes a `path` string and returns an array of path items.
6
+ *
7
+ * @param path The path string to split.
8
+ *
9
+ */
10
+ (path: string) => readonly string[];
11
+
12
+ /**
13
+ * Splits a `path` string using the `separator`, omitting those prefixed with a `separatorEscape`.
14
+ *
15
+ * If `path` is `undefined`, returns a function that takes `path` and splits it according to the provided `separator` and `separatorEscape` arguments.
16
+ *
17
+ * @param separator The separator string to use (defaults to `"/"`).
18
+ * @param separatorEscape The separator escape string to use (default to `"\\"`).
19
+ * @param path The path string to split.
20
+ * @returns An array containing the splitted path items if `path` is defined, or a function that takes a `path` string and returns an array.
21
+ */
22
+ export function splitPath(
23
+ separator: string | undefined,
24
+ separatorEscape: string | undefined,
25
+ path: string,
26
+ ): readonly string[];
27
+ export function splitPath(
28
+ separator?: string,
29
+ separatorEscape?: string,
30
+ ): PathSplitter;
31
+ export function splitPath(
32
+ separator = "/",
33
+ separatorEscape = "\\",
34
+ path?: string,
35
+ ): readonly string[] | PathSplitter {
36
+ const fieldSeparatorRegexp = !separator
37
+ ? null
38
+ : new RegExp(
39
+ !separatorEscape
40
+ ? escapeRegex(separator)
41
+ : `(?<!${escapeRegex(separatorEscape)})${escapeRegex(separator)}`,
42
+ "g",
43
+ );
44
+ if (path == null) {
45
+ if (fieldSeparatorRegexp == null) {
46
+ return (path: string) => [path];
47
+ }
48
+ return (path: string) => path.split(fieldSeparatorRegexp);
49
+ }
50
+ if (fieldSeparatorRegexp == null) {
51
+ return [path];
52
+ }
53
+ return path.split(fieldSeparatorRegexp);
54
+ }
@@ -322,7 +322,7 @@ test("tests filter with children predicates", () => {
322
322
  { operator: "children", value: ".a" },
323
323
  { path: ".a.b" },
324
324
  {
325
- pathFieldKey: "path",
325
+ pathField: "path",
326
326
  pathFieldSeparator: ".",
327
327
  },
328
328
  ),
@@ -332,7 +332,7 @@ test("tests filter with children predicates", () => {
332
332
  { operator: "notChildren", value: ".a" },
333
333
  { path: ".a.b" },
334
334
  {
335
- pathFieldKey: "path",
335
+ pathField: "path",
336
336
  pathFieldSeparator: ".",
337
337
  },
338
338
  ),
@@ -368,7 +368,7 @@ test("tests filter with children predicates", () => {
368
368
  { operator: "children", value: "ba" },
369
369
  { path: ".a.b" },
370
370
  {
371
- pathFieldKey: "path",
371
+ pathField: "path",
372
372
  pathFieldSeparator: ".",
373
373
  },
374
374
  ),
@@ -378,7 +378,7 @@ test("tests filter with children predicates", () => {
378
378
  { operator: "notChildren", value: "ba" },
379
379
  { path: ".a.b" },
380
380
  {
381
- pathFieldKey: "path",
381
+ pathField: "path",
382
382
  pathFieldSeparator: ".",
383
383
  },
384
384
  ),
@@ -1,3 +1,5 @@
1
+ import { EMPTY_OBJECT } from "unchangeable";
2
+
1
3
  import { CACHE } from "../constants/CACHE.js";
2
4
  import type { QuerySettings } from "../types/QuerySettings.js";
3
5
  import type { FieldFiltered, Filter, FilterString } from "../types.js";
@@ -113,12 +115,12 @@ export function testFilter<T>(
113
115
  break;
114
116
  default: {
115
117
  const {
116
- pathFieldKey = "id" as FieldFiltered<T, string>,
117
- pathFieldSeparator = "/",
118
- } = settings || {};
118
+ pathField = "id" as FieldFiltered<T, string>,
119
+ pathFieldSeparator,
120
+ } = settings || (EMPTY_OBJECT as QuerySettings<T>);
119
121
  filter[CACHE] = filterChildren(
120
122
  filter.value as string,
121
- pathFieldKey,
123
+ pathField,
122
124
  filter.deep,
123
125
  pathFieldSeparator,
124
126
  );
package/lib/tools.ts CHANGED
@@ -12,5 +12,7 @@ export { isFilterGroup } from "./tools/isFilterGroup.js";
12
12
  export { normalizeOrder } from "./tools/normalizeOrder.js";
13
13
  export { queryItemList } from "./tools/queryItemList.js";
14
14
  export { reverseOrder } from "./tools/reverseOrder.js";
15
+ export { sameField } from "./tools/sameField.js";
15
16
  export { sortItemList } from "./tools/sortItemList.js";
17
+ export { splitPath } from "./tools/splitPath.js";
16
18
  export { testFilter } from "./tools/testFilter.js";
@@ -1,9 +1,7 @@
1
- import type { SELF } from "../constants/SELF.js";
2
-
3
1
  import type { CombineUnion } from "./CombineUnion";
2
+ import type { FieldKey } from "./FieldKey.js";
4
3
  import type { Path } from "./Path";
5
- import type { Primitive } from "./Primitive";
6
4
 
7
5
  export type Field<T> = KeyOrPath<CombineUnion<T>>;
8
6
 
9
- type KeyOrPath<T> = (T extends Primitive ? typeof SELF : keyof T) | Path<T>;
7
+ type KeyOrPath<T> = FieldKey<T> | Path<T>;
@@ -0,0 +1,5 @@
1
+ import type { SELF } from "../constants/SELF.ts";
2
+
3
+ import type { Primitive } from "./Primitive";
4
+
5
+ export type FieldKey<T> = T extends Primitive ? typeof SELF : keyof T;
@@ -0,0 +1,6 @@
1
+ import type { Field } from "./Field";
2
+
3
+ /**
4
+ * Maps the fields of the provided value `T` to a specific value `V`.
5
+ */
6
+ export type FieldMap<T, V> = readonly [Field<T>, V][];
@@ -6,15 +6,22 @@ import type { FilterChildren } from "./FilterChildren";
6
6
  * Settings to use when doing a query.
7
7
  */
8
8
  export type QuerySettings<T> = {
9
- // TODO: Move `path*` and `transform*` to fetch middleware?
10
9
  /**
11
- * String used to separate the path nodes of an item.
10
+ * Path to the field that contains the path value of an item, used for displaying items in a tree.
12
11
  */
13
- pathFieldSeparator?: string;
12
+ pathField?: FieldFiltered<T, string>;
13
+ /**
14
+ * String used to escape the separator.
15
+ *
16
+ * @default "\\"
17
+ */
18
+ pathFieldSeparatorEscape?: string;
14
19
  /**
15
- * Field key to that contains the path value of an item.
20
+ * Maps path fields to a string used to separate the path nodes of a field value.
21
+ *
22
+ * @default "/"
16
23
  */
17
- pathFieldKey?: FieldFiltered<T, string>;
24
+ pathFieldSeparator?: string;
18
25
  /**
19
26
  * Returns a filter that captures the items expressed by the provided `FilterChildren`. The return filter cannot use filters of type `FilterChildren`.
20
27
  *
@@ -23,7 +30,7 @@ export type QuerySettings<T> = {
23
30
  */
24
31
  transformFilterChildren?: (
25
32
  filter: FilterChildren<T>,
26
- ) => Exclude<Filter<T>, { operator: "children" }>;
33
+ ) => Exclude<Filter<T>, { operator: "children" | "notChildren" }>;
27
34
  /**
28
35
  * Abort signal to abort the query.
29
36
  */
@@ -0,0 +1,14 @@
1
+ import type { Primitive } from "./Primitive";
2
+
3
+ /**
4
+ * Maps the properties of the provided value `T` to a specific value `V`.
5
+ */
6
+ export type ValueMap<T, V> = T extends Primitive
7
+ ? V
8
+ : T extends Array<infer P>
9
+ ? Record<number, ValueMap<P, V>>
10
+ : T extends object
11
+ ? {
12
+ [K in keyof T]?: ValueMap<T[K], V>;
13
+ }
14
+ : never;
package/lib/types.ts CHANGED
@@ -12,6 +12,8 @@ export type { FieldFunction } from "./types/FieldFunction";
12
12
  export type { FieldFunctionCustom } from "./types/FieldFunctionCustom";
13
13
  export type { FieldFunctionFormatDate } from "./types/FieldFunctionFormatDate";
14
14
  export type { FieldFunctionReturn } from "./types/FieldFunctionReturn";
15
+ export type { FieldKey } from "./types/FieldKey";
16
+ export type { FieldMap } from "./types/FieldMap";
15
17
  export type { Filter } from "./types/Filter";
16
18
  export type { FilterArray } from "./types/FilterArray";
17
19
  export type { FilterBoolean } from "./types/FilterBoolean";
@@ -60,3 +62,4 @@ export type { QueryUpdateMultiple } from "./types/QueryUpdateMultiple";
60
62
  export type { Result } from "./types/Result";
61
63
  export type { Store } from "./types/Store";
62
64
  export type { Value } from "./types/Value";
65
+ export type { ValueMap } from "./types/ValueMap";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quetch",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "main": "./dist/main.js",
6
6
  "exports": {