@strapi/utils 4.0.7 → 4.0.8
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/content-types.js +12 -3
- package/lib/convert-query-params.js +85 -2
- package/lib/parse-type.js +5 -1
- package/package.json +2 -2
package/lib/content-types.js
CHANGED
|
@@ -104,13 +104,21 @@ const isPrivateAttribute = (model = {}, attributeName) => {
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
const isScalarAttribute = attribute => {
|
|
107
|
-
return !['component', 'relation', 'dynamiczone'].includes(attribute.type);
|
|
107
|
+
return !['media', 'component', 'relation', 'dynamiczone'].includes(attribute.type);
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
-
const
|
|
111
|
-
return
|
|
110
|
+
const getScalarAttributes = schema => {
|
|
111
|
+
return _.reduce(
|
|
112
|
+
schema.attributes,
|
|
113
|
+
(acc, attr, attrName) => {
|
|
114
|
+
if (isScalarAttribute(attr)) acc.push(attrName);
|
|
115
|
+
return acc;
|
|
116
|
+
},
|
|
117
|
+
[]
|
|
118
|
+
);
|
|
112
119
|
};
|
|
113
120
|
|
|
121
|
+
const isMediaAttribute = attribute => attribute.type === 'media';
|
|
114
122
|
const isRelationalAttribute = attribute => attribute.type === 'relation';
|
|
115
123
|
const isComponentAttribute = attribute => ['component', 'dynamiczone'].includes(attribute.type);
|
|
116
124
|
|
|
@@ -144,6 +152,7 @@ module.exports = {
|
|
|
144
152
|
isPrivateAttribute,
|
|
145
153
|
constants,
|
|
146
154
|
getNonWritableAttributes,
|
|
155
|
+
getScalarAttributes,
|
|
147
156
|
getWritableAttributes,
|
|
148
157
|
isWritableAttribute,
|
|
149
158
|
getNonVisibleAttributes,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Converts the standard Strapi REST query params to a more usable format for querying
|
|
5
5
|
* You can read more here: https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#filters
|
|
6
6
|
*/
|
|
7
|
-
const { has } = require('lodash/fp');
|
|
7
|
+
const { has, isEmpty, isObject, cloneDeep, get } = require('lodash/fp');
|
|
8
8
|
const _ = require('lodash');
|
|
9
9
|
const parseType = require('./parse-type');
|
|
10
10
|
const contentTypesUtils = require('./content-types');
|
|
@@ -218,7 +218,90 @@ const convertFieldsQueryParams = (fields, depth = 0) => {
|
|
|
218
218
|
throw new Error('Invalid fields parameter. Expected a string or an array of strings');
|
|
219
219
|
};
|
|
220
220
|
|
|
221
|
-
const convertFiltersQueryParams = filters =>
|
|
221
|
+
const convertFiltersQueryParams = (filters, schema) => {
|
|
222
|
+
// Filters need to be either an array or an object
|
|
223
|
+
// Here we're only checking for 'object' type since typeof [] => object and typeof {} => object
|
|
224
|
+
if (!isObject(filters)) {
|
|
225
|
+
throw new Error('The filters parameter must be an object or an array');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Don't mutate the original object
|
|
229
|
+
const filtersCopy = cloneDeep(filters);
|
|
230
|
+
|
|
231
|
+
return convertAndSanitizeFilters(filtersCopy, schema);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const convertAndSanitizeFilters = (filters, schema) => {
|
|
235
|
+
if (!isObject(filters)) {
|
|
236
|
+
return filters;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (Array.isArray(filters)) {
|
|
240
|
+
return (
|
|
241
|
+
filters
|
|
242
|
+
// Sanitize each filter
|
|
243
|
+
.map(filter => convertAndSanitizeFilters(filter, schema))
|
|
244
|
+
// Filter out empty filters
|
|
245
|
+
.filter(filter => !isObject(filter) || !isEmpty(filter))
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const removeOperator = operator => delete filters[operator];
|
|
250
|
+
|
|
251
|
+
// Here, `key` can either be an operator or an attribute name
|
|
252
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
253
|
+
const attribute = get('key', schema.attributes);
|
|
254
|
+
|
|
255
|
+
// Handle attributes
|
|
256
|
+
if (attribute) {
|
|
257
|
+
// Relations
|
|
258
|
+
if (attribute.type === 'relation') {
|
|
259
|
+
filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.target));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Components
|
|
263
|
+
else if (attribute.type === 'component') {
|
|
264
|
+
filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.component));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Media
|
|
268
|
+
else if (attribute.type === 'media') {
|
|
269
|
+
filters[key] = convertAndSanitizeFilters(value, strapi.getModel('plugin::upload.file'));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Dynamic Zones
|
|
273
|
+
else if (attribute.type === 'dynamiczone') {
|
|
274
|
+
removeOperator(key);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Scalar attributes
|
|
278
|
+
else {
|
|
279
|
+
// Always remove password attributes from filters object
|
|
280
|
+
if (attribute.type === 'password') {
|
|
281
|
+
removeOperator(key);
|
|
282
|
+
} else {
|
|
283
|
+
filters[key] = convertAndSanitizeFilters(value);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Handle operators
|
|
289
|
+
else {
|
|
290
|
+
if (['$null', '$notNull'].includes(key)) {
|
|
291
|
+
filters[key] = parseType({ type: 'boolean', value: filters[key], forceCast: true });
|
|
292
|
+
} else if (isObject(value)) {
|
|
293
|
+
filters[key] = convertAndSanitizeFilters(value, schema);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Remove empty objects & arrays
|
|
298
|
+
if (isObject(filters[key]) && isEmpty(filters[key])) {
|
|
299
|
+
removeOperator(key);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return filters;
|
|
304
|
+
};
|
|
222
305
|
|
|
223
306
|
const convertPublicationStateParams = (type, params = {}, query = {}) => {
|
|
224
307
|
if (!type) {
|
package/lib/parse-type.js
CHANGED
|
@@ -57,7 +57,7 @@ const parseDateTimeOrTimestamp = value => {
|
|
|
57
57
|
* @param {string} options.type - type of the atribute
|
|
58
58
|
* @param {*} options.value - value tu cast
|
|
59
59
|
*/
|
|
60
|
-
const parseType = ({ type, value }) => {
|
|
60
|
+
const parseType = ({ type, value, forceCast = false }) => {
|
|
61
61
|
switch (type) {
|
|
62
62
|
case 'boolean': {
|
|
63
63
|
if (typeof value === 'boolean') return value;
|
|
@@ -70,6 +70,10 @@ const parseType = ({ type, value }) => {
|
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
if (forceCast) {
|
|
74
|
+
return Boolean(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
73
77
|
throw new Error('Invalid boolean input. Expected "t","1","true","false","0","f"');
|
|
74
78
|
}
|
|
75
79
|
case 'integer':
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/utils",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.8",
|
|
4
4
|
"description": "Shared utilities for the Strapi packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"node": ">=12.22.0 <=16.x.x",
|
|
46
46
|
"npm": ">=6.0.0"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "669bb2f0440d3b21a23c8d665fdba98bd3d8cc71"
|
|
49
49
|
}
|