@autofleet/sheilta 1.0.0-aaron-error-fix → 1.0.0-beta-test-2
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/.DS_Store +0 -0
- package/lib/formatter/index.d.ts +32 -2
- package/lib/formatter/index.js +177 -19
- package/lib/formatter/index.test.js +80 -6
- package/lib/index.d.ts +2 -2
- package/lib/middleware/index.d.ts +16 -4
- package/lib/middleware/index.js +33 -5
- package/lib/operators/index.d.ts +17 -0
- package/lib/operators/index.js +18 -1
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +6 -1
- package/lib/validations/index.d.ts +4 -2
- package/lib/validations/index.js +33 -16
- package/lib/validations/index.test.js +35 -0
- package/package.json +29 -9
package/lib/.DS_Store
ADDED
|
Binary file
|
package/lib/formatter/index.d.ts
CHANGED
|
@@ -1,18 +1,48 @@
|
|
|
1
|
+
import type { LiteralAttribute } from '../middleware';
|
|
1
2
|
declare type OrderItem = string | [string, string];
|
|
2
3
|
declare type SequelizeOrder = string | OrderItem[];
|
|
4
|
+
export declare type FormatPayloadOptions = {
|
|
5
|
+
includeRawPayload?: boolean;
|
|
6
|
+
literalAttributes?: LiteralAttribute[];
|
|
7
|
+
DBFormatter?: any;
|
|
8
|
+
skipSearchTermFormat?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare type ConditionWithOperator = {
|
|
11
|
+
operator: string;
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
export declare type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
15
|
+
/**
|
|
16
|
+
* Generates replacements for the given conditions.
|
|
17
|
+
*
|
|
18
|
+
* @param conditions - The conditions to generate replacements for.
|
|
19
|
+
* @returns The replacements object.
|
|
20
|
+
*/
|
|
21
|
+
export declare const generateFilterReplacements: (conditions: Record<string, ConditionValue>) => Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Generates replacements for the given order array.
|
|
24
|
+
*
|
|
25
|
+
* @param order - The order array to generate replacements for.
|
|
26
|
+
* @returns The replacements object.
|
|
27
|
+
*/
|
|
28
|
+
export declare const generateOrderReplacements: (order: string[]) => Record<string, string>;
|
|
3
29
|
declare const formatPayload: ({ order, page, perPage, include, query, attributes, searchTerm, }: {
|
|
4
|
-
order
|
|
30
|
+
order?: any[];
|
|
5
31
|
page?: number;
|
|
6
32
|
perPage?: number;
|
|
7
33
|
include?: any[];
|
|
8
34
|
query?: {};
|
|
9
35
|
attributes?: any;
|
|
10
36
|
searchTerm?: any;
|
|
11
|
-
}, model?: any) => {
|
|
37
|
+
}, model?: any, options?: any) => {
|
|
38
|
+
attributes: any[] | {
|
|
39
|
+
include: any[];
|
|
40
|
+
};
|
|
12
41
|
query: {};
|
|
13
42
|
order: SequelizeOrder[];
|
|
14
43
|
page: any;
|
|
15
44
|
perPage: any;
|
|
16
45
|
include: any;
|
|
46
|
+
scopes: any[];
|
|
17
47
|
};
|
|
18
48
|
export default formatPayload;
|
package/lib/formatter/index.js
CHANGED
|
@@ -3,11 +3,114 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateOrderReplacements = exports.generateFilterReplacements = void 0;
|
|
6
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const common_types_1 = require("@autofleet/common-types");
|
|
7
9
|
const utils_1 = require("../utils");
|
|
10
|
+
const operators_1 = require("../operators");
|
|
11
|
+
const DEFAULT_ORDER = 'id';
|
|
8
12
|
const DESCENDING_KEY = 'DESC';
|
|
9
|
-
const
|
|
10
|
-
|
|
13
|
+
const ASCENDING_KEY = 'ASC';
|
|
14
|
+
const CUSTOM_FIELDS_QUERY_PREFIX = 'customFields.';
|
|
15
|
+
const { CUSTOM_FIELDS_FILTER_SCOPE, CUSTOM_FIELDS_SORT_SCOPE } = common_types_1.customFields;
|
|
16
|
+
const parseCustomFieldScopeQueryValue = (value) => {
|
|
17
|
+
if (['string', 'number'].includes(typeof value) || Array.isArray(value)) {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
return Object.entries(value).map(([operator, conditionValue]) => ({
|
|
21
|
+
operator: operators_1.OPERATORS_TO_SQL[operator],
|
|
22
|
+
value: conditionValue,
|
|
23
|
+
}));
|
|
24
|
+
};
|
|
25
|
+
const getAttributeFromOrder = (order, options = {}) => {
|
|
26
|
+
const { literalAttributes = [], DBFormatter = undefined } = options;
|
|
27
|
+
const [formattedOrder, attributes] = order.reduce((acc, o) => {
|
|
28
|
+
const [item, orderStyle = 'ASC'] = Array.isArray(o) ? o : [o];
|
|
29
|
+
const found = literalAttributes === null || literalAttributes === void 0 ? void 0 : literalAttributes.find(obj => obj.attribute === item);
|
|
30
|
+
if (found) {
|
|
31
|
+
acc[1].push(found.literal);
|
|
32
|
+
acc[0].push([DBFormatter ? DBFormatter(`"${found.attribute}" ${orderStyle}`) : `${found.attribute} ${orderStyle}`]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
acc[0].push(o);
|
|
36
|
+
}
|
|
37
|
+
return acc;
|
|
38
|
+
}, [[], []]);
|
|
39
|
+
return [formattedOrder, attributes];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Generates replacements for the given conditions.
|
|
43
|
+
*
|
|
44
|
+
* @param conditions - The conditions to generate replacements for.
|
|
45
|
+
* @returns The replacements object.
|
|
46
|
+
*/
|
|
47
|
+
exports.generateFilterReplacements = (conditions) => {
|
|
48
|
+
const replacements = {};
|
|
49
|
+
Object.entries(conditions).forEach(([key, condition]) => {
|
|
50
|
+
const replacementKey = utils_1.generateRandomString();
|
|
51
|
+
// eslint-disable-next-line prefer-destructuring
|
|
52
|
+
replacements[replacementKey] = key.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
53
|
+
if (Array.isArray(condition)) {
|
|
54
|
+
condition.forEach((value) => {
|
|
55
|
+
const valueKey = utils_1.generateRandomString();
|
|
56
|
+
replacements[valueKey] = typeof value === 'string' ? value : value.value;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else if (typeof condition === 'string' || typeof condition === 'number') {
|
|
60
|
+
const conditionKey = utils_1.generateRandomString();
|
|
61
|
+
replacements[conditionKey] = condition;
|
|
62
|
+
}
|
|
63
|
+
else if (condition === null || condition === void 0 ? void 0 : condition.operator) {
|
|
64
|
+
const operatorKey = utils_1.generateRandomString();
|
|
65
|
+
replacements[operatorKey] = condition.value;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return replacements;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Generates replacements for the given order array.
|
|
72
|
+
*
|
|
73
|
+
* @param order - The order array to generate replacements for.
|
|
74
|
+
* @returns The replacements object.
|
|
75
|
+
*/
|
|
76
|
+
exports.generateOrderReplacements = (order) => {
|
|
77
|
+
const replacementMap = {};
|
|
78
|
+
order.forEach((o) => {
|
|
79
|
+
if (o.startsWith(CUSTOM_FIELDS_QUERY_PREFIX)) {
|
|
80
|
+
const rand = utils_1.generateRandomString();
|
|
81
|
+
// eslint-disable-next-line prefer-destructuring
|
|
82
|
+
replacementMap[rand] = o.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
83
|
+
}
|
|
84
|
+
else if (o.substring(1).startsWith(CUSTOM_FIELDS_QUERY_PREFIX)) {
|
|
85
|
+
const rand = utils_1.generateRandomString();
|
|
86
|
+
// eslint-disable-next-line prefer-destructuring
|
|
87
|
+
replacementMap[rand] = o.substring(1).split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return replacementMap;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Creates a combined replacement map from order and query.
|
|
94
|
+
*
|
|
95
|
+
* @param order - The order array.
|
|
96
|
+
* @param query - The query object.
|
|
97
|
+
* @returns The combined replacements object.
|
|
98
|
+
*/
|
|
99
|
+
const createReplacementMap = (order, query) => (Object.assign(Object.assign({}, exports.generateOrderReplacements(order)), exports.generateFilterReplacements(query)));
|
|
100
|
+
const formatOrder = ({ order, associationModels = [], replacementsMap = {}, }) => {
|
|
101
|
+
const formattedOrders = [];
|
|
102
|
+
const orderScopesMap = new Map();
|
|
103
|
+
order.forEach((o) => {
|
|
104
|
+
if ([o, o.substring(1)].some(t => t.startsWith(CUSTOM_FIELDS_QUERY_PREFIX))) {
|
|
105
|
+
if (!orderScopesMap.has(CUSTOM_FIELDS_SORT_SCOPE)) {
|
|
106
|
+
orderScopesMap.set(CUSTOM_FIELDS_SORT_SCOPE, {});
|
|
107
|
+
}
|
|
108
|
+
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);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
11
114
|
const formattedOrder = [utils_1.extractAttributeNameFromOrder(o, associationModels)];
|
|
12
115
|
const isOrderDescOrder = utils_1.isOrderDesc(o);
|
|
13
116
|
const isOrderAssociation = utils_1.isAttributeByAssociation(isOrderDescOrder
|
|
@@ -19,17 +122,71 @@ const formatOrder = ({ order = [], associationModels = [], }) => (order.length =
|
|
|
19
122
|
if (isOrderDescOrder) {
|
|
20
123
|
formattedOrder.push(DESCENDING_KEY);
|
|
21
124
|
}
|
|
22
|
-
|
|
23
|
-
})
|
|
125
|
+
formattedOrders.push(formattedOrder);
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
formattedOrders,
|
|
129
|
+
replacementsMap,
|
|
130
|
+
orderScopes: Array.from(orderScopesMap.entries()).map(([scopeName, scopeValue]) => {
|
|
131
|
+
if (!scopeValue) {
|
|
132
|
+
return scopeName;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
method: [scopeName, {
|
|
136
|
+
replacementsMap,
|
|
137
|
+
scopeValue,
|
|
138
|
+
}],
|
|
139
|
+
};
|
|
140
|
+
}),
|
|
141
|
+
};
|
|
142
|
+
};
|
|
24
143
|
const formatPage = page => page || utils_1.PAGE_DEFAULT;
|
|
25
144
|
const formatPerPage = perPage => perPage || utils_1.PER_PAGE_DEFAULT;
|
|
26
145
|
const formatInclude = (include, associationsMap = {}) => {
|
|
27
|
-
let formattedInclude = include.map(i =>
|
|
146
|
+
let formattedInclude = include.map((i) => {
|
|
147
|
+
var _a;
|
|
148
|
+
const includedAssociation = associationsMap[typeof i === 'string' ? i : (i.association || i.model)];
|
|
149
|
+
return Object.assign(Object.assign(Object.assign({}, i), { association: includedAssociation, required: i.required !== false }), (i.include && {
|
|
150
|
+
include: formatInclude(i.include, (_a = includedAssociation === null || includedAssociation === void 0 ? void 0 : includedAssociation.target) === null || _a === void 0 ? void 0 : _a.associations),
|
|
151
|
+
}));
|
|
152
|
+
});
|
|
28
153
|
formattedInclude = formattedInclude.map(i => lodash_1.default.omit(i, ['model']));
|
|
29
154
|
return formattedInclude;
|
|
30
155
|
};
|
|
31
|
-
const formatQuery = (query, associationModels
|
|
32
|
-
|
|
156
|
+
const formatQuery = (query, associationModels, replacementsMap) => {
|
|
157
|
+
const formattedQuery = {};
|
|
158
|
+
const formattedScopeMap = new Map();
|
|
159
|
+
Object.entries(query).forEach(([queryItemKey, queryItemValue]) => {
|
|
160
|
+
if (queryItemKey.startsWith(CUSTOM_FIELDS_QUERY_PREFIX)) {
|
|
161
|
+
if (!formattedScopeMap.has(CUSTOM_FIELDS_FILTER_SCOPE)) {
|
|
162
|
+
formattedScopeMap.set(CUSTOM_FIELDS_FILTER_SCOPE, {});
|
|
163
|
+
}
|
|
164
|
+
const scopeKey = queryItemKey.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
165
|
+
formattedScopeMap.get(CUSTOM_FIELDS_FILTER_SCOPE)[scopeKey] =
|
|
166
|
+
parseCustomFieldScopeQueryValue(queryItemValue);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const key = utils_1.isAttributeByAssociation(queryItemKey, associationModels)
|
|
170
|
+
? utils_1.wrapAttributeWithOperator(queryItemKey)
|
|
171
|
+
: queryItemKey;
|
|
172
|
+
formattedQuery[key] = queryItemValue;
|
|
173
|
+
});
|
|
174
|
+
const formattedScopes = Array.from(formattedScopeMap.entries()).map(([scopeName, scopeValue]) => {
|
|
175
|
+
if (!scopeValue) {
|
|
176
|
+
return scopeName;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
method: [scopeName, {
|
|
180
|
+
replacementsMap,
|
|
181
|
+
scopeValue,
|
|
182
|
+
}],
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
formattedQuery,
|
|
187
|
+
formattedScopes,
|
|
188
|
+
};
|
|
189
|
+
};
|
|
33
190
|
const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
34
191
|
$and: searchTerm.split(' ').map(term => ({
|
|
35
192
|
$or: attributesToSend.filter(attrKey => rawAttributes[attrKey].type.key === 'STRING').map(attr => ({
|
|
@@ -39,17 +196,24 @@ const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
|
39
196
|
})),
|
|
40
197
|
})),
|
|
41
198
|
});
|
|
42
|
-
const formatPayload = ({ order, page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model) => {
|
|
199
|
+
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model, options) => {
|
|
200
|
+
const replacementsMap = createReplacementMap(order, query);
|
|
43
201
|
const associationModels = Object.keys((model === null || model === void 0 ? void 0 : model.associations) || {});
|
|
44
|
-
const
|
|
45
|
-
order,
|
|
202
|
+
const { formattedOrders, orderScopes } = formatOrder({
|
|
203
|
+
order: [...order, DEFAULT_ORDER],
|
|
46
204
|
associationModels,
|
|
205
|
+
replacementsMap,
|
|
47
206
|
});
|
|
207
|
+
const [filteredFormattedOrder, filteredLiteralAttributes] = getAttributeFromOrder(formattedOrders, options);
|
|
208
|
+
const allAttributes = [...filteredLiteralAttributes, ...(attributes || [])];
|
|
209
|
+
const formattedAttribute = (attributes === null || attributes === void 0 ? void 0 : attributes.length) ? allAttributes : { include: allAttributes };
|
|
48
210
|
const formattedInclude = formatInclude(include, model === null || model === void 0 ? void 0 : model.associations);
|
|
49
211
|
const formattedPage = formatPage(page);
|
|
50
212
|
const formattedPerPage = formatPerPage(perPage);
|
|
51
|
-
|
|
52
|
-
|
|
213
|
+
const result = formatQuery(query, associationModels, replacementsMap);
|
|
214
|
+
const queryScopes = result.formattedScopes;
|
|
215
|
+
let { formattedQuery } = result;
|
|
216
|
+
if (searchTerm && !(options === null || options === void 0 ? void 0 : options.skipSearchTermFormat)) {
|
|
53
217
|
const attributesToSend = (attributes === null || attributes === void 0 ? void 0 : attributes.length) ? attributes : Object.keys(model.rawAttributes);
|
|
54
218
|
const queryWithSearchTerm = formatSearchTerm(searchTerm, attributesToSend, model.rawAttributes);
|
|
55
219
|
formattedQuery = lodash_1.default.isEmpty(formattedQuery) ? queryWithSearchTerm : {
|
|
@@ -59,12 +223,6 @@ const formatPayload = ({ order, page = utils_1.PAGE_DEFAULT, perPage = utils_1.P
|
|
|
59
223
|
],
|
|
60
224
|
};
|
|
61
225
|
}
|
|
62
|
-
return {
|
|
63
|
-
query: formattedQuery,
|
|
64
|
-
order: formattedOrder,
|
|
65
|
-
page: formattedPage,
|
|
66
|
-
perPage: formattedPerPage,
|
|
67
|
-
include: formattedInclude,
|
|
68
|
-
};
|
|
226
|
+
return Object.assign({ query: formattedQuery, order: filteredFormattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: [...queryScopes, ...orderScopes] }, (formattedAttribute && { attributes: formattedAttribute }));
|
|
69
227
|
};
|
|
70
228
|
exports.default = formatPayload;
|
|
@@ -135,13 +135,13 @@ describe('formatting test', () => {
|
|
|
135
135
|
const { order } = _1.default({
|
|
136
136
|
order: ['startTime', '-endTime'],
|
|
137
137
|
});
|
|
138
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime', 'DESC']]));
|
|
138
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime', 'DESC'], ['id']]));
|
|
139
139
|
});
|
|
140
140
|
it('simple check asc', () => {
|
|
141
141
|
const { order } = _1.default({
|
|
142
142
|
order: ['startTime', 'endTime'],
|
|
143
143
|
});
|
|
144
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime']]));
|
|
144
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['startTime'], ['endTime'], ['id']]));
|
|
145
145
|
});
|
|
146
146
|
it('by included model', () => {
|
|
147
147
|
const { order } = _1.default({
|
|
@@ -154,7 +154,7 @@ describe('formatting test', () => {
|
|
|
154
154
|
status: {},
|
|
155
155
|
},
|
|
156
156
|
});
|
|
157
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name']]));
|
|
157
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name'], ['id']]));
|
|
158
158
|
});
|
|
159
159
|
it('by included model descending', () => {
|
|
160
160
|
const { order } = _1.default({
|
|
@@ -167,7 +167,7 @@ describe('formatting test', () => {
|
|
|
167
167
|
status: {},
|
|
168
168
|
},
|
|
169
169
|
});
|
|
170
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name', 'DESC']]));
|
|
170
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['status', 'name', 'DESC'], ['id']]));
|
|
171
171
|
});
|
|
172
172
|
it('by json field', () => {
|
|
173
173
|
const { order } = _1.default({
|
|
@@ -177,7 +177,7 @@ describe('formatting test', () => {
|
|
|
177
177
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', json: '',
|
|
178
178
|
},
|
|
179
179
|
});
|
|
180
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name']]));
|
|
180
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name'], ['id']]));
|
|
181
181
|
});
|
|
182
182
|
it('by json field descending', () => {
|
|
183
183
|
const { order } = _1.default({
|
|
@@ -187,7 +187,81 @@ describe('formatting test', () => {
|
|
|
187
187
|
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', json: '',
|
|
188
188
|
},
|
|
189
189
|
});
|
|
190
|
-
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name', 'DESC']]));
|
|
190
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([['status.name', 'DESC'], ['id']]));
|
|
191
|
+
});
|
|
192
|
+
it('by literal field ascending', () => {
|
|
193
|
+
const literalAttribute = { attribute: 'genericField', literal: [{ 0: e => `${e}0` }] };
|
|
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([[`${literalAttribute.attribute} ASC`], ['id']]));
|
|
204
|
+
expect(JSON.stringify(attributes))
|
|
205
|
+
.toBe(JSON.stringify({ include: [literalAttribute.literal] }));
|
|
206
|
+
});
|
|
207
|
+
it('by literal field descending', () => {
|
|
208
|
+
const literalAttribute = { attribute: 'genericField', literal: ['void', 'field'] };
|
|
209
|
+
const { order, attributes } = _1.default({
|
|
210
|
+
order: [`-${literalAttribute.attribute}`, 'currencySymbol'],
|
|
211
|
+
attributes: ['endTime'],
|
|
212
|
+
}, {
|
|
213
|
+
rawAttributes: {
|
|
214
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
215
|
+
},
|
|
216
|
+
}, {
|
|
217
|
+
literalAttributes: [literalAttribute],
|
|
218
|
+
});
|
|
219
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([[`${literalAttribute.attribute} DESC`], ['currencySymbol'], ['id']]));
|
|
220
|
+
expect(JSON.stringify(attributes))
|
|
221
|
+
.toBe(JSON.stringify([[literalAttribute.literal[0], literalAttribute.literal[1]], 'endTime']));
|
|
222
|
+
});
|
|
223
|
+
it('by literal field - not found', () => {
|
|
224
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
225
|
+
const { order, attributes } = _1.default({
|
|
226
|
+
order: [`-O${literalAttribute.attribute}`],
|
|
227
|
+
}, {
|
|
228
|
+
rawAttributes: {
|
|
229
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '',
|
|
230
|
+
},
|
|
231
|
+
}, {
|
|
232
|
+
literalAttributes: [literalAttribute],
|
|
233
|
+
});
|
|
234
|
+
expect(JSON.stringify(order)).toBe(JSON.stringify([[`O${literalAttribute.attribute}`, 'DESC'], ['id']]));
|
|
235
|
+
expect(JSON.stringify(attributes)).toBe(JSON.stringify({ include: [] }));
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('include formatting', () => {
|
|
239
|
+
it('include required should be true', () => {
|
|
240
|
+
const { include } = _1.default({
|
|
241
|
+
order: [],
|
|
242
|
+
include: [{
|
|
243
|
+
model: 'status',
|
|
244
|
+
}],
|
|
245
|
+
}, {
|
|
246
|
+
associations: {
|
|
247
|
+
status: {},
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
expect(include[0].required).toBe(true);
|
|
251
|
+
});
|
|
252
|
+
it('include required should be false', () => {
|
|
253
|
+
const { include } = _1.default({
|
|
254
|
+
order: [],
|
|
255
|
+
include: [{
|
|
256
|
+
model: 'status',
|
|
257
|
+
required: false,
|
|
258
|
+
}],
|
|
259
|
+
}, {
|
|
260
|
+
associations: {
|
|
261
|
+
status: {},
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
expect(include[0].required).toBe(false);
|
|
191
265
|
});
|
|
192
266
|
});
|
|
193
267
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { formatOperators } from './operators';
|
|
2
|
-
import { queryFormatMiddleware, queryValidationMiddleware } from './middleware';
|
|
3
|
-
export { formatOperators, queryFormatMiddleware, queryValidationMiddleware, };
|
|
2
|
+
import { queryFormatMiddleware, queryValidationMiddleware, MiddlewareValidationOption, LiteralAttribute } from './middleware';
|
|
3
|
+
export { formatOperators, queryFormatMiddleware, queryValidationMiddleware, MiddlewareValidationOption, LiteralAttribute, };
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare
|
|
1
|
+
import { FormatPayloadOptions } from '../formatter';
|
|
2
|
+
declare type literal = any;
|
|
3
|
+
declare type LiteralQuery = (literal | string)[] | literal;
|
|
4
|
+
export declare type LiteralAttribute = {
|
|
5
|
+
attribute: string;
|
|
6
|
+
literal: LiteralQuery;
|
|
7
|
+
};
|
|
8
|
+
export declare type MiddlewareValidationOption = {
|
|
9
|
+
literalAttributes?: LiteralAttribute[];
|
|
10
|
+
enrichmentAttributes?: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const newQueryValidationMiddleware: (inner?: string) => (model: any, options?: MiddlewareValidationOption) => (req: any, res: any, next: any) => Promise<void>;
|
|
13
|
+
export declare const newQueryFormatMiddleware: (inner?: string) => (model: any, options?: FormatPayloadOptions) => (req: any, res: any, next: any) => Promise<void>;
|
|
14
|
+
export declare const queryValidationMiddleware: (model: any, options?: MiddlewareValidationOption) => (req: any, res: any, next: any) => Promise<void>;
|
|
15
|
+
export declare const queryFormatMiddleware: (model: any, options?: FormatPayloadOptions) => (req: any, res: any, next: any) => Promise<void>;
|
|
16
|
+
export {};
|
package/lib/middleware/index.js
CHANGED
|
@@ -14,11 +14,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.queryFormatMiddleware = exports.queryValidationMiddleware = exports.newQueryFormatMiddleware = exports.newQueryValidationMiddleware = void 0;
|
|
16
16
|
const errors_1 = require("@autofleet/errors");
|
|
17
|
+
const joi_1 = require("joi");
|
|
17
18
|
const formatter_1 = __importDefault(require("../formatter"));
|
|
18
19
|
const validations_1 = require("../validations");
|
|
19
|
-
|
|
20
|
+
const querySchema = joi_1.object({
|
|
21
|
+
query: joi_1.object(),
|
|
22
|
+
attributes: joi_1.array().items(joi_1.string()),
|
|
23
|
+
order: joi_1.array().items(joi_1.string()),
|
|
24
|
+
page: joi_1.number(),
|
|
25
|
+
perPage: joi_1.number(),
|
|
26
|
+
include: joi_1.array().items(joi_1.any()),
|
|
27
|
+
searchTerm: joi_1.string(),
|
|
28
|
+
enrichmentAttributes: joi_1.array().items(joi_1.string()),
|
|
29
|
+
});
|
|
30
|
+
exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {}) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
31
|
const { query, attributes, order, page, perPage, include, } = req[inner];
|
|
21
32
|
try {
|
|
33
|
+
const result = querySchema.validate(req[inner]);
|
|
34
|
+
if (result.error) {
|
|
35
|
+
throw new errors_1.BadRequest([result.error], null);
|
|
36
|
+
}
|
|
22
37
|
validations_1.validatePayload({
|
|
23
38
|
query,
|
|
24
39
|
attributes,
|
|
@@ -26,7 +41,7 @@ exports.newQueryValidationMiddleware = (inner = 'body') => model => (req, res, n
|
|
|
26
41
|
page,
|
|
27
42
|
perPage,
|
|
28
43
|
include,
|
|
29
|
-
}, model);
|
|
44
|
+
}, model, options);
|
|
30
45
|
return next();
|
|
31
46
|
}
|
|
32
47
|
catch (error) {
|
|
@@ -41,9 +56,9 @@ exports.newQueryValidationMiddleware = (inner = 'body') => model => (req, res, n
|
|
|
41
56
|
});
|
|
42
57
|
}
|
|
43
58
|
});
|
|
44
|
-
exports.newQueryFormatMiddleware = (inner = 'body') => model => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
+
exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
60
|
const { order, page, perPage, include, query, attributes, searchTerm, } = req[inner];
|
|
46
|
-
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, } = formatter_1.default({
|
|
61
|
+
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, attributes: formattedAttribute, } = formatter_1.default({
|
|
47
62
|
query,
|
|
48
63
|
order,
|
|
49
64
|
page,
|
|
@@ -51,12 +66,25 @@ exports.newQueryFormatMiddleware = (inner = 'body') => model => (req, res, next)
|
|
|
51
66
|
include,
|
|
52
67
|
attributes,
|
|
53
68
|
searchTerm,
|
|
54
|
-
}, model);
|
|
69
|
+
}, model, options);
|
|
55
70
|
req[inner].query = formattedQuery;
|
|
56
71
|
req[inner].order = formattedOrder;
|
|
72
|
+
req[inner].attributes = formattedAttribute;
|
|
57
73
|
req[inner].page = formattedPage;
|
|
58
74
|
req[inner].perPage = formattedPerPage;
|
|
59
75
|
req[inner].include = formattedInclude;
|
|
76
|
+
req[inner].scopes = formattedScopes;
|
|
77
|
+
if (options.includeRawPayload) {
|
|
78
|
+
req[inner].rawPayload = {
|
|
79
|
+
order,
|
|
80
|
+
page,
|
|
81
|
+
perPage,
|
|
82
|
+
include,
|
|
83
|
+
query,
|
|
84
|
+
attributes,
|
|
85
|
+
searchTerm,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
60
88
|
return next();
|
|
61
89
|
});
|
|
62
90
|
exports.queryValidationMiddleware = exports.newQueryValidationMiddleware();
|
package/lib/operators/index.d.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
export declare const OPERATORS: string[];
|
|
2
2
|
export declare const OPERATOR_PREFIX = "$";
|
|
3
|
+
export declare const OPERATORS_TO_SQL: {
|
|
4
|
+
$eq: string;
|
|
5
|
+
$ne: string;
|
|
6
|
+
$gte: string;
|
|
7
|
+
$gt: string;
|
|
8
|
+
$lte: string;
|
|
9
|
+
$lt: string;
|
|
10
|
+
$not: string;
|
|
11
|
+
$in: string;
|
|
12
|
+
$notIn: string;
|
|
13
|
+
$is: string;
|
|
14
|
+
$like: string;
|
|
15
|
+
$iLike: string;
|
|
16
|
+
$notLike: string;
|
|
17
|
+
$and: string;
|
|
18
|
+
$or: string;
|
|
19
|
+
};
|
|
3
20
|
export declare const formatOperators: (Sequelize: any) => {};
|
package/lib/operators/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatOperators = exports.OPERATOR_PREFIX = exports.OPERATORS = void 0;
|
|
3
|
+
exports.formatOperators = exports.OPERATORS_TO_SQL = exports.OPERATOR_PREFIX = exports.OPERATORS = void 0;
|
|
4
4
|
exports.OPERATORS = [
|
|
5
5
|
'eq',
|
|
6
6
|
'ne',
|
|
@@ -22,6 +22,23 @@ exports.OPERATORS = [
|
|
|
22
22
|
'contains',
|
|
23
23
|
];
|
|
24
24
|
exports.OPERATOR_PREFIX = '$';
|
|
25
|
+
exports.OPERATORS_TO_SQL = {
|
|
26
|
+
$eq: '=',
|
|
27
|
+
$ne: '!=',
|
|
28
|
+
$gte: '>=',
|
|
29
|
+
$gt: '>',
|
|
30
|
+
$lte: '<=',
|
|
31
|
+
$lt: '<',
|
|
32
|
+
$not: 'NOT',
|
|
33
|
+
$in: 'IN',
|
|
34
|
+
$notIn: 'NOT IN',
|
|
35
|
+
$is: 'IS',
|
|
36
|
+
$like: 'LIKE',
|
|
37
|
+
$iLike: 'ILIKE',
|
|
38
|
+
$notLike: 'NOT LIKE',
|
|
39
|
+
$and: 'AND',
|
|
40
|
+
$or: 'OR',
|
|
41
|
+
};
|
|
25
42
|
exports.formatOperators = (Sequelize) => {
|
|
26
43
|
const { Op } = Sequelize;
|
|
27
44
|
return exports.OPERATORS.reduce((map, o) => {
|
package/lib/utils.d.ts
CHANGED
|
@@ -11,3 +11,4 @@ export declare const extractAttributeNameFromOrder: (order: any, associationMode
|
|
|
11
11
|
export declare const isOrderDesc: (order: any) => boolean;
|
|
12
12
|
export declare const throwBadRequestError: (message: string) => never;
|
|
13
13
|
export declare const extractAssociatedAttributeNameFromOrder: (order: any) => string;
|
|
14
|
+
export declare const generateRandomString: (length?: number) => string;
|
package/lib/utils.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractAssociatedAttributeNameFromOrder = exports.throwBadRequestError = exports.isOrderDesc = exports.extractAttributeNameFromOrder = exports.isAttributeByAssociation = exports.wrapAttributeWithOperator = exports.PAGE_MIN = exports.PER_PAGE_MIN_LIMIT = exports.PER_PAGE_MAX_LIMIT = exports.PAGE_DEFAULT = exports.PER_PAGE_DEFAULT = exports.ASSOCIATION_PREFIX = exports.ORDER_PREFIX = void 0;
|
|
3
|
+
exports.generateRandomString = exports.extractAssociatedAttributeNameFromOrder = exports.throwBadRequestError = exports.isOrderDesc = exports.extractAttributeNameFromOrder = exports.isAttributeByAssociation = exports.wrapAttributeWithOperator = exports.PAGE_MIN = exports.PER_PAGE_MIN_LIMIT = exports.PER_PAGE_MAX_LIMIT = exports.PAGE_DEFAULT = exports.PER_PAGE_DEFAULT = exports.ASSOCIATION_PREFIX = exports.ORDER_PREFIX = void 0;
|
|
4
4
|
const errors_1 = require("@autofleet/errors");
|
|
5
5
|
const operators_1 = require("./operators");
|
|
6
|
+
const randomInt = max => Math.floor(Math.random() * Math.floor(max));
|
|
6
7
|
exports.ORDER_PREFIX = '-';
|
|
7
8
|
exports.ASSOCIATION_PREFIX = '.';
|
|
8
9
|
exports.PER_PAGE_DEFAULT = 20;
|
|
@@ -29,3 +30,7 @@ exports.throwBadRequestError = (message) => {
|
|
|
29
30
|
throw new errors_1.BadRequest([{ message }], null);
|
|
30
31
|
};
|
|
31
32
|
exports.extractAssociatedAttributeNameFromOrder = (order) => order.split(exports.ASSOCIATION_PREFIX)[1];
|
|
33
|
+
exports.generateRandomString = (length = 5) => {
|
|
34
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
35
|
+
return Array.from({ length }, () => characters.charAt(randomInt(characters.length))).join('');
|
|
36
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { MiddlewareValidationOption } from '../middleware';
|
|
2
|
+
export declare const validatePayload: ({ query, order, attributes, include, page, perPage, enrichments, }: {
|
|
2
3
|
query?: {};
|
|
3
4
|
order?: any[];
|
|
4
5
|
attributes?: any[];
|
|
5
6
|
include?: any[];
|
|
6
7
|
page?: number;
|
|
7
8
|
perPage?: number;
|
|
8
|
-
|
|
9
|
+
enrichments?: any[];
|
|
10
|
+
}, model?: any, options?: MiddlewareValidationOption) => boolean;
|
package/lib/validations/index.js
CHANGED
|
@@ -11,7 +11,8 @@ const validateOperator = (operator) => operators_1.OPERATORS.includes(operator.s
|
|
|
11
11
|
const validateQueryAttribute = (attribute, modelAttributes = [], associationModels = []) => [...modelAttributes, ...associationModels]
|
|
12
12
|
.includes(attribute.includes(utils_1.ASSOCIATION_PREFIX)
|
|
13
13
|
? attribute.split(utils_1.ASSOCIATION_PREFIX)[0] : attribute);
|
|
14
|
-
const validateSingleOrder = (currentOrder, rawAttributes, associationModels) => {
|
|
14
|
+
const validateSingleOrder = (currentOrder, rawAttributes, associationModels, options = {}) => {
|
|
15
|
+
var _a, _b;
|
|
15
16
|
const isOrderDescOrder = utils_1.isOrderDesc(currentOrder);
|
|
16
17
|
if (isOrderDescOrder && currentOrder[0] !== utils_1.ORDER_PREFIX) {
|
|
17
18
|
utils_1.throwBadRequestError(`${utils_1.ORDER_PREFIX} must be only at the beginning of the word`);
|
|
@@ -20,11 +21,12 @@ const validateSingleOrder = (currentOrder, rawAttributes, associationModels) =>
|
|
|
20
21
|
currentOrder.split(utils_1.ORDER_PREFIX)[1] : currentOrder;
|
|
21
22
|
const isOrderAssociation = utils_1.isAttributeByAssociation(orderStringWithoutDesc, associationModels);
|
|
22
23
|
let formattedOrderString = utils_1.extractAttributeNameFromOrder(currentOrder, associationModels);
|
|
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);
|
|
23
25
|
if (!isOrderAssociation && formattedOrderString.includes(utils_1.ASSOCIATION_PREFIX)) {
|
|
24
26
|
[formattedOrderString] = formattedOrderString.split(utils_1.ASSOCIATION_PREFIX);
|
|
25
27
|
}
|
|
26
|
-
if (!(rawAttributes.includes(formattedOrderString) || isOrderAssociation)) {
|
|
27
|
-
utils_1.throwBadRequestError(`${currentOrder} is invalid`);
|
|
28
|
+
if (!(rawAttributes.includes(formattedOrderString) || isOrderAssociation || isLiteralAttribute)) {
|
|
29
|
+
utils_1.throwBadRequestError(`${currentOrder} is invalid. isLiteralAttribute: ${isLiteralAttribute}`);
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
const validateSingleAttribute = (currentAttribute, rawAttributes) => {
|
|
@@ -32,17 +34,27 @@ const validateSingleAttribute = (currentAttribute, rawAttributes) => {
|
|
|
32
34
|
utils_1.throwBadRequestError(`${currentAttribute} is invalid`);
|
|
33
35
|
}
|
|
34
36
|
};
|
|
35
|
-
const validateOrderAttributes = (order, rawAttributes, associationModels = []) => {
|
|
36
|
-
order.map(o => validateSingleOrder(o, rawAttributes, associationModels));
|
|
37
|
+
const validateOrderAttributes = (order, rawAttributes, associationModels = [], options = {}) => {
|
|
38
|
+
order.map(o => validateSingleOrder(o, rawAttributes, associationModels, options));
|
|
37
39
|
};
|
|
38
40
|
const validateAttributes = (attributes, rawAttributes) => {
|
|
39
41
|
attributes.map(a => validateSingleAttribute(a, rawAttributes));
|
|
40
42
|
};
|
|
43
|
+
const validateEnrichments = (enrichments, options) => {
|
|
44
|
+
if (!(enrichments === null || enrichments === void 0 ? void 0 : enrichments.length)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const invalidEnrichment = enrichments
|
|
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)); });
|
|
49
|
+
if (invalidEnrichment) {
|
|
50
|
+
utils_1.throwBadRequestError(`enrichment attribute ${enrichments} is invalid`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
41
53
|
const validateQueryPayload = (query, rawAttributes, associationModels = []) => {
|
|
42
54
|
// eslint-disable-next-line array-callback-return
|
|
43
55
|
Object.keys(query).map((key) => {
|
|
44
56
|
const value = query[key];
|
|
45
|
-
if (
|
|
57
|
+
if (Array.isArray(value)) {
|
|
46
58
|
if (lodash_1.default.isObject(value[0])) {
|
|
47
59
|
value.map(v => validateQueryPayload(v, rawAttributes, associationModels));
|
|
48
60
|
}
|
|
@@ -76,21 +88,22 @@ const validateIncludePayload = (include, associations) => {
|
|
|
76
88
|
utils_1.throwBadRequestError('model not found in associations');
|
|
77
89
|
}
|
|
78
90
|
const { rawAttributes } = target;
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
const attributeKeys = Object.keys(rawAttributes);
|
|
92
|
+
if (i.where) {
|
|
93
|
+
validateQueryPayload(i.where, attributeKeys);
|
|
81
94
|
}
|
|
82
|
-
if (
|
|
83
|
-
validateOrderAttributes(i.order,
|
|
95
|
+
if (i.order) {
|
|
96
|
+
validateOrderAttributes(i.order, attributeKeys);
|
|
84
97
|
}
|
|
85
|
-
if (
|
|
86
|
-
validateAttributes(i.attributes,
|
|
98
|
+
if (i.attributes) {
|
|
99
|
+
validateAttributes(i.attributes, attributeKeys);
|
|
87
100
|
}
|
|
88
|
-
if (!lodash_1.default.isNil(
|
|
101
|
+
if (!lodash_1.default.isNil(i.required) && !lodash_1.default.isBoolean(i.required)) {
|
|
89
102
|
utils_1.throwBadRequestError('include.required must be a boolean');
|
|
90
103
|
}
|
|
91
104
|
});
|
|
92
105
|
};
|
|
93
|
-
exports.validatePayload = ({ query = {}, order = [], attributes = [], include = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, }, model) => {
|
|
106
|
+
exports.validatePayload = ({ query = {}, order = [], attributes = [], include = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, enrichments = [], }, model, options = {}) => {
|
|
94
107
|
const rawAttributes = Object.keys(model.rawAttributes);
|
|
95
108
|
const associationModels = Object.keys((model === null || model === void 0 ? void 0 : model.associations) || {});
|
|
96
109
|
if (!attributes || attributes.length === 0) {
|
|
@@ -100,11 +113,15 @@ exports.validatePayload = ({ query = {}, order = [], attributes = [], include =
|
|
|
100
113
|
else {
|
|
101
114
|
validateAttributes(attributes, rawAttributes);
|
|
102
115
|
}
|
|
103
|
-
validateOrderAttributes(order, rawAttributes, associationModels);
|
|
116
|
+
validateOrderAttributes(order, rawAttributes, associationModels, options);
|
|
104
117
|
validateQueryPayload(query, rawAttributes, associationModels);
|
|
105
|
-
|
|
118
|
+
validateEnrichments(enrichments, options);
|
|
119
|
+
if (include.length && typeof include === 'object') {
|
|
106
120
|
validateIncludePayload(include, model === null || model === void 0 ? void 0 : model.associations);
|
|
107
121
|
}
|
|
122
|
+
else if (include && typeof include !== 'object') {
|
|
123
|
+
utils_1.throwBadRequestError('include must be an array');
|
|
124
|
+
}
|
|
108
125
|
validatePagination({
|
|
109
126
|
page,
|
|
110
127
|
perPage,
|
|
@@ -180,5 +180,40 @@ describe('validations test', () => {
|
|
|
180
180
|
expect(error.statusCode).toBe(400);
|
|
181
181
|
}
|
|
182
182
|
});
|
|
183
|
+
it('try order by literal field that exist', () => {
|
|
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}`] }, {
|
|
197
|
+
rawAttributes: {
|
|
198
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
199
|
+
},
|
|
200
|
+
}, {
|
|
201
|
+
literalAttributes: [literalAttribute],
|
|
202
|
+
});
|
|
203
|
+
expect(payload).toBe(true);
|
|
204
|
+
});
|
|
205
|
+
it('try order by literal field that doesnt exist', () => {
|
|
206
|
+
const literalAttribute = { attribute: 'genericField', literal: 'void' };
|
|
207
|
+
try {
|
|
208
|
+
_1.validatePayload({ order: ['here'] }, {
|
|
209
|
+
rawAttributes: {
|
|
210
|
+
startTime: '', endTime: '', currencySymbol: '', currencyCode: '', startStationId: '', status: '',
|
|
211
|
+
},
|
|
212
|
+
}, { literalAttributes: [literalAttribute] });
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
expect(error.statusCode).toBe(400);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
183
218
|
});
|
|
184
219
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sheilta",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta-test-2",
|
|
4
4
|
"description": "manage cache",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -10,7 +10,24 @@
|
|
|
10
10
|
"coverage": "jest --coverage --forceExit --runInBand",
|
|
11
11
|
"test": "jest --forceExit --runInBand",
|
|
12
12
|
"test-auto": "jest --watch --runInBand",
|
|
13
|
-
"linter": "./node_modules/.bin/eslint src/**/*.ts"
|
|
13
|
+
"linter": "./node_modules/.bin/eslint src/**/*.ts",
|
|
14
|
+
"build-to-local-repo": "npm run build && cp -r lib/* ../$REPO/node_modules/$npm_package_name/lib",
|
|
15
|
+
"watch": "npm-watch build-to-local-repo"
|
|
16
|
+
},
|
|
17
|
+
"watch": {
|
|
18
|
+
"build-to-local-repo": {
|
|
19
|
+
"extensions": [
|
|
20
|
+
"js",
|
|
21
|
+
"jsx",
|
|
22
|
+
"ts",
|
|
23
|
+
"tsx",
|
|
24
|
+
"css"
|
|
25
|
+
],
|
|
26
|
+
"patterns": [
|
|
27
|
+
"src"
|
|
28
|
+
],
|
|
29
|
+
"quiet": false
|
|
30
|
+
}
|
|
14
31
|
},
|
|
15
32
|
"jest": {
|
|
16
33
|
"setupTestFrameworkScriptFile": "jest-extended",
|
|
@@ -27,21 +44,24 @@
|
|
|
27
44
|
},
|
|
28
45
|
"homepage": "https://github.com/Autofleet/sheilta",
|
|
29
46
|
"dependencies": {
|
|
47
|
+
"@autofleet/common-types": "^1.7.42",
|
|
30
48
|
"@autofleet/errors": "^1.0.10",
|
|
31
|
-
"
|
|
49
|
+
"joi": "^17.9.2",
|
|
32
50
|
"lodash": "^4.17.21"
|
|
33
51
|
},
|
|
34
52
|
"devDependencies": {
|
|
35
|
-
"
|
|
53
|
+
"@types/jest": "^24.9.0",
|
|
54
|
+
"@types/node": "^16.11.68",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
|
56
|
+
"@typescript-eslint/parser": "^2.23.0",
|
|
36
57
|
"eslint": "^6.8.0",
|
|
37
58
|
"eslint-config-airbnb": "^16.1.0",
|
|
38
59
|
"eslint-plugin-import": "^2.20.1",
|
|
39
|
-
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
|
40
|
-
"@typescript-eslint/parser": "^2.23.0",
|
|
41
|
-
"typescript-eslint": "0.0.1-alpha.0",
|
|
42
|
-
"ts-jest": "^25.0.0",
|
|
43
60
|
"jest": "^25.1.0",
|
|
44
|
-
"
|
|
61
|
+
"ts-jest": "^25.0.0",
|
|
62
|
+
"typescript": "^3.9.5",
|
|
63
|
+
"typescript-eslint": "0.0.1-alpha.0",
|
|
64
|
+
"npm-watch": "^0.13.0"
|
|
45
65
|
},
|
|
46
66
|
"files": [
|
|
47
67
|
"lib/**/*"
|