@strapi/utils 4.11.3 → 4.12.0-beta.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.
Files changed (184) hide show
  1. package/dist/async.d.ts +10 -0
  2. package/dist/async.js +33 -0
  3. package/dist/async.js.map +1 -0
  4. package/dist/code-generator.d.ts +2 -0
  5. package/dist/code-generator.js +11 -0
  6. package/dist/code-generator.js.map +1 -0
  7. package/dist/config.d.ts +8 -0
  8. package/dist/config.js +79 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/content-types.d.ts +60 -0
  11. package/dist/content-types.js +151 -0
  12. package/dist/content-types.js.map +1 -0
  13. package/dist/convert-query-params.d.ts +75 -0
  14. package/dist/convert-query-params.js +476 -0
  15. package/dist/convert-query-params.js.map +1 -0
  16. package/dist/env-helper.d.ts +18 -0
  17. package/dist/env-helper.js +84 -0
  18. package/dist/env-helper.js.map +1 -0
  19. package/dist/errors.d.ts +37 -0
  20. package/dist/errors.js +100 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/file.d.ts +16 -0
  23. package/dist/file.js +54 -0
  24. package/dist/file.js.map +1 -0
  25. package/dist/format-yup-error.d.ts +10 -0
  26. package/dist/format-yup-error.js +17 -0
  27. package/dist/format-yup-error.js.map +1 -0
  28. package/dist/hooks.d.ts +63 -0
  29. package/dist/hooks.js +89 -0
  30. package/dist/hooks.js.map +1 -0
  31. package/dist/import-default.d.ts +1 -0
  32. package/dist/import-default.js +9 -0
  33. package/dist/import-default.js.map +1 -0
  34. package/dist/index.d.ts +30 -0
  35. package/dist/index.js +99 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/object-formatting.d.ts +3 -0
  38. package/dist/object-formatting.js +14 -0
  39. package/dist/object-formatting.js.map +1 -0
  40. package/dist/operators.d.ts +2 -0
  41. package/dist/operators.js +70 -0
  42. package/dist/operators.js.map +1 -0
  43. package/dist/pagination.d.ts +14 -0
  44. package/dist/pagination.js +80 -0
  45. package/dist/pagination.js.map +1 -0
  46. package/dist/parse-multipart.d.ts +8 -0
  47. package/dist/parse-multipart.js +36 -0
  48. package/dist/parse-multipart.js.map +1 -0
  49. package/dist/parse-type.d.ts +21 -0
  50. package/dist/parse-type.js +108 -0
  51. package/dist/parse-type.js.map +1 -0
  52. package/dist/policy.d.ts +41 -0
  53. package/dist/policy.js +109 -0
  54. package/dist/policy.js.map +1 -0
  55. package/dist/print-value.d.ts +2 -0
  56. package/dist/print-value.js +50 -0
  57. package/dist/print-value.js.map +1 -0
  58. package/dist/provider-factory.d.ts +29 -0
  59. package/dist/provider-factory.js +80 -0
  60. package/dist/provider-factory.js.map +1 -0
  61. package/dist/relations.d.ts +10 -0
  62. package/dist/relations.js +23 -0
  63. package/dist/relations.js.map +1 -0
  64. package/dist/sanitize/index.d.ts +23 -0
  65. package/dist/sanitize/index.js +135 -0
  66. package/dist/sanitize/index.js.map +1 -0
  67. package/dist/sanitize/sanitizers.d.ts +10 -0
  68. package/dist/sanitize/sanitizers.js +114 -0
  69. package/dist/sanitize/sanitizers.js.map +1 -0
  70. package/dist/sanitize/visitors/allowed-fields.d.ts +3 -0
  71. package/{lib → dist}/sanitize/visitors/allowed-fields.js +17 -32
  72. package/dist/sanitize/visitors/allowed-fields.js.map +1 -0
  73. package/dist/sanitize/visitors/index.d.ts +7 -0
  74. package/dist/sanitize/visitors/index.js +21 -0
  75. package/dist/sanitize/visitors/index.js.map +1 -0
  76. package/dist/sanitize/visitors/remove-dynamic-zones.d.ts +3 -0
  77. package/dist/sanitize/visitors/remove-dynamic-zones.js +10 -0
  78. package/dist/sanitize/visitors/remove-dynamic-zones.js.map +1 -0
  79. package/dist/sanitize/visitors/remove-morph-to-relations.d.ts +3 -0
  80. package/dist/sanitize/visitors/remove-morph-to-relations.js +10 -0
  81. package/dist/sanitize/visitors/remove-morph-to-relations.js.map +1 -0
  82. package/dist/sanitize/visitors/remove-password.d.ts +3 -0
  83. package/dist/sanitize/visitors/remove-password.js +9 -0
  84. package/dist/sanitize/visitors/remove-password.js.map +1 -0
  85. package/dist/sanitize/visitors/remove-private.d.ts +3 -0
  86. package/dist/sanitize/visitors/remove-private.js +14 -0
  87. package/dist/sanitize/visitors/remove-private.js.map +1 -0
  88. package/dist/sanitize/visitors/remove-restricted-relations.d.ts +3 -0
  89. package/dist/sanitize/visitors/remove-restricted-relations.js +88 -0
  90. package/dist/sanitize/visitors/remove-restricted-relations.js.map +1 -0
  91. package/dist/sanitize/visitors/restricted-fields.d.ts +3 -0
  92. package/dist/sanitize/visitors/restricted-fields.js +25 -0
  93. package/dist/sanitize/visitors/restricted-fields.js.map +1 -0
  94. package/dist/set-creator-fields.d.ts +9 -0
  95. package/dist/set-creator-fields.js +39 -0
  96. package/dist/set-creator-fields.js.map +1 -0
  97. package/dist/string-formatting.d.ts +15 -0
  98. package/dist/string-formatting.js +85 -0
  99. package/dist/string-formatting.js.map +1 -0
  100. package/dist/template-configuration.d.ts +5 -0
  101. package/dist/template-configuration.js +30 -0
  102. package/dist/template-configuration.js.map +1 -0
  103. package/dist/template.d.ts +9 -0
  104. package/dist/template.js +20 -0
  105. package/dist/template.js.map +1 -0
  106. package/dist/traverse/factory.d.ts +78 -0
  107. package/dist/traverse/factory.js +127 -0
  108. package/dist/traverse/factory.js.map +1 -0
  109. package/dist/traverse/index.d.ts +5 -0
  110. package/dist/traverse/index.js +17 -0
  111. package/dist/traverse/index.js.map +1 -0
  112. package/dist/traverse/query-fields.d.ts +3 -0
  113. package/dist/traverse/query-fields.js +35 -0
  114. package/dist/traverse/query-fields.js.map +1 -0
  115. package/dist/traverse/query-filters.d.ts +3 -0
  116. package/dist/traverse/query-filters.js +75 -0
  117. package/dist/traverse/query-filters.js.map +1 -0
  118. package/dist/traverse/query-populate.d.ts +3 -0
  119. package/dist/traverse/query-populate.js +144 -0
  120. package/dist/traverse/query-populate.js.map +1 -0
  121. package/dist/traverse/query-sort.d.ts +3 -0
  122. package/dist/traverse/query-sort.js +116 -0
  123. package/dist/traverse/query-sort.js.map +1 -0
  124. package/dist/traverse-entity.d.ts +31 -0
  125. package/dist/traverse-entity.js +134 -0
  126. package/dist/traverse-entity.js.map +1 -0
  127. package/dist/types.d.ts +65 -0
  128. package/dist/types.js +3 -0
  129. package/dist/types.js.map +1 -0
  130. package/dist/validators.d.ts +13 -0
  131. package/dist/validators.js +120 -0
  132. package/dist/validators.js.map +1 -0
  133. package/dist/webhook.d.ts +5 -0
  134. package/dist/webhook.js +27 -0
  135. package/dist/webhook.js.map +1 -0
  136. package/package.json +19 -4
  137. package/.eslintignore +0 -3
  138. package/.eslintrc.js +0 -4
  139. package/index.d.ts +0 -5
  140. package/lib/async.d.ts +0 -21
  141. package/lib/async.js +0 -45
  142. package/lib/build-query.js +0 -208
  143. package/lib/code-generator.js +0 -13
  144. package/lib/config.js +0 -88
  145. package/lib/content-types.js +0 -196
  146. package/lib/convert-query-params.js +0 -586
  147. package/lib/env-helper.js +0 -98
  148. package/lib/errors.js +0 -113
  149. package/lib/file.js +0 -60
  150. package/lib/format-yup-error.js +0 -20
  151. package/lib/hooks.js +0 -110
  152. package/lib/import-default.js +0 -10
  153. package/lib/index.js +0 -99
  154. package/lib/object-formatting.js +0 -15
  155. package/lib/operators.js +0 -74
  156. package/lib/pagination.js +0 -99
  157. package/lib/parse-multipart.js +0 -44
  158. package/lib/parse-type.js +0 -100
  159. package/lib/policy.js +0 -129
  160. package/lib/print-value.js +0 -52
  161. package/lib/provider-factory.js +0 -116
  162. package/lib/relations.js +0 -31
  163. package/lib/sanitize/index.js +0 -143
  164. package/lib/sanitize/sanitizers.js +0 -163
  165. package/lib/sanitize/visitors/index.js +0 -11
  166. package/lib/sanitize/visitors/remove-dynamic-zones.js +0 -9
  167. package/lib/sanitize/visitors/remove-morph-to-relations.js +0 -9
  168. package/lib/sanitize/visitors/remove-password.js +0 -7
  169. package/lib/sanitize/visitors/remove-private.js +0 -15
  170. package/lib/sanitize/visitors/remove-restricted-relations.js +0 -81
  171. package/lib/sanitize/visitors/restricted-fields.js +0 -32
  172. package/lib/set-creator-fields.js +0 -17
  173. package/lib/string-formatting.js +0 -79
  174. package/lib/template-configuration.js +0 -32
  175. package/lib/template.js +0 -28
  176. package/lib/traverse/factory.js +0 -157
  177. package/lib/traverse/index.js +0 -16
  178. package/lib/traverse/query-fields.js +0 -39
  179. package/lib/traverse/query-filters.js +0 -97
  180. package/lib/traverse/query-populate.js +0 -191
  181. package/lib/traverse/query-sort.js +0 -171
  182. package/lib/traverse-entity.js +0 -166
  183. package/lib/validators.js +0 -120
  184. package/lib/webhook.js +0 -30
@@ -1,586 +0,0 @@
1
- /* eslint-disable max-classes-per-file */
2
-
3
- 'use strict';
4
-
5
- /**
6
- * Converts the standard Strapi REST query params to a more usable format for querying
7
- * You can read more here: https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#filters
8
- */
9
-
10
- const {
11
- isNil,
12
- toNumber,
13
- isInteger,
14
- has,
15
- isEmpty,
16
- isObject,
17
- isPlainObject,
18
- cloneDeep,
19
- get,
20
- mergeAll,
21
- isString,
22
- } = require('lodash/fp');
23
- const _ = require('lodash');
24
- const parseType = require('./parse-type');
25
- const contentTypesUtils = require('./content-types');
26
- const { PaginationError } = require('./errors');
27
- const {
28
- isMediaAttribute,
29
- isDynamicZoneAttribute,
30
- isMorphToRelationalAttribute,
31
- } = require('./content-types');
32
- const { isOperator } = require('./operators');
33
-
34
- const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
35
-
36
- class InvalidOrderError extends Error {
37
- constructor() {
38
- super();
39
- this.message = 'Invalid order. order can only be one of asc|desc|ASC|DESC';
40
- }
41
- }
42
- class InvalidSortError extends Error {
43
- constructor() {
44
- super();
45
- this.message =
46
- 'Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects';
47
- }
48
- }
49
-
50
- const validateOrder = (order) => {
51
- if (!isString(order) || !['asc', 'desc'].includes(order.toLocaleLowerCase())) {
52
- throw new InvalidOrderError();
53
- }
54
- };
55
-
56
- const convertCountQueryParams = (countQuery) => {
57
- return parseType({ type: 'boolean', value: countQuery });
58
- };
59
-
60
- const convertOrderingQueryParams = (ordering) => {
61
- return ordering;
62
- };
63
-
64
- /**
65
- * Sort query parser
66
- * @param {string} sortQuery - ex: id:asc,price:desc
67
- */
68
- const convertSortQueryParams = (sortQuery) => {
69
- if (typeof sortQuery === 'string') {
70
- return sortQuery.split(',').map((value) => convertSingleSortQueryParam(value));
71
- }
72
-
73
- if (Array.isArray(sortQuery)) {
74
- return sortQuery.flatMap((sortValue) => convertSortQueryParams(sortValue));
75
- }
76
-
77
- if (_.isPlainObject(sortQuery)) {
78
- return convertNestedSortQueryParam(sortQuery);
79
- }
80
-
81
- throw new InvalidSortError();
82
- };
83
-
84
- const convertSingleSortQueryParam = (sortQuery) => {
85
- if (!sortQuery) {
86
- return {};
87
- }
88
- if (!isString(sortQuery)) {
89
- throw new Error('Invalid sort query');
90
- }
91
-
92
- // split field and order param with default order to ascending
93
- const [field, order = 'asc'] = sortQuery.split(':');
94
-
95
- if (field.length === 0) {
96
- throw new Error('Field cannot be empty');
97
- }
98
-
99
- validateOrder(order);
100
-
101
- // TODO: field should be a valid path on an object model
102
-
103
- return _.set({}, field, order);
104
- };
105
-
106
- const convertNestedSortQueryParam = (sortQuery) => {
107
- const transformedSort = {};
108
- for (const field of Object.keys(sortQuery)) {
109
- const order = sortQuery[field];
110
-
111
- // this is a deep sort
112
- if (_.isPlainObject(order)) {
113
- transformedSort[field] = convertNestedSortQueryParam(order);
114
- } else {
115
- validateOrder(order);
116
- transformedSort[field] = order;
117
- }
118
- }
119
-
120
- return transformedSort;
121
- };
122
-
123
- /**
124
- * Start query parser
125
- * @param {string} startQuery
126
- */
127
- const convertStartQueryParams = (startQuery) => {
128
- const startAsANumber = _.toNumber(startQuery);
129
-
130
- if (!_.isInteger(startAsANumber) || startAsANumber < 0) {
131
- throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
132
- }
133
-
134
- return startAsANumber;
135
- };
136
-
137
- /**
138
- * Limit query parser
139
- * @param {string} limitQuery
140
- */
141
- const convertLimitQueryParams = (limitQuery) => {
142
- const limitAsANumber = _.toNumber(limitQuery);
143
-
144
- if (!_.isInteger(limitAsANumber) || (limitAsANumber !== -1 && limitAsANumber < 0)) {
145
- throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
146
- }
147
-
148
- if (limitAsANumber === -1) return null;
149
-
150
- return limitAsANumber;
151
- };
152
-
153
- const convertPageQueryParams = (page) => {
154
- const pageVal = toNumber(page);
155
-
156
- if (!isInteger(pageVal) || pageVal <= 0) {
157
- throw new PaginationError(
158
- `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
159
- );
160
- }
161
-
162
- return pageVal;
163
- };
164
-
165
- const convertPageSizeQueryParams = (pageSize, page) => {
166
- const pageSizeVal = toNumber(pageSize);
167
-
168
- if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
169
- throw new PaginationError(
170
- `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
171
- );
172
- }
173
-
174
- return pageSizeVal;
175
- };
176
-
177
- const validatePaginationParams = (page, pageSize, start, limit) => {
178
- const isPagePagination = !isNil(page) || !isNil(pageSize);
179
- const isOffsetPagination = !isNil(start) || !isNil(limit);
180
-
181
- if (isPagePagination && isOffsetPagination) {
182
- throw new PaginationError(
183
- 'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
184
- );
185
- }
186
- };
187
-
188
- class InvalidPopulateError extends Error {
189
- constructor() {
190
- super();
191
- this.message =
192
- 'Invalid populate parameter. Expected a string, an array of strings, a populate object';
193
- }
194
- }
195
-
196
- // NOTE: we could support foo.* or foo.bar.* etc later on
197
- const convertPopulateQueryParams = (populate, schema, depth = 0) => {
198
- if (depth === 0 && populate === '*') {
199
- return true;
200
- }
201
-
202
- if (typeof populate === 'string') {
203
- return populate.split(',').map((value) => _.trim(value));
204
- }
205
-
206
- if (Array.isArray(populate)) {
207
- // map convert
208
- return _.uniq(
209
- populate.flatMap((value) => {
210
- if (typeof value !== 'string') {
211
- throw new InvalidPopulateError();
212
- }
213
-
214
- return value.split(',').map((value) => _.trim(value));
215
- })
216
- );
217
- }
218
-
219
- if (_.isPlainObject(populate)) {
220
- return convertPopulateObject(populate, schema);
221
- }
222
-
223
- throw new InvalidPopulateError();
224
- };
225
-
226
- const convertPopulateObject = (populate, schema) => {
227
- if (!schema) {
228
- return {};
229
- }
230
-
231
- const { attributes } = schema;
232
-
233
- return Object.entries(populate).reduce((acc, [key, subPopulate]) => {
234
- const attribute = attributes[key];
235
-
236
- if (!attribute) {
237
- return acc;
238
- }
239
-
240
- // Allow adding an 'on' strategy to populate queries for polymorphic relations, media and dynamic zones
241
- const isAllowedAttributeForFragmentPopulate =
242
- isDynamicZoneAttribute(attribute) ||
243
- isMediaAttribute(attribute) ||
244
- isMorphToRelationalAttribute(attribute);
245
-
246
- const hasFragmentPopulateDefined =
247
- typeof subPopulate === 'object' && 'on' in subPopulate && !isNil(subPopulate.on);
248
-
249
- if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined) {
250
- return {
251
- ...acc,
252
- [key]: {
253
- on: Object.entries(subPopulate.on).reduce(
254
- (acc, [type, typeSubPopulate]) => ({
255
- ...acc,
256
- [type]: convertNestedPopulate(typeSubPopulate, strapi.getModel(type)),
257
- }),
258
- {}
259
- ),
260
- },
261
- };
262
- }
263
-
264
- // TODO: This is a query's populate fallback for DynamicZone and is kept for legacy purpose.
265
- // Removing it could break existing user queries but it should be removed in V5.
266
- if (attribute.type === 'dynamiczone') {
267
- const populates = attribute.components
268
- .map((uid) => strapi.getModel(uid))
269
- .map((schema) => convertNestedPopulate(subPopulate, schema))
270
- .map((populate) => (populate === true ? {} : populate)) // cast boolean to empty object to avoid merging issues
271
- .filter((populate) => populate !== false);
272
-
273
- if (isEmpty(populates)) {
274
- return acc;
275
- }
276
-
277
- return {
278
- ...acc,
279
- [key]: mergeAll(populates),
280
- };
281
- }
282
-
283
- // NOTE: Retrieve the target schema UID.
284
- // Only handles basic relations, medias and component since it's not possible
285
- // to populate with options for a dynamic zone or a polymorphic relation
286
- let targetSchemaUID;
287
-
288
- if (attribute.type === 'relation') {
289
- targetSchemaUID = attribute.target;
290
- } else if (attribute.type === 'component') {
291
- targetSchemaUID = attribute.component;
292
- } else if (attribute.type === 'media') {
293
- targetSchemaUID = 'plugin::upload.file';
294
- } else {
295
- return acc;
296
- }
297
-
298
- const targetSchema = strapi.getModel(targetSchemaUID);
299
-
300
- if (!targetSchema) {
301
- return acc;
302
- }
303
-
304
- const populateObject = convertNestedPopulate(subPopulate, targetSchema);
305
-
306
- if (!populateObject) {
307
- return acc;
308
- }
309
-
310
- return {
311
- ...acc,
312
- [key]: populateObject,
313
- };
314
- }, {});
315
- };
316
-
317
- const convertNestedPopulate = (subPopulate, schema) => {
318
- if (_.isString(subPopulate)) {
319
- return parseType({ type: 'boolean', value: subPopulate, forceCast: true });
320
- }
321
-
322
- if (_.isBoolean(subPopulate)) {
323
- return subPopulate;
324
- }
325
-
326
- if (!_.isPlainObject(subPopulate)) {
327
- throw new Error(`Invalid nested populate. Expected '*' or an object`);
328
- }
329
-
330
- const { sort, filters, fields, populate, count, ordering, page, pageSize, start, limit } =
331
- subPopulate;
332
-
333
- const query = {};
334
-
335
- if (sort) {
336
- query.orderBy = convertSortQueryParams(sort);
337
- }
338
-
339
- if (filters) {
340
- query.where = convertFiltersQueryParams(filters, schema);
341
- }
342
-
343
- if (fields) {
344
- query.select = convertFieldsQueryParams(fields);
345
- }
346
-
347
- if (populate) {
348
- query.populate = convertPopulateQueryParams(populate, schema);
349
- }
350
-
351
- if (count) {
352
- query.count = convertCountQueryParams(count);
353
- }
354
-
355
- if (ordering) {
356
- query.ordering = convertOrderingQueryParams(ordering);
357
- }
358
-
359
- validatePaginationParams(page, pageSize, start, limit);
360
-
361
- if (!isNil(page)) {
362
- query.page = convertPageQueryParams(page);
363
- }
364
-
365
- if (!isNil(pageSize)) {
366
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
367
- }
368
-
369
- if (!isNil(start)) {
370
- query.offset = convertStartQueryParams(start);
371
- }
372
-
373
- if (!isNil(limit)) {
374
- query.limit = convertLimitQueryParams(limit);
375
- }
376
-
377
- convertPublicationStateParams(schema, subPopulate, query);
378
-
379
- return query;
380
- };
381
-
382
- // TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)
383
- const convertFieldsQueryParams = (fields, depth = 0) => {
384
- if (depth === 0 && fields === '*') {
385
- return undefined;
386
- }
387
-
388
- if (typeof fields === 'string') {
389
- const fieldsValues = fields.split(',').map((value) => _.trim(value));
390
- return _.uniq(['id', ...fieldsValues]);
391
- }
392
-
393
- if (Array.isArray(fields)) {
394
- // map convert
395
- const fieldsValues = fields.flatMap((value) => convertFieldsQueryParams(value, depth + 1));
396
- return _.uniq(['id', ...fieldsValues]);
397
- }
398
-
399
- throw new Error('Invalid fields parameter. Expected a string or an array of strings');
400
- };
401
-
402
- const isValidSchemaAttribute = (key, schema) => {
403
- if (key === 'id') {
404
- return true;
405
- }
406
-
407
- if (!schema) {
408
- return false;
409
- }
410
-
411
- return Object.keys(schema.attributes).includes(key);
412
- };
413
-
414
- const convertFiltersQueryParams = (filters, schema) => {
415
- // Filters need to be either an array or an object
416
- // Here we're only checking for 'object' type since typeof [] => object and typeof {} => object
417
- if (!isObject(filters)) {
418
- throw new Error('The filters parameter must be an object or an array');
419
- }
420
-
421
- // Don't mutate the original object
422
- const filtersCopy = cloneDeep(filters);
423
-
424
- return convertAndSanitizeFilters(filtersCopy, schema);
425
- };
426
-
427
- const convertAndSanitizeFilters = (filters, schema) => {
428
- if (Array.isArray(filters)) {
429
- return (
430
- filters
431
- // Sanitize each filter
432
- .map((filter) => convertAndSanitizeFilters(filter, schema))
433
- // Filter out empty filters
434
- .filter((filter) => !isObject(filter) || !isEmpty(filter))
435
- );
436
- }
437
-
438
- // This must come after check for Array or else arrays are not filtered
439
- if (!isPlainObject(filters)) {
440
- return filters;
441
- }
442
-
443
- const removeOperator = (operator) => delete filters[operator];
444
-
445
- // Here, `key` can either be an operator or an attribute name
446
- for (const [key, value] of Object.entries(filters)) {
447
- const attribute = get(key, schema?.attributes);
448
- const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
449
-
450
- if (!validKey) {
451
- removeOperator(key);
452
- }
453
- // Handle attributes
454
- else if (attribute) {
455
- // Relations
456
- if (attribute.type === 'relation') {
457
- filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.target));
458
- }
459
-
460
- // Components
461
- else if (attribute.type === 'component') {
462
- filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.component));
463
- }
464
-
465
- // Media
466
- else if (attribute.type === 'media') {
467
- filters[key] = convertAndSanitizeFilters(value, strapi.getModel('plugin::upload.file'));
468
- }
469
-
470
- // Dynamic Zones
471
- else if (attribute.type === 'dynamiczone') {
472
- removeOperator(key);
473
- }
474
-
475
- // Password attributes
476
- else if (attribute.type === 'password') {
477
- // Always remove password attributes from filters object
478
- removeOperator(key);
479
- }
480
-
481
- // Scalar attributes
482
- else {
483
- filters[key] = convertAndSanitizeFilters(value, schema);
484
- }
485
- }
486
-
487
- // Handle operators
488
- else if (['$null', '$notNull'].includes(key)) {
489
- filters[key] = parseType({ type: 'boolean', value: filters[key], forceCast: true });
490
- } else if (isObject(value)) {
491
- filters[key] = convertAndSanitizeFilters(value, schema);
492
- }
493
-
494
- // Remove empty objects & arrays
495
- if (isPlainObject(filters[key]) && isEmpty(filters[key])) {
496
- removeOperator(key);
497
- }
498
- }
499
-
500
- return filters;
501
- };
502
-
503
- const convertPublicationStateParams = (type, params = {}, query = {}) => {
504
- if (!type) {
505
- return;
506
- }
507
-
508
- const { publicationState } = params;
509
-
510
- if (!_.isNil(publicationState)) {
511
- if (!contentTypesUtils.constants.DP_PUB_STATES.includes(publicationState)) {
512
- throw new Error(
513
- `Invalid publicationState. Expected one of 'preview','live' received: ${publicationState}.`
514
- );
515
- }
516
-
517
- // NOTE: this is the query layer filters not the entity service filters
518
- query.filters = ({ meta }) => {
519
- if (publicationState === 'live' && has(PUBLISHED_AT_ATTRIBUTE, meta.attributes)) {
520
- return { [PUBLISHED_AT_ATTRIBUTE]: { $notNull: true } };
521
- }
522
- };
523
- }
524
- };
525
-
526
- const transformParamsToQuery = (uid, params) => {
527
- // NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
528
- const schema = strapi.getModel(uid);
529
-
530
- const query = {};
531
-
532
- const { _q, sort, filters, fields, populate, page, pageSize, start, limit } = params;
533
-
534
- if (!isNil(_q)) {
535
- query._q = _q;
536
- }
537
-
538
- if (!isNil(sort)) {
539
- query.orderBy = convertSortQueryParams(sort);
540
- }
541
-
542
- if (!isNil(filters)) {
543
- query.where = convertFiltersQueryParams(filters, schema);
544
- }
545
-
546
- if (!isNil(fields)) {
547
- query.select = convertFieldsQueryParams(fields);
548
- }
549
-
550
- if (!isNil(populate)) {
551
- query.populate = convertPopulateQueryParams(populate, schema);
552
- }
553
-
554
- validatePaginationParams(page, pageSize, start, limit);
555
-
556
- if (!isNil(page)) {
557
- query.page = convertPageQueryParams(page);
558
- }
559
-
560
- if (!isNil(pageSize)) {
561
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
562
- }
563
-
564
- if (!isNil(start)) {
565
- query.offset = convertStartQueryParams(start);
566
- }
567
-
568
- if (!isNil(limit)) {
569
- query.limit = convertLimitQueryParams(limit);
570
- }
571
-
572
- convertPublicationStateParams(schema, params, query);
573
-
574
- return query;
575
- };
576
-
577
- module.exports = {
578
- convertSortQueryParams,
579
- convertStartQueryParams,
580
- convertLimitQueryParams,
581
- convertPopulateQueryParams,
582
- convertFiltersQueryParams,
583
- convertFieldsQueryParams,
584
- convertPublicationStateParams,
585
- transformParamsToQuery,
586
- };
package/lib/env-helper.js DELETED
@@ -1,98 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash');
4
-
5
- function env(key, defaultValue) {
6
- return _.has(process.env, key) ? process.env[key] : defaultValue;
7
- }
8
-
9
- const utils = {
10
- int(key, defaultValue) {
11
- if (!_.has(process.env, key)) {
12
- return defaultValue;
13
- }
14
-
15
- const value = process.env[key];
16
- return parseInt(value, 10);
17
- },
18
-
19
- float(key, defaultValue) {
20
- if (!_.has(process.env, key)) {
21
- return defaultValue;
22
- }
23
-
24
- const value = process.env[key];
25
- return parseFloat(value);
26
- },
27
-
28
- bool(key, defaultValue) {
29
- if (!_.has(process.env, key)) {
30
- return defaultValue;
31
- }
32
-
33
- const value = process.env[key];
34
- return value === 'true';
35
- },
36
-
37
- json(key, defaultValue) {
38
- if (!_.has(process.env, key)) {
39
- return defaultValue;
40
- }
41
-
42
- const value = process.env[key];
43
- try {
44
- return JSON.parse(value);
45
- } catch (error) {
46
- throw new Error(`Invalid json environment variable ${key}: ${error.message}`);
47
- }
48
- },
49
-
50
- array(key, defaultValue) {
51
- if (!_.has(process.env, key)) {
52
- return defaultValue;
53
- }
54
-
55
- let value = process.env[key];
56
-
57
- if (value.startsWith('[') && value.endsWith(']')) {
58
- value = value.substring(1, value.length - 1);
59
- }
60
-
61
- return value.split(',').map((v) => {
62
- return _.trim(_.trim(v, ' '), '"');
63
- });
64
- },
65
-
66
- date(key, defaultValue) {
67
- if (!_.has(process.env, key)) {
68
- return defaultValue;
69
- }
70
-
71
- const value = process.env[key];
72
- return new Date(value);
73
- },
74
-
75
- /**
76
- * Gets a value from env that matches oneOf provided values
77
- * @param {string} key
78
- * @param {string[]} expectedValues
79
- * @param {string|undefined} defaultValue
80
- * @returns {string|undefined}
81
- */
82
- oneOf(key, expectedValues, defaultValue) {
83
- if (!expectedValues) {
84
- throw new Error(`env.oneOf requires expectedValues`);
85
- }
86
-
87
- if (defaultValue && !expectedValues.includes(defaultValue)) {
88
- throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
89
- }
90
-
91
- const rawValue = env(key, defaultValue);
92
- return expectedValues.includes(rawValue) ? rawValue : defaultValue;
93
- },
94
- };
95
-
96
- Object.assign(env, utils);
97
-
98
- module.exports = env;