@antelopejs/interface-data-api 0.4.0 → 0.6.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 (165) hide show
  1. package/README.md +26 -22
  2. package/dist/antelope.test.js +1 -5
  3. package/dist/antelope.test.js.map +1 -1
  4. package/dist/components.d.ts +67 -39
  5. package/dist/components.js +106 -685
  6. package/dist/components.js.map +1 -1
  7. package/dist/index.d.ts +57 -68
  8. package/dist/index.js +114 -100
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal/computed.d.ts +6 -0
  11. package/dist/internal/computed.js +51 -0
  12. package/dist/internal/computed.js.map +1 -0
  13. package/dist/internal/controller-types.d.ts +34 -0
  14. package/dist/internal/controller-types.js +4 -0
  15. package/dist/internal/controller-types.js.map +1 -0
  16. package/dist/internal/default-filter.d.ts +4 -0
  17. package/dist/internal/default-filter.js +29 -0
  18. package/dist/internal/default-filter.js.map +1 -0
  19. package/dist/internal/deferred-joined-stream.d.ts +11 -0
  20. package/dist/internal/deferred-joined-stream.js +125 -0
  21. package/dist/internal/deferred-joined-stream.js.map +1 -0
  22. package/dist/internal/extractors.d.ts +25 -0
  23. package/dist/internal/extractors.js +31 -0
  24. package/dist/internal/extractors.js.map +1 -0
  25. package/dist/internal/field-types.d.ts +199 -0
  26. package/dist/internal/field-types.js +4 -0
  27. package/dist/internal/field-types.js.map +1 -0
  28. package/dist/internal/filters.d.ts +6 -0
  29. package/dist/internal/filters.js +22 -0
  30. package/dist/internal/filters.js.map +1 -0
  31. package/dist/internal/foreign.d.ts +6 -0
  32. package/dist/internal/foreign.js +116 -0
  33. package/dist/internal/foreign.js.map +1 -0
  34. package/dist/internal/guards.d.ts +39 -0
  35. package/dist/internal/guards.js +116 -0
  36. package/dist/internal/guards.js.map +1 -0
  37. package/dist/internal/joined.d.ts +28 -0
  38. package/dist/internal/joined.js +127 -0
  39. package/dist/internal/joined.js.map +1 -0
  40. package/dist/internal/list.d.ts +16 -0
  41. package/dist/internal/list.js +182 -0
  42. package/dist/internal/list.js.map +1 -0
  43. package/dist/internal/meta-records.d.ts +19 -0
  44. package/dist/internal/meta-records.js +78 -0
  45. package/dist/internal/meta-records.js.map +1 -0
  46. package/dist/internal/properties.d.ts +4 -0
  47. package/dist/internal/properties.js +45 -0
  48. package/dist/internal/properties.js.map +1 -0
  49. package/dist/internal/prototypes.d.ts +14 -0
  50. package/dist/internal/prototypes.js +38 -0
  51. package/dist/internal/prototypes.js.map +1 -0
  52. package/dist/internal/read-properties.d.ts +3 -0
  53. package/dist/internal/read-properties.js +29 -0
  54. package/dist/internal/read-properties.js.map +1 -0
  55. package/dist/internal/table-reference.d.ts +11 -0
  56. package/dist/internal/table-reference.js +46 -0
  57. package/dist/internal/table-reference.js.map +1 -0
  58. package/dist/internal/tables.d.ts +28 -0
  59. package/dist/internal/tables.js +48 -0
  60. package/dist/internal/tables.js.map +1 -0
  61. package/dist/internal/validation.d.ts +12 -0
  62. package/dist/internal/validation.js +100 -0
  63. package/dist/internal/validation.js.map +1 -0
  64. package/dist/metadata.d.ts +27 -228
  65. package/dist/metadata.js +84 -213
  66. package/dist/metadata.js.map +1 -1
  67. package/dist/tests/components/access_control.test.js +28 -20
  68. package/dist/tests/components/access_control.test.js.map +1 -1
  69. package/dist/tests/components/computed.test.js +36 -27
  70. package/dist/tests/components/computed.test.js.map +1 -1
  71. package/dist/tests/components/cross_instance.test.js +8 -6
  72. package/dist/tests/components/cross_instance.test.js.map +1 -1
  73. package/dist/tests/components/deferred_joined.test.js +57 -54
  74. package/dist/tests/components/deferred_joined.test.js.map +1 -1
  75. package/dist/tests/components/extract_generic.test.d.ts +1 -0
  76. package/dist/tests/components/extract_generic.test.js +64 -0
  77. package/dist/tests/components/extract_generic.test.js.map +1 -0
  78. package/dist/tests/components/filter_comparisons.test.d.ts +1 -0
  79. package/dist/tests/components/filter_comparisons.test.js +34 -0
  80. package/dist/tests/components/filter_comparisons.test.js.map +1 -0
  81. package/dist/tests/components/filter_list_route.test.d.ts +1 -0
  82. package/dist/tests/components/filter_list_route.test.js +182 -0
  83. package/dist/tests/components/filter_list_route.test.js.map +1 -0
  84. package/dist/tests/components/filter_options.test.js +11 -10
  85. package/dist/tests/components/filter_options.test.js.map +1 -1
  86. package/dist/tests/components/foreign_computed.test.js +23 -14
  87. package/dist/tests/components/foreign_computed.test.js.map +1 -1
  88. package/dist/tests/components/foreign_joined.test.js +31 -27
  89. package/dist/tests/components/foreign_joined.test.js.map +1 -1
  90. package/dist/tests/components/joined.test.js +59 -45
  91. package/dist/tests/components/joined.test.js.map +1 -1
  92. package/dist/tests/components/listable.test.js +78 -58
  93. package/dist/tests/components/listable.test.js.map +1 -1
  94. package/dist/tests/components/localized_sort.test.js +14 -11
  95. package/dist/tests/components/localized_sort.test.js.map +1 -1
  96. package/dist/tests/components/mandatory.test.js +25 -25
  97. package/dist/tests/components/mandatory.test.js.map +1 -1
  98. package/dist/tests/components/modifier_key.test.js +27 -18
  99. package/dist/tests/components/modifier_key.test.js.map +1 -1
  100. package/dist/tests/components/parse_body.test.d.ts +1 -0
  101. package/dist/tests/components/parse_body.test.js +76 -0
  102. package/dist/tests/components/parse_body.test.js.map +1 -0
  103. package/dist/tests/components/parsed_value.test.js +23 -21
  104. package/dist/tests/components/parsed_value.test.js.map +1 -1
  105. package/dist/tests/components/partial_edit.test.js +38 -32
  106. package/dist/tests/components/partial_edit.test.js.map +1 -1
  107. package/dist/tests/components/per_action_access.test.js +20 -12
  108. package/dist/tests/components/per_action_access.test.js.map +1 -1
  109. package/dist/tests/components/prototype_named_filter.test.d.ts +1 -0
  110. package/dist/tests/components/prototype_named_filter.test.js +87 -0
  111. package/dist/tests/components/prototype_named_filter.test.js.map +1 -0
  112. package/dist/tests/components/validator.test.js +45 -37
  113. package/dist/tests/components/validator.test.js.map +1 -1
  114. package/dist/tests/components/written_row.test.d.ts +1 -0
  115. package/dist/tests/components/written_row.test.js +99 -0
  116. package/dist/tests/components/written_row.test.js.map +1 -0
  117. package/dist/tests/helpers/other-instance.d.ts +11 -1
  118. package/dist/tests/helpers/other-instance.js +35 -9
  119. package/dist/tests/helpers/other-instance.js.map +1 -1
  120. package/dist/tests/index/field_decorator_target.test.d.ts +1 -0
  121. package/dist/tests/index/field_decorator_target.test.js +20 -0
  122. package/dist/tests/index/field_decorator_target.test.js.map +1 -0
  123. package/dist/tests/index/get_guard.test.js +6 -6
  124. package/dist/tests/index/get_guard.test.js.map +1 -1
  125. package/dist/tests/index/inheritance.test.js +14 -9
  126. package/dist/tests/index/inheritance.test.js.map +1 -1
  127. package/dist/tests/index/metadata_names.test.d.ts +1 -0
  128. package/dist/tests/index/metadata_names.test.js +91 -0
  129. package/dist/tests/index/metadata_names.test.js.map +1 -0
  130. package/dist/tests/index/routes.test.js +49 -44
  131. package/dist/tests/index/routes.test.js.map +1 -1
  132. package/dist/tests/integration.test.d.ts +1 -1
  133. package/dist/tests/integration.test.js +66 -729
  134. package/dist/tests/integration.test.js.map +1 -1
  135. package/dist/tests/internal/controller-fields.test.d.ts +1 -0
  136. package/dist/tests/internal/controller-fields.test.js +25 -0
  137. package/dist/tests/internal/controller-fields.test.js.map +1 -0
  138. package/dist/tests/internal/http.d.ts +35 -0
  139. package/dist/tests/internal/http.js +56 -0
  140. package/dist/tests/internal/http.js.map +1 -0
  141. package/dist/tests/internal/shop-api.d.ts +1 -0
  142. package/dist/tests/internal/shop-api.js +331 -0
  143. package/dist/tests/internal/shop-api.js.map +1 -0
  144. package/dist/tests/internal/shop-schema.d.ts +162 -0
  145. package/dist/tests/internal/shop-schema.js +387 -0
  146. package/dist/tests/internal/shop-schema.js.map +1 -0
  147. package/dist/tests/utils.d.ts +8 -10
  148. package/dist/tests/utils.js +1 -3
  149. package/dist/tests/utils.js.map +1 -1
  150. package/dist/tests/utils.test.js +10 -11
  151. package/dist/tests/utils.test.js.map +1 -1
  152. package/docs/1.introduction.md +38 -35
  153. package/docs/10.joined.md +51 -40
  154. package/docs/11.computed.md +91 -47
  155. package/docs/2.data-controllers.md +50 -42
  156. package/docs/3.routes.md +156 -134
  157. package/docs/4.access-rights.md +48 -44
  158. package/docs/5.validators.md +65 -47
  159. package/docs/6.listable.md +53 -49
  160. package/docs/7.foreign-keys.md +55 -48
  161. package/docs/8.filters.md +65 -54
  162. package/docs/9.modifiers.md +29 -25
  163. package/package.json +34 -13
  164. package/skills/data-api-interface/SKILL.md +13 -3
  165. package/skills/data-api-interface/cases.json +99 -0
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /** @internal @packageDocumentation */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Foreign = Foreign;
5
+ const interface_database_1 = require("@antelopejs/interface-database");
6
+ const tables_1 = require("./tables");
7
+ function Foreign(db, meta, query, pluck) {
8
+ if ((0, interface_database_1.IsStream)(query)) {
9
+ for (const [name, field] of Object.entries(meta.fields)) {
10
+ if (!field.foreign || (pluck && !pluck.has(name))) {
11
+ continue;
12
+ }
13
+ const [table, tableClass, index, multi, pluckField, schemaName, targetJoined,] = field.foreign;
14
+ const other = (0, tables_1.targetTable)(db, { table, tableClass, schemaName });
15
+ const hasTargetJoined = !multi && !!targetJoined?.length;
16
+ if (pluckField) {
17
+ const lookupPluck = hasTargetJoined
18
+ ? Array.from(new Set([...pluckField, ...targetJoined.map((g) => g.localKey)]))
19
+ : pluckField;
20
+ query = query.lookup((0, tables_1.pluckedTable)(other, ...lookupPluck), name, index || "_id");
21
+ }
22
+ else {
23
+ query = query.lookup(other, name, index || "_id");
24
+ }
25
+ if (hasTargetJoined) {
26
+ query = applyForeignJoinedStream(db, query, name, targetJoined);
27
+ }
28
+ }
29
+ return query;
30
+ }
31
+ else {
32
+ const oldForeign = (obj) => {
33
+ const changedFields = {};
34
+ for (const [name, field] of Object.entries(meta.fields)) {
35
+ if (!field.foreign || (pluck && !pluck.has(name))) {
36
+ continue;
37
+ }
38
+ const [table, tableClass, index, multi, pluckField, schemaName, targetJoined,] = field.foreign;
39
+ const remote = (0, tables_1.targetTable)(db, { table, tableClass, schemaName });
40
+ if (multi) {
41
+ changedFields[name] = obj
42
+ .key(name)
43
+ .cast()
44
+ .default([])
45
+ .map((val) => {
46
+ let foreignObject = (0, tables_1.Get)(remote, val, index);
47
+ if (pluckField) {
48
+ foreignObject = foreignObject.pluck("_internal", ...pluckField);
49
+ }
50
+ return foreignObject.default(null);
51
+ });
52
+ }
53
+ else {
54
+ let foreignObject = (0, tables_1.Get)(remote, obj.key(name).cast(), index);
55
+ if (targetJoined && targetJoined.length > 0) {
56
+ foreignObject = applyForeignJoinedDatum(db, foreignObject, targetJoined);
57
+ }
58
+ changedFields[name] = foreignObject.default(null);
59
+ }
60
+ }
61
+ return obj.merge(changedFields);
62
+ };
63
+ return query.do(oldForeign);
64
+ }
65
+ }
66
+ /**
67
+ * Re-materializes the `@Joined` fields of a relation target on the looked-up
68
+ * sub-object (Stream/list path). The base `Foreign` lookup only plucks the
69
+ * target's physical columns, so a joined label would come back empty; here we
70
+ * resolve each joined field with a second lookup keyed on the target's
71
+ * (already plucked) local key, then merge it back into the relation object.
72
+ * For an orphan foreign key the merge yields `{ [joined]: null }`: the
73
+ * database DSL has no value-level conditional to null the relation here, so
74
+ * {@link Validation.ClearInternal} normalizes it back to a null relation.
75
+ */
76
+ function applyForeignJoinedStream(db, stream, foreignName, groups) {
77
+ let s = stream;
78
+ for (const group of groups) {
79
+ const remoteTable = (0, tables_1.pluckedTable)((0, tables_1.targetTable)(db, group), group.remoteIndex, group.remoteField);
80
+ const tmpKey = `__fjoin_${foreignName}_${group.name}`;
81
+ s = s
82
+ .map((row) => row.merge({
83
+ [tmpKey]: row.key(foreignName).key(group.localKey),
84
+ }))
85
+ .lookup(remoteTable, tmpKey, group.remoteIndex)
86
+ .map((row) => row.merge({
87
+ [foreignName]: row.key(foreignName).merge({
88
+ [group.name]: row
89
+ .key(tmpKey)
90
+ .default({})
91
+ .key(group.remoteField)
92
+ .default(null),
93
+ }),
94
+ }))
95
+ .without(tmpKey);
96
+ }
97
+ return s;
98
+ }
99
+ /**
100
+ * Datum/get counterpart of {@link applyForeignJoinedStream}: resolves each of
101
+ * the target's `@Joined` fields with a secondary `Get` and merges it into the
102
+ * relation object.
103
+ */
104
+ function applyForeignJoinedDatum(db, datum, groups) {
105
+ let d = datum;
106
+ for (const group of groups) {
107
+ const remoteTable = (0, tables_1.targetTable)(db, group);
108
+ d = d.do((row) => row.merge({
109
+ [group.name]: (0, tables_1.Get)(remoteTable, row.key(group.localKey), group.remoteIndex)
110
+ .key(group.remoteField)
111
+ .default(null),
112
+ }));
113
+ }
114
+ return d;
115
+ }
116
+ //# sourceMappingURL=foreign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreign.js","sourceRoot":"","sources":["../../src/internal/foreign.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /** @internal @packageDocumentation */
2
+ import type { Class } from "@antelopejs/interface-core/decorators";
3
+ import type { WriteDocument, WriteValue } from "@antelopejs/interface-database/common";
4
+ import type { FieldValue, FieldValues, RowFields } from "./field-types";
5
+ /** Whether a value is a string. */
6
+ export declare function isString(value: unknown): value is string;
7
+ /** Whether `typeof` calls a value an object and it is not `null`: arrays qualify, functions do not (the predicate `object` still types a function as one). */
8
+ export declare function isObject(value: unknown): value is object;
9
+ /** Whether a value is a function, whatever its parameters. */
10
+ export declare function isFunction(value: unknown): value is Function;
11
+ /**
12
+ * Whether a value is a class: a function with an object `prototype`, which
13
+ * arrow functions, methods and bound functions lack. A generator function
14
+ * has one too, a language limit this check shares with every `prototype`
15
+ * test.
16
+ */
17
+ export declare function isClass(value: unknown): value is Class<object>;
18
+ /** Whether a value is a number. */
19
+ export declare function isNumber(value: unknown): value is number;
20
+ /** Whether a value is a boolean. */
21
+ export declare function isBoolean(value: unknown): value is boolean;
22
+ /**
23
+ * Whether a value is a {@link FieldValue}: JSON or `Date` all the way down,
24
+ * with no cycle. The walk keeps its own stack, so a deeply nested body is
25
+ * not bounded by the call stack.
26
+ */
27
+ export declare function isFieldValue(value: unknown): value is FieldValue;
28
+ /** Whether a value is {@link FieldValues}: a plain object holding field values. */
29
+ export declare function isFieldValues(value: unknown): value is FieldValues;
30
+ /**
31
+ * Whether a value is a {@link WriteValue}: `null`, text, a number, a boolean,
32
+ * `undefined`, or an object whose own enumerable values are write values, all
33
+ * the way down. A `bigint`, a `symbol` or a function anywhere fails. An object
34
+ * is read by its own values whatever its prototype, as the type reads it, and
35
+ * an object met again, as in a cycle, is read once.
36
+ */
37
+ export declare function isWriteValue(value: unknown): value is WriteValue;
38
+ /** Whether every own field of a row holds a {@link WriteValue}. */
39
+ export declare function isWriteDocument(row: RowFields): row is WriteDocument;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /** @internal @packageDocumentation */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isString = isString;
5
+ exports.isObject = isObject;
6
+ exports.isFunction = isFunction;
7
+ exports.isClass = isClass;
8
+ exports.isNumber = isNumber;
9
+ exports.isBoolean = isBoolean;
10
+ exports.isFieldValue = isFieldValue;
11
+ exports.isFieldValues = isFieldValues;
12
+ exports.isWriteValue = isWriteValue;
13
+ exports.isWriteDocument = isWriteDocument;
14
+ /** Whether a value is a string. */
15
+ function isString(value) {
16
+ return typeof value === "string";
17
+ }
18
+ /** Whether `typeof` calls a value an object and it is not `null`: arrays qualify, functions do not (the predicate `object` still types a function as one). */
19
+ function isObject(value) {
20
+ return typeof value === "object" && value !== null;
21
+ }
22
+ /** Whether a value is a function, whatever its parameters. */
23
+ function isFunction(value) {
24
+ return typeof value === "function";
25
+ }
26
+ /**
27
+ * Whether a value is a class: a function with an object `prototype`, which
28
+ * arrow functions, methods and bound functions lack. A generator function
29
+ * has one too, a language limit this check shares with every `prototype`
30
+ * test.
31
+ */
32
+ function isClass(value) {
33
+ return isFunction(value) && isObject(value.prototype);
34
+ }
35
+ /** Whether a value is a number. */
36
+ function isNumber(value) {
37
+ return typeof value === "number";
38
+ }
39
+ /** Whether a value is a boolean. */
40
+ function isBoolean(value) {
41
+ return typeof value === "boolean";
42
+ }
43
+ /**
44
+ * Whether a value is a {@link FieldValue}: JSON or `Date` all the way down,
45
+ * with no cycle. The walk keeps its own stack, so a deeply nested body is
46
+ * not bounded by the call stack.
47
+ */
48
+ function isFieldValue(value) {
49
+ const ancestors = new Set();
50
+ const steps = [{ value, leaving: false }];
51
+ for (let step = steps.pop(); step; step = steps.pop()) {
52
+ if (step.leaving) {
53
+ ancestors.delete(step.value);
54
+ continue;
55
+ }
56
+ const current = step.value;
57
+ if (current === null || isString(current) || isNumber(current))
58
+ continue;
59
+ if (isBoolean(current) || current instanceof Date)
60
+ continue;
61
+ if (!isObject(current) || ancestors.has(current))
62
+ return false;
63
+ const isArray = Array.isArray(current);
64
+ const prototype = Object.getPrototypeOf(current);
65
+ if (!isArray && prototype !== Object.prototype && prototype !== null) {
66
+ return false;
67
+ }
68
+ ancestors.add(current);
69
+ steps.push({ value: current, leaving: true });
70
+ for (const member of Object.values(current)) {
71
+ if (member === undefined && isArray)
72
+ return false;
73
+ if (member !== undefined)
74
+ steps.push({ value: member, leaving: false });
75
+ }
76
+ }
77
+ return true;
78
+ }
79
+ /** Whether a value is {@link FieldValues}: a plain object holding field values. */
80
+ function isFieldValues(value) {
81
+ return (isFieldValue(value) &&
82
+ isObject(value) &&
83
+ !Array.isArray(value) &&
84
+ !(value instanceof Date));
85
+ }
86
+ /** The `typeof` answers of the primitives a {@link WriteValue} may be. */
87
+ const STORED_PRIMITIVES = new Set(["string", "number", "boolean", "undefined"]);
88
+ /**
89
+ * Whether a value is a {@link WriteValue}: `null`, text, a number, a boolean,
90
+ * `undefined`, or an object whose own enumerable values are write values, all
91
+ * the way down. A `bigint`, a `symbol` or a function anywhere fails. An object
92
+ * is read by its own values whatever its prototype, as the type reads it, and
93
+ * an object met again, as in a cycle, is read once.
94
+ */
95
+ function isWriteValue(value) {
96
+ const seen = new Set();
97
+ const pending = [value];
98
+ while (pending.length > 0) {
99
+ const current = pending.pop();
100
+ if (current === null || STORED_PRIMITIVES.has(typeof current))
101
+ continue;
102
+ if (!isObject(current))
103
+ return false;
104
+ if (seen.has(current))
105
+ continue;
106
+ seen.add(current);
107
+ for (const member of Object.values(current))
108
+ pending.push(member);
109
+ }
110
+ return true;
111
+ }
112
+ /** Whether every own field of a row holds a {@link WriteValue}. */
113
+ function isWriteDocument(row) {
114
+ return Object.values(row).every(isWriteValue);
115
+ }
116
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/internal/guards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /** @internal @packageDocumentation */
2
+ import { type Datum, type SchemaInstance, type Stream } from "@antelopejs/interface-database";
3
+ import type { DataAPIMeta, FieldFilter } from "../metadata";
4
+ export interface JoinedFieldSplit {
5
+ filter: Set<string>;
6
+ sort: Set<string>;
7
+ }
8
+ /**
9
+ * Splits the joined fields of `meta` between those {@link List} must
10
+ * materialize before the filter and count (`filter`) and those it only
11
+ * needs after the count (`sort`). Joined fields referenced by neither are
12
+ * left out so the list route can defer their lookups to the returned page.
13
+ *
14
+ * Computed expressions may read joined fields, so materializing a computed
15
+ * field pulls every remaining joined group in with it. Groups whose local
16
+ * key is also a foreign field must resolve before `Foreign` replaces the
17
+ * key with the looked-up record.
18
+ */
19
+ export declare function splitJoinedFields(meta: DataAPIMeta, sorting?: [string, "asc" | "desc" | undefined], filters?: Record<string, FieldFilter>): JoinedFieldSplit;
20
+ /**
21
+ * Joined field names that {@link List} does not materialize for the given
22
+ * split. The default list route resolves these after pagination so their
23
+ * lookups only run on the returned page.
24
+ */
25
+ export declare function deferredJoinedFields(meta: DataAPIMeta, split: JoinedFieldSplit): Set<string>;
26
+ export declare function Joined(db: SchemaInstance<any>, meta: DataAPIMeta, query: Stream<any>, only?: Set<string>): Stream<any>;
27
+ export declare function Joined(db: SchemaInstance<any>, meta: DataAPIMeta, query: Datum<any>, only?: Set<string>): Datum<any>;
28
+ export declare function Joined(db: SchemaInstance<any>, meta: DataAPIMeta, query: Stream<any> | Datum<any>, only?: Set<string>): Stream<any> | Datum<any>;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ /** @internal @packageDocumentation */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.splitJoinedFields = splitJoinedFields;
5
+ exports.deferredJoinedFields = deferredJoinedFields;
6
+ exports.Joined = Joined;
7
+ const interface_database_1 = require("@antelopejs/interface-database");
8
+ const tables_1 = require("./tables");
9
+ function collectJoinedGroups(meta) {
10
+ const groups = new Map();
11
+ for (const [name, field] of Object.entries(meta.fields)) {
12
+ if (!field.joined)
13
+ continue;
14
+ const j = field.joined;
15
+ const groupKey = `${j.schemaName ?? ""}|${j.table}|${j.localKey}|${j.remoteIndex}`;
16
+ let group = groups.get(groupKey);
17
+ if (!group) {
18
+ group = {
19
+ table: j.table,
20
+ tableClass: j.tableClass,
21
+ localKey: j.localKey,
22
+ remoteIndex: j.remoteIndex,
23
+ schemaName: j.schemaName,
24
+ fields: [],
25
+ };
26
+ groups.set(groupKey, group);
27
+ }
28
+ group.fields.push({ name, remoteField: j.remoteField });
29
+ }
30
+ return Array.from(groups.values());
31
+ }
32
+ function addAll(target, names) {
33
+ for (const name of names) {
34
+ target.add(name);
35
+ }
36
+ }
37
+ /**
38
+ * Splits the joined fields of `meta` between those {@link List} must
39
+ * materialize before the filter and count (`filter`) and those it only
40
+ * needs after the count (`sort`). Joined fields referenced by neither are
41
+ * left out so the list route can defer their lookups to the returned page.
42
+ *
43
+ * Computed expressions may read joined fields, so materializing a computed
44
+ * field pulls every remaining joined group in with it. Groups whose local
45
+ * key is also a foreign field must resolve before `Foreign` replaces the
46
+ * key with the looked-up record.
47
+ */
48
+ function splitJoinedFields(meta, sorting, filters) {
49
+ const split = { filter: new Set(), sort: new Set() };
50
+ const filterNames = Object.keys(meta.filters).filter((name) => filters && Object.hasOwn(filters, name));
51
+ const hasComputedFilter = filterNames.some((name) => meta.fields[name]?.computed);
52
+ const sortField = sorting?.[0];
53
+ const hasComputedSort = !!sortField && !!meta.fields[sortField]?.computed;
54
+ for (const group of collectJoinedGroups(meta)) {
55
+ const names = group.fields.map((field) => field.name);
56
+ if (hasComputedFilter || names.some((name) => filterNames.includes(name))) {
57
+ addAll(split.filter, names);
58
+ }
59
+ else if (hasComputedSort ||
60
+ (sortField && names.includes(sortField)) ||
61
+ meta.fields[group.localKey]?.foreign) {
62
+ addAll(split.sort, names);
63
+ }
64
+ }
65
+ return split;
66
+ }
67
+ /**
68
+ * Joined field names that {@link List} does not materialize for the given
69
+ * split. The default list route resolves these after pagination so their
70
+ * lookups only run on the returned page.
71
+ */
72
+ function deferredJoinedFields(meta, split) {
73
+ return new Set(Object.entries(meta.fields)
74
+ .filter(([name, field]) => field.joined && !split.filter.has(name) && !split.sort.has(name))
75
+ .map(([name]) => name));
76
+ }
77
+ function Joined(db, meta, query, only) {
78
+ const groups = collectJoinedGroups(meta).filter((group) => !only || group.fields.some((field) => only.has(field.name)));
79
+ if (groups.length === 0) {
80
+ return query;
81
+ }
82
+ const emptyRemote = {};
83
+ const tmpKeyFor = (localKey) => `__joined_orig_${localKey}`;
84
+ if ((0, interface_database_1.IsStream)(query)) {
85
+ let stream = query;
86
+ const tmpKeys = [];
87
+ for (const group of groups) {
88
+ const remoteFields = group.fields.map((f) => f.remoteField);
89
+ const remoteTable = (0, tables_1.pluckedTable)((0, tables_1.targetTable)(db, group), group.remoteIndex, ...remoteFields);
90
+ const tmpKey = tmpKeyFor(group.localKey);
91
+ tmpKeys.push(tmpKey);
92
+ stream = stream
93
+ .map((row) => row.merge({ [tmpKey]: row.key(group.localKey) }))
94
+ .lookup(remoteTable, group.localKey, group.remoteIndex)
95
+ .map((row) => {
96
+ const merged = {};
97
+ const remote = row.key(group.localKey).default(emptyRemote);
98
+ for (const f of group.fields) {
99
+ merged[f.name] = remote.key(f.remoteField).default(null);
100
+ }
101
+ merged[group.localKey] = row.key(tmpKey);
102
+ return row.merge(merged);
103
+ });
104
+ }
105
+ return stream.without(...tmpKeys);
106
+ }
107
+ let datum = query;
108
+ for (const group of groups) {
109
+ const remoteFields = group.fields.map((f) => f.remoteField);
110
+ const remoteTable = (0, tables_1.pluckedTable)((0, tables_1.targetTable)(db, group), group.remoteIndex, ...remoteFields);
111
+ const tmpKey = tmpKeyFor(group.localKey);
112
+ datum = datum
113
+ .do((row) => row.merge({ [tmpKey]: row.key(group.localKey) }))
114
+ .lookup(remoteTable, group.localKey, group.remoteIndex)
115
+ .do((row) => {
116
+ const merged = {};
117
+ const remote = row.key(group.localKey).default(emptyRemote);
118
+ for (const f of group.fields) {
119
+ merged[f.name] = remote.key(f.remoteField).default(null);
120
+ }
121
+ merged[group.localKey] = row.key(tmpKey);
122
+ return row.merge(merged);
123
+ });
124
+ }
125
+ return datum;
126
+ }
127
+ //# sourceMappingURL=joined.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"joined.js","sourceRoot":"","sources":["../../src/internal/joined.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** @internal @packageDocumentation */
2
+ import type { RequestContext } from "@antelopejs/interface-api";
3
+ import type { Datum, SchemaInstance, Stream, Table } from "@antelopejs/interface-database";
4
+ import type { Query } from "../components";
5
+ import { type DataAPIMeta, type DataControllerInstance } from "../metadata";
6
+ type ListPageOptions = Query.ListPageOptions;
7
+ /** The arguments {@link Query.List} takes after the request context. */
8
+ interface ListArguments {
9
+ sorting?: Parameters<typeof Query.List>[4];
10
+ filters?: Parameters<typeof Query.List>[5];
11
+ db?: Parameters<typeof Query.List>[6];
12
+ options?: Parameters<typeof Query.List>[7];
13
+ }
14
+ export declare function List<T extends Record<string, any>>(obj: DataControllerInstance, meta: DataAPIMeta, request: Table<T>, reqCtx: RequestContext, { sorting, filters, db, options }: ListArguments): [sorted: Stream<T>, total: Datum<number>, deferredJoined: Set<string>];
15
+ export declare function ListPage(db: SchemaInstance<any>, meta: DataAPIMeta, query: Stream<any>, options: ListPageOptions): Stream<any>;
16
+ export {};
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ /** @internal @packageDocumentation */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.List = List;
5
+ exports.ListPage = ListPage;
6
+ const common_1 = require("@antelopejs/interface-database-decorators/common");
7
+ const common_2 = require("@antelopejs/interface-database-decorators/modifiers/common");
8
+ const metadata_1 = require("../metadata");
9
+ const computed_1 = require("./computed");
10
+ const deferred_joined_stream_1 = require("./deferred-joined-stream");
11
+ const foreign_1 = require("./foreign");
12
+ const joined_1 = require("./joined");
13
+ const validation_1 = require("./validation");
14
+ function listResultTuple(tmpRequest, total, meta, joinedSplit, { db, options }) {
15
+ const deferredJoined = (0, joined_1.deferredJoinedFields)(meta, joinedSplit);
16
+ if (options?.exposeDeferredJoined || !db || deferredJoined.size === 0) {
17
+ return [tmpRequest, total, deferredJoined];
18
+ }
19
+ return [
20
+ (0, deferred_joined_stream_1.wrapDeferredJoined)(db, meta, deferredJoined, tmpRequest),
21
+ total,
22
+ new Set(),
23
+ ];
24
+ }
25
+ /** Where a list sorted on a modifier-held field keeps the value it sorts on. */
26
+ const MODIFIED_SORT_KEY = "__dataApiSortValue";
27
+ /**
28
+ * Whether a field is held by a modifier the controller keys (a localized
29
+ * field read in the request's locale): stored under the modifier, it sorts
30
+ * on the value the request reads, not on the stored field.
31
+ */
32
+ function isHeldByKeyedModifier(meta, field) {
33
+ const keyed = new Set(Array.from(meta.modifierKeys.keys(), (modifier) => modifier.name));
34
+ return ((0, common_1.getMetadata)(meta.tableClass, common_2.ModifiersStaticMetadata).fields[field]?.some(({ id }) => keyed.has(id)) ?? false);
35
+ }
36
+ /** The filters a request holds for a field, none when it holds none. */
37
+ function filterValuesIn(filters, field) {
38
+ return filters && Object.hasOwn(filters, field)
39
+ ? (0, metadata_1.FilterValuesOf)(filters[field])
40
+ : [];
41
+ }
42
+ /**
43
+ * The rows {@link List} starts from: the index lookup serving the one field
44
+ * filtered once with `eq` on a single-field index, else the whole table.
45
+ */
46
+ function indexedSource(meta, request, filterList, filters) {
47
+ const indexed = filterList.find(([field]) => {
48
+ const fieldFilters = filterValuesIn(filters, field);
49
+ return (fieldFilters.length === 1 &&
50
+ fieldFilters[0][1] === "eq" &&
51
+ meta.fields[field]?.indexable);
52
+ })?.[0];
53
+ const indexName = indexed
54
+ ? meta.fields[indexed].dbName || indexed
55
+ : undefined;
56
+ const equality = indexed ? filterValuesIn(filters, indexed)[0] : undefined;
57
+ const source = indexName
58
+ ? request.getAll(equality?.[0] ?? "", indexName)
59
+ : request;
60
+ return { indexFilter: indexed, source };
61
+ }
62
+ /**
63
+ * Merges the joined and computed fields the filters read, before
64
+ * {@link List} filters and counts.
65
+ */
66
+ function materializeFilterFields(source, meta, db, joinedSplit, { filterList }) {
67
+ const joined = db && joinedSplit.filter.size > 0
68
+ ? (0, joined_1.Joined)(db, meta, source, joinedSplit.filter)
69
+ : source;
70
+ const filteredComputed = new Set(filterList
71
+ .map(([field]) => field)
72
+ .filter((field) => meta.fields[field]?.computed));
73
+ const stream = db && filteredComputed.size > 0
74
+ ? (0, computed_1.Computed)(db, meta, joined, filteredComputed)
75
+ : joined;
76
+ return { stream, filteredComputed };
77
+ }
78
+ /** The field a list request sorts on, how, and whether a modifier holds it. */
79
+ function sortPlan(meta, sorting) {
80
+ const sortField = sorting?.[0];
81
+ const shouldSort = sortField ? meta.fields[sortField]?.sortable : undefined;
82
+ const isModifiedSort = !!shouldSort && !!sortField && isHeldByKeyedModifier(meta, sortField);
83
+ return { sortField, shouldSort, isModifiedSort };
84
+ }
85
+ /** Sorts on an indexed field before the filters, when the plan allows it. */
86
+ function orderedByIndex(stream, { sortField, shouldSort, isModifiedSort }, sorting) {
87
+ if (shouldSort?.indexed && sortField && !isModifiedSort) {
88
+ return stream.orderBy(sortField, sorting?.[1] ?? "asc");
89
+ }
90
+ return stream;
91
+ }
92
+ /**
93
+ * Merges the joined fields the sort reads, then a computed sort field no
94
+ * filter already merged, after {@link List} counts.
95
+ */
96
+ function materializeSortFields(stream, sortField, { db, meta, joinedSplit, filteredComputed }) {
97
+ if (!db)
98
+ return stream;
99
+ const joined = joinedSplit.sort.size > 0
100
+ ? (0, joined_1.Joined)(db, meta, stream, joinedSplit.sort)
101
+ : stream;
102
+ const sortsOnComputed = !!sortField &&
103
+ !!meta.fields[sortField]?.computed &&
104
+ !filteredComputed.has(sortField);
105
+ return sortsOnComputed
106
+ ? (0, computed_1.Computed)(db, meta, joined, new Set([sortField]))
107
+ : joined;
108
+ }
109
+ function List(obj, meta, request, reqCtx, { sorting, filters, db, options }) {
110
+ const filterList = Object.entries(meta.filters).filter(([name]) => filters && Object.hasOwn(filters, name));
111
+ const { indexFilter, source } = indexedSource(meta, request, filterList, filters);
112
+ const joinedSplit = (0, joined_1.splitJoinedFields)(meta, sorting, filters);
113
+ const filtering = materializeFilterFields(source, meta, db, joinedSplit, {
114
+ filterList,
115
+ });
116
+ const plan = sortPlan(meta, sorting);
117
+ const { sortField, shouldSort, isModifiedSort } = plan;
118
+ let tmpRequest = orderedByIndex(filtering.stream, plan, sorting);
119
+ if (filterList.length > 0) {
120
+ tmpRequest = filterList.reduce((req, [name, filter]) => {
121
+ const fieldFilter = filters?.[name];
122
+ if (!fieldFilter || name === indexFilter)
123
+ return req;
124
+ return (0, metadata_1.FilterValuesOf)(fieldFilter).reduce((filtered, [value, mode]) => filtered.filter((row) => filter(Object.assign(reqCtx, { this: obj }), (0, validation_1.UnlockRequest)(obj, meta, row, name), name, value, mode, row.cast())), req);
125
+ }, tmpRequest);
126
+ }
127
+ const total = tmpRequest.count();
128
+ tmpRequest = materializeSortFields(tmpRequest, sortField, {
129
+ db,
130
+ meta,
131
+ joinedSplit,
132
+ filteredComputed: filtering.filteredComputed,
133
+ });
134
+ if (isModifiedSort && sortField) {
135
+ tmpRequest = tmpRequest
136
+ .cast()
137
+ .map((row) => row.merge({
138
+ [MODIFIED_SORT_KEY]: (0, validation_1.UnlockRequest)(obj, meta, row, sortField),
139
+ }))
140
+ .orderBy(MODIFIED_SORT_KEY, sorting?.[1] ?? "asc")
141
+ .without(MODIFIED_SORT_KEY)
142
+ .cast();
143
+ }
144
+ else if (shouldSort && !shouldSort.indexed && sortField) {
145
+ tmpRequest = tmpRequest.orderBy(sortField, sorting?.[1] ?? "asc");
146
+ }
147
+ return listResultTuple(tmpRequest, total, meta, joinedSplit, {
148
+ db,
149
+ options,
150
+ });
151
+ }
152
+ function pageComputedFields(meta, options) {
153
+ const merged = new Set(Object.keys(options.filters ?? {}).filter((name) => Object.hasOwn(meta.filters, name)));
154
+ if (options.sortKey)
155
+ merged.add(options.sortKey);
156
+ const names = Object.entries(meta.fields)
157
+ .filter(([name, field]) => field.computed &&
158
+ !merged.has(name) &&
159
+ (!options.pluck || options.pluck.has(name)))
160
+ .map(([name]) => name);
161
+ return new Set(names);
162
+ }
163
+ function pageJoinedFields(options, materializeAll) {
164
+ const deferred = options.deferredJoined ?? new Set();
165
+ if (materializeAll || !options.pluck)
166
+ return deferred;
167
+ const pluck = options.pluck;
168
+ return new Set(Array.from(deferred).filter((name) => pluck.has(name)));
169
+ }
170
+ function ListPage(db, meta, query, options) {
171
+ let page = query.slice(options.offset, options.limit);
172
+ const computed = pageComputedFields(meta, options);
173
+ const joined = pageJoinedFields(options, computed.size > 0);
174
+ if (joined.size > 0)
175
+ page = (0, joined_1.Joined)(db, meta, page, joined);
176
+ if (computed.size > 0)
177
+ page = (0, computed_1.Computed)(db, meta, page, computed);
178
+ if (!options.noForeign)
179
+ page = (0, foreign_1.Foreign)(db, meta, page, options.pluck);
180
+ return options.pluck ? page.pluck("_internal", ...options.pluck) : page;
181
+ }
182
+ //# sourceMappingURL=list.js.map