@strapi/plugin-graphql 4.0.0-next.9 → 4.0.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 (122) hide show
  1. package/README.md +1 -1
  2. package/admin/src/index.js +0 -8
  3. package/package.json +39 -34
  4. package/server/bootstrap.js +148 -0
  5. package/server/config/default-config.js +13 -0
  6. package/server/config/index.js +7 -0
  7. package/server/format-graphql-error.js +50 -0
  8. package/server/services/builders/dynamic-zones.js +97 -0
  9. package/server/services/builders/entity-meta.js +7 -0
  10. package/server/services/builders/entity.js +43 -0
  11. package/server/services/builders/enums.js +24 -0
  12. package/server/services/builders/filters/content-type.js +93 -0
  13. package/server/services/builders/filters/index.js +7 -0
  14. package/server/services/builders/filters/operators/and.js +15 -0
  15. package/server/services/builders/filters/operators/between.js +15 -0
  16. package/server/services/builders/filters/operators/contains.js +13 -0
  17. package/server/services/builders/filters/operators/containsi.js +13 -0
  18. package/server/services/builders/filters/operators/ends-with.js +13 -0
  19. package/server/services/builders/filters/operators/eq.js +23 -0
  20. package/server/services/builders/filters/operators/gt.js +13 -0
  21. package/server/services/builders/filters/operators/gte.js +13 -0
  22. package/server/services/builders/filters/operators/in.js +15 -0
  23. package/server/services/builders/filters/operators/index.js +38 -0
  24. package/server/services/builders/filters/operators/lt.js +13 -0
  25. package/server/services/builders/filters/operators/lte.js +13 -0
  26. package/server/services/builders/filters/operators/ne.js +13 -0
  27. package/server/services/builders/filters/operators/not-contains.js +13 -0
  28. package/server/services/builders/filters/operators/not-containsi.js +13 -0
  29. package/server/services/builders/filters/operators/not-in.js +15 -0
  30. package/server/services/builders/filters/operators/not-null.js +13 -0
  31. package/server/services/builders/filters/operators/not.js +19 -0
  32. package/server/services/builders/filters/operators/null.js +13 -0
  33. package/server/services/builders/filters/operators/or.js +15 -0
  34. package/server/services/builders/filters/operators/starts-with.js +13 -0
  35. package/server/services/builders/generic-morph.js +41 -0
  36. package/server/services/builders/index.js +92 -0
  37. package/server/services/builders/input.js +121 -0
  38. package/server/services/builders/mutations/collection-type.js +191 -0
  39. package/server/services/builders/mutations/index.js +9 -0
  40. package/server/services/builders/mutations/single-type.js +141 -0
  41. package/server/services/builders/queries/collection-type.js +120 -0
  42. package/server/services/builders/queries/index.js +9 -0
  43. package/server/services/builders/queries/single-type.js +70 -0
  44. package/server/services/builders/relation-response-collection.js +35 -0
  45. package/server/services/builders/resolvers/association.js +85 -0
  46. package/server/services/builders/resolvers/component.js +18 -0
  47. package/server/services/builders/resolvers/dynamic-zone.js +9 -0
  48. package/server/services/builders/resolvers/index.js +18 -0
  49. package/server/services/builders/resolvers/mutation.js +33 -0
  50. package/server/services/builders/resolvers/query.js +19 -0
  51. package/server/services/builders/response-collection.js +43 -0
  52. package/server/services/builders/response.js +32 -0
  53. package/server/services/builders/type.js +364 -0
  54. package/server/services/builders/utils.js +134 -0
  55. package/server/services/constants.js +147 -0
  56. package/server/services/content-api/index.js +179 -0
  57. package/server/services/content-api/policy.js +60 -0
  58. package/server/services/content-api/register-functions/collection-type.js +72 -0
  59. package/server/services/content-api/register-functions/component.js +15 -0
  60. package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
  61. package/server/services/content-api/register-functions/content-type/enums.js +33 -0
  62. package/server/services/content-api/register-functions/content-type/filters.js +15 -0
  63. package/server/services/content-api/register-functions/content-type/index.js +13 -0
  64. package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
  65. package/server/services/content-api/register-functions/index.js +22 -0
  66. package/server/services/content-api/register-functions/internals.js +13 -0
  67. package/server/services/content-api/register-functions/polymorphic.js +69 -0
  68. package/server/services/content-api/register-functions/scalars.js +14 -0
  69. package/server/services/content-api/register-functions/single-type.js +72 -0
  70. package/server/services/content-api/wrap-resolvers.js +144 -0
  71. package/server/services/extension/extension.js +95 -0
  72. package/server/services/extension/index.js +5 -0
  73. package/server/services/extension/shadow-crud-manager.js +159 -0
  74. package/server/services/format/index.js +7 -0
  75. package/server/services/format/return-types.js +27 -0
  76. package/server/services/index.js +21 -0
  77. package/server/services/internals/args/index.js +11 -0
  78. package/server/services/internals/args/pagination.js +19 -0
  79. package/server/services/internals/args/publication-state.js +12 -0
  80. package/server/services/internals/args/sort.js +10 -0
  81. package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
  82. package/server/services/internals/helpers/index.js +7 -0
  83. package/server/services/internals/index.js +13 -0
  84. package/server/services/internals/scalars/index.js +18 -0
  85. package/server/services/internals/scalars/time.js +36 -0
  86. package/server/services/internals/types/error.js +34 -0
  87. package/server/services/internals/types/filters.js +39 -0
  88. package/server/services/internals/types/index.js +29 -0
  89. package/server/services/internals/types/pagination.js +24 -0
  90. package/server/services/internals/types/publication-state.js +24 -0
  91. package/server/services/internals/types/response-collection-meta.js +38 -0
  92. package/server/services/type-registry.js +104 -0
  93. package/server/services/utils/attributes.js +84 -0
  94. package/server/services/utils/index.js +11 -0
  95. package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
  96. package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +109 -0
  97. package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
  98. package/server/services/utils/mappers/index.js +13 -0
  99. package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +25 -0
  100. package/server/services/utils/naming.js +287 -0
  101. package/strapi-admin.js +3 -0
  102. package/strapi-server.js +7 -9
  103. package/admin/src/assets/images/logo.svg +0 -38
  104. package/config/routes.json +0 -3
  105. package/config/schema.graphql +0 -1
  106. package/config/settings.json +0 -12
  107. package/controllers/GraphQL.js +0 -9
  108. package/hooks/graphql/defaults.json +0 -5
  109. package/hooks/graphql/index.js +0 -174
  110. package/hooks/graphql/load-config.js +0 -42
  111. package/services/build-aggregation.js +0 -565
  112. package/services/data-loaders.js +0 -55
  113. package/services/naming.js +0 -15
  114. package/services/resolvers-builder.js +0 -204
  115. package/services/schema-definitions.js +0 -131
  116. package/services/schema-generator.js +0 -178
  117. package/services/shadow-crud.js +0 -612
  118. package/services/type-builder.js +0 -311
  119. package/services/utils.js +0 -200
  120. package/types/dynamiczoneScalar.js +0 -40
  121. package/types/publication-state.js +0 -16
  122. package/types/time.js +0 -26
@@ -1,565 +0,0 @@
1
- /**
2
- * Aggregator.js service
3
- *
4
- * @description: A set of functions similar to controller's actions to avoid code duplication.
5
- */
6
-
7
- 'use strict';
8
-
9
- const _ = require('lodash');
10
- const pluralize = require('pluralize');
11
- const { convertRestQueryParams, buildQuery } = require('@strapi/utils');
12
-
13
- const { buildQuery: buildQueryResolver } = require('./resolvers-builder');
14
- const { convertToParams, convertToQuery, nonRequired } = require('./utils');
15
- const { toSDL } = require('./schema-definitions');
16
-
17
- /**
18
- * Returns all fields of type primitive
19
- *
20
- * @returns {Boolean}
21
- */
22
- const isPrimitiveType = type => {
23
- const nonRequiredType = nonRequired(type);
24
- return (
25
- nonRequiredType === 'Int' ||
26
- nonRequiredType === 'Float' ||
27
- nonRequiredType === 'String' ||
28
- nonRequiredType === 'Boolean' ||
29
- nonRequiredType === 'DateTime' ||
30
- nonRequiredType === 'JSON'
31
- );
32
- };
33
-
34
- /**
35
- * Checks if the field is of type enum
36
- *
37
- * @returns {Boolean}
38
- */
39
- const isEnumType = type => {
40
- return type === 'enumeration';
41
- };
42
-
43
- /**
44
- * Returns all fields that are not of type array
45
- *
46
- * @returns {Boolean}
47
- *
48
- * @example
49
- *
50
- * isNotOfTypeArray([String])
51
- * // => false
52
- * isNotOfTypeArray(String!)
53
- * // => true
54
- */
55
- const isNotOfTypeArray = type => {
56
- return !/(\[\w+!?\])/.test(type);
57
- };
58
-
59
- /**
60
- * Returns all fields of type Integer or float
61
- */
62
- const isNumberType = type => {
63
- const nonRequiredType = nonRequired(type);
64
- return nonRequiredType === 'Int' || nonRequiredType === 'Float';
65
- };
66
-
67
- /**
68
- * Returns a list of fields that have type included in fieldTypes.
69
- */
70
- const getFieldsByTypes = (fields, typeCheck, returnType) => {
71
- return _.reduce(
72
- fields,
73
- (acc, fieldType, fieldName) => {
74
- if (typeCheck(fieldType)) {
75
- acc[fieldName] = returnType(fieldType, fieldName);
76
- }
77
- return acc;
78
- },
79
- {}
80
- );
81
- };
82
-
83
- /**
84
- * Use the field resolver otherwise fall through the field value
85
- *
86
- * @returns {function}
87
- */
88
- const fieldResolver = (field, key) => {
89
- return object => {
90
- const resolver =
91
- field.resolve ||
92
- function resolver(obj) {
93
- // eslint-disable-line no-unused-vars
94
- return obj[key];
95
- };
96
- return resolver(object);
97
- };
98
- };
99
-
100
- /**
101
- * Create fields resolvers
102
- *
103
- * @return {Object}
104
- */
105
- const createFieldsResolver = function(fields, resolverFn, typeCheck) {
106
- const resolver = Object.keys(fields).reduce((acc, fieldKey) => {
107
- const field = fields[fieldKey];
108
- // Check if the field is of the correct type
109
- if (typeCheck(field)) {
110
- return _.set(acc, fieldKey, (obj, options, context) => {
111
- return resolverFn(
112
- obj,
113
- options,
114
- context,
115
- fieldResolver(field, fieldKey),
116
- fieldKey,
117
- obj,
118
- field
119
- );
120
- });
121
- }
122
- return acc;
123
- }, {});
124
-
125
- return resolver;
126
- };
127
-
128
- /**
129
- * Convert non-primitive type to string (non-primitive types corresponds to a reference to an other model)
130
- *
131
- * @returns {String}
132
- *
133
- * @example
134
- *
135
- * extractType(String!)
136
- * // => String
137
- *
138
- * extractType(user)
139
- * // => ID
140
- *
141
- * extractType(ENUM_TEST_FIELD, enumeration)
142
- * // => String
143
- *
144
- */
145
- const extractType = function(_type, attributeType) {
146
- return isPrimitiveType(_type)
147
- ? _type.replace('!', '')
148
- : isEnumType(attributeType)
149
- ? 'String'
150
- : 'ID';
151
- };
152
-
153
- /**
154
- * Create the resolvers for each aggregation field
155
- *
156
- * @return {Object}
157
- *
158
- * @example
159
- *
160
- * const model = // Strapi model
161
- *
162
- * const fields = {
163
- * username: String,
164
- * age: Int,
165
- * }
166
- *
167
- * const typeCheck = (type) => type === 'Int' || type === 'Float',
168
- *
169
- * const fieldsResoler = createAggregationFieldsResolver(model, fields, 'sum', typeCheck);
170
- *
171
- * // => {
172
- * age: function ageResolver() { .... }
173
- * }
174
- */
175
- const createAggregationFieldsResolver = function(model, fields, operation, typeCheck) {
176
- return createFieldsResolver(
177
- fields,
178
- async (obj, options, context, fieldResolver, fieldKey) => {
179
- const filters = convertRestQueryParams({
180
- ...convertToParams(_.omit(obj, 'where')),
181
- ...convertToQuery(obj.where),
182
- });
183
-
184
- if (model.orm === 'mongoose') {
185
- return buildQuery({ model, filters, aggregate: true })
186
- .group({
187
- _id: null,
188
- [fieldKey]: { [`$${operation}`]: `$${fieldKey}` },
189
- })
190
- .exec()
191
- .then(result => _.get(result, [0, fieldKey]));
192
- }
193
-
194
- if (model.orm === 'bookshelf') {
195
- return model
196
- .query(qb => {
197
- // apply filters
198
- buildQuery({ model, filters })(qb);
199
-
200
- // `sum, avg, min, max` pass nicely to knex :->
201
- qb[operation](`${fieldKey} as ${operation}_${fieldKey}`);
202
- })
203
- .fetch()
204
- .then(result => result.get(`${operation}_${fieldKey}`));
205
- }
206
- },
207
- typeCheck
208
- );
209
- };
210
-
211
- /**
212
- * Correctly format the data returned by the group by
213
- */
214
- const preProcessGroupByData = function({ result, fieldKey, filters }) {
215
- const _result = _.toArray(result).filter(value => Boolean(value._id));
216
- return _.map(_result, value => {
217
- return {
218
- key: value._id.toString(),
219
- connection: () => {
220
- // filter by the grouped by value in next connection
221
-
222
- return {
223
- ...filters,
224
- where: {
225
- ...(filters.where || {}),
226
- [fieldKey]: value._id.toString(),
227
- },
228
- };
229
- },
230
- };
231
- });
232
- };
233
-
234
- /**
235
- * Create the resolvers for each group by field
236
- *
237
- * @return {Object}
238
- *
239
- * @example
240
- *
241
- * const model = // Strapi model
242
- * const fields = {
243
- * username: [UserConnectionUsername],
244
- * email: [UserConnectionEmail],
245
- * }
246
- * const fieldsResoler = createGroupByFieldsResolver(model, fields);
247
- *
248
- * // => {
249
- * username: function usernameResolver() { .... }
250
- * email: function emailResolver() { .... }
251
- * }
252
- */
253
- const createGroupByFieldsResolver = function(model, fields) {
254
- const resolver = async (filters, options, context, fieldResolver, fieldKey) => {
255
- const params = convertRestQueryParams({
256
- ...convertToParams(_.omit(filters, 'where')),
257
- ...convertToQuery(filters.where),
258
- });
259
-
260
- if (model.orm === 'mongoose') {
261
- const result = await buildQuery({
262
- model,
263
- filters: params,
264
- aggregate: true,
265
- }).group({
266
- _id: `$${fieldKey === 'id' ? model.primaryKey : fieldKey}`,
267
- });
268
-
269
- return preProcessGroupByData({
270
- result,
271
- fieldKey,
272
- filters,
273
- });
274
- }
275
-
276
- if (model.orm === 'bookshelf') {
277
- return model
278
- .query(qb => {
279
- buildQuery({ model, filters: params })(qb);
280
- qb.groupBy(fieldKey);
281
- qb.select(fieldKey);
282
- })
283
- .fetchAll()
284
- .then(result => {
285
- let values = result.models
286
- .map(m => m.get(fieldKey)) // extract aggregate field
287
- .filter(v => !!v) // remove null
288
- .map(v => '' + v); // convert to string
289
- return values.map(v => ({
290
- key: v,
291
- connection: () => {
292
- return {
293
- ..._.omit(filters, ['limit']), // we shouldn't carry limit to sub-field
294
- where: {
295
- ...(filters.where || {}),
296
- [fieldKey]: v,
297
- },
298
- };
299
- },
300
- }));
301
- });
302
- }
303
- };
304
-
305
- return createFieldsResolver(fields, resolver, () => true);
306
- };
307
- /**
308
- * Generate the connection type of each non-array field of the model
309
- *
310
- * @return {String}
311
- */
312
- const generateConnectionFieldsTypes = function(fields, model) {
313
- const { globalId, attributes } = model;
314
- const primitiveFields = getFieldsByTypes(fields, isNotOfTypeArray, (type, name) =>
315
- extractType(type, (attributes[name] || {}).type)
316
- );
317
-
318
- const connectionFields = _.mapValues(primitiveFields, fieldType => ({
319
- key: fieldType,
320
- connection: `${globalId}Connection`,
321
- }));
322
-
323
- return Object.keys(primitiveFields)
324
- .map(
325
- fieldKey =>
326
- `type ${globalId}Connection${_.upperFirst(fieldKey)} {${toSDL(connectionFields[fieldKey])}}`
327
- )
328
- .join('\n\n');
329
- };
330
-
331
- const formatConnectionGroupBy = function(fields, model) {
332
- const { globalId } = model;
333
- const groupByGlobalId = `${globalId}GroupBy`;
334
-
335
- // Extract all primitive fields and change their types
336
- const groupByFields = getFieldsByTypes(
337
- fields,
338
- isNotOfTypeArray,
339
- (fieldType, fieldName) => `[${globalId}Connection${_.upperFirst(fieldName)}]`
340
- );
341
-
342
- // Get the generated field types
343
- let groupByTypes = `type ${groupByGlobalId} {${toSDL(groupByFields)}}\n\n`;
344
- groupByTypes += generateConnectionFieldsTypes(fields, model);
345
-
346
- return {
347
- globalId: groupByGlobalId,
348
- type: groupByTypes,
349
- resolver: {
350
- [groupByGlobalId]: createGroupByFieldsResolver(model, groupByFields),
351
- },
352
- };
353
- };
354
-
355
- const formatConnectionAggregator = function(fields, model, modelName) {
356
- const { globalId } = model;
357
-
358
- // Extract all fields of type Integer and Float and change their type to Float
359
- const numericFields = getFieldsByTypes(fields, isNumberType, () => 'Float');
360
-
361
- // Don't create an aggregator field if the model has not number fields
362
- const aggregatorGlobalId = `${globalId}Aggregator`;
363
- const initialFields = {
364
- count: 'Int',
365
- totalCount: 'Int',
366
- };
367
-
368
- // Only add the aggregator's operations if there are some numeric fields
369
- if (!_.isEmpty(numericFields)) {
370
- ['sum', 'avg', 'min', 'max'].forEach(agg => {
371
- initialFields[agg] = `${aggregatorGlobalId}${_.startCase(agg)}`;
372
- });
373
- }
374
-
375
- const gqlNumberFormat = toSDL(numericFields);
376
- let aggregatorTypes = `type ${aggregatorGlobalId} {${toSDL(initialFields)}}\n\n`;
377
-
378
- let resolvers = {
379
- [aggregatorGlobalId]: {
380
- count(obj) {
381
- const opts = convertToQuery(obj.where);
382
-
383
- if (opts._q) {
384
- // allow search param
385
- return strapi.query(modelName, model.plugin).countSearch(opts);
386
- }
387
- return strapi.query(modelName, model.plugin).count(opts);
388
- },
389
- totalCount() {
390
- return strapi.query(modelName, model.plugin).count({});
391
- },
392
- },
393
- };
394
-
395
- // Only add the aggregator's operations types and resolver if there are some numeric fields
396
- if (!_.isEmpty(numericFields)) {
397
- // Returns the actual object and handle aggregation in the query resolvers
398
- const defaultAggregatorFunc = obj => {
399
- // eslint-disable-line no-unused-vars
400
- return obj;
401
- };
402
-
403
- aggregatorTypes += `type ${aggregatorGlobalId}Sum {${gqlNumberFormat}}\n\n`;
404
- aggregatorTypes += `type ${aggregatorGlobalId}Avg {${gqlNumberFormat}}\n\n`;
405
- aggregatorTypes += `type ${aggregatorGlobalId}Min {${gqlNumberFormat}}\n\n`;
406
- aggregatorTypes += `type ${aggregatorGlobalId}Max {${gqlNumberFormat}}\n\n`;
407
-
408
- _.merge(resolvers[aggregatorGlobalId], {
409
- sum: defaultAggregatorFunc,
410
- avg: defaultAggregatorFunc,
411
- min: defaultAggregatorFunc,
412
- max: defaultAggregatorFunc,
413
- });
414
-
415
- resolvers = {
416
- ...resolvers,
417
- [`${aggregatorGlobalId}Sum`]: createAggregationFieldsResolver(
418
- model,
419
- fields,
420
- 'sum',
421
- isNumberType
422
- ),
423
- [`${aggregatorGlobalId}Avg`]: createAggregationFieldsResolver(
424
- model,
425
- fields,
426
- 'avg',
427
- isNumberType
428
- ),
429
- [`${aggregatorGlobalId}Min`]: createAggregationFieldsResolver(
430
- model,
431
- fields,
432
- 'min',
433
- isNumberType
434
- ),
435
- [`${aggregatorGlobalId}Max`]: createAggregationFieldsResolver(
436
- model,
437
- fields,
438
- 'max',
439
- isNumberType
440
- ),
441
- };
442
- }
443
-
444
- return {
445
- globalId: aggregatorGlobalId,
446
- type: aggregatorTypes,
447
- resolver: resolvers,
448
- };
449
- };
450
-
451
- /**
452
- * This method is the entry point to the GraphQL's Aggregation.
453
- * It takes as param the model and its fields and it'll create the aggregation types and resolver to it
454
- * Example:
455
- * type User {
456
- * username: String,
457
- * age: Int,
458
- * }
459
- *
460
- * It'll create
461
- * type UserConnection {
462
- * values: [User],
463
- * groupBy: UserGroupBy,
464
- * aggreate: UserAggregate
465
- * }
466
- *
467
- * type UserAggregate {
468
- * count: Int
469
- * sum: UserAggregateSum
470
- * avg: UserAggregateAvg
471
- * }
472
- *
473
- * type UserAggregateSum {
474
- * age: Float
475
- * }
476
- *
477
- * type UserAggregateAvg {
478
- * age: Float
479
- * }
480
- *
481
- * type UserGroupBy {
482
- * username: [UserConnectionUsername]
483
- * age: [UserConnectionAge]
484
- * }
485
- *
486
- * type UserConnectionUsername {
487
- * key: String
488
- * connection: UserConnection
489
- * }
490
- *
491
- * type UserConnectionAge {
492
- * key: Int
493
- * connection: UserConnection
494
- * }
495
- *
496
- */
497
- const formatModelConnectionsGQL = function({ fields, model: contentType, name, resolver }) {
498
- const { globalId } = contentType;
499
- const model = strapi.getModel(contentType.uid);
500
-
501
- const connectionGlobalId = `${globalId}Connection`;
502
-
503
- const aggregatorFormat = formatConnectionAggregator(fields, model, name);
504
- const groupByFormat = formatConnectionGroupBy(fields, model);
505
- const connectionFields = {
506
- values: `[${globalId}]`,
507
- groupBy: `${globalId}GroupBy`,
508
- aggregate: `${globalId}Aggregator`,
509
- };
510
- const pluralName = pluralize.plural(_.camelCase(name));
511
-
512
- let modelConnectionTypes = `type ${connectionGlobalId} {${toSDL(connectionFields)}}\n\n`;
513
- if (aggregatorFormat) {
514
- modelConnectionTypes += aggregatorFormat.type;
515
- }
516
- modelConnectionTypes += groupByFormat.type;
517
-
518
- const connectionResolver = buildQueryResolver(`${pluralName}Connection.values`, resolver);
519
-
520
- const connectionQueryName = `${pluralName}Connection`;
521
-
522
- return {
523
- globalId: connectionGlobalId,
524
- definition: modelConnectionTypes,
525
- query: {
526
- [`${pluralName}Connection`]: {
527
- args: {
528
- sort: 'String',
529
- limit: 'Int',
530
- start: 'Int',
531
- where: 'JSON',
532
- ...(resolver.args || {}),
533
- },
534
- type: connectionGlobalId,
535
- },
536
- },
537
- resolvers: {
538
- Query: {
539
- [connectionQueryName]: buildQueryResolver(connectionQueryName, {
540
- resolverOf: resolver.resolverOf || resolver.resolver,
541
- resolver(obj, options) {
542
- return options;
543
- },
544
- }),
545
- },
546
- [connectionGlobalId]: {
547
- values(obj, options, gqlCtx) {
548
- return connectionResolver(obj, obj, gqlCtx);
549
- },
550
- groupBy(obj) {
551
- return obj;
552
- },
553
- aggregate(obj) {
554
- return obj;
555
- },
556
- },
557
- ...aggregatorFormat.resolver,
558
- ...groupByFormat.resolver,
559
- },
560
- };
561
- };
562
-
563
- module.exports = {
564
- formatModelConnectionsGQL,
565
- };
@@ -1,55 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Loaders.js service
5
- *
6
- * @description: A set of functions similar to controller's actions to avoid code duplication.
7
- */
8
-
9
- const _ = require('lodash');
10
- const DataLoader = require('dataloader');
11
-
12
- module.exports = {
13
- loaders: {},
14
-
15
- initializeLoader() {
16
- this.resetLoaders();
17
-
18
- // Create loaders for each relational field (exclude core models & plugins).
19
- Object.values(strapi.contentTypes).forEach(model => this.createLoader(model.uid));
20
- },
21
-
22
- resetLoaders() {
23
- this.loaders = {};
24
- },
25
-
26
- createLoader(modelUID) {
27
- if (this.loaders[modelUID]) {
28
- return this.loaders[modelUID];
29
- }
30
-
31
- const loadFn = queries => this.batchQuery(modelUID, queries);
32
- const loadOptions = {
33
- cacheKeyFn: key => this.serializeKey(key),
34
- };
35
-
36
- this.loaders[modelUID] = new DataLoader(loadFn, loadOptions);
37
- },
38
-
39
- serializeKey(key) {
40
- return _.isObjectLike(key) ? JSON.stringify(key) : key;
41
- },
42
-
43
- async batchQuery(modelUID, queries) {
44
- // Extract queries from keys and merge similar queries.
45
- return Promise.all(queries.map(query => this.makeQuery(modelUID, query)));
46
- },
47
-
48
- async makeQuery(modelUID, query = {}) {
49
- if (query.single === true) {
50
- return strapi.query(modelUID).findOne(query.filters, []);
51
- }
52
-
53
- return strapi.query(modelUID).find(query.filters, []);
54
- },
55
- };
@@ -1,15 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash');
4
- const pluralize = require('pluralize');
5
-
6
- const toPlural = str => pluralize(_.camelCase(str));
7
- const toSingular = str => _.camelCase(pluralize.singular(str));
8
-
9
- const toInputName = str => `${_.upperFirst(toSingular(str))}Input`;
10
-
11
- module.exports = {
12
- toSingular,
13
- toPlural,
14
- toInputName,
15
- };