@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.
Files changed (107) hide show
  1. package/README.md +19 -16
  2. package/README.ru.md +20 -17
  3. package/dist/bin/deep-json-server.d.ts +2 -0
  4. package/dist/bin/deep-json-server.js +11 -0
  5. package/dist/bin/deep-json-server.js.map +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/src/cli.d.ts +4 -0
  10. package/dist/src/cli.js +80 -0
  11. package/dist/src/cli.js.map +1 -0
  12. package/dist/src/config.d.ts +54 -0
  13. package/dist/src/config.js +145 -0
  14. package/dist/src/config.js.map +1 -0
  15. package/{src → dist/src}/constants.js +1 -0
  16. package/dist/src/constants.js.map +1 -0
  17. package/dist/src/database.d.ts +20 -0
  18. package/dist/src/database.js +136 -0
  19. package/dist/src/database.js.map +1 -0
  20. package/dist/src/files/contract.d.ts +67 -0
  21. package/dist/src/files/contract.js +106 -0
  22. package/dist/src/files/contract.js.map +1 -0
  23. package/dist/src/files/disk-store.d.ts +5 -0
  24. package/dist/src/files/disk-store.js +313 -0
  25. package/dist/src/files/disk-store.js.map +1 -0
  26. package/dist/src/files/index.d.ts +5 -0
  27. package/dist/src/files/index.js +6 -0
  28. package/dist/src/files/index.js.map +1 -0
  29. package/dist/src/files/memory-store.d.ts +3 -0
  30. package/dist/src/files/memory-store.js +80 -0
  31. package/dist/src/files/memory-store.js.map +1 -0
  32. package/dist/src/files/routes.d.ts +6 -0
  33. package/dist/src/files/routes.js +77 -0
  34. package/dist/src/files/routes.js.map +1 -0
  35. package/dist/src/openapi/config.d.ts +11 -0
  36. package/dist/src/openapi/config.js +204 -0
  37. package/dist/src/openapi/config.js.map +1 -0
  38. package/dist/src/openapi/document.d.ts +9 -0
  39. package/dist/src/openapi/document.js +338 -0
  40. package/dist/src/openapi/document.js.map +1 -0
  41. package/dist/src/openapi/index.d.ts +10 -0
  42. package/dist/src/openapi/index.js +27 -0
  43. package/dist/src/openapi/index.js.map +1 -0
  44. package/dist/src/openapi/inference.d.ts +14 -0
  45. package/dist/src/openapi/inference.js +145 -0
  46. package/dist/src/openapi/inference.js.map +1 -0
  47. package/dist/src/query/filter.d.ts +6 -0
  48. package/dist/src/query/filter.js +248 -0
  49. package/dist/src/query/filter.js.map +1 -0
  50. package/{src → dist/src}/query/index.js +1 -0
  51. package/dist/src/query/index.js.map +1 -0
  52. package/dist/src/query/pagination.d.ts +11 -0
  53. package/dist/src/query/pagination.js +28 -0
  54. package/dist/src/query/pagination.js.map +1 -0
  55. package/dist/src/query/sort.d.ts +1 -0
  56. package/dist/src/query/sort.js +54 -0
  57. package/dist/src/query/sort.js.map +1 -0
  58. package/dist/src/relation-metadata.d.ts +10 -0
  59. package/dist/src/relation-metadata.js +32 -0
  60. package/dist/src/relation-metadata.js.map +1 -0
  61. package/dist/src/relations.d.ts +12 -0
  62. package/dist/src/relations.js +155 -0
  63. package/dist/src/relations.js.map +1 -0
  64. package/dist/src/server.d.ts +13 -0
  65. package/dist/src/server.js +188 -0
  66. package/dist/src/server.js.map +1 -0
  67. package/dist/src/types.d.ts +52 -0
  68. package/dist/src/types.js +2 -0
  69. package/dist/src/types.js.map +1 -0
  70. package/dist/src/utils.d.ts +20 -0
  71. package/dist/src/utils.js +63 -0
  72. package/dist/src/utils.js.map +1 -0
  73. package/package.json +17 -16
  74. package/bin/deep-json-server.js +0 -11
  75. package/index.js +0 -12
  76. package/src/cli.js +0 -91
  77. package/src/config.js +0 -203
  78. package/src/database.js +0 -148
  79. package/src/files.js +0 -633
  80. package/src/openapi/config.js +0 -124
  81. package/src/openapi/document.js +0 -394
  82. package/src/openapi/index.js +0 -36
  83. package/src/openapi/inference.js +0 -187
  84. package/src/query/filter.js +0 -283
  85. package/src/query/pagination.js +0 -44
  86. package/src/query/sort.js +0 -63
  87. package/src/relation-metadata.js +0 -41
  88. package/src/relations.js +0 -173
  89. package/src/server.js +0 -250
  90. package/src/utils.js +0 -84
  91. package/types/index.d.ts +0 -21
  92. package/types/src/config.d.ts +0 -73
  93. package/types/src/database.d.ts +0 -33
  94. package/types/src/files.d.ts +0 -64
  95. package/types/src/openapi/config.d.ts +0 -3
  96. package/types/src/openapi/document.d.ts +0 -11
  97. package/types/src/openapi/index.d.ts +0 -9
  98. package/types/src/openapi/inference.d.ts +0 -9
  99. package/types/src/query/filter.d.ts +0 -3
  100. package/types/src/query/pagination.d.ts +0 -8
  101. package/types/src/query/sort.d.ts +0 -1
  102. package/types/src/relation-metadata.d.ts +0 -9
  103. package/types/src/relations.d.ts +0 -3
  104. package/types/src/server.d.ts +0 -14
  105. package/types/src/utils.d.ts +0 -18
  106. /package/{types → dist}/src/constants.d.ts +0 -0
  107. /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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"}
@@ -1,3 +1,4 @@
1
1
  export { matchesWhere, parseWhere, validateWhere } from './filter.js';
2
2
  export { paginateItems, parsePagination } from './pagination.js';
3
3
  export { sortItems } from './sort.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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