@autofleet/sheilta 1.4.2 → 1.4.3
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/lib/formatter/index.d.ts +5 -5
- package/lib/formatter/index.js +54 -43
- package/lib/formatter/index.test.js +16 -16
- package/lib/middleware/index.d.ts +4 -4
- package/lib/middleware/index.js +24 -28
- package/lib/operators/index.js +2 -1
- package/lib/utils.js +16 -9
- package/lib/validations/index.js +32 -41
- package/lib/validations/index.test.js +15 -15
- package/package.json +22 -21
package/lib/formatter/index.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import type { LiteralAttribute } from '../middleware';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
2
|
+
type OrderItem = string | [string, string];
|
|
3
|
+
type SequelizeOrder = string | OrderItem[];
|
|
4
|
+
export type FormatPayloadOptions = {
|
|
5
5
|
includeRawPayload?: boolean;
|
|
6
6
|
literalAttributes?: LiteralAttribute[];
|
|
7
7
|
DBFormatter?: any;
|
|
8
8
|
skipSearchTermFormat?: boolean;
|
|
9
9
|
};
|
|
10
|
-
|
|
10
|
+
type ConditionWithOperator = {
|
|
11
11
|
operator: string;
|
|
12
12
|
value: string;
|
|
13
13
|
};
|
|
14
|
-
export
|
|
14
|
+
export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
15
15
|
/**
|
|
16
16
|
* Generates replacements for the given conditions.
|
|
17
17
|
*
|
package/lib/formatter/index.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.generateOrderReplacements = exports.generateFilterReplacements = void 0;
|
|
7
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
8
4
|
const common_types_1 = require("@autofleet/common-types");
|
|
9
5
|
const utils_1 = require("../utils");
|
|
10
6
|
const operators_1 = require("../operators");
|
|
@@ -26,7 +22,7 @@ const getAttributeFromOrder = (order, options = {}) => {
|
|
|
26
22
|
const { literalAttributes = [], DBFormatter = undefined } = options;
|
|
27
23
|
const [formattedOrder, attributes] = order.reduce((acc, o) => {
|
|
28
24
|
const [item, orderStyle = 'ASC'] = Array.isArray(o) ? o : [o];
|
|
29
|
-
const found = literalAttributes
|
|
25
|
+
const found = literalAttributes?.find((obj) => obj.attribute === item);
|
|
30
26
|
if (found) {
|
|
31
27
|
acc[1].push(found.literal);
|
|
32
28
|
acc[0].push([DBFormatter ? DBFormatter(`"${found.attribute}" ${orderStyle}`) : `${found.attribute} ${orderStyle}`]);
|
|
@@ -44,51 +40,53 @@ const getAttributeFromOrder = (order, options = {}) => {
|
|
|
44
40
|
* @param conditions - The conditions to generate replacements for.
|
|
45
41
|
* @returns The replacements object.
|
|
46
42
|
*/
|
|
47
|
-
|
|
43
|
+
const generateFilterReplacements = (conditions) => {
|
|
48
44
|
const replacements = {};
|
|
49
45
|
Object.entries(conditions).forEach(([key, condition]) => {
|
|
50
|
-
const replacementKey = utils_1.generateRandomString();
|
|
46
|
+
const replacementKey = (0, utils_1.generateRandomString)();
|
|
51
47
|
// eslint-disable-next-line prefer-destructuring
|
|
52
48
|
replacements[replacementKey] = key.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
53
49
|
if (Array.isArray(condition)) {
|
|
54
50
|
condition.forEach((value) => {
|
|
55
|
-
const valueKey = utils_1.generateRandomString();
|
|
51
|
+
const valueKey = (0, utils_1.generateRandomString)();
|
|
56
52
|
replacements[valueKey] = typeof value === 'string' ? value : value.value;
|
|
57
53
|
});
|
|
58
54
|
}
|
|
59
55
|
else if (typeof condition === 'string' || typeof condition === 'number') {
|
|
60
|
-
const conditionKey = utils_1.generateRandomString();
|
|
56
|
+
const conditionKey = (0, utils_1.generateRandomString)();
|
|
61
57
|
replacements[conditionKey] = condition;
|
|
62
58
|
}
|
|
63
|
-
else if (condition
|
|
64
|
-
const operatorKey = utils_1.generateRandomString();
|
|
59
|
+
else if (condition?.operator) {
|
|
60
|
+
const operatorKey = (0, utils_1.generateRandomString)();
|
|
65
61
|
replacements[operatorKey] = condition.value;
|
|
66
62
|
}
|
|
67
63
|
});
|
|
68
64
|
return replacements;
|
|
69
65
|
};
|
|
66
|
+
exports.generateFilterReplacements = generateFilterReplacements;
|
|
70
67
|
/**
|
|
71
68
|
* Generates replacements for the given order array.
|
|
72
69
|
*
|
|
73
70
|
* @param order - The order array to generate replacements for.
|
|
74
71
|
* @returns The replacements object.
|
|
75
72
|
*/
|
|
76
|
-
|
|
73
|
+
const generateOrderReplacements = (order) => {
|
|
77
74
|
const replacementMap = {};
|
|
78
75
|
order.forEach((o) => {
|
|
79
76
|
if (o.startsWith(CUSTOM_FIELDS_QUERY_PREFIX)) {
|
|
80
|
-
const rand = utils_1.generateRandomString();
|
|
77
|
+
const rand = (0, utils_1.generateRandomString)();
|
|
81
78
|
// eslint-disable-next-line prefer-destructuring
|
|
82
79
|
replacementMap[rand] = o.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
83
80
|
}
|
|
84
81
|
else if (o.substring(1).startsWith(CUSTOM_FIELDS_QUERY_PREFIX)) {
|
|
85
|
-
const rand = utils_1.generateRandomString();
|
|
82
|
+
const rand = (0, utils_1.generateRandomString)();
|
|
86
83
|
// eslint-disable-next-line prefer-destructuring
|
|
87
84
|
replacementMap[rand] = o.substring(1).split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
88
85
|
}
|
|
89
86
|
});
|
|
90
87
|
return replacementMap;
|
|
91
88
|
};
|
|
89
|
+
exports.generateOrderReplacements = generateOrderReplacements;
|
|
92
90
|
/**
|
|
93
91
|
* Creates a combined replacement map from order and query.
|
|
94
92
|
*
|
|
@@ -96,28 +94,29 @@ exports.generateOrderReplacements = (order) => {
|
|
|
96
94
|
* @param query - The query object.
|
|
97
95
|
* @returns The combined replacements object.
|
|
98
96
|
*/
|
|
99
|
-
const createReplacementMap = (order, query) => (
|
|
97
|
+
const createReplacementMap = (order, query) => ({
|
|
98
|
+
...(0, exports.generateOrderReplacements)(order),
|
|
99
|
+
...(0, exports.generateFilterReplacements)(query),
|
|
100
|
+
});
|
|
100
101
|
const formatOrder = ({ order, associationModels = [], replacementsMap = {}, }) => {
|
|
101
102
|
const formattedOrders = [];
|
|
102
103
|
const orderScopesMap = new Map();
|
|
103
104
|
order.forEach((o) => {
|
|
104
|
-
if ([o, o.substring(1)].some(t => t.startsWith(CUSTOM_FIELDS_QUERY_PREFIX))) {
|
|
105
|
+
if ([o, o.substring(1)].some((t) => t.startsWith(CUSTOM_FIELDS_QUERY_PREFIX))) {
|
|
105
106
|
if (!orderScopesMap.has(CUSTOM_FIELDS_SORT_SCOPE)) {
|
|
106
107
|
orderScopesMap.set(CUSTOM_FIELDS_SORT_SCOPE, {});
|
|
107
108
|
}
|
|
108
109
|
const scopeKey = o.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
109
|
-
orderScopesMap.get(CUSTOM_FIELDS_SORT_SCOPE)[scopeKey] = (utils_1.isOrderDesc(o) ?
|
|
110
|
-
DESCENDING_KEY :
|
|
111
|
-
ASCENDING_KEY);
|
|
110
|
+
orderScopesMap.get(CUSTOM_FIELDS_SORT_SCOPE)[scopeKey] = ((0, utils_1.isOrderDesc)(o) ? DESCENDING_KEY : ASCENDING_KEY);
|
|
112
111
|
return;
|
|
113
112
|
}
|
|
114
|
-
const formattedOrder = [utils_1.extractAttributeNameFromOrder(o, associationModels)];
|
|
115
|
-
const isOrderDescOrder = utils_1.isOrderDesc(o);
|
|
116
|
-
const isOrderAssociation = utils_1.isAttributeByAssociation(isOrderDescOrder
|
|
113
|
+
const formattedOrder = [(0, utils_1.extractAttributeNameFromOrder)(o, associationModels)];
|
|
114
|
+
const isOrderDescOrder = (0, utils_1.isOrderDesc)(o);
|
|
115
|
+
const isOrderAssociation = (0, utils_1.isAttributeByAssociation)(isOrderDescOrder
|
|
117
116
|
? o.split(utils_1.ORDER_PREFIX)[1]
|
|
118
117
|
: o, associationModels);
|
|
119
118
|
if (isOrderAssociation) {
|
|
120
|
-
formattedOrder.push(utils_1.extractAssociatedAttributeNameFromOrder(o));
|
|
119
|
+
formattedOrder.push((0, utils_1.extractAssociatedAttributeNameFromOrder)(o));
|
|
121
120
|
}
|
|
122
121
|
if (isOrderDescOrder) {
|
|
123
122
|
formattedOrder.push(DESCENDING_KEY);
|
|
@@ -140,17 +139,21 @@ const formatOrder = ({ order, associationModels = [], replacementsMap = {}, }) =
|
|
|
140
139
|
}),
|
|
141
140
|
};
|
|
142
141
|
};
|
|
143
|
-
const formatPage = page => page || utils_1.PAGE_DEFAULT;
|
|
144
|
-
const formatPerPage = perPage => perPage || utils_1.PER_PAGE_DEFAULT;
|
|
142
|
+
const formatPage = (page) => page || utils_1.PAGE_DEFAULT;
|
|
143
|
+
const formatPerPage = (perPage) => perPage || utils_1.PER_PAGE_DEFAULT;
|
|
145
144
|
const formatInclude = (include, associationsMap = {}) => {
|
|
146
145
|
let formattedInclude = include.map((i) => {
|
|
147
|
-
var _a;
|
|
148
146
|
const includedAssociation = associationsMap[typeof i === 'string' ? i : (i.association || i.model)];
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
return {
|
|
148
|
+
...i,
|
|
149
|
+
association: includedAssociation,
|
|
150
|
+
required: i.required !== false,
|
|
151
|
+
...(i.include && {
|
|
152
|
+
include: formatInclude(i.include, includedAssociation?.target?.associations),
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
152
155
|
});
|
|
153
|
-
formattedInclude = formattedInclude.map(i =>
|
|
156
|
+
formattedInclude = formattedInclude.map(({ model: _model, ...i }) => i);
|
|
154
157
|
return formattedInclude;
|
|
155
158
|
};
|
|
156
159
|
const formatQuery = (query, associationModels, replacementsMap) => {
|
|
@@ -162,12 +165,11 @@ const formatQuery = (query, associationModels, replacementsMap) => {
|
|
|
162
165
|
formattedScopeMap.set(CUSTOM_FIELDS_FILTER_SCOPE, {});
|
|
163
166
|
}
|
|
164
167
|
const scopeKey = queryItemKey.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
165
|
-
formattedScopeMap.get(CUSTOM_FIELDS_FILTER_SCOPE)[scopeKey] =
|
|
166
|
-
parseCustomFieldScopeQueryValue(queryItemValue);
|
|
168
|
+
formattedScopeMap.get(CUSTOM_FIELDS_FILTER_SCOPE)[scopeKey] = parseCustomFieldScopeQueryValue(queryItemValue);
|
|
167
169
|
return;
|
|
168
170
|
}
|
|
169
|
-
const key = utils_1.isAttributeByAssociation(queryItemKey, associationModels)
|
|
170
|
-
? utils_1.wrapAttributeWithOperator(queryItemKey)
|
|
171
|
+
const key = (0, utils_1.isAttributeByAssociation)(queryItemKey, associationModels)
|
|
172
|
+
? (0, utils_1.wrapAttributeWithOperator)(queryItemKey)
|
|
171
173
|
: queryItemKey;
|
|
172
174
|
formattedQuery[key] = queryItemValue;
|
|
173
175
|
});
|
|
@@ -188,8 +190,8 @@ const formatQuery = (query, associationModels, replacementsMap) => {
|
|
|
188
190
|
};
|
|
189
191
|
};
|
|
190
192
|
const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
191
|
-
$and: searchTerm.split(' ').map(term => ({
|
|
192
|
-
$or: attributesToSend.filter(attrKey => rawAttributes[attrKey].type.key === 'STRING').map(attr => ({
|
|
193
|
+
$and: searchTerm.split(' ').map((term) => ({
|
|
194
|
+
$or: attributesToSend.filter((attrKey) => rawAttributes[attrKey].type.key === 'STRING').map((attr) => ({
|
|
193
195
|
[attr]: {
|
|
194
196
|
$iLike: `%${term}%`,
|
|
195
197
|
},
|
|
@@ -198,7 +200,7 @@ const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
|
198
200
|
});
|
|
199
201
|
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model, options) => {
|
|
200
202
|
const replacementsMap = createReplacementMap(order, query);
|
|
201
|
-
const associationModels = Object.keys(
|
|
203
|
+
const associationModels = Object.keys(model?.associations || {});
|
|
202
204
|
const { formattedOrders, orderScopes } = formatOrder({
|
|
203
205
|
order: [...order, DEFAULT_ORDER],
|
|
204
206
|
associationModels,
|
|
@@ -206,23 +208,32 @@ const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = util
|
|
|
206
208
|
});
|
|
207
209
|
const [filteredFormattedOrder, filteredLiteralAttributes] = getAttributeFromOrder(formattedOrders, options);
|
|
208
210
|
const allAttributes = [...filteredLiteralAttributes, ...(attributes || [])];
|
|
209
|
-
const formattedAttribute =
|
|
210
|
-
const formattedInclude = formatInclude(include, model
|
|
211
|
+
const formattedAttribute = attributes?.length ? allAttributes : { include: allAttributes };
|
|
212
|
+
const formattedInclude = formatInclude(include, model?.associations);
|
|
211
213
|
const formattedPage = formatPage(page);
|
|
212
214
|
const formattedPerPage = formatPerPage(perPage);
|
|
213
215
|
const result = formatQuery(query, associationModels, replacementsMap);
|
|
214
216
|
const queryScopes = result.formattedScopes;
|
|
215
217
|
let { formattedQuery } = result;
|
|
216
|
-
if (searchTerm && !
|
|
217
|
-
const attributesToSend =
|
|
218
|
+
if (searchTerm && !options?.skipSearchTermFormat) {
|
|
219
|
+
const attributesToSend = attributes?.length ? attributes : Object.keys(model.rawAttributes);
|
|
218
220
|
const queryWithSearchTerm = formatSearchTerm(searchTerm, attributesToSend, model.rawAttributes);
|
|
219
|
-
formattedQuery =
|
|
221
|
+
formattedQuery = !formattedQuery || Object.keys(formattedQuery).length === 0 ? queryWithSearchTerm : {
|
|
220
222
|
$and: [
|
|
221
223
|
formattedQuery,
|
|
222
224
|
queryWithSearchTerm,
|
|
223
225
|
],
|
|
224
226
|
};
|
|
225
227
|
}
|
|
226
|
-
return
|
|
228
|
+
return {
|
|
229
|
+
query: formattedQuery,
|
|
230
|
+
order: filteredFormattedOrder,
|
|
231
|
+
page: formattedPage,
|
|
232
|
+
perPage: formattedPerPage,
|
|
233
|
+
include: formattedInclude,
|
|
234
|
+
scopes: [...queryScopes, ...orderScopes],
|
|
235
|
+
// ...((allAttributes.length > 0) && { attributes: allAttributes }),
|
|
236
|
+
...(formattedAttribute && { attributes: formattedAttribute }),
|
|
237
|
+
};
|
|
227
238
|
};
|
|
228
239
|
exports.default = formatPayload;
|
|
@@ -7,7 +7,7 @@ const _1 = __importDefault(require("."));
|
|
|
7
7
|
describe('formatting test', () => {
|
|
8
8
|
describe('query formatting', () => {
|
|
9
9
|
it('query json field', () => {
|
|
10
|
-
const { query } = _1.default({
|
|
10
|
+
const { query } = (0, _1.default)({
|
|
11
11
|
order: [],
|
|
12
12
|
query: {
|
|
13
13
|
'json.field': {
|
|
@@ -22,7 +22,7 @@ describe('formatting test', () => {
|
|
|
22
22
|
expect(JSON.stringify(query)).toBe(JSON.stringify({ 'json.field': { $gt: 4 } }));
|
|
23
23
|
});
|
|
24
24
|
it('query included model field', () => {
|
|
25
|
-
const { query } = _1.default({
|
|
25
|
+
const { query } = (0, _1.default)({
|
|
26
26
|
order: [],
|
|
27
27
|
query: {
|
|
28
28
|
'status.field': {
|
|
@@ -41,7 +41,7 @@ describe('formatting test', () => {
|
|
|
41
41
|
});
|
|
42
42
|
it('query with searchTerm', () => {
|
|
43
43
|
const searchTerm = 'aviv';
|
|
44
|
-
const { query } = _1.default({
|
|
44
|
+
const { query } = (0, _1.default)({
|
|
45
45
|
order: [],
|
|
46
46
|
query: {
|
|
47
47
|
'json.field': {
|
|
@@ -80,7 +80,7 @@ describe('formatting test', () => {
|
|
|
80
80
|
it('query with searchTerm with spaces', () => {
|
|
81
81
|
const searchTerm = 'aviv good guy';
|
|
82
82
|
const splitSearch = searchTerm.split(' ');
|
|
83
|
-
const { query } = _1.default({
|
|
83
|
+
const { query } = (0, _1.default)({
|
|
84
84
|
order: [],
|
|
85
85
|
query: {
|
|
86
86
|
'json.field': {
|
|
@@ -132,19 +132,19 @@ describe('formatting test', () => {
|
|
|
132
132
|
});
|
|
133
133
|
describe('order formatting', () => {
|
|
134
134
|
it('simple check', () => {
|
|
135
|
-
const { order } = _1.default({
|
|
135
|
+
const { order } = (0, _1.default)({
|
|
136
136
|
order: ['startTime', '-endTime'],
|
|
137
137
|
});
|
|
138
138
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime', 'DESC'], ['id']]));
|
|
139
139
|
});
|
|
140
140
|
it('simple check asc', () => {
|
|
141
|
-
const { order } = _1.default({
|
|
141
|
+
const { order } = (0, _1.default)({
|
|
142
142
|
order: ['startTime', 'endTime'],
|
|
143
143
|
});
|
|
144
144
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime'], ['id']]));
|
|
145
145
|
});
|
|
146
146
|
it('by included model', () => {
|
|
147
|
-
const { order } = _1.default({
|
|
147
|
+
const { order } = (0, _1.default)({
|
|
148
148
|
order: ['status.name'],
|
|
149
149
|
}, {
|
|
150
150
|
rawAttributes: {
|
|
@@ -157,7 +157,7 @@ describe('formatting test', () => {
|
|
|
157
157
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name'], ['id']]));
|
|
158
158
|
});
|
|
159
159
|
it('by included model descending', () => {
|
|
160
|
-
const { order } = _1.default({
|
|
160
|
+
const { order } = (0, _1.default)({
|
|
161
161
|
order: ['-status.name'],
|
|
162
162
|
}, {
|
|
163
163
|
rawAttributes: {
|
|
@@ -170,7 +170,7 @@ describe('formatting test', () => {
|
|
|
170
170
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name', 'DESC'], ['id']]));
|
|
171
171
|
});
|
|
172
172
|
it('by json field', () => {
|
|
173
|
-
const { order } = _1.default({
|
|
173
|
+
const { order } = (0, _1.default)({
|
|
174
174
|
order: ['status.name'],
|
|
175
175
|
}, {
|
|
176
176
|
rawAttributes: {
|
|
@@ -180,7 +180,7 @@ describe('formatting test', () => {
|
|
|
180
180
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name'], ['id']]));
|
|
181
181
|
});
|
|
182
182
|
it('by json field descending', () => {
|
|
183
|
-
const { order } = _1.default({
|
|
183
|
+
const { order } = (0, _1.default)({
|
|
184
184
|
order: ['-status.name'],
|
|
185
185
|
}, {
|
|
186
186
|
rawAttributes: {
|
|
@@ -190,8 +190,8 @@ describe('formatting test', () => {
|
|
|
190
190
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name', 'DESC'], ['id']]));
|
|
191
191
|
});
|
|
192
192
|
it('by literal field ascending', () => {
|
|
193
|
-
const literalAttribute = { attribute: 'genericField', literal: [{ 0: e => `${e}0` }] };
|
|
194
|
-
const { order, attributes } = _1.default({
|
|
193
|
+
const literalAttribute = { attribute: 'genericField', literal: [{ 0: (e) => `${e}0` }] };
|
|
194
|
+
const { order, attributes } = (0, _1.default)({
|
|
195
195
|
order: [literalAttribute.attribute],
|
|
196
196
|
}, {
|
|
197
197
|
rawAttributes: {
|
|
@@ -206,7 +206,7 @@ describe('formatting test', () => {
|
|
|
206
206
|
});
|
|
207
207
|
it('by literal field descending', () => {
|
|
208
208
|
const literalAttribute = { attribute: 'genericField', literal: ['void', 'field'] };
|
|
209
|
-
const { order, attributes } = _1.default({
|
|
209
|
+
const { order, attributes } = (0, _1.default)({
|
|
210
210
|
order: [`-${literalAttribute.attribute}`, 'currencySymbol'],
|
|
211
211
|
attributes: ['endTime'],
|
|
212
212
|
}, {
|
|
@@ -222,7 +222,7 @@ describe('formatting test', () => {
|
|
|
222
222
|
});
|
|
223
223
|
it('by literal field - not found', () => {
|
|
224
224
|
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
225
|
-
const { order, attributes } = _1.default({
|
|
225
|
+
const { order, attributes } = (0, _1.default)({
|
|
226
226
|
order: [`-O${literalAttribute.attribute}`],
|
|
227
227
|
}, {
|
|
228
228
|
rawAttributes: {
|
|
@@ -237,7 +237,7 @@ describe('formatting test', () => {
|
|
|
237
237
|
});
|
|
238
238
|
describe('include formatting', () => {
|
|
239
239
|
it('include required should be true', () => {
|
|
240
|
-
const { include } = _1.default({
|
|
240
|
+
const { include } = (0, _1.default)({
|
|
241
241
|
order: [],
|
|
242
242
|
include: [{
|
|
243
243
|
model: 'status',
|
|
@@ -250,7 +250,7 @@ describe('formatting test', () => {
|
|
|
250
250
|
expect(include[0].required).toBe(true);
|
|
251
251
|
});
|
|
252
252
|
it('include required should be false', () => {
|
|
253
|
-
const { include } = _1.default({
|
|
253
|
+
const { include } = (0, _1.default)({
|
|
254
254
|
order: [],
|
|
255
255
|
include: [{
|
|
256
256
|
model: 'status',
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { FormatPayloadOptions } from '../formatter';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
2
|
+
type literal = any;
|
|
3
|
+
type LiteralQuery = (literal | string)[] | literal;
|
|
4
|
+
export type LiteralAttribute = {
|
|
5
5
|
attribute: string;
|
|
6
6
|
literal: LiteralQuery;
|
|
7
7
|
};
|
|
8
|
-
export
|
|
8
|
+
export type MiddlewareValidationOption = {
|
|
9
9
|
literalAttributes?: LiteralAttribute[];
|
|
10
10
|
enrichmentAttributes?: string[];
|
|
11
11
|
};
|
package/lib/middleware/index.js
CHANGED
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
14
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
6
|
exports.queryFormatMiddleware = exports.queryValidationMiddleware = exports.newQueryFormatMiddleware = exports.newQueryValidationMiddleware = void 0;
|
|
7
|
+
const logger_1 = __importDefault(require("@autofleet/logger"));
|
|
16
8
|
const errors_1 = require("@autofleet/errors");
|
|
17
9
|
const joi_1 = require("joi");
|
|
18
10
|
const formatter_1 = __importDefault(require("../formatter"));
|
|
19
11
|
const validations_1 = require("../validations");
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
const logger = (0, logger_1.default)();
|
|
13
|
+
const querySchema = (0, joi_1.object)({
|
|
14
|
+
query: (0, joi_1.object)(),
|
|
15
|
+
attributes: (0, joi_1.array)().items((0, joi_1.string)()),
|
|
16
|
+
order: (0, joi_1.array)().items((0, joi_1.string)()),
|
|
17
|
+
page: (0, joi_1.number)(),
|
|
18
|
+
perPage: (0, joi_1.number)(),
|
|
19
|
+
include: (0, joi_1.array)().items((0, joi_1.any)()),
|
|
20
|
+
searchTerm: (0, joi_1.string)(),
|
|
21
|
+
group: (0, joi_1.array)().items((0, joi_1.string)()),
|
|
22
|
+
enrichments: (0, joi_1.alternatives)((0, joi_1.array)().items((0, joi_1.string)()), (0, joi_1.object)().pattern((0, joi_1.string)(), { exclude: (0, joi_1.array)().items((0, joi_1.string)()) })),
|
|
30
23
|
});
|
|
31
|
-
|
|
24
|
+
const newQueryValidationMiddleware = (inner = 'body') => (model, options = {}) => async (req, res, next) => {
|
|
32
25
|
const { query, attributes, order, page, perPage, include, group, enrichments, } = req[inner];
|
|
33
26
|
try {
|
|
34
27
|
const result = querySchema.validate(req[inner]);
|
|
35
28
|
if (result.error) {
|
|
36
29
|
throw new errors_1.BadRequest([result.error], null);
|
|
37
30
|
}
|
|
38
|
-
validations_1.validatePayload({
|
|
31
|
+
(0, validations_1.validatePayload)({
|
|
39
32
|
query,
|
|
40
33
|
attributes,
|
|
41
34
|
order,
|
|
@@ -48,7 +41,8 @@ exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {})
|
|
|
48
41
|
return next();
|
|
49
42
|
}
|
|
50
43
|
catch (error) {
|
|
51
|
-
return errors_1.handleError(error, res, {
|
|
44
|
+
return (0, errors_1.handleError)(error, res, {
|
|
45
|
+
logger,
|
|
52
46
|
message: 'error in query middleware',
|
|
53
47
|
payload: {
|
|
54
48
|
error,
|
|
@@ -58,10 +52,11 @@ exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {})
|
|
|
58
52
|
},
|
|
59
53
|
});
|
|
60
54
|
}
|
|
61
|
-
}
|
|
62
|
-
exports.
|
|
55
|
+
};
|
|
56
|
+
exports.newQueryValidationMiddleware = newQueryValidationMiddleware;
|
|
57
|
+
const newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) => async (req, res, next) => {
|
|
63
58
|
const { order, page, perPage, include, query, attributes, searchTerm, } = req[inner];
|
|
64
|
-
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, attributes: formattedAttribute, } = formatter_1.default({
|
|
59
|
+
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, attributes: formattedAttribute, } = (0, formatter_1.default)({
|
|
65
60
|
query,
|
|
66
61
|
order,
|
|
67
62
|
page,
|
|
@@ -89,6 +84,7 @@ exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) =>
|
|
|
89
84
|
};
|
|
90
85
|
}
|
|
91
86
|
return next();
|
|
92
|
-
}
|
|
93
|
-
exports.
|
|
94
|
-
exports.
|
|
87
|
+
};
|
|
88
|
+
exports.newQueryFormatMiddleware = newQueryFormatMiddleware;
|
|
89
|
+
exports.queryValidationMiddleware = (0, exports.newQueryValidationMiddleware)();
|
|
90
|
+
exports.queryFormatMiddleware = (0, exports.newQueryFormatMiddleware)();
|
package/lib/operators/index.js
CHANGED
|
@@ -39,7 +39,7 @@ exports.OPERATORS_TO_SQL = {
|
|
|
39
39
|
$and: 'AND',
|
|
40
40
|
$or: 'OR',
|
|
41
41
|
};
|
|
42
|
-
|
|
42
|
+
const formatOperators = (Sequelize) => {
|
|
43
43
|
const { Op } = Sequelize;
|
|
44
44
|
return exports.OPERATORS.reduce((map, o) => {
|
|
45
45
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -47,3 +47,4 @@ exports.formatOperators = (Sequelize) => {
|
|
|
47
47
|
return map;
|
|
48
48
|
}, {});
|
|
49
49
|
};
|
|
50
|
+
exports.formatOperators = formatOperators;
|
package/lib/utils.js
CHANGED
|
@@ -11,26 +11,33 @@ exports.PAGE_DEFAULT = 1;
|
|
|
11
11
|
exports.PER_PAGE_MAX_LIMIT = 100;
|
|
12
12
|
exports.PER_PAGE_MIN_LIMIT = 1;
|
|
13
13
|
exports.PAGE_MIN = 1;
|
|
14
|
-
|
|
15
|
-
exports.
|
|
14
|
+
const wrapAttributeWithOperator = attribute => `${operators_1.OPERATOR_PREFIX}${attribute}${operators_1.OPERATOR_PREFIX}`;
|
|
15
|
+
exports.wrapAttributeWithOperator = wrapAttributeWithOperator;
|
|
16
|
+
const isAttributeByAssociation = (attributeName, associatedModels) => attributeName.includes(exports.ASSOCIATION_PREFIX)
|
|
16
17
|
&& associatedModels.includes(attributeName.split(exports.ASSOCIATION_PREFIX)[0]);
|
|
17
|
-
exports.
|
|
18
|
+
exports.isAttributeByAssociation = isAttributeByAssociation;
|
|
19
|
+
const extractAttributeNameFromOrder = (order, associationModels) => {
|
|
18
20
|
let formattedOrder = order;
|
|
19
21
|
if (order.includes(exports.ORDER_PREFIX)) {
|
|
20
22
|
// eslint-disable-next-line prefer-destructuring
|
|
21
23
|
formattedOrder = formattedOrder.split(exports.ORDER_PREFIX)[1];
|
|
22
24
|
}
|
|
23
|
-
if (exports.isAttributeByAssociation(formattedOrder, associationModels)) {
|
|
25
|
+
if ((0, exports.isAttributeByAssociation)(formattedOrder, associationModels)) {
|
|
24
26
|
[formattedOrder] = formattedOrder.split(exports.ASSOCIATION_PREFIX);
|
|
25
27
|
}
|
|
26
28
|
return formattedOrder;
|
|
27
29
|
};
|
|
28
|
-
exports.
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
exports.extractAttributeNameFromOrder = extractAttributeNameFromOrder;
|
|
31
|
+
const isOrderDesc = (order) => order.includes(exports.ORDER_PREFIX);
|
|
32
|
+
exports.isOrderDesc = isOrderDesc;
|
|
33
|
+
const throwBadRequestError = (message) => {
|
|
34
|
+
throw new errors_1.BadRequest([new Error(message)], null);
|
|
31
35
|
};
|
|
32
|
-
exports.
|
|
33
|
-
|
|
36
|
+
exports.throwBadRequestError = throwBadRequestError;
|
|
37
|
+
const extractAssociatedAttributeNameFromOrder = (order) => order.split(exports.ASSOCIATION_PREFIX)[1];
|
|
38
|
+
exports.extractAssociatedAttributeNameFromOrder = extractAssociatedAttributeNameFromOrder;
|
|
39
|
+
const generateRandomString = (length = 5) => {
|
|
34
40
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
35
41
|
return Array.from({ length }, () => characters.charAt(randomInt(characters.length))).join('');
|
|
36
42
|
};
|
|
43
|
+
exports.generateRandomString = generateRandomString;
|
package/lib/validations/index.js
CHANGED
|
@@ -1,53 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.validatePayload = void 0;
|
|
7
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
8
4
|
const utils_1 = require("../utils");
|
|
9
5
|
const operators_1 = require("../operators");
|
|
10
6
|
const validateOperator = (operator) => operators_1.OPERATORS.includes(operator.split(operators_1.OPERATOR_PREFIX)[1]);
|
|
11
|
-
const validateQueryAttribute = (attribute, modelAttributes = [], associationModels = []) => [...modelAttributes, ...associationModels]
|
|
12
|
-
.includes(attribute.includes(utils_1.ASSOCIATION_PREFIX)
|
|
13
|
-
? attribute.split(utils_1.ASSOCIATION_PREFIX)[0] : attribute);
|
|
7
|
+
const validateQueryAttribute = (attribute, modelAttributes = [], associationModels = []) => [...modelAttributes, ...associationModels].includes(attribute.includes(utils_1.ASSOCIATION_PREFIX) ? attribute.split(utils_1.ASSOCIATION_PREFIX)[0] : attribute);
|
|
14
8
|
const validateSingleOrder = (currentOrder, rawAttributes, associationModels, options = {}) => {
|
|
15
|
-
|
|
16
|
-
const isOrderDescOrder = utils_1.isOrderDesc(currentOrder);
|
|
9
|
+
const isOrderDescOrder = (0, utils_1.isOrderDesc)(currentOrder);
|
|
17
10
|
if (isOrderDescOrder && currentOrder[0] !== utils_1.ORDER_PREFIX) {
|
|
18
|
-
utils_1.throwBadRequestError(`${utils_1.ORDER_PREFIX} must be only at the beginning of the word`);
|
|
11
|
+
(0, utils_1.throwBadRequestError)(`${utils_1.ORDER_PREFIX} must be only at the beginning of the word`);
|
|
19
12
|
}
|
|
20
|
-
const orderStringWithoutDesc = isOrderDescOrder ?
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const isLiteralAttribute = (_b = (_a = options === null || options === void 0 ? void 0 : options.literalAttributes) === null || _a === void 0 ? void 0 : _a.map(la => la.attribute)) === null || _b === void 0 ? void 0 : _b.includes(orderStringWithoutDesc);
|
|
13
|
+
const orderStringWithoutDesc = isOrderDescOrder ? currentOrder.split(utils_1.ORDER_PREFIX)[1] : currentOrder;
|
|
14
|
+
const isOrderAssociation = (0, utils_1.isAttributeByAssociation)(orderStringWithoutDesc, associationModels);
|
|
15
|
+
let formattedOrderString = (0, utils_1.extractAttributeNameFromOrder)(currentOrder, associationModels);
|
|
16
|
+
const isLiteralAttribute = options?.literalAttributes?.map((la) => la.attribute)?.includes(orderStringWithoutDesc);
|
|
25
17
|
if (!isOrderAssociation && formattedOrderString.includes(utils_1.ASSOCIATION_PREFIX)) {
|
|
26
18
|
[formattedOrderString] = formattedOrderString.split(utils_1.ASSOCIATION_PREFIX);
|
|
27
19
|
}
|
|
28
20
|
if (!(rawAttributes.includes(formattedOrderString) || isOrderAssociation || isLiteralAttribute)) {
|
|
29
|
-
utils_1.throwBadRequestError(`${currentOrder} is invalid. isLiteralAttribute: ${isLiteralAttribute}`);
|
|
21
|
+
(0, utils_1.throwBadRequestError)(`${currentOrder} is invalid. isLiteralAttribute: ${isLiteralAttribute}`);
|
|
30
22
|
}
|
|
31
23
|
};
|
|
32
24
|
const validateSingleAttribute = (currentAttribute, rawAttributes) => {
|
|
33
25
|
if (!rawAttributes.includes(currentAttribute)) {
|
|
34
|
-
utils_1.throwBadRequestError(`${currentAttribute} is invalid`);
|
|
26
|
+
(0, utils_1.throwBadRequestError)(`${currentAttribute} is invalid`);
|
|
35
27
|
}
|
|
36
28
|
};
|
|
37
29
|
const validateOrderAttributes = (order, rawAttributes, associationModels = [], options = {}) => {
|
|
38
|
-
order.
|
|
30
|
+
order.forEach((o) => validateSingleOrder(o, rawAttributes, associationModels, options));
|
|
39
31
|
};
|
|
40
32
|
const validateAttributes = (attributes, rawAttributes) => {
|
|
41
|
-
attributes.
|
|
33
|
+
attributes.forEach((a) => validateSingleAttribute(a, rawAttributes));
|
|
42
34
|
};
|
|
43
35
|
const validateEnrichments = (enrichments, options) => {
|
|
44
|
-
|
|
36
|
+
const enrichmentKeys = Array.isArray(enrichments) ? enrichments : Object.keys(enrichments);
|
|
37
|
+
if (!enrichmentKeys?.length) {
|
|
45
38
|
return;
|
|
46
39
|
}
|
|
47
|
-
const invalidEnrichment =
|
|
48
|
-
.find(enrichment => { var _a; return !((_a = options === null || options === void 0 ? void 0 : options.enrichmentAttributes) === null || _a === void 0 ? void 0 : _a.includes(enrichment)); });
|
|
40
|
+
const invalidEnrichment = enrichmentKeys.find((enrichment) => !options?.enrichmentAttributes?.includes(enrichment));
|
|
49
41
|
if (invalidEnrichment) {
|
|
50
|
-
utils_1.throwBadRequestError(`enrichment attribute ${invalidEnrichment} is invalid`);
|
|
42
|
+
(0, utils_1.throwBadRequestError)(`enrichment attribute ${invalidEnrichment} is invalid`);
|
|
51
43
|
}
|
|
52
44
|
};
|
|
53
45
|
const validateQueryPayload = (query, rawAttributes, associationModels = []) => {
|
|
@@ -55,37 +47,35 @@ const validateQueryPayload = (query, rawAttributes, associationModels = []) => {
|
|
|
55
47
|
Object.keys(query).map((key) => {
|
|
56
48
|
const value = query[key];
|
|
57
49
|
if (Array.isArray(value)) {
|
|
58
|
-
if (
|
|
59
|
-
value.map(v => validateQueryPayload(v, rawAttributes, associationModels));
|
|
50
|
+
if (value[0] && typeof value[0] === 'object') {
|
|
51
|
+
value.map((v) => validateQueryPayload(v, rawAttributes, associationModels));
|
|
60
52
|
}
|
|
61
53
|
}
|
|
62
|
-
else if (validateOperator(key)
|
|
63
|
-
|
|
64
|
-
if (lodash_1.default.isObject(value)) {
|
|
54
|
+
else if (validateOperator(key) || validateQueryAttribute(key, rawAttributes, associationModels)) {
|
|
55
|
+
if (value && typeof value === 'object') {
|
|
65
56
|
validateQueryPayload(value, rawAttributes);
|
|
66
57
|
}
|
|
67
58
|
}
|
|
68
59
|
else {
|
|
69
|
-
utils_1.throwBadRequestError(`invalid key: ${key}`);
|
|
60
|
+
(0, utils_1.throwBadRequestError)(`invalid key: ${key}`);
|
|
70
61
|
}
|
|
71
62
|
});
|
|
72
63
|
};
|
|
73
64
|
const validatePagination = ({ page, perPage, }) => {
|
|
74
65
|
if (page < utils_1.PAGE_MIN) {
|
|
75
|
-
utils_1.throwBadRequestError('Page must be greater than 0');
|
|
66
|
+
(0, utils_1.throwBadRequestError)('Page must be greater than 0');
|
|
76
67
|
}
|
|
77
68
|
if (perPage > utils_1.PER_PAGE_MAX_LIMIT || perPage < utils_1.PER_PAGE_MIN_LIMIT) {
|
|
78
|
-
utils_1.throwBadRequestError(`PerPage must be between ${utils_1.PER_PAGE_MIN_LIMIT} to ${utils_1.PER_PAGE_MAX_LIMIT}`);
|
|
69
|
+
(0, utils_1.throwBadRequestError)(`PerPage must be between ${utils_1.PER_PAGE_MIN_LIMIT} to ${utils_1.PER_PAGE_MAX_LIMIT}`);
|
|
79
70
|
}
|
|
80
71
|
};
|
|
81
72
|
const validateIncludePayload = (include, associations) => {
|
|
82
73
|
const associationsKeys = Object.keys(associations);
|
|
83
74
|
include.forEach((i) => {
|
|
84
|
-
var _a;
|
|
85
75
|
validateQueryAttribute(i.model, associationsKeys);
|
|
86
|
-
const target =
|
|
76
|
+
const target = associations[i.model]?.target;
|
|
87
77
|
if (!target) {
|
|
88
|
-
utils_1.throwBadRequestError('model not found in associations');
|
|
78
|
+
(0, utils_1.throwBadRequestError)('model not found in associations');
|
|
89
79
|
}
|
|
90
80
|
const { rawAttributes } = target;
|
|
91
81
|
const attributeKeys = Object.keys(rawAttributes);
|
|
@@ -98,14 +88,14 @@ const validateIncludePayload = (include, associations) => {
|
|
|
98
88
|
if (i.attributes) {
|
|
99
89
|
validateAttributes(i.attributes, attributeKeys);
|
|
100
90
|
}
|
|
101
|
-
if (!
|
|
102
|
-
utils_1.throwBadRequestError('include.required must be a boolean');
|
|
91
|
+
if (![null, undefined, true, false].includes(i.required)) {
|
|
92
|
+
(0, utils_1.throwBadRequestError)('include.required must be a boolean');
|
|
103
93
|
}
|
|
104
94
|
});
|
|
105
95
|
};
|
|
106
|
-
|
|
96
|
+
const validatePayload = ({ query = {}, order = [], attributes = [], include = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, enrichments = [], group = [], }, model, options = {}) => {
|
|
107
97
|
const rawAttributes = Object.keys(model.rawAttributes);
|
|
108
|
-
const associationModels = Object.keys(
|
|
98
|
+
const associationModels = Object.keys(model?.associations || {});
|
|
109
99
|
if (!attributes || attributes.length === 0) {
|
|
110
100
|
// eslint-disable-next-line no-param-reassign
|
|
111
101
|
attributes = rawAttributes;
|
|
@@ -117,13 +107,13 @@ exports.validatePayload = ({ query = {}, order = [], attributes = [], include =
|
|
|
117
107
|
validateQueryPayload(query, rawAttributes, associationModels);
|
|
118
108
|
validateEnrichments(enrichments, options);
|
|
119
109
|
if (!Array.isArray(group)) {
|
|
120
|
-
utils_1.throwBadRequestError('group must be an array');
|
|
110
|
+
(0, utils_1.throwBadRequestError)('group must be an array');
|
|
121
111
|
}
|
|
122
112
|
if (include.length && typeof include === 'object') {
|
|
123
|
-
validateIncludePayload(include, model
|
|
113
|
+
validateIncludePayload(include, model?.associations);
|
|
124
114
|
}
|
|
125
115
|
else if (include && typeof include !== 'object') {
|
|
126
|
-
utils_1.throwBadRequestError('include must be an array');
|
|
116
|
+
(0, utils_1.throwBadRequestError)('include must be an array');
|
|
127
117
|
}
|
|
128
118
|
validatePagination({
|
|
129
119
|
page,
|
|
@@ -131,3 +121,4 @@ exports.validatePayload = ({ query = {}, order = [], attributes = [], include =
|
|
|
131
121
|
});
|
|
132
122
|
return true;
|
|
133
123
|
};
|
|
124
|
+
exports.validatePayload = validatePayload;
|
|
@@ -40,7 +40,7 @@ const order = ['startTime', '-endTime'];
|
|
|
40
40
|
describe('validations test', () => {
|
|
41
41
|
describe('query validation', () => {
|
|
42
42
|
it('check query validation', () => {
|
|
43
|
-
const payload = _1.validatePayload({ query }, {
|
|
43
|
+
const payload = (0, _1.validatePayload)({ query }, {
|
|
44
44
|
rawAttributes: {
|
|
45
45
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
46
46
|
},
|
|
@@ -48,7 +48,7 @@ describe('validations test', () => {
|
|
|
48
48
|
expect(payload).toBe(true);
|
|
49
49
|
});
|
|
50
50
|
it('check query by json property field', () => {
|
|
51
|
-
const payload = _1.validatePayload({
|
|
51
|
+
const payload = (0, _1.validatePayload)({
|
|
52
52
|
query: {
|
|
53
53
|
'jsonField.exampleField': {
|
|
54
54
|
$eq: 'a',
|
|
@@ -62,7 +62,7 @@ describe('validations test', () => {
|
|
|
62
62
|
expect(payload).toBe(true);
|
|
63
63
|
});
|
|
64
64
|
it('check query by included model field', () => {
|
|
65
|
-
const payload = _1.validatePayload({
|
|
65
|
+
const payload = (0, _1.validatePayload)({
|
|
66
66
|
query: {
|
|
67
67
|
'status.name': {
|
|
68
68
|
$eq: 'a',
|
|
@@ -80,7 +80,7 @@ describe('validations test', () => {
|
|
|
80
80
|
});
|
|
81
81
|
it('check query by non existent field', () => {
|
|
82
82
|
try {
|
|
83
|
-
_1.validatePayload({
|
|
83
|
+
(0, _1.validatePayload)({
|
|
84
84
|
query: {
|
|
85
85
|
nonExistent: {
|
|
86
86
|
$eq: 'a',
|
|
@@ -99,7 +99,7 @@ describe('validations test', () => {
|
|
|
99
99
|
});
|
|
100
100
|
describe('order validation', () => {
|
|
101
101
|
it('check order validation', () => {
|
|
102
|
-
const payload = _1.validatePayload({ order }, {
|
|
102
|
+
const payload = (0, _1.validatePayload)({ order }, {
|
|
103
103
|
rawAttributes: {
|
|
104
104
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
105
105
|
},
|
|
@@ -108,7 +108,7 @@ describe('validations test', () => {
|
|
|
108
108
|
});
|
|
109
109
|
it('order does not exist', () => {
|
|
110
110
|
try {
|
|
111
|
-
_1.validatePayload({ order: ['aviv'] }, {
|
|
111
|
+
(0, _1.validatePayload)({ order: ['aviv'] }, {
|
|
112
112
|
rawAttributes: {
|
|
113
113
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
114
114
|
},
|
|
@@ -120,7 +120,7 @@ describe('validations test', () => {
|
|
|
120
120
|
});
|
|
121
121
|
it('prefix in the wrong place', () => {
|
|
122
122
|
try {
|
|
123
|
-
_1.validatePayload({ order: ['startTime-', 'currencySymbol'] }, {
|
|
123
|
+
(0, _1.validatePayload)({ order: ['startTime-', 'currencySymbol'] }, {
|
|
124
124
|
rawAttributes: {
|
|
125
125
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
126
126
|
},
|
|
@@ -131,7 +131,7 @@ describe('validations test', () => {
|
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
133
|
it('order by included model', () => {
|
|
134
|
-
const payload = _1.validatePayload({ order: ['status.title'] }, {
|
|
134
|
+
const payload = (0, _1.validatePayload)({ order: ['status.title'] }, {
|
|
135
135
|
rawAttributes: {
|
|
136
136
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
137
137
|
},
|
|
@@ -142,7 +142,7 @@ describe('validations test', () => {
|
|
|
142
142
|
expect(payload).toBe(true);
|
|
143
143
|
});
|
|
144
144
|
it('order by included model descending', () => {
|
|
145
|
-
const payload = _1.validatePayload({ order: ['-status.title'] }, {
|
|
145
|
+
const payload = (0, _1.validatePayload)({ order: ['-status.title'] }, {
|
|
146
146
|
rawAttributes: {
|
|
147
147
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
148
148
|
},
|
|
@@ -153,7 +153,7 @@ describe('validations test', () => {
|
|
|
153
153
|
expect(payload).toBe(true);
|
|
154
154
|
});
|
|
155
155
|
it('order by json field', () => {
|
|
156
|
-
const payload = _1.validatePayload({ order: ['status.title'] }, {
|
|
156
|
+
const payload = (0, _1.validatePayload)({ order: ['status.title'] }, {
|
|
157
157
|
rawAttributes: {
|
|
158
158
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
159
159
|
},
|
|
@@ -161,7 +161,7 @@ describe('validations test', () => {
|
|
|
161
161
|
expect(payload).toBe(true);
|
|
162
162
|
});
|
|
163
163
|
it('order by json field desc', () => {
|
|
164
|
-
const payload = _1.validatePayload({ order: ['-status.title'] }, {
|
|
164
|
+
const payload = (0, _1.validatePayload)({ order: ['-status.title'] }, {
|
|
165
165
|
rawAttributes: {
|
|
166
166
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
167
167
|
},
|
|
@@ -170,7 +170,7 @@ describe('validations test', () => {
|
|
|
170
170
|
});
|
|
171
171
|
it('try order by json field that doesnt exist', () => {
|
|
172
172
|
try {
|
|
173
|
-
_1.validatePayload({ order: ['-stas.title'] }, {
|
|
173
|
+
(0, _1.validatePayload)({ order: ['-stas.title'] }, {
|
|
174
174
|
rawAttributes: {
|
|
175
175
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
176
176
|
},
|
|
@@ -182,7 +182,7 @@ describe('validations test', () => {
|
|
|
182
182
|
});
|
|
183
183
|
it('try order by literal field that exist', () => {
|
|
184
184
|
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
185
|
-
const payload = _1.validatePayload({ order: [literalAttribute.attribute] }, {
|
|
185
|
+
const payload = (0, _1.validatePayload)({ order: [literalAttribute.attribute] }, {
|
|
186
186
|
rawAttributes: {
|
|
187
187
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
188
188
|
},
|
|
@@ -193,7 +193,7 @@ describe('validations test', () => {
|
|
|
193
193
|
});
|
|
194
194
|
it('try order by literal field that exist - desc', () => {
|
|
195
195
|
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
196
|
-
const payload = _1.validatePayload({ order: [`-${literalAttribute.attribute}`] }, {
|
|
196
|
+
const payload = (0, _1.validatePayload)({ order: [`-${literalAttribute.attribute}`] }, {
|
|
197
197
|
rawAttributes: {
|
|
198
198
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
199
199
|
},
|
|
@@ -205,7 +205,7 @@ describe('validations test', () => {
|
|
|
205
205
|
it('try order by literal field that doesnt exist', () => {
|
|
206
206
|
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
207
207
|
try {
|
|
208
|
-
_1.validatePayload({ order: ['here'] }, {
|
|
208
|
+
(0, _1.validatePayload)({ order: ['here'] }, {
|
|
209
209
|
rawAttributes: {
|
|
210
210
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
211
211
|
},
|
package/package.json
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sheilta",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.4.3",
|
|
4
|
+
"description": "Middlewares for validation and parsing of endpoints meant for data querying.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=16"
|
|
9
|
+
},
|
|
7
10
|
"scripts": {
|
|
8
11
|
"build": "rm -rf lib && tsc",
|
|
9
12
|
"prepublish": "npm run build",
|
|
10
13
|
"coverage": "jest --coverage --forceExit --runInBand",
|
|
11
14
|
"test": "jest --forceExit --runInBand",
|
|
12
15
|
"test-auto": "jest --watch --runInBand",
|
|
13
|
-
"linter": "
|
|
16
|
+
"linter": "eslint src/**/*.ts",
|
|
14
17
|
"build-to-local-repo": "npm run build && cp -r lib/* ../$REPO/node_modules/$npm_package_name/lib",
|
|
15
18
|
"watch": "npm-watch build-to-local-repo"
|
|
16
19
|
},
|
|
@@ -29,10 +32,6 @@
|
|
|
29
32
|
"quiet": false
|
|
30
33
|
}
|
|
31
34
|
},
|
|
32
|
-
"jest": {
|
|
33
|
-
"setupTestFrameworkScriptFile": "jest-extended",
|
|
34
|
-
"testURL": "http://localhost:8085/"
|
|
35
|
-
},
|
|
36
35
|
"repository": {
|
|
37
36
|
"type": "git",
|
|
38
37
|
"url": "git+ssh://git@gitlab.com/AutoFleet/sheilta.git"
|
|
@@ -44,23 +43,25 @@
|
|
|
44
43
|
},
|
|
45
44
|
"homepage": "https://github.com/Autofleet/sheilta",
|
|
46
45
|
"dependencies": {
|
|
47
|
-
"@autofleet/common-types": "^1.7.
|
|
48
|
-
"@autofleet/errors": "^1.
|
|
49
|
-
"joi": "^17.9.2"
|
|
50
|
-
|
|
46
|
+
"@autofleet/common-types": "^1.7.58",
|
|
47
|
+
"@autofleet/errors": "^1.2.3",
|
|
48
|
+
"joi": "^17.9.2"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@autofleet/logger": "*"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
|
-
"@
|
|
54
|
+
"@autofleet/logger": "4.1.0",
|
|
55
|
+
"@types/jest": "^29.5.13",
|
|
54
56
|
"@types/node": "^16.11.68",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
56
|
-
"@typescript-eslint/parser": "^
|
|
57
|
-
"eslint": "^
|
|
58
|
-
"eslint-config-airbnb": "^
|
|
59
|
-
"eslint-plugin-import": "^2.
|
|
60
|
-
"jest": "^
|
|
61
|
-
"ts-jest": "^
|
|
62
|
-
"typescript": "^
|
|
63
|
-
"typescript-eslint": "0.0.1-alpha.0",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
58
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
59
|
+
"eslint": "^8.57.0",
|
|
60
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
61
|
+
"eslint-plugin-import": "^2.31.0",
|
|
62
|
+
"jest": "^29.7.0",
|
|
63
|
+
"ts-jest": "^29.2.5",
|
|
64
|
+
"typescript": "^5.6.2",
|
|
64
65
|
"npm-watch": "^0.13.0"
|
|
65
66
|
},
|
|
66
67
|
"files": [
|