@kollors/deep-json-server 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -16
- package/README.ru.md +20 -17
- 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 +17 -16
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/openapi/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,IAAY,EAAU,EAAE;IAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAEhC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,MAAM,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpF,OAAO,UAAU,UAAU,IAAI,UAAU,EAAE,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,QAAQ,EACR,KAAK,EACL,IAAI,GAAG,YAAY,EACnB,WAAW,EACX,IAAI,GAAG,YAAY,EACnB,MAAM,GAQP,EAAmB,EAAE;IACpB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAEhF,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAEvD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,QAAyB,EAAE,UAAkB,EAAiB,EAAE;IACjG,MAAM,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE/C,MAAM,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,SAAS,CAAC,kBAAkB,EAAE,SAAS,CAAC,QAAQ,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AACnH,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue, OpenapiSchema } from '../types.js';
|
|
2
|
+
type InferredSchema = Omit<OpenapiSchema, 'type'> & {
|
|
3
|
+
type?: OpenapiSchema['type'] | 'null';
|
|
4
|
+
};
|
|
5
|
+
export declare const mergeSchemas: (schemas: InferredSchema[]) => OpenapiSchema;
|
|
6
|
+
export declare const mergeSchemaOverrides: (schema: OpenapiSchema, overrides: unknown) => OpenapiSchema;
|
|
7
|
+
export declare const applyRequiredFields: (schema: OpenapiSchema, path: string, requiredFields: Set<string>) => OpenapiSchema;
|
|
8
|
+
export declare const inferSchema: (values: JsonValue[]) => OpenapiSchema;
|
|
9
|
+
export declare function inferObjectSchema(values: JsonObject[]): OpenapiSchema;
|
|
10
|
+
export declare const ensureGeneratedIdSchema: (schema: OpenapiSchema) => OpenapiSchema;
|
|
11
|
+
export declare const getSchemasAtPath: (schema: OpenapiSchema, keys: string[]) => OpenapiSchema[];
|
|
12
|
+
export declare const updateSchemasAtPath: (schema: OpenapiSchema, keys: string[], update: (schema: OpenapiSchema) => OpenapiSchema) => OpenapiSchema;
|
|
13
|
+
export declare const omitId: (schema: OpenapiSchema, keepRequired: boolean) => OpenapiSchema;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { isObject } from '../utils.js';
|
|
2
|
+
export const mergeSchemas = (schemas) => {
|
|
3
|
+
const uniqueSchemas = [...new Map(schemas.map((schema) => [JSON.stringify(schema), schema])).values()];
|
|
4
|
+
const nullable = uniqueSchemas.some((schema) => schema.type === 'null');
|
|
5
|
+
let nonNullSchemas = uniqueSchemas.filter((schema) => schema.type !== 'null');
|
|
6
|
+
if (nonNullSchemas.some((schema) => schema.type === 'number')) {
|
|
7
|
+
nonNullSchemas = nonNullSchemas.filter((schema) => schema.type !== 'integer');
|
|
8
|
+
}
|
|
9
|
+
if (nonNullSchemas.length === 0) {
|
|
10
|
+
return { enum: [null], nullable: true };
|
|
11
|
+
}
|
|
12
|
+
if (nonNullSchemas.length === 1) {
|
|
13
|
+
return nullable ? { ...nonNullSchemas[0], nullable: true } : nonNullSchemas[0];
|
|
14
|
+
}
|
|
15
|
+
return { oneOf: nonNullSchemas, ...(nullable && { nullable: true }) };
|
|
16
|
+
};
|
|
17
|
+
export const mergeSchemaOverrides = (schema, overrides) => {
|
|
18
|
+
if (!isObject(overrides)) {
|
|
19
|
+
return schema;
|
|
20
|
+
}
|
|
21
|
+
const result = { ...schema, ...overrides };
|
|
22
|
+
if (Object.hasOwn(overrides, 'type') && !Object.hasOwn(overrides, 'oneOf')) {
|
|
23
|
+
delete result.oneOf;
|
|
24
|
+
}
|
|
25
|
+
if (isObject(schema.properties) || isObject(overrides.properties)) {
|
|
26
|
+
const properties = isObject(schema.properties) ? { ...schema.properties } : {};
|
|
27
|
+
Object.entries(isObject(overrides.properties) ? overrides.properties : {}).forEach(([key, value]) => {
|
|
28
|
+
properties[key] = mergeSchemaOverrides(properties[key] ?? {}, value);
|
|
29
|
+
});
|
|
30
|
+
result.properties = properties;
|
|
31
|
+
}
|
|
32
|
+
if (isObject(schema.items) && isObject(overrides.items)) {
|
|
33
|
+
result.items = mergeSchemaOverrides(schema.items, overrides.items);
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
export const applyRequiredFields = (schema, path, requiredFields) => {
|
|
38
|
+
if (Array.isArray(schema.oneOf)) {
|
|
39
|
+
return { ...schema, oneOf: schema.oneOf.map((nestedSchema) => applyRequiredFields(nestedSchema, path, requiredFields)) };
|
|
40
|
+
}
|
|
41
|
+
if (schema.type === 'array') {
|
|
42
|
+
return { ...schema, items: applyRequiredFields(schema.items ?? {}, path, requiredFields) };
|
|
43
|
+
}
|
|
44
|
+
if (schema.type !== 'object' || !isObject(schema.properties)) {
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
const properties = Object.fromEntries(Object.entries(schema.properties).map(([key, value]) => {
|
|
48
|
+
const fieldPath = path === '' ? key : `${path}.${key}`;
|
|
49
|
+
return [key, applyRequiredFields(value, fieldPath, requiredFields)];
|
|
50
|
+
}));
|
|
51
|
+
const required = Object.keys(properties).filter((key) => {
|
|
52
|
+
const fieldPath = path === '' ? key : `${path}.${key}`;
|
|
53
|
+
return (path === '' && key === 'id') || requiredFields.has(fieldPath);
|
|
54
|
+
});
|
|
55
|
+
const result = { ...schema, properties };
|
|
56
|
+
delete result.required;
|
|
57
|
+
return required.length === 0 ? result : { ...result, required };
|
|
58
|
+
};
|
|
59
|
+
export const inferSchema = (values) => {
|
|
60
|
+
const schemas = [];
|
|
61
|
+
const arrays = values.filter((value) => Array.isArray(value));
|
|
62
|
+
const objects = values.filter((value) => isObject(value));
|
|
63
|
+
if (arrays.length > 0) {
|
|
64
|
+
const items = arrays.flat();
|
|
65
|
+
schemas.push({ items: items.length === 0 ? {} : inferSchema(items), type: 'array' });
|
|
66
|
+
}
|
|
67
|
+
if (objects.length > 0) {
|
|
68
|
+
schemas.push(inferObjectSchema(objects));
|
|
69
|
+
}
|
|
70
|
+
values
|
|
71
|
+
.filter((value) => !Array.isArray(value) && !isObject(value))
|
|
72
|
+
.forEach((value) => {
|
|
73
|
+
if (value === null) {
|
|
74
|
+
schemas.push({ type: 'null' });
|
|
75
|
+
}
|
|
76
|
+
else if (typeof value === 'number') {
|
|
77
|
+
schemas.push({ type: Number.isInteger(value) ? 'integer' : 'number' });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
schemas.push({ type: typeof value });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return mergeSchemas(schemas);
|
|
84
|
+
};
|
|
85
|
+
export function inferObjectSchema(values) {
|
|
86
|
+
const keys = [...new Set(values.flatMap((value) => Object.keys(value)))].sort((left, right) => (left === 'id' ? -1 : right === 'id' ? 1 : left.localeCompare(right)));
|
|
87
|
+
const properties = Object.fromEntries(keys.map((key) => {
|
|
88
|
+
const fieldValues = values.filter((value) => Object.hasOwn(value, key)).map((value) => value[key]);
|
|
89
|
+
return [key, inferSchema(fieldValues)];
|
|
90
|
+
}));
|
|
91
|
+
return { properties, type: 'object' };
|
|
92
|
+
}
|
|
93
|
+
export const ensureGeneratedIdSchema = (schema) => {
|
|
94
|
+
const idSchema = schema.properties?.id ?? {};
|
|
95
|
+
const idSchemas = Array.isArray(idSchema.oneOf) ? idSchema.oneOf : [idSchema];
|
|
96
|
+
const properties = {
|
|
97
|
+
...schema.properties,
|
|
98
|
+
id: idSchemas.some(({ type }) => type === 'string') ? idSchema : { oneOf: [...idSchemas, { type: 'string' }] },
|
|
99
|
+
};
|
|
100
|
+
return { ...schema, properties };
|
|
101
|
+
};
|
|
102
|
+
export const getSchemasAtPath = (schema, keys) => {
|
|
103
|
+
if (Array.isArray(schema.oneOf)) {
|
|
104
|
+
return schema.oneOf.flatMap((nestedSchema) => getSchemasAtPath(nestedSchema, keys));
|
|
105
|
+
}
|
|
106
|
+
if (schema.type === 'array') {
|
|
107
|
+
return getSchemasAtPath(schema.items ?? {}, keys);
|
|
108
|
+
}
|
|
109
|
+
if (keys.length === 0) {
|
|
110
|
+
return [schema];
|
|
111
|
+
}
|
|
112
|
+
if (schema.type !== 'object' || !isObject(schema.properties) || !Object.hasOwn(schema.properties, keys[0])) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
return getSchemasAtPath(schema.properties[keys[0]], keys.slice(1));
|
|
116
|
+
};
|
|
117
|
+
export const updateSchemasAtPath = (schema, keys, update) => {
|
|
118
|
+
if (Array.isArray(schema.oneOf)) {
|
|
119
|
+
return { ...schema, oneOf: schema.oneOf.map((nestedSchema) => updateSchemasAtPath(nestedSchema, keys, update)) };
|
|
120
|
+
}
|
|
121
|
+
if (schema.type === 'array') {
|
|
122
|
+
return { ...schema, items: updateSchemasAtPath(schema.items ?? {}, keys, update) };
|
|
123
|
+
}
|
|
124
|
+
if (keys.length === 0) {
|
|
125
|
+
return update(schema);
|
|
126
|
+
}
|
|
127
|
+
if (schema.type !== 'object' || !isObject(schema.properties) || !Object.hasOwn(schema.properties, keys[0])) {
|
|
128
|
+
return schema;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
...schema,
|
|
132
|
+
properties: {
|
|
133
|
+
...schema.properties,
|
|
134
|
+
[keys[0]]: updateSchemasAtPath(schema.properties[keys[0]], keys.slice(1), update),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
export const omitId = (schema, keepRequired) => {
|
|
139
|
+
const properties = Object.fromEntries(Object.entries(schema.properties ?? {}).filter(([key]) => key !== 'id'));
|
|
140
|
+
const required = keepRequired ? schema.required?.filter((key) => key !== 'id') : undefined;
|
|
141
|
+
const result = { ...schema, properties };
|
|
142
|
+
delete result.required;
|
|
143
|
+
return required != null && required.length > 0 ? { ...result, required } : result;
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=inference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inference.js","sourceRoot":"","sources":["../../../src/openapi/inference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Query } from '../types.js';
|
|
2
|
+
type Where = Record<string, unknown>;
|
|
3
|
+
export declare function matchesWhere(value: unknown, where: unknown): boolean;
|
|
4
|
+
export declare const parseWhere: (query: Query) => Where;
|
|
5
|
+
export declare const validateWhere: (where: Where, items: unknown[], path?: string) => void;
|
|
6
|
+
export {};
|
|
@@ -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
|