@strapi/utils 4.1.1 → 4.2.0-alpha.O

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.
@@ -124,7 +124,7 @@ class InvalidPopulateError extends Error {
124
124
  }
125
125
 
126
126
  // NOTE: we could support foo.* or foo.bar.* etc later on
127
- const convertPopulateQueryParams = (populate, depth = 0) => {
127
+ const convertPopulateQueryParams = (populate, schema, depth = 0) => {
128
128
  if (depth === 0 && populate === '*') {
129
129
  return true;
130
130
  }
@@ -147,18 +147,72 @@ const convertPopulateQueryParams = (populate, depth = 0) => {
147
147
  }
148
148
 
149
149
  if (_.isPlainObject(populate)) {
150
- const transformedPopulate = {};
151
- for (const key in populate) {
152
- transformedPopulate[key] = convertNestedPopulate(populate[key]);
153
- }
154
-
155
- return transformedPopulate;
150
+ return convertPopulateObject(populate, schema);
156
151
  }
157
152
 
158
153
  throw new InvalidPopulateError();
159
154
  };
160
155
 
161
- const convertNestedPopulate = subPopulate => {
156
+ const convertPopulateObject = (populate, schema) => {
157
+ if (!schema) {
158
+ return {};
159
+ }
160
+
161
+ const { attributes } = schema;
162
+
163
+ return Object.entries(populate).reduce((acc, [key, subPopulate]) => {
164
+ const attribute = attributes[key];
165
+
166
+ if (!attribute) {
167
+ return acc;
168
+ }
169
+
170
+ // FIXME: This is a temporary solution for dynamic zones that should be
171
+ // fixed when we'll implement a more accurate way to query them
172
+ if (attribute.type === 'dynamiczone') {
173
+ const generatedFakeDynamicZoneSchema = {
174
+ uid: `${schema.uid}.${key}`,
175
+ attributes: attribute.components
176
+ .sort()
177
+ .map(uid => strapi.getModel(uid).attributes)
178
+ .reduce((acc, componentAttributes) => ({ ...acc, ...componentAttributes }), {}),
179
+ };
180
+
181
+ return {
182
+ ...acc,
183
+ [key]: convertNestedPopulate(subPopulate, generatedFakeDynamicZoneSchema),
184
+ };
185
+ }
186
+
187
+ // NOTE: Retrieve the target schema UID.
188
+ // Only handles basic relations, medias and component since it's not possible
189
+ // to populate with options for a dynamic zone or a polymorphic relation
190
+ let targetSchemaUID;
191
+
192
+ if (attribute.type === 'relation') {
193
+ targetSchemaUID = attribute.target;
194
+ } else if (attribute.type === 'component') {
195
+ targetSchemaUID = attribute.component;
196
+ } else if (attribute.type === 'media') {
197
+ targetSchemaUID = 'plugin::upload.file';
198
+ } else {
199
+ return acc;
200
+ }
201
+
202
+ const targetSchema = strapi.getModel(targetSchemaUID);
203
+
204
+ if (!targetSchema) {
205
+ return acc;
206
+ }
207
+
208
+ return {
209
+ ...acc,
210
+ [key]: convertNestedPopulate(subPopulate, targetSchema),
211
+ };
212
+ }, {});
213
+ };
214
+
215
+ const convertNestedPopulate = (subPopulate, schema) => {
162
216
  if (subPopulate === '*') {
163
217
  return true;
164
218
  }
@@ -181,7 +235,7 @@ const convertNestedPopulate = subPopulate => {
181
235
  }
182
236
 
183
237
  if (filters) {
184
- query.where = convertFiltersQueryParams(filters);
238
+ query.where = convertFiltersQueryParams(filters, schema);
185
239
  }
186
240
 
187
241
  if (fields) {
@@ -189,7 +243,7 @@ const convertNestedPopulate = subPopulate => {
189
243
  }
190
244
 
191
245
  if (populate) {
192
- query.populate = convertPopulateQueryParams(populate);
246
+ query.populate = convertPopulateQueryParams(populate, schema);
193
247
  }
194
248
 
195
249
  if (count) {
@@ -250,7 +304,7 @@ const convertAndSanitizeFilters = (filters, schema) => {
250
304
 
251
305
  // Here, `key` can either be an operator or an attribute name
252
306
  for (const [key, value] of Object.entries(filters)) {
253
- const attribute = get('key', schema.attributes);
307
+ const attribute = get(key, schema.attributes);
254
308
 
255
309
  // Handle attributes
256
310
  if (attribute) {
@@ -280,7 +334,7 @@ const convertAndSanitizeFilters = (filters, schema) => {
280
334
  if (attribute.type === 'password') {
281
335
  removeOperator(key);
282
336
  } else {
283
- filters[key] = convertAndSanitizeFilters(value);
337
+ filters[key] = convertAndSanitizeFilters(value, schema);
284
338
  }
285
339
  }
286
340
  }
package/lib/index.js CHANGED
@@ -19,6 +19,8 @@ const {
19
19
  stringEquals,
20
20
  isKebabCase,
21
21
  isCamelCase,
22
+ toRegressedEnumValue,
23
+ startsWithANumber,
22
24
  } = require('./string-formatting');
23
25
  const { removeUndefined } = require('./object-formatting');
24
26
  const { getConfigUrls, getAbsoluteAdminUrl, getAbsoluteServerUrl } = require('./config');
@@ -47,6 +49,8 @@ module.exports = {
47
49
  traverseEntity,
48
50
  parseType,
49
51
  nameToSlug,
52
+ toRegressedEnumValue,
53
+ startsWithANumber,
50
54
  nameToCollectionName,
51
55
  getCommonBeginning,
52
56
  getConfigUrls,
@@ -2,6 +2,7 @@
2
2
 
3
3
  const ACTIONS_TO_VERIFY = ['find'];
4
4
 
5
+ // FIXME: Support populating creator fields
5
6
  module.exports = auth => async ({ data, key, attribute }, { remove, set }) => {
6
7
  const isRelation = attribute.type === 'relation';
7
8
 
@@ -6,6 +6,13 @@ const nameToSlug = (name, options = { separator: '-' }) => slugify(name, options
6
6
 
7
7
  const nameToCollectionName = name => slugify(name, { separator: '_' });
8
8
 
9
+ const toRegressedEnumValue = value =>
10
+ slugify(value, {
11
+ decamelize: false,
12
+ lowercase: false,
13
+ separator: '_',
14
+ });
15
+
9
16
  const getCommonBeginning = (...strings) =>
10
17
  _.takeWhile(strings[0], (char, index) => strings.every(string => string[index] === char)).join(
11
18
  ''
@@ -35,6 +42,7 @@ const stringIncludes = (arr, val) => arr.map(String).includes(String(val));
35
42
  const stringEquals = (a, b) => String(a) === String(b);
36
43
  const isCamelCase = value => /^[a-z][a-zA-Z0-9]+$/.test(value);
37
44
  const isKebabCase = value => /^([a-z][a-z0-9]*)(-[a-z0-9]+)*$/.test(value);
45
+ const startsWithANumber = value => /^[0-9]/.test(value);
38
46
 
39
47
  module.exports = {
40
48
  nameToSlug,
@@ -46,4 +54,6 @@ module.exports = {
46
54
  stringEquals,
47
55
  isCamelCase,
48
56
  isKebabCase,
57
+ toRegressedEnumValue,
58
+ startsWithANumber,
49
59
  };
@@ -41,6 +41,7 @@ const traverseEntity = async (visitor, options, entity) => {
41
41
  const isRelation = attribute.type === 'relation';
42
42
  const isComponent = attribute.type === 'component';
43
43
  const isDynamicZone = attribute.type === 'dynamiczone';
44
+ const isMedia = attribute.type === 'media';
44
45
 
45
46
  if (isRelation) {
46
47
  const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
@@ -61,6 +62,22 @@ const traverseEntity = async (visitor, options, entity) => {
61
62
  : await traverseTarget(value);
62
63
  }
63
64
 
65
+ if (isMedia) {
66
+ const traverseTarget = entry => {
67
+ const targetSchemaUID = 'plugin::upload.file';
68
+ const targetSchema = strapi.getModel(targetSchemaUID);
69
+
70
+ const traverseOptions = { schema: targetSchema, path: newPath };
71
+
72
+ return traverseEntity(visitor, traverseOptions, entry);
73
+ };
74
+
75
+ // need to update copy
76
+ copy[key] = isArray(value)
77
+ ? await Promise.all(value.map(traverseTarget))
78
+ : await traverseTarget(value);
79
+ }
80
+
64
81
  if (isComponent) {
65
82
  const targetSchema = strapi.getModel(attribute.component);
66
83
  const traverseOptions = { schema: targetSchema, path: newPath };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/utils",
3
- "version": "4.1.1",
3
+ "version": "4.2.0-alpha.O",
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": "3a4db96af2a2d3fa54fe04bd09b1a4bf364caf3c"
48
+ "gitHead": "0e1f1ae08565a5f2427753582f37645a43c00cb2"
49
49
  }