@kollors/deep-json-server 0.7.0 → 0.8.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.
- package/README.md +12 -9
- package/README.ru.md +12 -9
- package/dist/bin/deep-json-server.d.ts +2 -0
- package/dist/bin/deep-json-server.js +11 -0
- package/dist/bin/deep-json-server.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/src/cli.d.ts +4 -0
- package/dist/src/cli.js +80 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +54 -0
- package/dist/src/config.js +145 -0
- package/dist/src/config.js.map +1 -0
- package/{src → dist/src}/constants.js +1 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/database.d.ts +20 -0
- package/dist/src/database.js +136 -0
- package/dist/src/database.js.map +1 -0
- package/dist/src/files/contract.d.ts +67 -0
- package/dist/src/files/contract.js +106 -0
- package/dist/src/files/contract.js.map +1 -0
- package/dist/src/files/disk-store.d.ts +5 -0
- package/dist/src/files/disk-store.js +313 -0
- package/dist/src/files/disk-store.js.map +1 -0
- package/dist/src/files/index.d.ts +5 -0
- package/dist/src/files/index.js +6 -0
- package/dist/src/files/index.js.map +1 -0
- package/dist/src/files/memory-store.d.ts +3 -0
- package/dist/src/files/memory-store.js +80 -0
- package/dist/src/files/memory-store.js.map +1 -0
- package/dist/src/files/routes.d.ts +6 -0
- package/dist/src/files/routes.js +77 -0
- package/dist/src/files/routes.js.map +1 -0
- package/dist/src/openapi/config.d.ts +11 -0
- package/dist/src/openapi/config.js +204 -0
- package/dist/src/openapi/config.js.map +1 -0
- package/dist/src/openapi/document.d.ts +9 -0
- package/dist/src/openapi/document.js +338 -0
- package/dist/src/openapi/document.js.map +1 -0
- package/dist/src/openapi/index.d.ts +10 -0
- package/dist/src/openapi/index.js +27 -0
- package/dist/src/openapi/index.js.map +1 -0
- package/dist/src/openapi/inference.d.ts +14 -0
- package/dist/src/openapi/inference.js +145 -0
- package/dist/src/openapi/inference.js.map +1 -0
- package/dist/src/query/filter.d.ts +6 -0
- package/dist/src/query/filter.js +248 -0
- package/dist/src/query/filter.js.map +1 -0
- package/{src → dist/src}/query/index.js +1 -0
- package/dist/src/query/index.js.map +1 -0
- package/dist/src/query/pagination.d.ts +11 -0
- package/dist/src/query/pagination.js +28 -0
- package/dist/src/query/pagination.js.map +1 -0
- package/dist/src/query/sort.d.ts +1 -0
- package/dist/src/query/sort.js +54 -0
- package/dist/src/query/sort.js.map +1 -0
- package/dist/src/relation-metadata.d.ts +10 -0
- package/dist/src/relation-metadata.js +32 -0
- package/dist/src/relation-metadata.js.map +1 -0
- package/dist/src/relations.d.ts +12 -0
- package/dist/src/relations.js +155 -0
- package/dist/src/relations.js.map +1 -0
- package/dist/src/server.d.ts +13 -0
- package/dist/src/server.js +188 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/types.d.ts +52 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +20 -0
- package/dist/src/utils.js +63 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +16 -15
- package/bin/deep-json-server.js +0 -11
- package/index.js +0 -12
- package/src/cli.js +0 -91
- package/src/config.js +0 -203
- package/src/database.js +0 -148
- package/src/files.js +0 -633
- package/src/openapi/config.js +0 -124
- package/src/openapi/document.js +0 -394
- package/src/openapi/index.js +0 -36
- package/src/openapi/inference.js +0 -187
- package/src/query/filter.js +0 -283
- package/src/query/pagination.js +0 -44
- package/src/query/sort.js +0 -63
- package/src/relation-metadata.js +0 -41
- package/src/relations.js +0 -173
- package/src/server.js +0 -250
- package/src/utils.js +0 -84
- package/types/index.d.ts +0 -21
- package/types/src/config.d.ts +0 -73
- package/types/src/database.d.ts +0 -33
- package/types/src/files.d.ts +0 -64
- package/types/src/openapi/config.d.ts +0 -3
- package/types/src/openapi/document.d.ts +0 -11
- package/types/src/openapi/index.d.ts +0 -9
- package/types/src/openapi/inference.d.ts +0 -9
- package/types/src/query/filter.d.ts +0 -3
- package/types/src/query/pagination.d.ts +0 -8
- package/types/src/query/sort.d.ts +0 -1
- package/types/src/relation-metadata.d.ts +0 -9
- package/types/src/relations.d.ts +0 -3
- package/types/src/server.d.ts +0 -14
- package/types/src/utils.d.ts +0 -18
- /package/{types → dist}/src/constants.d.ts +0 -0
- /package/{types → dist}/src/query/index.d.ts +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { createHttpError, isEqual, isObject, isSafeKey, toArray } from '../utils.js';
|
|
2
|
+
const FIELD_OPERATORS = new Set(['contains', 'endsWith', 'eq', 'every', 'gt', 'gte', 'in', 'lt', 'lte', 'ne', 'none', 'not', 'some', 'startsWith']);
|
|
3
|
+
const RESERVED_QUERY_KEYS = new Set(['_embed', '_page', '_perPage', '_sort', '_where']);
|
|
4
|
+
const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
5
|
+
const isFilterEqual = (left, right) => {
|
|
6
|
+
if (isEqual(left, right)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (typeof left === 'number' && typeof right === 'string' && NUMBER_PATTERN.test(right)) {
|
|
10
|
+
// Query parameters are strings, so numeric strings must match stored numbers.
|
|
11
|
+
return left === Number(right);
|
|
12
|
+
}
|
|
13
|
+
return typeof right === 'number' && typeof left === 'string' && NUMBER_PATTERN.test(left) && right === Number(left);
|
|
14
|
+
};
|
|
15
|
+
const validateLogicalConditions = (operator, value) => {
|
|
16
|
+
if (!Array.isArray(value) || (operator === 'or' && value.length === 0) || value.some((condition) => !isObject(condition))) {
|
|
17
|
+
throw createHttpError(400, `Оператор «${operator}» должен содержать ${operator === 'or' ? 'непустой ' : ''}массив JSON-объектов`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
const isComparable = (value) => typeof value === 'number' || typeof value === 'string';
|
|
22
|
+
const matchesOperator = (field, operator, expectedValue) => {
|
|
23
|
+
switch (operator) {
|
|
24
|
+
case 'contains':
|
|
25
|
+
return typeof field === 'string' ? field.toLowerCase().includes(String(expectedValue).toLowerCase()) : Array.isArray(field) && field.some((value) => isFilterEqual(value, expectedValue));
|
|
26
|
+
case 'endsWith':
|
|
27
|
+
return typeof field === 'string' && field.toLowerCase().endsWith(String(expectedValue).toLowerCase());
|
|
28
|
+
case 'eq':
|
|
29
|
+
return isFilterEqual(field, expectedValue);
|
|
30
|
+
case 'every':
|
|
31
|
+
return Array.isArray(field) && field.every((value) => matchesValue(value, expectedValue));
|
|
32
|
+
case 'gt':
|
|
33
|
+
return isComparable(field) && isComparable(expectedValue) && field > expectedValue;
|
|
34
|
+
case 'gte':
|
|
35
|
+
return isComparable(field) && isComparable(expectedValue) && field >= expectedValue;
|
|
36
|
+
case 'in': {
|
|
37
|
+
const expectedValues = toArray(expectedValue);
|
|
38
|
+
return Array.isArray(field)
|
|
39
|
+
? field.some((value) => expectedValues.some((expectedItem) => isFilterEqual(value, expectedItem)))
|
|
40
|
+
: expectedValues.some((expectedItem) => isFilterEqual(field, expectedItem));
|
|
41
|
+
}
|
|
42
|
+
case 'lt':
|
|
43
|
+
return isComparable(field) && isComparable(expectedValue) && field < expectedValue;
|
|
44
|
+
case 'lte':
|
|
45
|
+
return isComparable(field) && isComparable(expectedValue) && field <= expectedValue;
|
|
46
|
+
case 'ne':
|
|
47
|
+
return !isFilterEqual(field, expectedValue);
|
|
48
|
+
case 'none':
|
|
49
|
+
return Array.isArray(field) && !field.some((value) => matchesValue(value, expectedValue));
|
|
50
|
+
case 'not':
|
|
51
|
+
return !matchesValue(field, expectedValue);
|
|
52
|
+
case 'some':
|
|
53
|
+
return Array.isArray(field) && field.some((value) => matchesValue(value, expectedValue));
|
|
54
|
+
case 'startsWith':
|
|
55
|
+
return typeof field === 'string' && field.toLowerCase().startsWith(String(expectedValue).toLowerCase());
|
|
56
|
+
default:
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
function matchesValue(field, condition) {
|
|
61
|
+
if (!isObject(condition)) {
|
|
62
|
+
return isFilterEqual(field, condition);
|
|
63
|
+
}
|
|
64
|
+
const conditionEntries = Object.entries(condition);
|
|
65
|
+
const operatorEntries = conditionEntries.filter((entry) => FIELD_OPERATORS.has(entry[0]));
|
|
66
|
+
const nestedEntries = conditionEntries.filter(([key]) => !FIELD_OPERATORS.has(key));
|
|
67
|
+
if (!operatorEntries.every(([operator, expectedValue]) => matchesOperator(field, operator, expectedValue))) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return nestedEntries.length === 0 || (isObject(field) && matchesWhere(field, Object.fromEntries(nestedEntries)));
|
|
71
|
+
}
|
|
72
|
+
export function matchesWhere(value, where) {
|
|
73
|
+
if (!isObject(value) || !isObject(where)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return Object.entries(where).every(([key, condition]) => {
|
|
77
|
+
if (key === 'and') {
|
|
78
|
+
return Array.isArray(condition) && condition.every((nestedWhere) => matchesWhere(value, nestedWhere));
|
|
79
|
+
}
|
|
80
|
+
if (key === 'or') {
|
|
81
|
+
return Array.isArray(condition) && condition.length > 0 && condition.some((nestedWhere) => matchesWhere(value, nestedWhere));
|
|
82
|
+
}
|
|
83
|
+
if (key === 'not') {
|
|
84
|
+
return isObject(condition) && !matchesWhere(value, condition);
|
|
85
|
+
}
|
|
86
|
+
return isSafeKey(key) && matchesValue(value[key], condition);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const parsePrimitive = (value) => {
|
|
90
|
+
if (typeof value !== 'string') {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
if (value === 'true') {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (value === 'false') {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
if (value === 'null') {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return NUMBER_PATTERN.test(value) && Number.isFinite(Number(value)) ? Number(value) : value;
|
|
103
|
+
};
|
|
104
|
+
const parseFilterKey = (key) => {
|
|
105
|
+
const colonIndex = key.lastIndexOf(':');
|
|
106
|
+
if (colonIndex !== -1) {
|
|
107
|
+
const path = key.slice(0, colonIndex);
|
|
108
|
+
const operator = key.slice(colonIndex + 1);
|
|
109
|
+
if (!FIELD_OPERATORS.has(operator)) {
|
|
110
|
+
throw createHttpError(400, `Неизвестный оператор «${operator}» в фильтре «${key}»`);
|
|
111
|
+
}
|
|
112
|
+
return { operator: operator, path };
|
|
113
|
+
}
|
|
114
|
+
return { operator: 'eq', path: key };
|
|
115
|
+
};
|
|
116
|
+
const setWhereOperator = (where, path, operator, value) => {
|
|
117
|
+
const keys = path.split('.');
|
|
118
|
+
if (keys.some((key) => key === '' || !isSafeKey(key))) {
|
|
119
|
+
throw createHttpError(400, `Недопустимый путь фильтра «${path}»`);
|
|
120
|
+
}
|
|
121
|
+
const fieldKey = keys.pop();
|
|
122
|
+
let currentValue = where;
|
|
123
|
+
keys.forEach((key) => {
|
|
124
|
+
currentValue[key] = isObject(currentValue[key]) ? currentValue[key] : {};
|
|
125
|
+
currentValue = currentValue[key];
|
|
126
|
+
});
|
|
127
|
+
currentValue[fieldKey] = isObject(currentValue[fieldKey]) ? currentValue[fieldKey] : {};
|
|
128
|
+
currentValue[fieldKey][operator] = operator === 'in' && typeof value === 'string' ? value.split(',').map((item) => parsePrimitive(item.trim())) : parsePrimitive(value);
|
|
129
|
+
};
|
|
130
|
+
export const parseWhere = (query) => {
|
|
131
|
+
const rawWhere = Array.isArray(query._where) ? query._where.at(-1) : query._where;
|
|
132
|
+
if (rawWhere != null) {
|
|
133
|
+
let where;
|
|
134
|
+
try {
|
|
135
|
+
where = JSON.parse(rawWhere);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
throw createHttpError(400, 'Параметр _where должен содержать JSON-объект');
|
|
139
|
+
}
|
|
140
|
+
if (!isObject(where)) {
|
|
141
|
+
throw createHttpError(400, 'Параметр _where должен содержать JSON-объект');
|
|
142
|
+
}
|
|
143
|
+
return where;
|
|
144
|
+
}
|
|
145
|
+
const where = {};
|
|
146
|
+
Object.entries(query).forEach(([key, rawValue]) => {
|
|
147
|
+
if (!RESERVED_QUERY_KEYS.has(key)) {
|
|
148
|
+
const filterKey = parseFilterKey(key);
|
|
149
|
+
const values = toArray(rawValue);
|
|
150
|
+
if (filterKey.operator === 'eq' && values.length > 1) {
|
|
151
|
+
setWhereOperator(where, filterKey.path, 'in', values.map(parsePrimitive));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
values.forEach((value) => {
|
|
155
|
+
setWhereOperator(where, filterKey.path, filterKey.operator, value);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
return where;
|
|
161
|
+
};
|
|
162
|
+
const validateExpectedValue = (operator, value, samples, path) => {
|
|
163
|
+
if (['startsWith', 'endsWith'].includes(operator) && typeof value !== 'string') {
|
|
164
|
+
throw createHttpError(400, `Оператор «${operator}» в фильтре «${path}» должен содержать строку`);
|
|
165
|
+
}
|
|
166
|
+
if (['gt', 'gte', 'lt', 'lte'].includes(operator) && !isComparable(value)) {
|
|
167
|
+
throw createHttpError(400, `Оператор «${operator}» в фильтре «${path}» должен содержать строку или число`);
|
|
168
|
+
}
|
|
169
|
+
if (operator === 'contains' && samples.some((sample) => typeof sample === 'string') && typeof value !== 'string') {
|
|
170
|
+
throw createHttpError(400, `Оператор «contains» в строковом фильтре «${path}» должен содержать строку`);
|
|
171
|
+
}
|
|
172
|
+
if (['every', 'none', 'some'].includes(operator) && isObject(value) && Object.keys(value).length === 0) {
|
|
173
|
+
throw createHttpError(400, `Оператор «${operator}» в фильтре «${path}» не должен содержать пустое условие`);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const validateCondition = (condition, samples, path) => {
|
|
177
|
+
if (!isObject(condition)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
Object.entries(condition).forEach(([key, value]) => {
|
|
181
|
+
if (key === 'and' || key === 'or') {
|
|
182
|
+
validateLogicalConditions(key, value).forEach((nestedWhere) => {
|
|
183
|
+
validateWhere(nestedWhere, samples, path);
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (FIELD_OPERATORS.has(key)) {
|
|
188
|
+
const operator = key;
|
|
189
|
+
validateExpectedValue(operator, value, samples, path);
|
|
190
|
+
if (['every', 'none', 'some'].includes(key)) {
|
|
191
|
+
if (samples.length > 0 && !samples.some(Array.isArray)) {
|
|
192
|
+
throw createHttpError(400, `Оператор «${key}» в фильтре «${path}» можно применить только к массиву`);
|
|
193
|
+
}
|
|
194
|
+
validateCondition(value, samples.flatMap((sample) => (Array.isArray(sample) ? sample : [])), `${path}.${key}`);
|
|
195
|
+
}
|
|
196
|
+
else if (key === 'not') {
|
|
197
|
+
validateCondition(value, samples, `${path}.not`);
|
|
198
|
+
}
|
|
199
|
+
else if (['endsWith', 'startsWith'].includes(key) && samples.length > 0 && !samples.some((sample) => typeof sample === 'string')) {
|
|
200
|
+
throw createHttpError(400, `Оператор «${key}» в фильтре «${path}» можно применить только к строке`);
|
|
201
|
+
}
|
|
202
|
+
else if (key === 'contains' && samples.length > 0 && !samples.some((sample) => typeof sample === 'string' || Array.isArray(sample))) {
|
|
203
|
+
throw createHttpError(400, `Оператор «contains» в фильтре «${path}» можно применить только к строке или массиву`);
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!isSafeKey(key)) {
|
|
208
|
+
throw createHttpError(400, `Недопустимый путь фильтра «${path}.${key}»`);
|
|
209
|
+
}
|
|
210
|
+
const objectSamples = samples.filter(isObject);
|
|
211
|
+
if (samples.length > 0 && objectSamples.length === 0) {
|
|
212
|
+
throw createHttpError(400, `Неизвестный оператор или вложенное поле «${path}.${key}»`);
|
|
213
|
+
}
|
|
214
|
+
const nestedSamples = objectSamples.filter((sample) => Object.hasOwn(sample, key)).map((sample) => sample[key]);
|
|
215
|
+
if (objectSamples.length > 0 && nestedSamples.length === 0) {
|
|
216
|
+
throw createHttpError(400, `Неизвестное поле фильтра «${path}.${key}»`);
|
|
217
|
+
}
|
|
218
|
+
validateCondition(value, nestedSamples, `${path}.${key}`);
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
export const validateWhere = (where, items, path = '') => {
|
|
222
|
+
Object.entries(where).forEach(([key, condition]) => {
|
|
223
|
+
if (key === 'and' || key === 'or') {
|
|
224
|
+
validateLogicalConditions(key, condition).forEach((nestedWhere) => {
|
|
225
|
+
validateWhere(nestedWhere, items, path);
|
|
226
|
+
});
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (key === 'not') {
|
|
230
|
+
if (!isObject(condition)) {
|
|
231
|
+
throw createHttpError(400, 'Оператор «not» должен содержать JSON-объект');
|
|
232
|
+
}
|
|
233
|
+
validateWhere(condition, items, path);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (!isSafeKey(key)) {
|
|
237
|
+
throw createHttpError(400, `Недопустимый путь фильтра «${path === '' ? key : `${path}.${key}`}»`);
|
|
238
|
+
}
|
|
239
|
+
const fieldPath = path === '' ? key : `${path}.${key}`;
|
|
240
|
+
const objectItems = items.filter(isObject);
|
|
241
|
+
const samples = objectItems.filter((item) => Object.hasOwn(item, key)).map((item) => item[key]);
|
|
242
|
+
if (objectItems.length > 0 && samples.length === 0) {
|
|
243
|
+
throw createHttpError(400, `Неизвестное поле фильтра «${fieldPath}»`);
|
|
244
|
+
}
|
|
245
|
+
validateCondition(condition, samples, fieldPath);
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/query/filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Query } from '../types.js';
|
|
2
|
+
export interface Pagination {
|
|
3
|
+
page: number;
|
|
4
|
+
pageSize: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Page<T> {
|
|
7
|
+
data: T[];
|
|
8
|
+
total: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const parsePagination: (query: Query, maxPageSize?: number) => Pagination;
|
|
11
|
+
export declare const paginateItems: <T>(items: T[], page: number, pageSize: number) => Page<T>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DEFAULT_MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE } from '../constants.js';
|
|
2
|
+
import { createHttpError } from '../utils.js';
|
|
3
|
+
const parsePositiveInteger = (value, name, defaultValue) => {
|
|
4
|
+
if (value == null) {
|
|
5
|
+
return defaultValue;
|
|
6
|
+
}
|
|
7
|
+
const number = Number(value);
|
|
8
|
+
if (Array.isArray(value) || !/^[1-9]\d*$/.test(String(value)) || !Number.isSafeInteger(number)) {
|
|
9
|
+
throw createHttpError(400, `Параметр ${name} должен быть положительным целым числом`);
|
|
10
|
+
}
|
|
11
|
+
return number;
|
|
12
|
+
};
|
|
13
|
+
export const parsePagination = (query, maxPageSize = DEFAULT_MAX_PAGE_SIZE) => {
|
|
14
|
+
const page = parsePositiveInteger(query._page, '_page', 1);
|
|
15
|
+
const pageSize = parsePositiveInteger(query._perPage, '_perPage', DEFAULT_PAGE_SIZE);
|
|
16
|
+
if (pageSize > maxPageSize) {
|
|
17
|
+
throw createHttpError(400, `Параметр _perPage не должен превышать ${maxPageSize}`);
|
|
18
|
+
}
|
|
19
|
+
return { page, pageSize };
|
|
20
|
+
};
|
|
21
|
+
export const paginateItems = (items, page, pageSize) => {
|
|
22
|
+
const offset = (page - 1) * pageSize;
|
|
23
|
+
return {
|
|
24
|
+
data: items.slice(offset, offset + pageSize),
|
|
25
|
+
total: items.length,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/query/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAY9C,MAAM,oBAAoB,GAAG,CAAC,KAAoB,EAAE,IAAY,EAAE,YAAoB,EAAU,EAAE;IAChG,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE7B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/F,MAAM,eAAe,CAAC,GAAG,EAAE,YAAY,IAAI,yCAAyC,CAAC,CAAC;IACxF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAY,EAAE,WAAW,GAAG,qBAAqB,EAAc,EAAE;IAC/F,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;IAErF,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,eAAe,CAAC,GAAG,EAAE,yCAAyC,WAAW,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAI,KAAU,EAAE,IAAY,EAAE,QAAgB,EAAW,EAAE;IACtF,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IAErC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC5C,KAAK,EAAE,KAAK,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sortItems: <T>(items: T[], sort: unknown, validationItems?: unknown[]) => T[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createHttpError, isObject, isSafeKey } from '../utils.js';
|
|
2
|
+
const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
|
|
3
|
+
const compareValues = (left, right) => {
|
|
4
|
+
if (Object.is(left, right)) {
|
|
5
|
+
return 0;
|
|
6
|
+
}
|
|
7
|
+
if (left == null) {
|
|
8
|
+
return 1;
|
|
9
|
+
}
|
|
10
|
+
if (right == null) {
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
return typeof left === 'number' && typeof right === 'number' ? left - right : collator.compare(String(left), String(right));
|
|
14
|
+
};
|
|
15
|
+
const getValueByPath = (value, path) => path.split('.').reduce((currentValue, key) => (isObject(currentValue) && isSafeKey(key) ? currentValue[key] : undefined), value);
|
|
16
|
+
const parseSortRules = (sort, items) => {
|
|
17
|
+
if (sort == null || sort === '') {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
if (typeof sort !== 'string') {
|
|
21
|
+
throw createHttpError(400, 'Параметр _sort должен содержать строку');
|
|
22
|
+
}
|
|
23
|
+
return sort.split(',').map((sortRule) => {
|
|
24
|
+
const isDescending = sortRule.startsWith('-');
|
|
25
|
+
const path = isDescending ? sortRule.slice(1) : sortRule;
|
|
26
|
+
const keys = path.split('.');
|
|
27
|
+
if (keys.some((key) => key === '' || !isSafeKey(key))) {
|
|
28
|
+
throw createHttpError(400, `Недопустимое поле сортировки «${path}»`);
|
|
29
|
+
}
|
|
30
|
+
const samples = items.map((item) => getValueByPath(item, path)).filter((value) => value !== undefined);
|
|
31
|
+
if (items.length > 0 && samples.length === 0) {
|
|
32
|
+
throw createHttpError(400, `Неизвестное поле сортировки «${path}»`);
|
|
33
|
+
}
|
|
34
|
+
if (samples.some((value) => isObject(value) || Array.isArray(value))) {
|
|
35
|
+
throw createHttpError(400, `Поле сортировки «${path}» должно содержать примитивные значения`);
|
|
36
|
+
}
|
|
37
|
+
return { isDescending, path };
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
export const sortItems = (items, sort, validationItems = items) => {
|
|
41
|
+
const sortRules = parseSortRules(sort, validationItems);
|
|
42
|
+
return sortRules.length === 0
|
|
43
|
+
? [...items]
|
|
44
|
+
: [...items].sort((left, right) => {
|
|
45
|
+
for (const { isDescending, path } of sortRules) {
|
|
46
|
+
const comparison = compareValues(getValueByPath(left, path), getValueByPath(right, path));
|
|
47
|
+
if (comparison !== 0) {
|
|
48
|
+
return isDescending ? -comparison : comparison;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return 0;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../../src/query/sort.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface RelationMetadata {
|
|
2
|
+
isMany: boolean;
|
|
3
|
+
relationName: string;
|
|
4
|
+
reverseRelationName: string;
|
|
5
|
+
sourceResource: string;
|
|
6
|
+
targetResource: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const getRelationKeys: (...names: string[]) => string[];
|
|
9
|
+
export declare const resolveRelationResource: (resourceNames: string[], relation: string, sourceResource: string) => string | undefined;
|
|
10
|
+
export declare const getRelationMetadata: (key: string, resourceNames: string[], sourceResource: string) => RelationMetadata | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { singularize } from './utils.js';
|
|
2
|
+
const SELF_RELATIONS = new Set(['child', 'children', 'parent', 'parents']);
|
|
3
|
+
export const getRelationKeys = (...names) => [...new Set(names.flatMap((name) => [`${name}Id`, `${name}Ids`]))];
|
|
4
|
+
export const resolveRelationResource = (resourceNames, relation, sourceResource) => {
|
|
5
|
+
const resource = resourceNames.find((resourceName) => resourceName === relation) ?? resourceNames.find((resourceName) => singularize(resourceName) === relation);
|
|
6
|
+
if (resource != null) {
|
|
7
|
+
return resource;
|
|
8
|
+
}
|
|
9
|
+
return SELF_RELATIONS.has(relation) && resourceNames.includes(sourceResource) ? sourceResource : undefined;
|
|
10
|
+
};
|
|
11
|
+
export const getRelationMetadata = (key, resourceNames, sourceResource) => {
|
|
12
|
+
// Relation fields follow the <resource>Id and <resource>Ids conventions.
|
|
13
|
+
const match = key.match(/^(.+)(Id|Ids)$/);
|
|
14
|
+
if (match == null) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const [, relation, suffix] = match;
|
|
18
|
+
const isMany = suffix === 'Ids';
|
|
19
|
+
const relationName = isMany ? (resourceNames.find((resource) => singularize(resource) === relation) ?? `${relation}s`) : relation;
|
|
20
|
+
const targetResource = resolveRelationResource(resourceNames, relationName, sourceResource);
|
|
21
|
+
if (targetResource == null) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
isMany,
|
|
26
|
+
relationName,
|
|
27
|
+
reverseRelationName: ['parent', 'parents'].includes(relationName) ? 'children' : sourceResource,
|
|
28
|
+
sourceResource,
|
|
29
|
+
targetResource,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=relation-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-metadata.js","sourceRoot":"","sources":["../../src/relation-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAU3E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAG,KAAe,EAAY,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpI,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,aAAuB,EAAE,QAAgB,EAAE,cAAsB,EAAsB,EAAE;IAC/H,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,KAAK,QAAQ,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC;IAEjK,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QACrB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7G,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAE,aAAuB,EAAE,cAAsB,EAAgC,EAAE;IAChI,yEAAyE;IACzE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAE1C,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,KAAK,KAAK,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClI,MAAM,cAAc,GAAG,uBAAuB,CAAC,aAAa,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;IAE5F,IAAI,cAAc,IAAI,IAAI,EAAE,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,MAAM;QACN,YAAY;QACZ,mBAAmB,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc;QAC/F,cAAc;QACd,cAAc;KACf,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DatabaseContainer } from './database.js';
|
|
2
|
+
import type { DatabaseRecord } from './types.js';
|
|
3
|
+
interface RelationContext {
|
|
4
|
+
forwardIndexes: Map<string, Map<string, DatabaseRecord>>;
|
|
5
|
+
resourceNames: string[];
|
|
6
|
+
reverseIndexes: Map<string, Map<string, DatabaseRecord[]>>;
|
|
7
|
+
}
|
|
8
|
+
export declare const createRelationContext: (database: DatabaseContainer) => RelationContext;
|
|
9
|
+
export declare const parseEmbedPaths: (embed: unknown) => string[][];
|
|
10
|
+
export declare const validateEmbedPaths: (database: DatabaseContainer, resource: string, items: DatabaseRecord[], embedPaths: string[][]) => void;
|
|
11
|
+
export declare const embedItem: (database: DatabaseContainer, item: DatabaseRecord, resource: string, embedPaths: string[][], context?: RelationContext) => DatabaseRecord;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { getRelationKeys, resolveRelationResource } from './relation-metadata.js';
|
|
2
|
+
import { createHttpError, getResourceNames, isObject, isSafeKey, singularize, toArray } from './utils.js';
|
|
3
|
+
export const createRelationContext = (database) => ({
|
|
4
|
+
forwardIndexes: new Map(),
|
|
5
|
+
resourceNames: getResourceNames(database.data),
|
|
6
|
+
reverseIndexes: new Map(),
|
|
7
|
+
});
|
|
8
|
+
const findLocalRelation = (item, relation, targetResource) => {
|
|
9
|
+
const relationKey = getRelationKeys(relation, singularize(relation), targetResource, singularize(targetResource)).find((key) => Object.hasOwn(item, key));
|
|
10
|
+
if (relationKey == null) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
return { ids: toArray(item[relationKey]).filter((id) => id != null), isMany: relationKey.endsWith('Ids') || Array.isArray(item[relationKey]) };
|
|
14
|
+
};
|
|
15
|
+
const collectReferences = (value, relationKeys, references) => {
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
value.forEach((item) => {
|
|
18
|
+
collectReferences(item, relationKeys, references);
|
|
19
|
+
});
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (!isObject(value)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
Object.entries(value).forEach(([key, nestedValue]) => {
|
|
26
|
+
if (!isSafeKey(key)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (relationKeys.includes(key)) {
|
|
30
|
+
toArray(nestedValue).forEach((id) => {
|
|
31
|
+
if (id != null) {
|
|
32
|
+
references.add(String(id));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
collectReferences(nestedValue, relationKeys, references);
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const getResourceIndex = (database, resource, context) => {
|
|
41
|
+
if (!context.forwardIndexes.has(resource)) {
|
|
42
|
+
context.forwardIndexes.set(resource, new Map(database.data[resource].map((item) => [String(item.id), item])));
|
|
43
|
+
}
|
|
44
|
+
return context.forwardIndexes.get(resource);
|
|
45
|
+
};
|
|
46
|
+
const getReverseIndex = (database, targetResource, relationKeys, context) => {
|
|
47
|
+
const cacheKey = `${targetResource}:${[...relationKeys].sort().join(',')}`;
|
|
48
|
+
const cachedIndex = context.reverseIndexes.get(cacheKey);
|
|
49
|
+
if (cachedIndex != null) {
|
|
50
|
+
return cachedIndex;
|
|
51
|
+
}
|
|
52
|
+
const index = new Map();
|
|
53
|
+
database.data[targetResource].forEach((item) => {
|
|
54
|
+
const references = new Set();
|
|
55
|
+
collectReferences(item, relationKeys, references);
|
|
56
|
+
references.forEach((id) => {
|
|
57
|
+
index.set(id, [...(index.get(id) ?? []), item]);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
context.reverseIndexes.set(cacheKey, index);
|
|
61
|
+
return index;
|
|
62
|
+
};
|
|
63
|
+
const findRelatedValue = (database, item, sourceResource, relation, targetResource, context) => {
|
|
64
|
+
const localRelation = findLocalRelation(item, relation, targetResource);
|
|
65
|
+
if (localRelation != null) {
|
|
66
|
+
const targetIndex = getResourceIndex(database, targetResource, context);
|
|
67
|
+
const relatedItems = localRelation.ids.map((id) => targetIndex.get(String(id))).filter((targetItem) => targetItem != null);
|
|
68
|
+
return localRelation.isMany ? relatedItems : (relatedItems[0] ?? null);
|
|
69
|
+
}
|
|
70
|
+
if (item.id == null) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const reverseRelationKeys = getRelationKeys(singularize(sourceResource));
|
|
74
|
+
if (relation === 'child' || relation === 'children') {
|
|
75
|
+
reverseRelationKeys.push('parentId', 'parentIds');
|
|
76
|
+
}
|
|
77
|
+
return getReverseIndex(database, targetResource, reverseRelationKeys, context).get(String(item.id)) ?? [];
|
|
78
|
+
};
|
|
79
|
+
const embedPath = (database, item, sourceResource, relations, context) => {
|
|
80
|
+
const [relation, ...nestedRelations] = relations;
|
|
81
|
+
if (relation == null || !isSafeKey(relation)) {
|
|
82
|
+
return item;
|
|
83
|
+
}
|
|
84
|
+
const currentValue = item[relation];
|
|
85
|
+
const targetResource = resolveRelationResource(context.resourceNames, relation, sourceResource);
|
|
86
|
+
const nestedSourceResource = targetResource ?? relation;
|
|
87
|
+
const localRelation = targetResource == null ? undefined : findLocalRelation(item, relation, targetResource);
|
|
88
|
+
if (localRelation == null) {
|
|
89
|
+
if (Array.isArray(currentValue)) {
|
|
90
|
+
return nestedRelations.length === 0
|
|
91
|
+
? item
|
|
92
|
+
: { ...item, [relation]: currentValue.map((value) => (isObject(value) ? embedPath(database, value, nestedSourceResource, nestedRelations, context) : value)) };
|
|
93
|
+
}
|
|
94
|
+
if (isObject(currentValue)) {
|
|
95
|
+
return nestedRelations.length === 0 ? item : { ...item, [relation]: embedPath(database, currentValue, nestedSourceResource, nestedRelations, context) };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (targetResource == null) {
|
|
99
|
+
return item;
|
|
100
|
+
}
|
|
101
|
+
const relatedValue = findRelatedValue(database, item, sourceResource, relation, targetResource, context);
|
|
102
|
+
if (relatedValue == null || nestedRelations.length === 0) {
|
|
103
|
+
return relatedValue === undefined ? item : { ...item, [relation]: relatedValue };
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
...item,
|
|
107
|
+
[relation]: Array.isArray(relatedValue)
|
|
108
|
+
? relatedValue.map((value) => embedPath(database, value, targetResource, nestedRelations, context))
|
|
109
|
+
: embedPath(database, relatedValue, targetResource, nestedRelations, context),
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
export const parseEmbedPaths = (embed) => {
|
|
113
|
+
if (embed == null) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const values = toArray(embed);
|
|
117
|
+
if (values.some((value) => typeof value !== 'string')) {
|
|
118
|
+
throw createHttpError(400, 'Параметр _embed должен содержать строковые пути связей');
|
|
119
|
+
}
|
|
120
|
+
return values
|
|
121
|
+
.flatMap((value) => value.split(','))
|
|
122
|
+
.map((path) => {
|
|
123
|
+
const keys = path.split('.');
|
|
124
|
+
if (keys.some((key) => key === '' || !isSafeKey(key))) {
|
|
125
|
+
throw createHttpError(400, `Недопустимый путь связи «${path}»`);
|
|
126
|
+
}
|
|
127
|
+
return keys;
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const getNestedSamples = (samples, relation) => samples.flatMap((sample) => {
|
|
131
|
+
if (!isObject(sample) || !Object.hasOwn(sample, relation)) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
return toArray(sample[relation]).filter(isObject);
|
|
135
|
+
});
|
|
136
|
+
const validateEmbedPath = (database, sourceResource, samples, relations, path = '', resourceNames = getResourceNames(database.data)) => {
|
|
137
|
+
const [relation, ...nestedRelations] = relations;
|
|
138
|
+
const relationPath = path === '' ? relation : `${path}.${relation}`;
|
|
139
|
+
const targetResource = resolveRelationResource(resourceNames, relation, sourceResource);
|
|
140
|
+
const nestedSamples = targetResource == null ? getNestedSamples(samples, relation) : database.data[targetResource];
|
|
141
|
+
if (targetResource == null && nestedSamples.length === 0) {
|
|
142
|
+
throw createHttpError(400, `Неизвестный путь связи «${relationPath}»`);
|
|
143
|
+
}
|
|
144
|
+
if (nestedRelations.length > 0) {
|
|
145
|
+
validateEmbedPath(database, targetResource ?? relation, nestedSamples, nestedRelations, relationPath, resourceNames);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export const validateEmbedPaths = (database, resource, items, embedPaths) => {
|
|
149
|
+
const resourceNames = getResourceNames(database.data);
|
|
150
|
+
embedPaths.forEach((path) => {
|
|
151
|
+
validateEmbedPath(database, resource, items, path, '', resourceNames);
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
export const embedItem = (database, item, resource, embedPaths, context = createRelationContext(database)) => embedPaths.reduce((embeddedItem, path) => embedPath(database, embeddedItem, resource, path, context), item);
|
|
155
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sourceRoot":"","sources":["../../src/relations.ts"],"names":[],"mappings":"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"}
|