@strapi/utils 5.12.1 → 5.12.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.
Files changed (233) hide show
  1. package/dist/async.js +28 -0
  2. package/dist/async.js.map +1 -0
  3. package/dist/async.mjs +24 -0
  4. package/dist/async.mjs.map +1 -0
  5. package/dist/content-types.js +201 -0
  6. package/dist/content-types.js.map +1 -0
  7. package/dist/content-types.mjs +167 -0
  8. package/dist/content-types.mjs.map +1 -0
  9. package/dist/convert-query-params.js +512 -0
  10. package/dist/convert-query-params.js.map +1 -0
  11. package/dist/convert-query-params.mjs +510 -0
  12. package/dist/convert-query-params.mjs.map +1 -0
  13. package/dist/env-helper.js +81 -0
  14. package/dist/env-helper.js.map +1 -0
  15. package/dist/env-helper.mjs +79 -0
  16. package/dist/env-helper.mjs.map +1 -0
  17. package/dist/errors.js +104 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/errors.mjs +88 -0
  20. package/dist/errors.mjs.map +1 -0
  21. package/dist/file.js +57 -0
  22. package/dist/file.js.map +1 -0
  23. package/dist/file.mjs +50 -0
  24. package/dist/file.mjs.map +1 -0
  25. package/dist/format-yup-error.js +19 -0
  26. package/dist/format-yup-error.js.map +1 -0
  27. package/dist/format-yup-error.mjs +17 -0
  28. package/dist/format-yup-error.mjs.map +1 -0
  29. package/dist/hooks.js +86 -0
  30. package/dist/hooks.js.map +1 -0
  31. package/dist/hooks.mjs +80 -0
  32. package/dist/hooks.mjs.map +1 -0
  33. package/dist/import-default.js +9 -0
  34. package/dist/import-default.js.map +1 -0
  35. package/dist/import-default.mjs +7 -0
  36. package/dist/import-default.mjs.map +1 -0
  37. package/dist/index.js +54 -4358
  38. package/dist/index.js.map +1 -1
  39. package/dist/index.mjs +48 -4317
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/machine-id.js +17 -0
  42. package/dist/machine-id.js.map +1 -0
  43. package/dist/machine-id.mjs +15 -0
  44. package/dist/machine-id.mjs.map +1 -0
  45. package/dist/operators.js +79 -0
  46. package/dist/operators.js.map +1 -0
  47. package/dist/operators.mjs +76 -0
  48. package/dist/operators.mjs.map +1 -0
  49. package/dist/package-manager.js +36 -0
  50. package/dist/package-manager.js.map +1 -0
  51. package/dist/package-manager.mjs +33 -0
  52. package/dist/package-manager.mjs.map +1 -0
  53. package/dist/pagination.js +163 -0
  54. package/dist/pagination.js.map +1 -0
  55. package/dist/pagination.mjs +159 -0
  56. package/dist/pagination.mjs.map +1 -0
  57. package/dist/parse-type.js +140 -0
  58. package/dist/parse-type.js.map +1 -0
  59. package/dist/parse-type.mjs +118 -0
  60. package/dist/parse-type.mjs.map +1 -0
  61. package/dist/policy.js +33 -0
  62. package/dist/policy.js.map +1 -0
  63. package/dist/policy.mjs +30 -0
  64. package/dist/policy.mjs.map +1 -0
  65. package/dist/primitives/arrays.js +7 -0
  66. package/dist/primitives/arrays.js.map +1 -0
  67. package/dist/primitives/arrays.mjs +5 -0
  68. package/dist/primitives/arrays.mjs.map +1 -0
  69. package/dist/primitives/dates.js +11 -0
  70. package/dist/primitives/dates.js.map +1 -0
  71. package/dist/primitives/dates.mjs +9 -0
  72. package/dist/primitives/dates.mjs.map +1 -0
  73. package/dist/primitives/objects.js +13 -0
  74. package/dist/primitives/objects.js.map +1 -0
  75. package/dist/primitives/objects.mjs +11 -0
  76. package/dist/primitives/objects.mjs.map +1 -0
  77. package/dist/primitives/strings.js +49 -0
  78. package/dist/primitives/strings.js.map +1 -0
  79. package/dist/primitives/strings.mjs +38 -0
  80. package/dist/primitives/strings.mjs.map +1 -0
  81. package/dist/print-value.js +42 -0
  82. package/dist/print-value.js.map +1 -0
  83. package/dist/print-value.mjs +40 -0
  84. package/dist/print-value.mjs.map +1 -0
  85. package/dist/provider-factory.js +82 -0
  86. package/dist/provider-factory.js.map +1 -0
  87. package/dist/provider-factory.mjs +80 -0
  88. package/dist/provider-factory.mjs.map +1 -0
  89. package/dist/relations.js +54 -0
  90. package/dist/relations.js.map +1 -0
  91. package/dist/relations.mjs +45 -0
  92. package/dist/relations.mjs.map +1 -0
  93. package/dist/sanitize/index.js +195 -0
  94. package/dist/sanitize/index.js.map +1 -0
  95. package/dist/sanitize/index.mjs +194 -0
  96. package/dist/sanitize/index.mjs.map +1 -0
  97. package/dist/sanitize/sanitizers.js +173 -0
  98. package/dist/sanitize/sanitizers.js.map +1 -0
  99. package/dist/sanitize/sanitizers.mjs +166 -0
  100. package/dist/sanitize/sanitizers.mjs.map +1 -0
  101. package/dist/sanitize/visitors/expand-wildcard-populate.js +20 -0
  102. package/dist/sanitize/visitors/expand-wildcard-populate.js.map +1 -0
  103. package/dist/sanitize/visitors/expand-wildcard-populate.mjs +18 -0
  104. package/dist/sanitize/visitors/expand-wildcard-populate.mjs.map +1 -0
  105. package/dist/sanitize/visitors/index.js +22 -0
  106. package/dist/sanitize/visitors/index.js.map +1 -0
  107. package/dist/sanitize/visitors/index.mjs +9 -0
  108. package/dist/sanitize/visitors/index.mjs.map +1 -0
  109. package/dist/sanitize/visitors/remove-disallowed-fields.js +87 -0
  110. package/dist/sanitize/visitors/remove-disallowed-fields.js.map +1 -0
  111. package/dist/sanitize/visitors/remove-disallowed-fields.mjs +85 -0
  112. package/dist/sanitize/visitors/remove-disallowed-fields.mjs.map +1 -0
  113. package/dist/sanitize/visitors/remove-dynamic-zones.js +12 -0
  114. package/dist/sanitize/visitors/remove-dynamic-zones.js.map +1 -0
  115. package/dist/sanitize/visitors/remove-dynamic-zones.mjs +10 -0
  116. package/dist/sanitize/visitors/remove-dynamic-zones.mjs.map +1 -0
  117. package/dist/sanitize/visitors/remove-morph-to-relations.js +12 -0
  118. package/dist/sanitize/visitors/remove-morph-to-relations.js.map +1 -0
  119. package/dist/sanitize/visitors/remove-morph-to-relations.mjs +10 -0
  120. package/dist/sanitize/visitors/remove-morph-to-relations.mjs.map +1 -0
  121. package/dist/sanitize/visitors/remove-password.js +10 -0
  122. package/dist/sanitize/visitors/remove-password.js.map +1 -0
  123. package/dist/sanitize/visitors/remove-password.mjs +8 -0
  124. package/dist/sanitize/visitors/remove-password.mjs.map +1 -0
  125. package/dist/sanitize/visitors/remove-private.js +16 -0
  126. package/dist/sanitize/visitors/remove-private.js.map +1 -0
  127. package/dist/sanitize/visitors/remove-private.mjs +14 -0
  128. package/dist/sanitize/visitors/remove-private.mjs.map +1 -0
  129. package/dist/sanitize/visitors/remove-restricted-fields.js +28 -0
  130. package/dist/sanitize/visitors/remove-restricted-fields.js.map +1 -0
  131. package/dist/sanitize/visitors/remove-restricted-fields.mjs +26 -0
  132. package/dist/sanitize/visitors/remove-restricted-fields.mjs.map +1 -0
  133. package/dist/sanitize/visitors/remove-restricted-relations.js +116 -0
  134. package/dist/sanitize/visitors/remove-restricted-relations.js.map +1 -0
  135. package/dist/sanitize/visitors/remove-restricted-relations.mjs +114 -0
  136. package/dist/sanitize/visitors/remove-restricted-relations.mjs.map +1 -0
  137. package/dist/set-creator-fields.js +18 -0
  138. package/dist/set-creator-fields.js.map +1 -0
  139. package/dist/set-creator-fields.mjs +16 -0
  140. package/dist/set-creator-fields.mjs.map +1 -0
  141. package/dist/template.js +18 -0
  142. package/dist/template.js.map +1 -0
  143. package/dist/template.mjs +15 -0
  144. package/dist/template.mjs.map +1 -0
  145. package/dist/traverse/factory.js +158 -0
  146. package/dist/traverse/factory.js.map +1 -0
  147. package/dist/traverse/factory.mjs +156 -0
  148. package/dist/traverse/factory.mjs.map +1 -0
  149. package/dist/traverse/index.js +14 -0
  150. package/dist/traverse/index.js.map +1 -0
  151. package/dist/traverse/index.mjs +5 -0
  152. package/dist/traverse/index.mjs.map +1 -0
  153. package/dist/traverse/query-fields.js +41 -0
  154. package/dist/traverse/query-fields.js.map +1 -0
  155. package/dist/traverse/query-fields.mjs +39 -0
  156. package/dist/traverse/query-fields.mjs.map +1 -0
  157. package/dist/traverse/query-filters.js +114 -0
  158. package/dist/traverse/query-filters.js.map +1 -0
  159. package/dist/traverse/query-filters.mjs +112 -0
  160. package/dist/traverse/query-filters.mjs.map +1 -0
  161. package/dist/traverse/query-populate.js +280 -0
  162. package/dist/traverse/query-populate.js.map +1 -0
  163. package/dist/traverse/query-populate.mjs +278 -0
  164. package/dist/traverse/query-populate.mjs.map +1 -0
  165. package/dist/traverse/query-sort.js +144 -0
  166. package/dist/traverse/query-sort.js.map +1 -0
  167. package/dist/traverse/query-sort.mjs +142 -0
  168. package/dist/traverse/query-sort.mjs.map +1 -0
  169. package/dist/traverse-entity.js +170 -0
  170. package/dist/traverse-entity.js.map +1 -0
  171. package/dist/traverse-entity.mjs +168 -0
  172. package/dist/traverse-entity.mjs.map +1 -0
  173. package/dist/validate/index.js +218 -0
  174. package/dist/validate/index.js.map +1 -0
  175. package/dist/validate/index.mjs +217 -0
  176. package/dist/validate/index.mjs.map +1 -0
  177. package/dist/validate/utils.js +27 -0
  178. package/dist/validate/utils.js.map +1 -0
  179. package/dist/validate/utils.mjs +24 -0
  180. package/dist/validate/utils.mjs.map +1 -0
  181. package/dist/validate/validators.js +369 -0
  182. package/dist/validate/validators.js.map +1 -0
  183. package/dist/validate/validators.mjs +356 -0
  184. package/dist/validate/validators.mjs.map +1 -0
  185. package/dist/validate/visitors/index.js +22 -0
  186. package/dist/validate/visitors/index.js.map +1 -0
  187. package/dist/validate/visitors/index.mjs +9 -0
  188. package/dist/validate/visitors/index.mjs.map +1 -0
  189. package/dist/validate/visitors/throw-disallowed-fields.js +91 -0
  190. package/dist/validate/visitors/throw-disallowed-fields.js.map +1 -0
  191. package/dist/validate/visitors/throw-disallowed-fields.mjs +89 -0
  192. package/dist/validate/visitors/throw-disallowed-fields.mjs.map +1 -0
  193. package/dist/validate/visitors/throw-dynamic-zones.js +16 -0
  194. package/dist/validate/visitors/throw-dynamic-zones.js.map +1 -0
  195. package/dist/validate/visitors/throw-dynamic-zones.mjs +14 -0
  196. package/dist/validate/visitors/throw-dynamic-zones.mjs.map +1 -0
  197. package/dist/validate/visitors/throw-morph-to-relations.js +16 -0
  198. package/dist/validate/visitors/throw-morph-to-relations.js.map +1 -0
  199. package/dist/validate/visitors/throw-morph-to-relations.mjs +14 -0
  200. package/dist/validate/visitors/throw-morph-to-relations.mjs.map +1 -0
  201. package/dist/validate/visitors/throw-password.js +15 -0
  202. package/dist/validate/visitors/throw-password.js.map +1 -0
  203. package/dist/validate/visitors/throw-password.mjs +13 -0
  204. package/dist/validate/visitors/throw-password.mjs.map +1 -0
  205. package/dist/validate/visitors/throw-private.js +20 -0
  206. package/dist/validate/visitors/throw-private.js.map +1 -0
  207. package/dist/validate/visitors/throw-private.mjs +18 -0
  208. package/dist/validate/visitors/throw-private.mjs.map +1 -0
  209. package/dist/validate/visitors/throw-restricted-fields.js +36 -0
  210. package/dist/validate/visitors/throw-restricted-fields.js.map +1 -0
  211. package/dist/validate/visitors/throw-restricted-fields.mjs +34 -0
  212. package/dist/validate/visitors/throw-restricted-fields.mjs.map +1 -0
  213. package/dist/validate/visitors/throw-restricted-relations.js +125 -0
  214. package/dist/validate/visitors/throw-restricted-relations.js.map +1 -0
  215. package/dist/validate/visitors/throw-restricted-relations.mjs +123 -0
  216. package/dist/validate/visitors/throw-restricted-relations.mjs.map +1 -0
  217. package/dist/validate/visitors/throw-unrecognized-fields.js +66 -0
  218. package/dist/validate/visitors/throw-unrecognized-fields.js.map +1 -0
  219. package/dist/validate/visitors/throw-unrecognized-fields.mjs +64 -0
  220. package/dist/validate/visitors/throw-unrecognized-fields.mjs.map +1 -0
  221. package/dist/validators.js +60 -0
  222. package/dist/validators.js.map +1 -0
  223. package/dist/validators.mjs +37 -0
  224. package/dist/validators.mjs.map +1 -0
  225. package/dist/yup.js +101 -0
  226. package/dist/yup.js.map +1 -0
  227. package/dist/yup.mjs +74 -0
  228. package/dist/yup.mjs.map +1 -0
  229. package/dist/zod.js +31 -0
  230. package/dist/zod.js.map +1 -0
  231. package/dist/zod.mjs +29 -0
  232. package/dist/zod.mjs.map +1 -0
  233. package/package.json +3 -3
@@ -0,0 +1,512 @@
1
+ 'use strict';
2
+
3
+ var _ = require('lodash');
4
+ var fp = require('lodash/fp');
5
+ var contentTypes = require('./content-types.js');
6
+ var errors = require('./errors.js');
7
+ var operators = require('./operators.js');
8
+ var parseType = require('./parse-type.js');
9
+
10
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, PUBLISHED_AT_ATTRIBUTE } = contentTypes.constants;
11
+ class InvalidOrderError extends Error {
12
+ constructor(){
13
+ super();
14
+ this.message = 'Invalid order. order can only be one of asc|desc|ASC|DESC';
15
+ }
16
+ }
17
+ class InvalidSortError extends Error {
18
+ constructor(){
19
+ super();
20
+ this.message = 'Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects';
21
+ }
22
+ }
23
+ function validateOrder(order) {
24
+ if (!fp.isString(order) || ![
25
+ 'asc',
26
+ 'desc'
27
+ ].includes(order.toLocaleLowerCase())) {
28
+ throw new InvalidOrderError();
29
+ }
30
+ }
31
+ const convertCountQueryParams = (countQuery)=>{
32
+ return parseType({
33
+ type: 'boolean',
34
+ value: countQuery
35
+ });
36
+ };
37
+ const convertOrderingQueryParams = (ordering)=>{
38
+ return ordering;
39
+ };
40
+ const isPlainObject = (value)=>_.isPlainObject(value);
41
+ const isStringArray = (value)=>fp.isArray(value) && value.every(fp.isString);
42
+ const createTransformer = ({ getModel })=>{
43
+ /**
44
+ * Sort query parser
45
+ */ const convertSortQueryParams = (sortQuery)=>{
46
+ if (typeof sortQuery === 'string') {
47
+ return convertStringSortQueryParam(sortQuery);
48
+ }
49
+ if (isStringArray(sortQuery)) {
50
+ return sortQuery.flatMap((sortValue)=>convertStringSortQueryParam(sortValue));
51
+ }
52
+ if (Array.isArray(sortQuery)) {
53
+ return sortQuery.map((sortValue)=>convertNestedSortQueryParam(sortValue));
54
+ }
55
+ if (isPlainObject(sortQuery)) {
56
+ return convertNestedSortQueryParam(sortQuery);
57
+ }
58
+ throw new InvalidSortError();
59
+ };
60
+ const convertStringSortQueryParam = (sortQuery)=>{
61
+ return sortQuery.split(',').map((value)=>convertSingleSortQueryParam(value));
62
+ };
63
+ const convertSingleSortQueryParam = (sortQuery)=>{
64
+ if (!sortQuery) {
65
+ return {};
66
+ }
67
+ if (!fp.isString(sortQuery)) {
68
+ throw new Error('Invalid sort query');
69
+ }
70
+ // split field and order param with default order to ascending
71
+ const [field, order = 'asc'] = sortQuery.split(':');
72
+ if (field.length === 0) {
73
+ throw new Error('Field cannot be empty');
74
+ }
75
+ validateOrder(order);
76
+ // TODO: field should be a valid path on an object model
77
+ return _.set({}, field, order);
78
+ };
79
+ const convertNestedSortQueryParam = (sortQuery)=>{
80
+ const transformedSort = {};
81
+ for (const field of Object.keys(sortQuery)){
82
+ const order = sortQuery[field];
83
+ // this is a deep sort
84
+ if (isPlainObject(order)) {
85
+ transformedSort[field] = convertNestedSortQueryParam(order);
86
+ } else if (typeof order === 'string') {
87
+ validateOrder(order);
88
+ transformedSort[field] = order;
89
+ } else {
90
+ throw Error(`Invalid sort type expected object or string got ${typeof order}`);
91
+ }
92
+ }
93
+ return transformedSort;
94
+ };
95
+ /**
96
+ * Start query parser
97
+ */ const convertStartQueryParams = (startQuery)=>{
98
+ const startAsANumber = fp.toNumber(startQuery);
99
+ if (!_.isInteger(startAsANumber) || startAsANumber < 0) {
100
+ throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
101
+ }
102
+ return startAsANumber;
103
+ };
104
+ /**
105
+ * Limit query parser
106
+ */ const convertLimitQueryParams = (limitQuery)=>{
107
+ const limitAsANumber = fp.toNumber(limitQuery);
108
+ if (!_.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
109
+ throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
110
+ }
111
+ if (limitAsANumber === -1) {
112
+ return undefined;
113
+ }
114
+ return limitAsANumber;
115
+ };
116
+ const convertPageQueryParams = (page)=>{
117
+ const pageVal = fp.toNumber(page);
118
+ if (!fp.isInteger(pageVal) || pageVal <= 0) {
119
+ throw new errors.PaginationError(`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`);
120
+ }
121
+ return pageVal;
122
+ };
123
+ const convertPageSizeQueryParams = (pageSize, page)=>{
124
+ const pageSizeVal = fp.toNumber(pageSize);
125
+ if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
126
+ throw new errors.PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`);
127
+ }
128
+ return pageSizeVal;
129
+ };
130
+ const validatePaginationParams = (page, pageSize, start, limit)=>{
131
+ const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
132
+ const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
133
+ if (isPagePagination && isOffsetPagination) {
134
+ throw new errors.PaginationError('Invalid pagination attributes. The page parameters are incorrect and must be in the pagination object');
135
+ }
136
+ };
137
+ class InvalidPopulateError extends Error {
138
+ constructor(){
139
+ super();
140
+ this.message = 'Invalid populate parameter. Expected a string, an array of strings, a populate object';
141
+ }
142
+ }
143
+ // NOTE: we could support foo.* or foo.bar.* etc later on
144
+ const convertPopulateQueryParams = (populate, schema, depth = 0)=>{
145
+ if (depth === 0 && populate === '*') {
146
+ return true;
147
+ }
148
+ if (typeof populate === 'string') {
149
+ return populate.split(',').map((value)=>_.trim(value));
150
+ }
151
+ if (Array.isArray(populate)) {
152
+ // map convert
153
+ return _.uniq(populate.flatMap((value)=>{
154
+ if (typeof value !== 'string') {
155
+ throw new InvalidPopulateError();
156
+ }
157
+ return value.split(',').map((value)=>_.trim(value));
158
+ }));
159
+ }
160
+ if (_.isPlainObject(populate)) {
161
+ return convertPopulateObject(populate, schema);
162
+ }
163
+ throw new InvalidPopulateError();
164
+ };
165
+ const hasPopulateFragmentDefined = (populate)=>{
166
+ return typeof populate === 'object' && 'on' in populate && !fp.isNil(populate.on);
167
+ };
168
+ const hasCountDefined = (populate)=>{
169
+ return typeof populate === 'object' && 'count' in populate && typeof populate.count === 'boolean';
170
+ };
171
+ const convertPopulateObject = (populate, schema)=>{
172
+ if (!schema) {
173
+ return {};
174
+ }
175
+ const { attributes } = schema;
176
+ return Object.entries(populate).reduce((acc, [key, subPopulate])=>{
177
+ // Try converting strings to regular booleans if possible
178
+ if (_.isString(subPopulate)) {
179
+ try {
180
+ const subPopulateAsBoolean = parseType({
181
+ type: 'boolean',
182
+ value: subPopulate
183
+ });
184
+ // Only true is accepted as a boolean populate value
185
+ return subPopulateAsBoolean ? {
186
+ ...acc,
187
+ [key]: true
188
+ } : acc;
189
+ } catch {
190
+ // ignore
191
+ }
192
+ }
193
+ if (_.isBoolean(subPopulate)) {
194
+ // Only true is accepted as a boolean populate value
195
+ return subPopulate === true ? {
196
+ ...acc,
197
+ [key]: true
198
+ } : acc;
199
+ }
200
+ const attribute = attributes[key];
201
+ if (!attribute) {
202
+ return acc;
203
+ }
204
+ // Allow adding an 'on' strategy to populate queries for morphTo relations and dynamic zones
205
+ const isMorphLikeRelationalAttribute = contentTypes.isDynamicZoneAttribute(attribute) || contentTypes.isMorphToRelationalAttribute(attribute);
206
+ if (isMorphLikeRelationalAttribute) {
207
+ const hasInvalidProperties = Object.keys(subPopulate).some((key)=>![
208
+ 'populate',
209
+ 'on',
210
+ 'count'
211
+ ].includes(key));
212
+ if (hasInvalidProperties) {
213
+ throw new Error(`Invalid nested populate for ${schema.info?.singularName}.${key} (${schema.uid}). Expected a fragment ("on") or "count" but found ${JSON.stringify(subPopulate)}`);
214
+ }
215
+ /**
216
+ * Validate nested population queries in the context of a polymorphic attribute (dynamic zone, morph relation).
217
+ *
218
+ * If 'populate' exists in subPopulate, its value should be constrained to a wildcard ('*').
219
+ */ if ('populate' in subPopulate && subPopulate.populate !== '*') {
220
+ throw new Error(`Invalid nested population query detected. When using 'populate' within polymorphic structures, ` + `its value must be '*' to indicate all second level links. Specific field targeting is not supported here. ` + `Consider using the fragment API for more granular population control.`);
221
+ }
222
+ // TODO: Remove the possibility to have multiple properties at the same time (on/count/populate)
223
+ const newSubPopulate = {};
224
+ // case: { populate: '*' }
225
+ if ('populate' in subPopulate) {
226
+ Object.assign(newSubPopulate, {
227
+ populate: true
228
+ });
229
+ }
230
+ // case: { on: { <clauses> } }
231
+ if (hasPopulateFragmentDefined(subPopulate)) {
232
+ // If the fragment API is used, it applies the transformation to every
233
+ // sub-populate, then assign the result to the new sub-populate
234
+ Object.assign(newSubPopulate, {
235
+ on: Object.entries(subPopulate.on).reduce((acc, [type, typeSubPopulate])=>({
236
+ ...acc,
237
+ [type]: convertNestedPopulate(typeSubPopulate, getModel(type))
238
+ }), {})
239
+ });
240
+ }
241
+ // case: { count: true | false }
242
+ if (hasCountDefined(subPopulate)) {
243
+ Object.assign(newSubPopulate, {
244
+ count: subPopulate.count
245
+ });
246
+ }
247
+ return {
248
+ ...acc,
249
+ [key]: newSubPopulate
250
+ };
251
+ }
252
+ // Edge case when trying to use the fragment ('on') on a non-morph like attribute
253
+ if (!isMorphLikeRelationalAttribute && hasPopulateFragmentDefined(subPopulate)) {
254
+ throw new Error(`Using fragments is not permitted to populate "${key}" in "${schema.uid}"`);
255
+ }
256
+ // NOTE: Retrieve the target schema UID.
257
+ // Only handles basic relations, medias and component since it's not possible
258
+ // to populate with options for a dynamic zone or a polymorphic relation
259
+ let targetSchemaUID;
260
+ if (attribute.type === 'relation') {
261
+ targetSchemaUID = attribute.target;
262
+ } else if (attribute.type === 'component') {
263
+ targetSchemaUID = attribute.component;
264
+ } else if (attribute.type === 'media') {
265
+ targetSchemaUID = 'plugin::upload.file';
266
+ } else {
267
+ return acc;
268
+ }
269
+ const targetSchema = getModel(targetSchemaUID);
270
+ // ignore the sub-populate for the current key if there is no schema associated
271
+ if (!targetSchema) {
272
+ return acc;
273
+ }
274
+ const populateObject = convertNestedPopulate(subPopulate, targetSchema);
275
+ if (!populateObject) {
276
+ return acc;
277
+ }
278
+ return {
279
+ ...acc,
280
+ [key]: populateObject
281
+ };
282
+ }, {});
283
+ };
284
+ const convertNestedPopulate = (subPopulate, schema)=>{
285
+ if (_.isString(subPopulate)) {
286
+ return parseType({
287
+ type: 'boolean',
288
+ value: subPopulate,
289
+ forceCast: true
290
+ });
291
+ }
292
+ if (_.isBoolean(subPopulate)) {
293
+ return subPopulate;
294
+ }
295
+ if (!isPlainObject(subPopulate)) {
296
+ throw new Error(`Invalid nested populate. Expected '*' or an object`);
297
+ }
298
+ const { sort, filters, fields, populate, count, ordering, page, pageSize, start, limit } = subPopulate;
299
+ const query = {};
300
+ if (sort) {
301
+ query.orderBy = convertSortQueryParams(sort);
302
+ }
303
+ if (filters) {
304
+ query.where = convertFiltersQueryParams(filters, schema);
305
+ }
306
+ if (fields) {
307
+ query.select = convertFieldsQueryParams(fields, schema);
308
+ }
309
+ if (populate) {
310
+ query.populate = convertPopulateQueryParams(populate, schema);
311
+ }
312
+ if (count) {
313
+ query.count = convertCountQueryParams(count);
314
+ }
315
+ if (ordering) {
316
+ query.ordering = convertOrderingQueryParams(ordering);
317
+ }
318
+ validatePaginationParams(page, pageSize, start, limit);
319
+ if (!fp.isNil(page)) {
320
+ query.page = convertPageQueryParams(page);
321
+ }
322
+ if (!fp.isNil(pageSize)) {
323
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
324
+ }
325
+ if (!fp.isNil(start)) {
326
+ query.offset = convertStartQueryParams(start);
327
+ }
328
+ if (!fp.isNil(limit)) {
329
+ query.limit = convertLimitQueryParams(limit);
330
+ }
331
+ return query;
332
+ };
333
+ // TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)
334
+ const convertFieldsQueryParams = (fields, schema, depth = 0)=>{
335
+ if (depth === 0 && fields === '*') {
336
+ return undefined;
337
+ }
338
+ if (typeof fields === 'string') {
339
+ const fieldsValues = fields.split(',').map((value)=>_.trim(value));
340
+ // NOTE: Only include the doc id if it's a content type
341
+ if (schema?.modelType === 'contentType') {
342
+ return _.uniq([
343
+ ID_ATTRIBUTE,
344
+ DOC_ID_ATTRIBUTE,
345
+ ...fieldsValues
346
+ ]);
347
+ }
348
+ return _.uniq([
349
+ ID_ATTRIBUTE,
350
+ ...fieldsValues
351
+ ]);
352
+ }
353
+ if (isStringArray(fields)) {
354
+ // map convert
355
+ const fieldsValues = fields.flatMap((value)=>convertFieldsQueryParams(value, schema, depth + 1)).filter((v)=>!fp.isNil(v));
356
+ // NOTE: Only include the doc id if it's a content type
357
+ if (schema?.modelType === 'contentType') {
358
+ return _.uniq([
359
+ ID_ATTRIBUTE,
360
+ DOC_ID_ATTRIBUTE,
361
+ ...fieldsValues
362
+ ]);
363
+ }
364
+ return _.uniq([
365
+ ID_ATTRIBUTE,
366
+ ...fieldsValues
367
+ ]);
368
+ }
369
+ throw new Error('Invalid fields parameter. Expected a string or an array of strings');
370
+ };
371
+ const isValidSchemaAttribute = (key, schema)=>{
372
+ if ([
373
+ DOC_ID_ATTRIBUTE,
374
+ ID_ATTRIBUTE
375
+ ].includes(key)) {
376
+ return true;
377
+ }
378
+ if (!schema) {
379
+ return false;
380
+ }
381
+ return Object.keys(schema.attributes).includes(key);
382
+ };
383
+ const convertFiltersQueryParams = (filters, schema)=>{
384
+ // Filters need to be either an array or an object
385
+ // Here we're only checking for 'object' type since typeof [] => object and typeof {} => object
386
+ if (!fp.isObject(filters)) {
387
+ throw new Error('The filters parameter must be an object or an array');
388
+ }
389
+ // Don't mutate the original object
390
+ const filtersCopy = fp.cloneDeep(filters);
391
+ return convertAndSanitizeFilters(filtersCopy, schema);
392
+ };
393
+ const convertAndSanitizeFilters = (filters, schema)=>{
394
+ if (Array.isArray(filters)) {
395
+ return filters// Sanitize each filter
396
+ .map((filter)=>convertAndSanitizeFilters(filter, schema))// Filter out empty filters
397
+ .filter((filter)=>!isPlainObject(filter) || !fp.isEmpty(filter));
398
+ }
399
+ if (!isPlainObject(filters)) {
400
+ return filters;
401
+ }
402
+ const removeOperator = (operator)=>delete filters[operator];
403
+ // Here, `key` can either be an operator or an attribute name
404
+ for (const [key, value] of Object.entries(filters)){
405
+ const attribute = fp.get(key, schema?.attributes);
406
+ const validKey = operators.isOperator(key) || isValidSchemaAttribute(key, schema);
407
+ if (!validKey) {
408
+ removeOperator(key);
409
+ } else if (attribute) {
410
+ // Relations
411
+ if (attribute.type === 'relation') {
412
+ filters[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
413
+ } else if (attribute.type === 'component') {
414
+ filters[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
415
+ } else if (attribute.type === 'media') {
416
+ filters[key] = convertAndSanitizeFilters(value, getModel('plugin::upload.file'));
417
+ } else if (attribute.type === 'dynamiczone') {
418
+ removeOperator(key);
419
+ } else if (attribute.type === 'password') {
420
+ // Always remove password attributes from filters object
421
+ removeOperator(key);
422
+ } else {
423
+ filters[key] = convertAndSanitizeFilters(value, schema);
424
+ }
425
+ } else if ([
426
+ '$null',
427
+ '$notNull'
428
+ ].includes(key)) {
429
+ filters[key] = parseType({
430
+ type: 'boolean',
431
+ value: filters[key],
432
+ forceCast: true
433
+ });
434
+ } else if (fp.isObject(value)) {
435
+ filters[key] = convertAndSanitizeFilters(value, schema);
436
+ }
437
+ // Remove empty objects & arrays
438
+ if (isPlainObject(filters[key]) && fp.isEmpty(filters[key])) {
439
+ removeOperator(key);
440
+ }
441
+ }
442
+ return filters;
443
+ };
444
+ const convertStatusParams = (status, query = {})=>{
445
+ // NOTE: this is the query layer filters not the document/entity service filters
446
+ query.filters = ({ meta })=>{
447
+ const contentType = getModel(meta.uid);
448
+ // Ignore if target model has disabled DP, as it doesn't make sense to filter by its status
449
+ if (!contentType || !contentTypes.hasDraftAndPublish(contentType)) {
450
+ return {};
451
+ }
452
+ return {
453
+ [PUBLISHED_AT_ATTRIBUTE]: {
454
+ $null: status === 'draft'
455
+ }
456
+ };
457
+ };
458
+ };
459
+ const transformQueryParams = (uid, params)=>{
460
+ // NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
461
+ const schema = getModel(uid);
462
+ const query = {};
463
+ const { _q, sort, filters, fields, populate, page, pageSize, start, limit, status, ...rest } = params;
464
+ if (!fp.isNil(status)) {
465
+ convertStatusParams(status, query);
466
+ }
467
+ if (!fp.isNil(_q)) {
468
+ query._q = _q;
469
+ }
470
+ if (!fp.isNil(sort)) {
471
+ query.orderBy = convertSortQueryParams(sort);
472
+ }
473
+ if (!fp.isNil(filters)) {
474
+ query.where = convertFiltersQueryParams(filters, schema);
475
+ }
476
+ if (!fp.isNil(fields)) {
477
+ query.select = convertFieldsQueryParams(fields, schema);
478
+ }
479
+ if (!fp.isNil(populate)) {
480
+ query.populate = convertPopulateQueryParams(populate, schema);
481
+ }
482
+ validatePaginationParams(page, pageSize, start, limit);
483
+ if (!fp.isNil(page)) {
484
+ query.page = convertPageQueryParams(page);
485
+ }
486
+ if (!fp.isNil(pageSize)) {
487
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
488
+ }
489
+ if (!fp.isNil(start)) {
490
+ query.offset = convertStartQueryParams(start);
491
+ }
492
+ if (!fp.isNil(limit)) {
493
+ query.limit = convertLimitQueryParams(limit);
494
+ }
495
+ return {
496
+ ...rest,
497
+ ...query
498
+ };
499
+ };
500
+ return {
501
+ private_convertSortQueryParams: convertSortQueryParams,
502
+ private_convertStartQueryParams: convertStartQueryParams,
503
+ private_convertLimitQueryParams: convertLimitQueryParams,
504
+ private_convertPopulateQueryParams: convertPopulateQueryParams,
505
+ private_convertFiltersQueryParams: convertFiltersQueryParams,
506
+ private_convertFieldsQueryParams: convertFieldsQueryParams,
507
+ transformQueryParams
508
+ };
509
+ };
510
+
511
+ exports.createTransformer = createTransformer;
512
+ //# sourceMappingURL=convert-query-params.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-query-params.js","sources":["../src/convert-query-params.ts"],"sourcesContent":["/* eslint-disable max-classes-per-file */\n\n/**\n * Converts the standard Strapi REST query params to a more usable format for querying\n * You can read more here: https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#filters\n */\n\nimport _ from 'lodash';\nimport {\n cloneDeep,\n get,\n isArray,\n isEmpty,\n isInteger,\n isNil,\n isObject,\n isString,\n toNumber,\n} from 'lodash/fp';\nimport {\n constants,\n hasDraftAndPublish,\n isDynamicZoneAttribute,\n isMorphToRelationalAttribute,\n} from './content-types';\nimport { PaginationError } from './errors';\nimport { isOperator } from './operators';\n\nimport parseType from './parse-type';\nimport { Model } from './types';\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, PUBLISHED_AT_ATTRIBUTE } = constants;\n\ntype SortOrder = 'asc' | 'desc';\n\nexport interface SortMap {\n [key: string]: SortOrder | SortMap;\n}\n\nexport interface SortParamsObject {\n [key: string]: SortOrder | SortParamsObject;\n}\n\ntype SortParams = string | string[] | SortParamsObject | SortParamsObject[];\ntype FieldsParams = string | string[];\n\ntype FiltersParams = unknown;\n\nexport interface PopulateAttributesParams {\n [key: string]: boolean | PopulateObjectParams;\n}\n\nexport interface PopulateObjectParams {\n sort?: SortParams;\n fields?: FieldsParams;\n filters?: FiltersParams;\n populate?: string | string[] | PopulateAttributesParams;\n on?: PopulateAttributesParams;\n count?: boolean;\n ordering?: unknown;\n _q?: string;\n limit?: number | string;\n start?: number | string;\n page?: number | string;\n pageSize?: number | string;\n}\n\ntype PopulateParams = string | string[] | PopulateAttributesParams;\n\nexport interface Params {\n sort?: SortParams;\n fields?: FieldsParams;\n filters?: FiltersParams;\n populate?: PopulateParams;\n count?: boolean;\n ordering?: unknown;\n _q?: string;\n limit?: number | string;\n start?: number | string;\n page?: number | string;\n pageSize?: number | string;\n status?: 'draft' | 'published';\n}\n\ntype FiltersQuery = (options: { meta: Model }) => WhereQuery | undefined;\ntype OrderByQuery = SortMap | SortMap[];\ntype SelectQuery = string | string[];\n\nexport interface WhereQuery {\n [key: string]: any;\n}\n\ntype PopulateQuery =\n | boolean\n | string[]\n | {\n [key: string]: PopulateQuery;\n };\n\nexport interface Query {\n orderBy?: OrderByQuery;\n select?: SelectQuery;\n where?: WhereQuery;\n // NOTE: those are internal DB filters do not modify\n filters?: FiltersQuery;\n populate?: PopulateQuery;\n count?: boolean;\n ordering?: unknown;\n _q?: string;\n limit?: number;\n offset?: number;\n page?: number;\n pageSize?: number;\n}\n\nclass InvalidOrderError extends Error {\n constructor() {\n super();\n this.message = 'Invalid order. order can only be one of asc|desc|ASC|DESC';\n }\n}\n\nclass InvalidSortError extends Error {\n constructor() {\n super();\n this.message =\n 'Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects';\n }\n}\n\nfunction validateOrder(order: string): asserts order is SortOrder {\n if (!isString(order) || !['asc', 'desc'].includes(order.toLocaleLowerCase())) {\n throw new InvalidOrderError();\n }\n}\n\nconst convertCountQueryParams = (countQuery: unknown): boolean => {\n return parseType({ type: 'boolean', value: countQuery });\n};\n\nconst convertOrderingQueryParams = (ordering: unknown) => {\n return ordering;\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => _.isPlainObject(value);\nconst isStringArray = (value: unknown): value is string[] =>\n isArray(value) && value.every(isString);\n\ninterface TransformerOptions {\n getModel: (uid: string) => Model | undefined;\n}\n\nconst createTransformer = ({ getModel }: TransformerOptions) => {\n /**\n * Sort query parser\n */\n const convertSortQueryParams = (sortQuery: SortParams): OrderByQuery => {\n if (typeof sortQuery === 'string') {\n return convertStringSortQueryParam(sortQuery);\n }\n\n if (isStringArray(sortQuery)) {\n return sortQuery.flatMap((sortValue: string) => convertStringSortQueryParam(sortValue));\n }\n\n if (Array.isArray(sortQuery)) {\n return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));\n }\n\n if (isPlainObject(sortQuery)) {\n return convertNestedSortQueryParam(sortQuery);\n }\n\n throw new InvalidSortError();\n };\n\n const convertStringSortQueryParam = (sortQuery: string): SortMap[] => {\n return sortQuery.split(',').map((value) => convertSingleSortQueryParam(value));\n };\n\n const convertSingleSortQueryParam = (sortQuery: string): SortMap => {\n if (!sortQuery) {\n return {};\n }\n\n if (!isString(sortQuery)) {\n throw new Error('Invalid sort query');\n }\n\n // split field and order param with default order to ascending\n const [field, order = 'asc'] = sortQuery.split(':');\n\n if (field.length === 0) {\n throw new Error('Field cannot be empty');\n }\n\n validateOrder(order);\n\n // TODO: field should be a valid path on an object model\n\n return _.set({}, field, order);\n };\n\n const convertNestedSortQueryParam = (sortQuery: SortParamsObject): SortMap => {\n const transformedSort: SortMap = {};\n for (const field of Object.keys(sortQuery)) {\n const order = sortQuery[field];\n\n // this is a deep sort\n if (isPlainObject(order)) {\n transformedSort[field] = convertNestedSortQueryParam(order);\n } else if (typeof order === 'string') {\n validateOrder(order);\n transformedSort[field] = order;\n } else {\n throw Error(`Invalid sort type expected object or string got ${typeof order}`);\n }\n }\n\n return transformedSort;\n };\n\n /**\n * Start query parser\n */\n const convertStartQueryParams = (startQuery: unknown): number => {\n const startAsANumber = toNumber(startQuery);\n\n if (!_.isInteger(startAsANumber) || startAsANumber < 0) {\n throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);\n }\n\n return startAsANumber;\n };\n\n /**\n * Limit query parser\n */\n const convertLimitQueryParams = (limitQuery: unknown): number | undefined => {\n const limitAsANumber = toNumber(limitQuery);\n\n if (!_.isInteger(limitAsANumber) || (limitAsANumber !== -1 && limitAsANumber < 0)) {\n throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);\n }\n\n if (limitAsANumber === -1) {\n return undefined;\n }\n\n return limitAsANumber;\n };\n\n const convertPageQueryParams = (page: unknown): number => {\n const pageVal = toNumber(page);\n\n if (!isInteger(pageVal) || pageVal <= 0) {\n throw new PaginationError(\n `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`\n );\n }\n\n return pageVal;\n };\n\n const convertPageSizeQueryParams = (pageSize: unknown, page: unknown): number => {\n const pageSizeVal = toNumber(pageSize);\n\n if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {\n throw new PaginationError(\n `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`\n );\n }\n\n return pageSizeVal;\n };\n\n const validatePaginationParams = (\n page: unknown,\n pageSize: unknown,\n start: unknown,\n limit: unknown\n ) => {\n const isPagePagination = !isNil(page) || !isNil(pageSize);\n const isOffsetPagination = !isNil(start) || !isNil(limit);\n\n if (isPagePagination && isOffsetPagination) {\n throw new PaginationError(\n 'Invalid pagination attributes. The page parameters are incorrect and must be in the pagination object'\n );\n }\n };\n\n class InvalidPopulateError extends Error {\n constructor() {\n super();\n this.message =\n 'Invalid populate parameter. Expected a string, an array of strings, a populate object';\n }\n }\n\n // NOTE: we could support foo.* or foo.bar.* etc later on\n const convertPopulateQueryParams = (\n populate: PopulateParams,\n schema?: Model,\n depth = 0\n ): PopulateQuery => {\n if (depth === 0 && populate === '*') {\n return true;\n }\n\n if (typeof populate === 'string') {\n return populate.split(',').map((value) => _.trim(value));\n }\n\n if (Array.isArray(populate)) {\n // map convert\n return _.uniq(\n populate.flatMap((value) => {\n if (typeof value !== 'string') {\n throw new InvalidPopulateError();\n }\n\n return value.split(',').map((value) => _.trim(value));\n })\n );\n }\n\n if (_.isPlainObject(populate)) {\n return convertPopulateObject(populate, schema);\n }\n\n throw new InvalidPopulateError();\n };\n\n const hasPopulateFragmentDefined = (\n populate: PopulateObjectParams\n ): populate is PopulateObjectParams & Required<Pick<PopulateObjectParams, 'on'>> => {\n return typeof populate === 'object' && 'on' in populate && !isNil(populate.on);\n };\n\n const hasCountDefined = (\n populate: PopulateObjectParams\n ): populate is PopulateObjectParams & { count: boolean } => {\n return (\n typeof populate === 'object' && 'count' in populate && typeof populate.count === 'boolean'\n );\n };\n\n const convertPopulateObject = (populate: PopulateAttributesParams, schema?: Model) => {\n if (!schema) {\n return {};\n }\n\n const { attributes } = schema;\n return Object.entries(populate).reduce((acc, [key, subPopulate]) => {\n // Try converting strings to regular booleans if possible\n if (_.isString(subPopulate)) {\n try {\n const subPopulateAsBoolean = parseType({ type: 'boolean', value: subPopulate });\n // Only true is accepted as a boolean populate value\n return subPopulateAsBoolean ? { ...acc, [key]: true } : acc;\n } catch {\n // ignore\n }\n }\n\n if (_.isBoolean(subPopulate)) {\n // Only true is accepted as a boolean populate value\n return subPopulate === true ? { ...acc, [key]: true } : acc;\n }\n\n const attribute = attributes[key];\n\n if (!attribute) {\n return acc;\n }\n\n // Allow adding an 'on' strategy to populate queries for morphTo relations and dynamic zones\n const isMorphLikeRelationalAttribute =\n isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);\n\n if (isMorphLikeRelationalAttribute) {\n const hasInvalidProperties = Object.keys(subPopulate).some(\n (key) => !['populate', 'on', 'count'].includes(key)\n );\n\n if (hasInvalidProperties) {\n throw new Error(\n `Invalid nested populate for ${schema.info?.singularName}.${key} (${schema.uid}). Expected a fragment (\"on\") or \"count\" but found ${JSON.stringify(subPopulate)}`\n );\n }\n\n /**\n * Validate nested population queries in the context of a polymorphic attribute (dynamic zone, morph relation).\n *\n * If 'populate' exists in subPopulate, its value should be constrained to a wildcard ('*').\n */\n if ('populate' in subPopulate && subPopulate.populate !== '*') {\n throw new Error(\n `Invalid nested population query detected. When using 'populate' within polymorphic structures, ` +\n `its value must be '*' to indicate all second level links. Specific field targeting is not supported here. ` +\n `Consider using the fragment API for more granular population control.`\n );\n }\n\n // TODO: Remove the possibility to have multiple properties at the same time (on/count/populate)\n const newSubPopulate = {};\n\n // case: { populate: '*' }\n if ('populate' in subPopulate) {\n Object.assign(newSubPopulate, { populate: true });\n }\n\n // case: { on: { <clauses> } }\n if (hasPopulateFragmentDefined(subPopulate)) {\n // If the fragment API is used, it applies the transformation to every\n // sub-populate, then assign the result to the new sub-populate\n Object.assign(newSubPopulate, {\n on: Object.entries(subPopulate.on).reduce(\n (acc, [type, typeSubPopulate]) => ({\n ...acc,\n [type]: convertNestedPopulate(typeSubPopulate, getModel(type)),\n }),\n {}\n ),\n });\n }\n\n // case: { count: true | false }\n if (hasCountDefined(subPopulate)) {\n Object.assign(newSubPopulate, { count: subPopulate.count });\n }\n\n return { ...acc, [key]: newSubPopulate };\n }\n\n // Edge case when trying to use the fragment ('on') on a non-morph like attribute\n if (!isMorphLikeRelationalAttribute && hasPopulateFragmentDefined(subPopulate)) {\n throw new Error(`Using fragments is not permitted to populate \"${key}\" in \"${schema.uid}\"`);\n }\n\n // NOTE: Retrieve the target schema UID.\n // Only handles basic relations, medias and component since it's not possible\n // to populate with options for a dynamic zone or a polymorphic relation\n let targetSchemaUID;\n\n if (attribute.type === 'relation') {\n targetSchemaUID = attribute.target;\n } else if (attribute.type === 'component') {\n targetSchemaUID = attribute.component;\n } else if (attribute.type === 'media') {\n targetSchemaUID = 'plugin::upload.file';\n } else {\n return acc;\n }\n\n const targetSchema = getModel(targetSchemaUID!);\n\n // ignore the sub-populate for the current key if there is no schema associated\n if (!targetSchema) {\n return acc;\n }\n\n const populateObject = convertNestedPopulate(subPopulate, targetSchema);\n\n if (!populateObject) {\n return acc;\n }\n\n return {\n ...acc,\n [key]: populateObject,\n };\n }, {});\n };\n\n const convertNestedPopulate = (subPopulate: boolean | PopulateObjectParams, schema?: Model) => {\n if (_.isString(subPopulate)) {\n return parseType({ type: 'boolean', value: subPopulate, forceCast: true });\n }\n\n if (_.isBoolean(subPopulate)) {\n return subPopulate;\n }\n\n if (!isPlainObject(subPopulate)) {\n throw new Error(`Invalid nested populate. Expected '*' or an object`);\n }\n\n const { sort, filters, fields, populate, count, ordering, page, pageSize, start, limit } =\n subPopulate as PopulateObjectParams;\n\n const query: Query = {};\n\n if (sort) {\n query.orderBy = convertSortQueryParams(sort);\n }\n\n if (filters) {\n query.where = convertFiltersQueryParams(filters, schema);\n }\n\n if (fields) {\n query.select = convertFieldsQueryParams(fields, schema);\n }\n\n if (populate) {\n query.populate = convertPopulateQueryParams(populate, schema);\n }\n\n if (count) {\n query.count = convertCountQueryParams(count);\n }\n\n if (ordering) {\n query.ordering = convertOrderingQueryParams(ordering);\n }\n\n validatePaginationParams(page, pageSize, start, limit);\n\n if (!isNil(page)) {\n query.page = convertPageQueryParams(page);\n }\n\n if (!isNil(pageSize)) {\n query.pageSize = convertPageSizeQueryParams(pageSize, page);\n }\n\n if (!isNil(start)) {\n query.offset = convertStartQueryParams(start);\n }\n\n if (!isNil(limit)) {\n query.limit = convertLimitQueryParams(limit);\n }\n\n return query;\n };\n\n // TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)\n const convertFieldsQueryParams = (\n fields: FieldsParams,\n schema?: Model,\n depth = 0\n ): SelectQuery | undefined => {\n if (depth === 0 && fields === '*') {\n return undefined;\n }\n\n if (typeof fields === 'string') {\n const fieldsValues = fields.split(',').map((value) => _.trim(value));\n\n // NOTE: Only include the doc id if it's a content type\n if (schema?.modelType === 'contentType') {\n return _.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);\n }\n return _.uniq([ID_ATTRIBUTE, ...fieldsValues]);\n }\n\n if (isStringArray(fields)) {\n // map convert\n const fieldsValues = fields\n .flatMap((value) => convertFieldsQueryParams(value, schema, depth + 1))\n .filter((v) => !isNil(v)) as string[];\n\n // NOTE: Only include the doc id if it's a content type\n if (schema?.modelType === 'contentType') {\n return _.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);\n }\n return _.uniq([ID_ATTRIBUTE, ...fieldsValues]);\n }\n\n throw new Error('Invalid fields parameter. Expected a string or an array of strings');\n };\n\n const isValidSchemaAttribute = (key: string, schema?: Model) => {\n if ([DOC_ID_ATTRIBUTE, ID_ATTRIBUTE].includes(key)) {\n return true;\n }\n\n if (!schema) {\n return false;\n }\n\n return Object.keys(schema.attributes).includes(key);\n };\n\n const convertFiltersQueryParams = (filters: FiltersParams, schema?: Model): WhereQuery => {\n // Filters need to be either an array or an object\n // Here we're only checking for 'object' type since typeof [] => object and typeof {} => object\n if (!isObject(filters)) {\n throw new Error('The filters parameter must be an object or an array');\n }\n\n // Don't mutate the original object\n const filtersCopy = cloneDeep(filters);\n\n return convertAndSanitizeFilters(filtersCopy, schema);\n };\n\n const convertAndSanitizeFilters = (filters: FiltersParams, schema?: Model): WhereQuery => {\n if (Array.isArray(filters)) {\n return (\n filters\n // Sanitize each filter\n .map((filter) => convertAndSanitizeFilters(filter, schema))\n // Filter out empty filters\n .filter((filter) => !isPlainObject(filter) || !isEmpty(filter))\n );\n }\n\n if (!isPlainObject(filters)) {\n return filters as WhereQuery;\n }\n\n const removeOperator = (operator: string) => delete filters[operator];\n\n // Here, `key` can either be an operator or an attribute name\n for (const [key, value] of Object.entries(filters)) {\n const attribute = get(key, schema?.attributes);\n const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);\n\n if (!validKey) {\n removeOperator(key);\n }\n // Handle attributes\n else if (attribute) {\n // Relations\n if (attribute.type === 'relation') {\n filters[key] = convertAndSanitizeFilters(value, getModel(attribute.target!));\n }\n\n // Components\n else if (attribute.type === 'component') {\n filters[key] = convertAndSanitizeFilters(value, getModel(attribute.component));\n }\n\n // Media\n else if (attribute.type === 'media') {\n filters[key] = convertAndSanitizeFilters(value, getModel('plugin::upload.file'));\n }\n\n // Dynamic Zones\n else if (attribute.type === 'dynamiczone') {\n removeOperator(key);\n }\n\n // Password attributes\n else if (attribute.type === 'password') {\n // Always remove password attributes from filters object\n removeOperator(key);\n }\n\n // Scalar attributes\n else {\n filters[key] = convertAndSanitizeFilters(value, schema);\n }\n }\n\n // Handle operators\n else if (['$null', '$notNull'].includes(key)) {\n filters[key] = parseType({ type: 'boolean', value: filters[key], forceCast: true });\n } else if (isObject(value)) {\n filters[key] = convertAndSanitizeFilters(value, schema);\n }\n\n // Remove empty objects & arrays\n if (isPlainObject(filters[key]) && isEmpty(filters[key])) {\n removeOperator(key);\n }\n }\n\n return filters;\n };\n\n const convertStatusParams = (status?: 'draft' | 'published', query: Query = {}) => {\n // NOTE: this is the query layer filters not the document/entity service filters\n query.filters = ({ meta }: { meta: Model }) => {\n const contentType = getModel(meta.uid);\n\n // Ignore if target model has disabled DP, as it doesn't make sense to filter by its status\n if (!contentType || !hasDraftAndPublish(contentType)) {\n return {};\n }\n\n return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === 'draft' } };\n };\n };\n\n const transformQueryParams = (uid: string, params: Params): Query => {\n // NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)\n const schema = getModel(uid);\n\n const query: Query = {};\n\n const { _q, sort, filters, fields, populate, page, pageSize, start, limit, status, ...rest } =\n params;\n\n if (!isNil(status)) {\n convertStatusParams(status, query);\n }\n\n if (!isNil(_q)) {\n query._q = _q;\n }\n\n if (!isNil(sort)) {\n query.orderBy = convertSortQueryParams(sort);\n }\n\n if (!isNil(filters)) {\n query.where = convertFiltersQueryParams(filters, schema);\n }\n\n if (!isNil(fields)) {\n query.select = convertFieldsQueryParams(fields, schema);\n }\n\n if (!isNil(populate)) {\n query.populate = convertPopulateQueryParams(populate, schema);\n }\n\n validatePaginationParams(page, pageSize, start, limit);\n\n if (!isNil(page)) {\n query.page = convertPageQueryParams(page);\n }\n\n if (!isNil(pageSize)) {\n query.pageSize = convertPageSizeQueryParams(pageSize, page);\n }\n\n if (!isNil(start)) {\n query.offset = convertStartQueryParams(start);\n }\n\n if (!isNil(limit)) {\n query.limit = convertLimitQueryParams(limit);\n }\n\n return {\n ...rest,\n ...query,\n };\n };\n\n return {\n private_convertSortQueryParams: convertSortQueryParams,\n private_convertStartQueryParams: convertStartQueryParams,\n private_convertLimitQueryParams: convertLimitQueryParams,\n private_convertPopulateQueryParams: convertPopulateQueryParams,\n private_convertFiltersQueryParams: convertFiltersQueryParams,\n private_convertFieldsQueryParams: convertFieldsQueryParams,\n transformQueryParams,\n };\n};\n\nexport { createTransformer };\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","PUBLISHED_AT_ATTRIBUTE","constants","InvalidOrderError","Error","constructor","message","InvalidSortError","validateOrder","order","isString","includes","toLocaleLowerCase","convertCountQueryParams","countQuery","parseType","type","value","convertOrderingQueryParams","ordering","isPlainObject","_","isStringArray","isArray","every","createTransformer","getModel","convertSortQueryParams","sortQuery","convertStringSortQueryParam","flatMap","sortValue","Array","map","convertNestedSortQueryParam","split","convertSingleSortQueryParam","field","length","set","transformedSort","Object","keys","convertStartQueryParams","startQuery","startAsANumber","toNumber","isInteger","convertLimitQueryParams","limitQuery","limitAsANumber","undefined","convertPageQueryParams","page","pageVal","PaginationError","convertPageSizeQueryParams","pageSize","pageSizeVal","validatePaginationParams","start","limit","isPagePagination","isNil","isOffsetPagination","InvalidPopulateError","convertPopulateQueryParams","populate","schema","depth","trim","uniq","convertPopulateObject","hasPopulateFragmentDefined","on","hasCountDefined","count","attributes","entries","reduce","acc","key","subPopulate","subPopulateAsBoolean","isBoolean","attribute","isMorphLikeRelationalAttribute","isDynamicZoneAttribute","isMorphToRelationalAttribute","hasInvalidProperties","some","info","singularName","uid","JSON","stringify","newSubPopulate","assign","typeSubPopulate","convertNestedPopulate","targetSchemaUID","target","component","targetSchema","populateObject","forceCast","sort","filters","fields","query","orderBy","where","convertFiltersQueryParams","select","convertFieldsQueryParams","offset","fieldsValues","modelType","filter","v","isValidSchemaAttribute","isObject","filtersCopy","cloneDeep","convertAndSanitizeFilters","isEmpty","removeOperator","operator","get","validKey","isOperator","convertStatusParams","status","meta","contentType","hasDraftAndPublish","$null","transformQueryParams","params","_q","rest","private_convertSortQueryParams","private_convertStartQueryParams","private_convertLimitQueryParams","private_convertPopulateQueryParams","private_convertFiltersQueryParams","private_convertFieldsQueryParams"],"mappings":"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"}