@autofleet/sheilta 1.3.2-2 → 1.3.2-5
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 +16 -1
- package/lib/formatter/index.js +16 -9
- package/lib/formatter/index.test.js +42 -0
- package/lib/interface.d.ts +5 -1
- package/lib/middleware/index.js +3 -2
- package/lib/validations/index.js +2 -2
- package/lib/validations/index.test.js +15 -3
- package/package.json +1 -1
package/lib/formatter/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { Attribute } from '../interface';
|
|
1
2
|
declare type OrderItem = string | [string, string];
|
|
2
3
|
declare type SequelizeOrder = string | OrderItem[];
|
|
3
4
|
export declare type FormatPayloadOptions = {
|
|
4
5
|
includeRawPayload?: boolean;
|
|
6
|
+
literalAttributes?: Attribute[];
|
|
5
7
|
};
|
|
6
8
|
declare const formatPayload: ({ order, page, perPage, include, query, attributes, searchTerm, }: {
|
|
7
9
|
order?: any[];
|
|
@@ -11,7 +13,20 @@ declare const formatPayload: ({ order, page, perPage, include, query, attributes
|
|
|
11
13
|
query?: {};
|
|
12
14
|
attributes?: any;
|
|
13
15
|
searchTerm?: any;
|
|
14
|
-
}, model?: any) => {
|
|
16
|
+
}, model?: any, options?: any) => {
|
|
17
|
+
attributes: {
|
|
18
|
+
include: any[];
|
|
19
|
+
};
|
|
20
|
+
query: {};
|
|
21
|
+
order: SequelizeOrder[];
|
|
22
|
+
page: any;
|
|
23
|
+
perPage: any;
|
|
24
|
+
include: any;
|
|
25
|
+
scopes: (string | {
|
|
26
|
+
method: any[];
|
|
27
|
+
})[];
|
|
28
|
+
} | {
|
|
29
|
+
attributes?: undefined;
|
|
15
30
|
query: {};
|
|
16
31
|
order: SequelizeOrder[];
|
|
17
32
|
page: any;
|
package/lib/formatter/index.js
CHANGED
|
@@ -8,8 +8,18 @@ const common_types_1 = require("@autofleet/common-types");
|
|
|
8
8
|
const utils_1 = require("../utils");
|
|
9
9
|
const DEFAULT_ORDER = 'id';
|
|
10
10
|
const DESCENDING_KEY = 'DESC';
|
|
11
|
+
const ASCENDING_KEY = 'ASC';
|
|
11
12
|
const CUSTOM_FIELDS_QUERY_PREFIX = 'customFields.';
|
|
12
13
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
14
|
+
const getAttributeFromOrder = (order, literalAttributes) => {
|
|
15
|
+
const [formattedOrder, attributes] = order.reduce((acc, o) => {
|
|
16
|
+
const [item, itemOrder = ASCENDING_KEY] = Array.isArray(o) ? o : [o];
|
|
17
|
+
const found = literalAttributes === null || literalAttributes === void 0 ? void 0 : literalAttributes.find(obj => obj.attribute === item);
|
|
18
|
+
(found ? acc[1] : acc[0]).push(found ? [`${found.literal} ${itemOrder}`] : o);
|
|
19
|
+
return acc;
|
|
20
|
+
}, [[], []]);
|
|
21
|
+
return [formattedOrder, attributes];
|
|
22
|
+
};
|
|
13
23
|
const formatOrder = ({ order, associationModels = [], }) => order.map((o) => {
|
|
14
24
|
const formattedOrder = [utils_1.extractAttributeNameFromOrder(o, associationModels)];
|
|
15
25
|
const isOrderDescOrder = utils_1.isOrderDesc(o);
|
|
@@ -68,12 +78,15 @@ const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
|
68
78
|
})),
|
|
69
79
|
})),
|
|
70
80
|
});
|
|
71
|
-
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model) => {
|
|
81
|
+
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model, options) => {
|
|
72
82
|
const associationModels = Object.keys((model === null || model === void 0 ? void 0 : model.associations) || {});
|
|
73
83
|
const formattedOrder = formatOrder({
|
|
74
84
|
order: [...order, DEFAULT_ORDER],
|
|
75
85
|
associationModels,
|
|
76
86
|
});
|
|
87
|
+
const [filteredFormattedOrder, filteredLiteralAttributes] = getAttributeFromOrder(formattedOrder, options === null || options === void 0 ? void 0 : options.literalAttributes);
|
|
88
|
+
const allAttributes = [...filteredLiteralAttributes, ...(attributes || [])];
|
|
89
|
+
const formattedAttribute = allAttributes.length ? { include: allAttributes } : null;
|
|
77
90
|
const formattedInclude = formatInclude(include, model === null || model === void 0 ? void 0 : model.associations);
|
|
78
91
|
const formattedPage = formatPage(page);
|
|
79
92
|
const formattedPerPage = formatPerPage(perPage);
|
|
@@ -89,13 +102,7 @@ const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = util
|
|
|
89
102
|
],
|
|
90
103
|
};
|
|
91
104
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
order: formattedOrder,
|
|
95
|
-
page: formattedPage,
|
|
96
|
-
perPage: formattedPerPage,
|
|
97
|
-
include: formattedInclude,
|
|
98
|
-
scopes: result.formattedScopes,
|
|
99
|
-
};
|
|
105
|
+
const selectedAttributes = formattedAttribute ? { attributes: formattedAttribute } : {};
|
|
106
|
+
return Object.assign({ query: formattedQuery, order: filteredFormattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: result.formattedScopes }, selectedAttributes);
|
|
100
107
|
};
|
|
101
108
|
exports.default = formatPayload;
|
|
@@ -189,6 +189,48 @@ describe('formatting test', () => {
|
|
|
189
189
|
});
|
|
190
190
|
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name', 'DESC'], ['id']]));
|
|
191
191
|
});
|
|
192
|
+
it('by literal field ascending', () => {
|
|
193
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
194
|
+
const { order, attributes } = _1.default({
|
|
195
|
+
order: [literalAttribute.attribute],
|
|
196
|
+
}, {
|
|
197
|
+
rawAttributes: {
|
|
198
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
199
|
+
},
|
|
200
|
+
}, {
|
|
201
|
+
literalAttributes: [literalAttribute],
|
|
202
|
+
});
|
|
203
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['id']]));
|
|
204
|
+
expect(JSON.stringify(attributes)).toBe(JSON.stringify({ include: [[`${literalAttribute.literal} ASC`]] }));
|
|
205
|
+
});
|
|
206
|
+
it('by literal field descending', () => {
|
|
207
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
208
|
+
const { order, attributes } = _1.default({
|
|
209
|
+
order: [`-${literalAttribute.attribute}`, 'currencySymbol'],
|
|
210
|
+
}, {
|
|
211
|
+
rawAttributes: {
|
|
212
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
213
|
+
},
|
|
214
|
+
}, {
|
|
215
|
+
literalAttributes: [literalAttribute],
|
|
216
|
+
});
|
|
217
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['currencySymbol'], ['id']]));
|
|
218
|
+
expect(JSON.stringify(attributes)).toBe(JSON.stringify({ include: [[`${literalAttribute.literal} DESC`]] }));
|
|
219
|
+
});
|
|
220
|
+
it('by literal field - not found', () => {
|
|
221
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
222
|
+
const { order, attributes } = _1.default({
|
|
223
|
+
order: [`-O${literalAttribute.attribute}`],
|
|
224
|
+
}, {
|
|
225
|
+
rawAttributes: {
|
|
226
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
227
|
+
},
|
|
228
|
+
}, {
|
|
229
|
+
literalAttributes: [literalAttribute],
|
|
230
|
+
});
|
|
231
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([[`O${literalAttribute.attribute}`, 'DESC'], ['id']]));
|
|
232
|
+
expect(JSON.stringify(attributes)).toBe(JSON.stringify(undefined));
|
|
233
|
+
});
|
|
192
234
|
});
|
|
193
235
|
describe('include formatting', () => {
|
|
194
236
|
it('include required should be true', () => {
|
package/lib/interface.d.ts
CHANGED
package/lib/middleware/index.js
CHANGED
|
@@ -57,7 +57,7 @@ exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {})
|
|
|
57
57
|
});
|
|
58
58
|
exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
59
|
const { order, page, perPage, include, query, attributes, searchTerm, } = req[inner];
|
|
60
|
-
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, } = formatter_1.default({
|
|
60
|
+
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, attributes: formattedAttribute, } = formatter_1.default({
|
|
61
61
|
query,
|
|
62
62
|
order,
|
|
63
63
|
page,
|
|
@@ -65,9 +65,10 @@ exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) =>
|
|
|
65
65
|
include,
|
|
66
66
|
attributes,
|
|
67
67
|
searchTerm,
|
|
68
|
-
}, model);
|
|
68
|
+
}, model, options);
|
|
69
69
|
req[inner].query = formattedQuery;
|
|
70
70
|
req[inner].order = formattedOrder;
|
|
71
|
+
req[inner].attributes = formattedAttribute;
|
|
71
72
|
req[inner].page = formattedPage;
|
|
72
73
|
req[inner].perPage = formattedPerPage;
|
|
73
74
|
req[inner].include = formattedInclude;
|
package/lib/validations/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const validateQueryAttribute = (attribute, modelAttributes = [], associationMode
|
|
|
12
12
|
.includes(attribute.includes(utils_1.ASSOCIATION_PREFIX)
|
|
13
13
|
? attribute.split(utils_1.ASSOCIATION_PREFIX)[0] : attribute);
|
|
14
14
|
const validateSingleOrder = (currentOrder, rawAttributes, associationModels, options = {}) => {
|
|
15
|
-
var _a;
|
|
15
|
+
var _a, _b;
|
|
16
16
|
const isOrderDescOrder = utils_1.isOrderDesc(currentOrder);
|
|
17
17
|
if (isOrderDescOrder && currentOrder[0] !== utils_1.ORDER_PREFIX) {
|
|
18
18
|
utils_1.throwBadRequestError(`${utils_1.ORDER_PREFIX} must be only at the beginning of the word`);
|
|
@@ -21,7 +21,7 @@ const validateSingleOrder = (currentOrder, rawAttributes, associationModels, opt
|
|
|
21
21
|
currentOrder.split(utils_1.ORDER_PREFIX)[1] : currentOrder;
|
|
22
22
|
const isOrderAssociation = utils_1.isAttributeByAssociation(orderStringWithoutDesc, associationModels);
|
|
23
23
|
let formattedOrderString = utils_1.extractAttributeNameFromOrder(currentOrder, associationModels);
|
|
24
|
-
const isLiteralAttribute = (_a = options === null || options === void 0 ? void 0 : options.literalAttributes) === null || _a === void 0 ? void 0 : _a.includes(orderStringWithoutDesc);
|
|
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);
|
|
25
25
|
if (!isOrderAssociation && formattedOrderString.includes(utils_1.ASSOCIATION_PREFIX)) {
|
|
26
26
|
[formattedOrderString] = formattedOrderString.split(utils_1.ASSOCIATION_PREFIX);
|
|
27
27
|
}
|
|
@@ -181,8 +181,19 @@ describe('validations test', () => {
|
|
|
181
181
|
}
|
|
182
182
|
});
|
|
183
183
|
it('try order by literal field that exist', () => {
|
|
184
|
-
const literalAttribute = 'genericField';
|
|
185
|
-
const payload = _1.validatePayload({ order: [literalAttribute] }, {
|
|
184
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
185
|
+
const payload = _1.validatePayload({ order: [literalAttribute.attribute] }, {
|
|
186
|
+
rawAttributes: {
|
|
187
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
188
|
+
},
|
|
189
|
+
}, {
|
|
190
|
+
literalAttributes: [literalAttribute],
|
|
191
|
+
});
|
|
192
|
+
expect(payload).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
it('try order by literal field that exist - desc', () => {
|
|
195
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
196
|
+
const payload = _1.validatePayload({ order: [`-${literalAttribute.attribute}`] }, {
|
|
186
197
|
rawAttributes: {
|
|
187
198
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
188
199
|
},
|
|
@@ -192,12 +203,13 @@ describe('validations test', () => {
|
|
|
192
203
|
expect(payload).toBe(true);
|
|
193
204
|
});
|
|
194
205
|
it('try order by literal field that doesnt exist', () => {
|
|
206
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
195
207
|
try {
|
|
196
208
|
_1.validatePayload({ order: ['here'] }, {
|
|
197
209
|
rawAttributes: {
|
|
198
210
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
199
211
|
},
|
|
200
|
-
}, { literalAttributes: [
|
|
212
|
+
}, { literalAttributes: [literalAttribute] });
|
|
201
213
|
}
|
|
202
214
|
catch (error) {
|
|
203
215
|
expect(error.statusCode).toBe(400);
|