quetch 0.27.0 → 0.28.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 (121) hide show
  1. package/dist/tools/filterChildren.d.ts +1 -1
  2. package/dist/tools/filterChildren.js +4 -4
  3. package/dist/tools/filterChildren.js.map +1 -1
  4. package/dist/tools/testFilter.js +23 -6
  5. package/dist/tools/testFilter.js.map +1 -1
  6. package/dist/types/Filter.d.ts +2 -1
  7. package/dist/types/FilterChildren.d.ts +13 -3
  8. package/dist/types/FilterContext.d.ts +11 -0
  9. package/dist/types/FilterContext.js +1 -0
  10. package/dist/types/FilterContext.js.map +1 -0
  11. package/dist/types/QuerySettings.d.ts +8 -0
  12. package/dist/types.d.ts +1 -0
  13. package/doc/README.md +1 -0
  14. package/doc/classes/RequestError.md +5 -5
  15. package/doc/functions/aggregate.md +1 -1
  16. package/doc/functions/branch.md +1 -1
  17. package/doc/functions/cache.md +1 -1
  18. package/doc/functions/combine.md +1 -1
  19. package/doc/functions/cork.md +1 -1
  20. package/doc/functions/defineCheckQuery.md +1 -1
  21. package/doc/functions/defineCustomFetch.md +1 -1
  22. package/doc/functions/defineGenericFetch.md +1 -1
  23. package/doc/functions/escapeRegex.md +1 -1
  24. package/doc/functions/fetchExternal.md +1 -1
  25. package/doc/functions/fetchLocal.md +1 -1
  26. package/doc/functions/fieldListFromFilter.md +1 -1
  27. package/doc/functions/filterChildren.md +8 -4
  28. package/doc/functions/filterFromValue.md +1 -1
  29. package/doc/functions/get.md +1 -1
  30. package/doc/functions/groupFilters.md +1 -1
  31. package/doc/functions/identity.md +1 -1
  32. package/doc/functions/isFilterGroup.md +1 -1
  33. package/doc/functions/log.md +1 -1
  34. package/doc/functions/normalizeOrder.md +1 -1
  35. package/doc/functions/queryItemList.md +1 -1
  36. package/doc/functions/retry.md +1 -1
  37. package/doc/functions/reverseOrder.md +1 -1
  38. package/doc/functions/sameField.md +1 -1
  39. package/doc/functions/sortItemList.md +1 -1
  40. package/doc/functions/splitPath.md +2 -2
  41. package/doc/functions/testFilter.md +1 -1
  42. package/doc/interfaces/CustomFetch.md +1 -1
  43. package/doc/type-aliases/AggregateFunction.md +1 -1
  44. package/doc/type-aliases/AggregateFunctionOperator.md +1 -1
  45. package/doc/type-aliases/CombineUnion.md +1 -1
  46. package/doc/type-aliases/Context.md +1 -1
  47. package/doc/type-aliases/CustomFieldAggregateMap.md +1 -1
  48. package/doc/type-aliases/CustomFieldMap.md +1 -1
  49. package/doc/type-aliases/Field.md +1 -1
  50. package/doc/type-aliases/FieldFiltered.md +1 -1
  51. package/doc/type-aliases/FieldFunction.md +1 -1
  52. package/doc/type-aliases/FieldFunctionCustom.md +1 -1
  53. package/doc/type-aliases/FieldFunctionFormatDate.md +1 -1
  54. package/doc/type-aliases/FieldFunctionReturn.md +1 -1
  55. package/doc/type-aliases/FieldKey.md +1 -1
  56. package/doc/type-aliases/FieldMap.md +1 -1
  57. package/doc/type-aliases/Filter.md +2 -2
  58. package/doc/type-aliases/FilterArray.md +1 -1
  59. package/doc/type-aliases/FilterBoolean.md +1 -1
  60. package/doc/type-aliases/FilterChildren.md +24 -5
  61. package/doc/type-aliases/FilterContext.md +33 -0
  62. package/doc/type-aliases/FilterCustom.md +1 -1
  63. package/doc/type-aliases/FilterField.md +1 -1
  64. package/doc/type-aliases/FilterGroup.md +1 -1
  65. package/doc/type-aliases/FilterNumber.md +1 -1
  66. package/doc/type-aliases/FilterOperator.md +1 -1
  67. package/doc/type-aliases/FilterString.md +1 -1
  68. package/doc/type-aliases/FilterStringIntersect.md +1 -1
  69. package/doc/type-aliases/FilterStringMatch.md +1 -1
  70. package/doc/type-aliases/Get.md +1 -1
  71. package/doc/type-aliases/Group.md +1 -1
  72. package/doc/type-aliases/Handler.md +1 -1
  73. package/doc/type-aliases/Immutable.md +1 -1
  74. package/doc/type-aliases/Increment.md +1 -1
  75. package/doc/type-aliases/InjectCustomFields.md +1 -1
  76. package/doc/type-aliases/IntersectUnion.md +1 -1
  77. package/doc/type-aliases/IntrinsicFilter.md +1 -1
  78. package/doc/type-aliases/Item.md +1 -1
  79. package/doc/type-aliases/Join.md +1 -1
  80. package/doc/type-aliases/Key.md +1 -1
  81. package/doc/type-aliases/KeyFiltered.md +1 -1
  82. package/doc/type-aliases/KeyFromUnion.md +1 -1
  83. package/doc/type-aliases/Locale.md +1 -1
  84. package/doc/type-aliases/NextHandler.md +1 -1
  85. package/doc/type-aliases/Order.md +1 -1
  86. package/doc/type-aliases/OrderNormalized.md +1 -1
  87. package/doc/type-aliases/Parameters.md +1 -1
  88. package/doc/type-aliases/Path.md +1 -1
  89. package/doc/type-aliases/PathFiltered.md +1 -1
  90. package/doc/type-aliases/Primitive.md +1 -1
  91. package/doc/type-aliases/PrimitiveObject.md +1 -1
  92. package/doc/type-aliases/Query.md +1 -1
  93. package/doc/type-aliases/QueryAggregate.md +1 -1
  94. package/doc/type-aliases/QueryCreate.md +1 -1
  95. package/doc/type-aliases/QueryCreateMultiple.md +1 -1
  96. package/doc/type-aliases/QueryDelete.md +1 -1
  97. package/doc/type-aliases/QueryDeleteMultiple.md +1 -1
  98. package/doc/type-aliases/QueryMethod.md +1 -1
  99. package/doc/type-aliases/QueryRead.md +1 -1
  100. package/doc/type-aliases/QueryReadMultiple.md +1 -1
  101. package/doc/type-aliases/QuerySettings.md +17 -1
  102. package/doc/type-aliases/QueryUpdate.md +1 -1
  103. package/doc/type-aliases/QueryUpdateMultiple.md +1 -1
  104. package/doc/type-aliases/Result.md +1 -1
  105. package/doc/type-aliases/Store.md +1 -1
  106. package/doc/type-aliases/Value.md +1 -1
  107. package/doc/type-aliases/ValueMap.md +1 -1
  108. package/doc/variables/CACHE.md +1 -1
  109. package/doc/variables/FILTER_ANY.md +1 -1
  110. package/doc/variables/FILTER_NONE.md +1 -1
  111. package/doc/variables/SELF.md +1 -1
  112. package/lib/tools/filterChildren.ts +6 -4
  113. package/lib/tools/filterFromValue.test.ts +18 -48
  114. package/lib/tools/testFilter.test.ts +84 -15
  115. package/lib/tools/testFilter.ts +43 -14
  116. package/lib/types/Filter.ts +2 -0
  117. package/lib/types/FilterChildren.ts +13 -3
  118. package/lib/types/FilterContext.ts +13 -0
  119. package/lib/types/QuerySettings.ts +8 -0
  120. package/lib/types.ts +1 -0
  121. package/package.json +1 -1
@@ -6,64 +6,34 @@ import { filterFromValue } from "./filterFromValue.js";
6
6
 
7
7
  test("returns filter from context", () => {
8
8
  expect(filterFromValue({ a: 1 })).toEqual({
9
- operator: "all",
10
- value: [
11
- {
12
- field: "a",
13
- operator: "equal",
14
- value: 1,
15
- },
16
- ],
9
+ field: "a",
10
+ operator: "equal",
11
+ value: 1,
17
12
  });
18
13
  expect(filterFromValue({ a: { b: 1 } })).toEqual({
19
- operator: "all",
20
- value: [
21
- {
22
- field: ["a", "b"],
23
- operator: "equal",
24
- value: 1,
25
- },
26
- ],
14
+ field: ["a", "b"],
15
+ operator: "equal",
16
+ value: 1,
27
17
  });
28
18
  expect(filterFromValue({ a: { b: undefined } })).toEqual({
29
- operator: "all",
30
- value: [
31
- {
32
- field: ["a", "b"],
33
- operator: "equal",
34
- value: undefined,
35
- },
36
- ],
19
+ field: ["a", "b"],
20
+ operator: "equal",
21
+ value: undefined,
37
22
  });
38
23
  expect(filterFromValue({ a: { b: null } })).toEqual({
39
- operator: "all",
40
- value: [
41
- {
42
- field: ["a", "b"],
43
- operator: "equal",
44
- value: null,
45
- },
46
- ],
24
+ field: ["a", "b"],
25
+ operator: "equal",
26
+ value: null,
47
27
  });
48
28
  expect(filterFromValue({ [SELF]: 3 })).toEqual({
49
- operator: "all",
50
- value: [
51
- {
52
- field: SELF,
53
- operator: "equal",
54
- value: 3,
55
- },
56
- ],
29
+ field: SELF,
30
+ operator: "equal",
31
+ value: 3,
57
32
  });
58
33
  expect(filterFromValue({ a: null })).toEqual({
59
- operator: "all",
60
- value: [
61
- {
62
- field: "a",
63
- operator: "equal",
64
- value: null,
65
- },
66
- ],
34
+ field: "a",
35
+ operator: "equal",
36
+ value: null,
67
37
  });
68
38
  expect(filterFromValue({ a: { b: 1 }, c: 2 })).toEqual({
69
39
  operator: "all",
@@ -2,7 +2,7 @@ import { expect, test } from "vitest";
2
2
 
3
3
  import { CACHE } from "../constants/CACHE.js";
4
4
  import { SELF } from "../constants.js";
5
- import type { FilterChildren } from "../types.js";
5
+ import type { FilterChildren, FilterContext } from "../types.js";
6
6
 
7
7
  import { filterFromValue } from "./filterFromValue.js";
8
8
  import { testFilter } from "./testFilter.js";
@@ -351,15 +351,15 @@ test("tests filter with paths", () => {
351
351
  });
352
352
 
353
353
  test("tests filter with children predicates", () => {
354
- expect(testFilter({ operator: "children", value: "a" }, { id: "a/b" })).toBe(
355
- true,
356
- );
357
354
  expect(
358
- testFilter({ operator: "notChildren", value: "a" }, { id: "a/b" }),
355
+ testFilter({ operator: "children", value: { id: "a" } }, { id: "a/b" }),
356
+ ).toBe(true);
357
+ expect(
358
+ testFilter({ operator: "notChildren", value: { id: "a" } }, { id: "a/b" }),
359
359
  ).toBe(false);
360
360
  expect(
361
361
  testFilter(
362
- { operator: "children", value: ".a" },
362
+ { operator: "children", value: { path: ".a" } },
363
363
  { path: ".a.b" },
364
364
  {
365
365
  pathField: "path",
@@ -369,7 +369,7 @@ test("tests filter with children predicates", () => {
369
369
  ).toBe(true);
370
370
  expect(
371
371
  testFilter(
372
- { operator: "notChildren", value: ".a" },
372
+ { operator: "notChildren", value: { path: ".a" } },
373
373
  { path: ".a.b" },
374
374
  {
375
375
  pathField: "path",
@@ -379,7 +379,7 @@ test("tests filter with children predicates", () => {
379
379
  ).toBe(false);
380
380
  const filterChildren: FilterChildren<{ path: string }> = {
381
381
  operator: "children",
382
- value: "a",
382
+ value: { path: "a" },
383
383
  };
384
384
  expect(
385
385
  testFilter(
@@ -390,22 +390,40 @@ test("tests filter with children predicates", () => {
390
390
  return {
391
391
  field: "path",
392
392
  operator: "startWith",
393
- value: `.${filter.value}.`,
393
+ value: `.${filter.value?.path}.`,
394
+ };
395
+ },
396
+ },
397
+ ),
398
+ ).toBe(true);
399
+ expect(
400
+ testFilter(
401
+ {
402
+ operator: "all",
403
+ value: [filterChildren],
404
+ },
405
+ { path: ".a.b" },
406
+ {
407
+ transformFilterChildren(filter) {
408
+ return {
409
+ field: "path",
410
+ operator: "startWith",
411
+ value: `.${filter.value?.path}.`,
394
412
  };
395
413
  },
396
414
  },
397
415
  ),
398
416
  ).toBe(true);
399
417
  expect(filterChildren[CACHE]).toBeDefined();
400
- expect(testFilter({ operator: "children", value: "b" }, { id: "a/b" })).toBe(
401
- false,
402
- );
403
418
  expect(
404
- testFilter({ operator: "notChildren", value: "b" }, { id: "a/b" }),
419
+ testFilter({ operator: "children", value: { id: "b" } }, { id: "a/b" }),
420
+ ).toBe(false);
421
+ expect(
422
+ testFilter({ operator: "notChildren", value: { id: "b" } }, { id: "a/b" }),
405
423
  ).toBe(true);
406
424
  expect(
407
425
  testFilter(
408
- { operator: "children", value: "ba" },
426
+ { operator: "children", value: { path: "ba" } },
409
427
  { path: ".a.b" },
410
428
  {
411
429
  pathField: "path",
@@ -415,7 +433,7 @@ test("tests filter with children predicates", () => {
415
433
  ).toBe(false);
416
434
  expect(
417
435
  testFilter(
418
- { operator: "notChildren", value: "ba" },
436
+ { operator: "notChildren", value: { path: "ba" } },
419
437
  { path: ".a.b" },
420
438
  {
421
439
  pathField: "path",
@@ -424,3 +442,54 @@ test("tests filter with children predicates", () => {
424
442
  ),
425
443
  ).toBe(true);
426
444
  });
445
+
446
+ test("tests filter with context predicates", () => {
447
+ const context = { id: "a" };
448
+ expect(testFilter({ operator: "is", value: context }, { id: "a" })).toBe(
449
+ true,
450
+ );
451
+ expect(testFilter({ operator: "notIs", value: context }, { id: "a" })).toBe(
452
+ false,
453
+ );
454
+ const filterContext: FilterContext<typeof context> = {
455
+ operator: "is",
456
+ value: context,
457
+ };
458
+ expect(
459
+ testFilter(
460
+ filterContext,
461
+ { id: "a" },
462
+ {
463
+ transformFilterContext(filter) {
464
+ return {
465
+ field: "id",
466
+ operator: "equal",
467
+ value: filter.value?.id ?? "",
468
+ };
469
+ },
470
+ },
471
+ ),
472
+ ).toBe(true);
473
+ expect(
474
+ testFilter(
475
+ { operator: "all", value: [filterContext] },
476
+ { id: "a" },
477
+ {
478
+ transformFilterContext(filter) {
479
+ return {
480
+ field: "id",
481
+ operator: "equal",
482
+ value: filter.value?.id ?? "",
483
+ };
484
+ },
485
+ },
486
+ ),
487
+ ).toBe(true);
488
+ expect(filterContext[CACHE]).toBeDefined();
489
+ expect(testFilter({ operator: "is", value: { id: "b" } }, { id: "a" })).toBe(
490
+ false,
491
+ );
492
+ expect(
493
+ testFilter({ operator: "notIs", value: { id: "b" } }, { id: "a" }),
494
+ ).toBe(true);
495
+ });
@@ -2,9 +2,16 @@ import { EMPTY_OBJECT } from "unchangeable";
2
2
 
3
3
  import { CACHE } from "../constants/CACHE.js";
4
4
  import type { QuerySettings } from "../types/QuerySettings.js";
5
- import type { FieldFiltered, Filter, FilterString } from "../types.js";
5
+ import type {
6
+ Context,
7
+ FieldFiltered,
8
+ Filter,
9
+ FilterString,
10
+ IntrinsicFilter,
11
+ } from "../types.js";
6
12
 
7
13
  import { filterChildren } from "./filterChildren.js";
14
+ import { filterFromValue } from "./filterFromValue.js";
8
15
  import { get } from "./get.js";
9
16
 
10
17
  const { isArray } = Array;
@@ -38,7 +45,9 @@ export function testFilter<T>(
38
45
  }
39
46
  switch (filter.operator) {
40
47
  case "all":
41
- return filter.value.every((filter) => testFilter(filter, value));
48
+ return filter.value.every((filter) =>
49
+ testFilter(filter, value, settings),
50
+ );
42
51
  case "any": {
43
52
  const length = filter.value?.length ?? 0;
44
53
  const minimum = filter.minimum ?? (length > 0 ? 1 : 0);
@@ -47,10 +56,13 @@ export function testFilter<T>(
47
56
  return true;
48
57
  }
49
58
  if (minimum === 1 && maximum >= length) {
50
- return filter.value.some((filter) => testFilter(filter, value));
59
+ return filter.value.some((filter) =>
60
+ testFilter(filter, value, settings),
61
+ );
51
62
  }
52
63
  const matched = filter.value.reduce(
53
- (count, filter) => count + (testFilter(filter, value) ? 1 : 0),
64
+ (count, filter) =>
65
+ count + (testFilter(filter, value, settings) ? 1 : 0),
54
66
  0,
55
67
  );
56
68
  return matched >= minimum && matched <= maximum;
@@ -59,7 +71,9 @@ export function testFilter<T>(
59
71
  if (filter.value === undefined || filter.value.length === 0) {
60
72
  return false;
61
73
  }
62
- return filter.value.every((filter) => !testFilter(filter, value));
74
+ return filter.value.every(
75
+ (filter) => !testFilter(filter, value, settings),
76
+ );
63
77
  }
64
78
  case "exist":
65
79
  return get(value, filter.field as any) !== undefined;
@@ -124,16 +138,31 @@ export function testFilter<T>(
124
138
  filter[CACHE] = settings.transformFilterChildren(filter);
125
139
  break;
126
140
  default: {
127
- const {
128
- pathField = "id" as FieldFiltered<T, string>,
129
- pathFieldSeparator,
130
- } = settings || EMPTY_OBJECT;
131
- filter[CACHE] = filterChildren(
132
- filter.value as string,
133
- pathField,
134
- filter.deep,
141
+ const { pathField = "id", pathFieldSeparator } =
142
+ settings || EMPTY_OBJECT;
143
+ pathField;
144
+ filter[CACHE] = filterChildren<Context<T>>(
145
+ (get(filter.value, pathField as any) as string) ?? "",
146
+ pathField as FieldFiltered<Context<T>, string>,
147
+ filter.minDepth,
148
+ filter.maxDepth,
135
149
  pathFieldSeparator,
136
- );
150
+ ) as IntrinsicFilter<T>;
151
+ }
152
+ }
153
+ }
154
+ return negate(testFilter(filter[CACHE], value, settings), not);
155
+ }
156
+ case "is":
157
+ case "notIs": {
158
+ const not = filter.operator[0] === "n";
159
+ if (filter[CACHE] === undefined) {
160
+ switch (true) {
161
+ case settings?.transformFilterContext !== undefined:
162
+ filter[CACHE] = settings.transformFilterContext(filter);
163
+ break;
164
+ default: {
165
+ filter[CACHE] = filterFromValue(filter.value as T);
137
166
  }
138
167
  }
139
168
  }
@@ -1,6 +1,7 @@
1
1
  import type { FilterArray } from "./FilterArray";
2
2
  import type { FilterBoolean } from "./FilterBoolean";
3
3
  import type { FilterChildren } from "./FilterChildren";
4
+ import type { FilterContext } from "./FilterContext";
4
5
  import type { FilterCustom } from "./FilterCustom";
5
6
  import type { FilterField } from "./FilterField";
6
7
  import type { FilterGroup } from "./FilterGroup";
@@ -22,4 +23,5 @@ export type Filter<T> =
22
23
  | FilterGroup<T>
23
24
  | FilterString<T>
24
25
  | FilterStringIntersect<T>
26
+ | FilterContext<T>
25
27
  | FilterStringMatch<T>;
@@ -5,11 +5,21 @@ import type { IntrinsicFilter } from "./IntrinsicFilter.js";
5
5
 
6
6
  /**
7
7
  * Matches the direct children of a specified `value` item.
8
- * If `deep` is `true`, also captures all the descendants.
9
8
  */
10
9
  export type FilterChildren<T> = {
11
10
  operator: "children" | "notChildren";
12
- value?: Context<T> | string;
13
- deep?: boolean;
11
+ value?: Context<T>;
12
+ /**
13
+ * Minimum depth of the children to match. If `0`, matches the direct children. If `1`, matches the grandchildren, and so on.
14
+ *
15
+ * @default 0
16
+ */
17
+ minDepth?: number;
18
+ /**
19
+ * Maximum depth of the children to match. If `0`, matches the direct children. If `1`, matches the grandchildren, and so on.
20
+ *
21
+ * @default Infinity
22
+ */
23
+ maxDepth?: number;
14
24
  [CACHE]?: IntrinsicFilter<T>;
15
25
  };
@@ -0,0 +1,13 @@
1
+ import type { CACHE } from "../constants/CACHE.js";
2
+
3
+ import type { Context } from "./Context";
4
+ import type { IntrinsicFilter } from "./IntrinsicFilter.js";
5
+
6
+ /**
7
+ * Matches items identified by their context.
8
+ */
9
+ export type FilterContext<T> = {
10
+ operator: "is" | "notIs";
11
+ value: Context<T>;
12
+ [CACHE]?: IntrinsicFilter<T>;
13
+ };
@@ -1,5 +1,6 @@
1
1
  import type { FieldFiltered } from "./FieldFiltered";
2
2
  import type { FilterChildren } from "./FilterChildren";
3
+ import type { FilterContext } from "./FilterContext";
3
4
  import type { IntrinsicFilter } from "./IntrinsicFilter";
4
5
 
5
6
  /**
@@ -29,6 +30,13 @@ export type QuerySettings<T> = {
29
30
  * @returns A filter that captures the items expressed by the provided `FilterChildren`.
30
31
  */
31
32
  transformFilterChildren?: (filter: FilterChildren<T>) => IntrinsicFilter<T>;
33
+ /**
34
+ * Returns a filter that captures the items expressed by the provided `FilterContext`. The return filter cannot use filters of type `FilterContext` or `FilterChildren`.
35
+ *
36
+ * @param filter
37
+ * @returns
38
+ */
39
+ transformFilterContext?: (filter: FilterContext<T>) => IntrinsicFilter<T>;
32
40
  /**
33
41
  * Abort signal to abort the query.
34
42
  */
package/lib/types.ts CHANGED
@@ -18,6 +18,7 @@ export type { Filter } from "./types/Filter";
18
18
  export type { FilterArray } from "./types/FilterArray";
19
19
  export type { FilterBoolean } from "./types/FilterBoolean";
20
20
  export type { FilterChildren } from "./types/FilterChildren";
21
+ export type { FilterContext } from "./types/FilterContext";
21
22
  export type { FilterCustom } from "./types/FilterCustom";
22
23
  export type { FilterField } from "./types/FilterField";
23
24
  export type { FilterGroup } from "./types/FilterGroup";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quetch",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "type": "module",
5
5
  "main": "./dist/main.js",
6
6
  "exports": {