@autofleet/sheilta 1.3.8 → 1.3.10-beta-34f81272.0
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 +3 -4
- package/lib/formatter/index.js +46 -21
- package/lib/middleware/index.js +4 -1
- package/lib/validations/index.js +18 -6
- package/package.json +5 -3
package/lib/formatter/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare type FormatPayloadOptions = {
|
|
|
7
7
|
DBFormatter?: any;
|
|
8
8
|
skipSearchTermFormat?: boolean;
|
|
9
9
|
};
|
|
10
|
-
declare const formatPayload: ({ order, page, perPage, include, query, attributes, searchTerm, }: {
|
|
10
|
+
declare const formatPayload: ({ order, page, perPage, include, query, attributes, searchTerm, allowedSearchableAttributes, }: {
|
|
11
11
|
order?: any[];
|
|
12
12
|
page?: number;
|
|
13
13
|
perPage?: number;
|
|
@@ -15,6 +15,7 @@ declare const formatPayload: ({ order, page, perPage, include, query, attributes
|
|
|
15
15
|
query?: {};
|
|
16
16
|
attributes?: any;
|
|
17
17
|
searchTerm?: any;
|
|
18
|
+
allowedSearchableAttributes?: any;
|
|
18
19
|
}, model?: any, options?: any) => {
|
|
19
20
|
attributes: any[] | {
|
|
20
21
|
include: any[];
|
|
@@ -24,8 +25,6 @@ declare const formatPayload: ({ order, page, perPage, include, query, attributes
|
|
|
24
25
|
page: any;
|
|
25
26
|
perPage: any;
|
|
26
27
|
include: any;
|
|
27
|
-
scopes:
|
|
28
|
-
method: any[];
|
|
29
|
-
})[];
|
|
28
|
+
scopes: any[];
|
|
30
29
|
};
|
|
31
30
|
export default formatPayload;
|
package/lib/formatter/index.js
CHANGED
|
@@ -9,8 +9,9 @@ const utils_1 = require("../utils");
|
|
|
9
9
|
const operators_1 = require("../operators");
|
|
10
10
|
const DEFAULT_ORDER = 'id';
|
|
11
11
|
const DESCENDING_KEY = 'DESC';
|
|
12
|
+
const ASCENDING_KEY = 'ASC';
|
|
12
13
|
const CUSTOM_FIELDS_QUERY_PREFIX = 'customFields.';
|
|
13
|
-
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
14
|
+
const { CUSTOM_FIELDS_FILTER_SCOPE, CUSTOM_FIELDS_SORT_SCOPE } = common_types_1.customFields;
|
|
14
15
|
const parseCustomFieldScopeQueryValue = (value) => {
|
|
15
16
|
if (typeof value === 'string') {
|
|
16
17
|
return value;
|
|
@@ -36,20 +37,43 @@ const getAttributeFromOrder = (order, options = {}) => {
|
|
|
36
37
|
}, [[], []]);
|
|
37
38
|
return [formattedOrder, attributes];
|
|
38
39
|
};
|
|
39
|
-
const formatOrder = ({ order, associationModels = [], }) =>
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
40
|
+
const formatOrder = ({ order, associationModels = [], }) => {
|
|
41
|
+
const formattedOrders = [];
|
|
42
|
+
const orderScopesMap = new Map();
|
|
43
|
+
order.forEach((o) => {
|
|
44
|
+
if ([o, o.substring(1)].some(t => t.startsWith(CUSTOM_FIELDS_QUERY_PREFIX))) {
|
|
45
|
+
if (!orderScopesMap.has(CUSTOM_FIELDS_SORT_SCOPE)) {
|
|
46
|
+
orderScopesMap.set(CUSTOM_FIELDS_SORT_SCOPE, {});
|
|
47
|
+
}
|
|
48
|
+
const scopeKey = o.split(CUSTOM_FIELDS_QUERY_PREFIX)[1];
|
|
49
|
+
orderScopesMap.get(CUSTOM_FIELDS_SORT_SCOPE)[scopeKey] = (utils_1.isOrderDesc(o) ?
|
|
50
|
+
DESCENDING_KEY :
|
|
51
|
+
ASCENDING_KEY);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const formattedOrder = [utils_1.extractAttributeNameFromOrder(o, associationModels)];
|
|
55
|
+
const isOrderDescOrder = utils_1.isOrderDesc(o);
|
|
56
|
+
const isOrderAssociation = utils_1.isAttributeByAssociation(isOrderDescOrder
|
|
57
|
+
? o.split(utils_1.ORDER_PREFIX)[1]
|
|
58
|
+
: o, associationModels);
|
|
59
|
+
if (isOrderAssociation) {
|
|
60
|
+
formattedOrder.push(utils_1.extractAssociatedAttributeNameFromOrder(o));
|
|
61
|
+
}
|
|
62
|
+
if (isOrderDescOrder) {
|
|
63
|
+
formattedOrder.push(DESCENDING_KEY);
|
|
64
|
+
}
|
|
65
|
+
formattedOrders.push(formattedOrder);
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
formattedOrders,
|
|
69
|
+
orderScopes: Array.from(orderScopesMap.entries()).map(([scopeName, scopeValue]) => {
|
|
70
|
+
if (!scopeValue) {
|
|
71
|
+
return scopeName;
|
|
72
|
+
}
|
|
73
|
+
return { method: [scopeName, scopeValue] };
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
53
77
|
const formatPage = page => page || utils_1.PAGE_DEFAULT;
|
|
54
78
|
const formatPerPage = perPage => perPage || utils_1.PER_PAGE_DEFAULT;
|
|
55
79
|
const formatInclude = (include, associationsMap = {}) => {
|
|
@@ -94,29 +118,30 @@ const formatQuery = (query, associationModels) => {
|
|
|
94
118
|
};
|
|
95
119
|
const formatSearchTerm = (searchTerm, attributesToSend, rawAttributes) => ({
|
|
96
120
|
$and: searchTerm.split(' ').map(term => ({
|
|
97
|
-
$or: attributesToSend.filter(attrKey => rawAttributes[attrKey].type.key === 'STRING').map(attr => ({
|
|
121
|
+
$or: attributesToSend.filter(attrKey => { var _a; return ((_a = rawAttributes[attrKey]) === null || _a === void 0 ? void 0 : _a.type.key) === 'STRING'; }).map(attr => ({
|
|
98
122
|
[attr]: {
|
|
99
123
|
$iLike: `%${term}%`,
|
|
100
124
|
},
|
|
101
125
|
})),
|
|
102
126
|
})),
|
|
103
127
|
});
|
|
104
|
-
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, }, model, options) => {
|
|
128
|
+
const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = utils_1.PER_PAGE_DEFAULT, include = [], query = {}, attributes = null, searchTerm = null, allowedSearchableAttributes = null, }, model, options) => {
|
|
105
129
|
const associationModels = Object.keys((model === null || model === void 0 ? void 0 : model.associations) || {});
|
|
106
|
-
const
|
|
130
|
+
const { formattedOrders, orderScopes } = formatOrder({
|
|
107
131
|
order: [...order, DEFAULT_ORDER],
|
|
108
132
|
associationModels,
|
|
109
133
|
});
|
|
110
|
-
const [filteredFormattedOrder, filteredLiteralAttributes] = getAttributeFromOrder(
|
|
134
|
+
const [filteredFormattedOrder, filteredLiteralAttributes] = getAttributeFromOrder(formattedOrders, options);
|
|
111
135
|
const allAttributes = [...filteredLiteralAttributes, ...(attributes || [])];
|
|
112
136
|
const formattedAttribute = (attributes === null || attributes === void 0 ? void 0 : attributes.length) ? allAttributes : { include: allAttributes };
|
|
113
137
|
const formattedInclude = formatInclude(include, model === null || model === void 0 ? void 0 : model.associations);
|
|
114
138
|
const formattedPage = formatPage(page);
|
|
115
139
|
const formattedPerPage = formatPerPage(perPage);
|
|
116
140
|
const result = formatQuery(query, associationModels);
|
|
141
|
+
const queryScopes = result.formattedScopes;
|
|
117
142
|
let { formattedQuery } = result;
|
|
118
143
|
if (searchTerm && !(options === null || options === void 0 ? void 0 : options.skipSearchTermFormat)) {
|
|
119
|
-
const attributesToSend = (attributes === null || attributes === void 0 ? void 0 : attributes.length) ? attributes : Object.keys(model.rawAttributes);
|
|
144
|
+
const attributesToSend = allowedSearchableAttributes || ((attributes === null || attributes === void 0 ? void 0 : attributes.length) ? attributes : Object.keys(model.rawAttributes));
|
|
120
145
|
const queryWithSearchTerm = formatSearchTerm(searchTerm, attributesToSend, model.rawAttributes);
|
|
121
146
|
formattedQuery = lodash_1.default.isEmpty(formattedQuery) ? queryWithSearchTerm : {
|
|
122
147
|
$and: [
|
|
@@ -125,6 +150,6 @@ const formatPayload = ({ order = [], page = utils_1.PAGE_DEFAULT, perPage = util
|
|
|
125
150
|
],
|
|
126
151
|
};
|
|
127
152
|
}
|
|
128
|
-
return Object.assign({ query: formattedQuery, order: filteredFormattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes:
|
|
153
|
+
return Object.assign({ query: formattedQuery, order: filteredFormattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: [...queryScopes, ...orderScopes] }, (formattedAttribute && { attributes: formattedAttribute }));
|
|
129
154
|
};
|
|
130
155
|
exports.default = formatPayload;
|
package/lib/middleware/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const querySchema = joi_1.object({
|
|
|
25
25
|
perPage: joi_1.number(),
|
|
26
26
|
include: joi_1.array().items(joi_1.any()),
|
|
27
27
|
searchTerm: joi_1.string(),
|
|
28
|
+
allowedSearchableAttributes: joi_1.array().items(joi_1.string()),
|
|
28
29
|
});
|
|
29
30
|
exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {}) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
31
|
const { query, attributes, order, page, perPage, include, } = req[inner];
|
|
@@ -56,7 +57,7 @@ exports.newQueryValidationMiddleware = (inner = 'body') => (model, options = {})
|
|
|
56
57
|
}
|
|
57
58
|
});
|
|
58
59
|
exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
-
const { order, page, perPage, include, query, attributes, searchTerm, } = req[inner];
|
|
60
|
+
const { order, page, perPage, include, query, attributes, searchTerm, allowedSearchableAttributes, } = req[inner];
|
|
60
61
|
const { query: formattedQuery, order: formattedOrder, page: formattedPage, perPage: formattedPerPage, include: formattedInclude, scopes: formattedScopes, attributes: formattedAttribute, } = formatter_1.default({
|
|
61
62
|
query,
|
|
62
63
|
order,
|
|
@@ -65,6 +66,7 @@ exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) =>
|
|
|
65
66
|
include,
|
|
66
67
|
attributes,
|
|
67
68
|
searchTerm,
|
|
69
|
+
allowedSearchableAttributes,
|
|
68
70
|
}, model, options);
|
|
69
71
|
req[inner].query = formattedQuery;
|
|
70
72
|
req[inner].order = formattedOrder;
|
|
@@ -73,6 +75,7 @@ exports.newQueryFormatMiddleware = (inner = 'body') => (model, options = {}) =>
|
|
|
73
75
|
req[inner].perPage = formattedPerPage;
|
|
74
76
|
req[inner].include = formattedInclude;
|
|
75
77
|
req[inner].scopes = formattedScopes;
|
|
78
|
+
req[inner].allowedSearchableAttributes = new Set(allowedSearchableAttributes);
|
|
76
79
|
if (options.includeRawPayload) {
|
|
77
80
|
req[inner].rawPayload = {
|
|
78
81
|
order,
|
package/lib/validations/index.js
CHANGED
|
@@ -7,10 +7,23 @@ exports.validatePayload = void 0;
|
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
8
|
const utils_1 = require("../utils");
|
|
9
9
|
const operators_1 = require("../operators");
|
|
10
|
+
const cleanAttributeFromPrefix = (attr, prefix) => {
|
|
11
|
+
if (attr.startsWith(prefix)) {
|
|
12
|
+
return attr.slice(1);
|
|
13
|
+
}
|
|
14
|
+
return attr.endsWith(prefix) ? attr.slice(0, -1) : attr;
|
|
15
|
+
};
|
|
10
16
|
const validateOperator = (operator) => operators_1.OPERATORS.includes(operator.split(operators_1.OPERATOR_PREFIX)[1]);
|
|
11
|
-
const validateQueryAttribute = (attribute, modelAttributes = [], associationModels = []) =>
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
const validateQueryAttribute = (attribute, modelAttributes = [], associationModels = []) => {
|
|
18
|
+
const attributes = [...modelAttributes, ...associationModels];
|
|
19
|
+
if (attribute.includes(utils_1.ASSOCIATION_PREFIX) && attribute.includes(operators_1.OPERATOR_PREFIX)) {
|
|
20
|
+
const parts = attribute.split(utils_1.ASSOCIATION_PREFIX);
|
|
21
|
+
return parts.every(part => attributes.includes(cleanAttributeFromPrefix(part, operators_1.OPERATOR_PREFIX)));
|
|
22
|
+
}
|
|
23
|
+
return attributes
|
|
24
|
+
.includes(attribute.includes(utils_1.ASSOCIATION_PREFIX)
|
|
25
|
+
? attribute.split(utils_1.ASSOCIATION_PREFIX)[0] : attribute);
|
|
26
|
+
};
|
|
14
27
|
const validateSingleOrder = (currentOrder, rawAttributes, associationModels, options = {}) => {
|
|
15
28
|
var _a, _b;
|
|
16
29
|
const isOrderDescOrder = utils_1.isOrderDesc(currentOrder);
|
|
@@ -42,9 +55,8 @@ const validateAttributes = (attributes, rawAttributes) => {
|
|
|
42
55
|
};
|
|
43
56
|
const validateQueryPayload = (query, rawAttributes, associationModels = []) => {
|
|
44
57
|
// eslint-disable-next-line array-callback-return
|
|
45
|
-
Object.
|
|
46
|
-
|
|
47
|
-
if (lodash_1.default.isArray(value)) {
|
|
58
|
+
Object.entries(query).map(([key, value]) => {
|
|
59
|
+
if (Array.isArray(value)) {
|
|
48
60
|
if (lodash_1.default.isObject(value[0])) {
|
|
49
61
|
value.map(v => validateQueryPayload(v, rawAttributes, associationModels));
|
|
50
62
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sheilta",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.10-beta-34f81272.0",
|
|
4
4
|
"description": "manage cache",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -44,10 +44,12 @@
|
|
|
44
44
|
},
|
|
45
45
|
"homepage": "https://github.com/Autofleet/sheilta",
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@autofleet/common-types": "^1.7.
|
|
47
|
+
"@autofleet/common-types": "^1.7.42",
|
|
48
48
|
"@autofleet/errors": "^1.0.10",
|
|
49
|
+
"@autofleet/sadot": "^0.6.6",
|
|
49
50
|
"joi": "^17.9.2",
|
|
50
|
-
"lodash": "^4.17.21"
|
|
51
|
+
"lodash": "^4.17.21",
|
|
52
|
+
"npm-watch": "^0.13.0"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
55
|
"@types/jest": "^24.9.0",
|