@strapi/plugin-graphql 4.0.0-next.2 → 4.0.0-next.20

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 (117) hide show
  1. package/admin/src/translations/zh-Hans.json +4 -0
  2. package/package.json +17 -15
  3. package/server/bootstrap.js +124 -0
  4. package/server/services/builders/dynamic-zones.js +96 -0
  5. package/server/services/builders/entity-meta.js +7 -0
  6. package/server/services/builders/entity.js +43 -0
  7. package/server/services/builders/enums.js +24 -0
  8. package/server/services/builders/filters/content-type.js +84 -0
  9. package/server/services/builders/filters/index.js +7 -0
  10. package/server/services/builders/filters/operators/and.js +15 -0
  11. package/server/services/builders/filters/operators/between.js +15 -0
  12. package/server/services/builders/filters/operators/contains.js +13 -0
  13. package/server/services/builders/filters/operators/containsi.js +13 -0
  14. package/server/services/builders/filters/operators/ends-with.js +13 -0
  15. package/server/services/builders/filters/operators/eq.js +19 -0
  16. package/server/services/builders/filters/operators/gt.js +13 -0
  17. package/server/services/builders/filters/operators/gte.js +13 -0
  18. package/server/services/builders/filters/operators/in.js +15 -0
  19. package/server/services/builders/filters/operators/index.js +38 -0
  20. package/server/services/builders/filters/operators/lt.js +13 -0
  21. package/server/services/builders/filters/operators/lte.js +13 -0
  22. package/server/services/builders/filters/operators/ne.js +13 -0
  23. package/server/services/builders/filters/operators/not-contains.js +13 -0
  24. package/server/services/builders/filters/operators/not-containsi.js +13 -0
  25. package/server/services/builders/filters/operators/not-in.js +15 -0
  26. package/server/services/builders/filters/operators/not-null.js +13 -0
  27. package/server/services/builders/filters/operators/not.js +19 -0
  28. package/server/services/builders/filters/operators/null.js +13 -0
  29. package/server/services/builders/filters/operators/or.js +15 -0
  30. package/server/services/builders/filters/operators/starts-with.js +13 -0
  31. package/server/services/builders/generic-morph.js +41 -0
  32. package/server/services/builders/index.js +92 -0
  33. package/server/services/builders/input.js +118 -0
  34. package/server/services/builders/mutations/collection-type.js +170 -0
  35. package/server/services/builders/mutations/index.js +9 -0
  36. package/server/services/builders/mutations/single-type.js +135 -0
  37. package/server/services/builders/queries/collection-type.js +120 -0
  38. package/server/services/builders/queries/index.js +9 -0
  39. package/server/services/builders/queries/single-type.js +70 -0
  40. package/server/services/builders/relation-response-collection.js +35 -0
  41. package/server/services/builders/resolvers/association.js +64 -0
  42. package/server/services/builders/resolvers/component.js +14 -0
  43. package/server/services/builders/resolvers/dynamic-zone.js +9 -0
  44. package/server/services/builders/resolvers/index.js +18 -0
  45. package/server/services/builders/resolvers/mutation.js +33 -0
  46. package/server/services/builders/resolvers/query.js +19 -0
  47. package/server/services/builders/response-collection.js +43 -0
  48. package/server/services/builders/response.js +32 -0
  49. package/server/services/builders/type.js +370 -0
  50. package/server/services/builders/utils.js +131 -0
  51. package/server/services/constants.js +147 -0
  52. package/server/services/content-api/index.js +168 -0
  53. package/server/services/content-api/policy.js +59 -0
  54. package/server/services/content-api/register-functions/collection-type.js +72 -0
  55. package/server/services/content-api/register-functions/component.js +15 -0
  56. package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
  57. package/server/services/content-api/register-functions/content-type/enums.js +33 -0
  58. package/server/services/content-api/register-functions/content-type/filters.js +15 -0
  59. package/server/services/content-api/register-functions/content-type/index.js +13 -0
  60. package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
  61. package/server/services/content-api/register-functions/index.js +22 -0
  62. package/server/services/content-api/register-functions/internals.js +13 -0
  63. package/server/services/content-api/register-functions/polymorphic.js +69 -0
  64. package/server/services/content-api/register-functions/scalars.js +14 -0
  65. package/server/services/content-api/register-functions/single-type.js +72 -0
  66. package/server/services/content-api/wrap-resolvers.js +146 -0
  67. package/server/services/extension/extension.js +95 -0
  68. package/server/services/extension/index.js +5 -0
  69. package/server/services/extension/shadow-crud-manager.js +159 -0
  70. package/server/services/format/index.js +7 -0
  71. package/server/services/format/return-types.js +27 -0
  72. package/server/services/index.js +21 -0
  73. package/server/services/internals/args/index.js +11 -0
  74. package/server/services/internals/args/pagination.js +19 -0
  75. package/server/services/internals/args/publication-state.js +12 -0
  76. package/server/services/internals/args/sort.js +10 -0
  77. package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
  78. package/server/services/internals/helpers/index.js +7 -0
  79. package/server/services/internals/index.js +13 -0
  80. package/server/services/internals/scalars/index.js +18 -0
  81. package/server/services/internals/scalars/time.js +35 -0
  82. package/server/services/internals/types/error.js +33 -0
  83. package/server/services/internals/types/filters.js +39 -0
  84. package/server/services/internals/types/index.js +29 -0
  85. package/server/services/internals/types/pagination.js +24 -0
  86. package/server/services/internals/types/publication-state.js +24 -0
  87. package/server/services/internals/types/response-collection-meta.js +38 -0
  88. package/server/services/type-registry.js +103 -0
  89. package/server/services/utils/attributes.js +84 -0
  90. package/server/services/utils/index.js +11 -0
  91. package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
  92. package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +107 -0
  93. package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
  94. package/server/services/utils/mappers/index.js +13 -0
  95. package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +24 -0
  96. package/server/services/utils/naming.js +282 -0
  97. package/strapi-admin.js +3 -0
  98. package/strapi-server.js +11 -0
  99. package/config/routes.json +0 -3
  100. package/config/schema.graphql +0 -1
  101. package/config/settings.json +0 -12
  102. package/controllers/GraphQL.js +0 -9
  103. package/hooks/graphql/defaults.json +0 -5
  104. package/hooks/graphql/index.js +0 -174
  105. package/hooks/graphql/load-config.js +0 -42
  106. package/services/build-aggregation.js +0 -565
  107. package/services/data-loaders.js +0 -55
  108. package/services/naming.js +0 -15
  109. package/services/resolvers-builder.js +0 -204
  110. package/services/schema-definitions.js +0 -131
  111. package/services/schema-generator.js +0 -178
  112. package/services/shadow-crud.js +0 -612
  113. package/services/type-builder.js +0 -311
  114. package/services/utils.js +0 -200
  115. package/types/dynamiczoneScalar.js +0 -40
  116. package/types/publication-state.js +0 -16
  117. package/types/time.js +0 -26
@@ -0,0 +1,146 @@
1
+ 'use strict';
2
+
3
+ const { get, getOr, isFunction, first, isNil } = require('lodash/fp');
4
+
5
+ const { GraphQLObjectType } = require('graphql');
6
+ const { createPoliciesMiddleware } = require('./policy');
7
+
8
+ const introspectionQueries = [
9
+ '__Schema',
10
+ '__Type',
11
+ '__Field',
12
+ '__InputValue',
13
+ '__EnumValue',
14
+ '__Directive',
15
+ ];
16
+
17
+ /**
18
+ * Wrap the schema's resolvers if they've been
19
+ * customized using the GraphQL extension service
20
+ * @param {object} options
21
+ * @param {GraphQLSchema} options.schema
22
+ * @param {object} options.strapi
23
+ * @param {object} options.extension
24
+ * @return {GraphQLSchema}
25
+ */
26
+ const wrapResolvers = ({ schema, strapi, extension = {} }) => {
27
+ // Get all the registered resolvers configuration
28
+ const { resolversConfig = {} } = extension;
29
+
30
+ // Fields filters
31
+ const isValidFieldName = ([field]) => !field.startsWith('__');
32
+
33
+ const typeMap = schema.getTypeMap();
34
+
35
+ // Iterate over every field from every type within the
36
+ // schema's type map and wrap its resolve attribute if needed
37
+ Object.entries(typeMap).forEach(([type, definition]) => {
38
+ const isGraphQLObjectType = definition instanceof GraphQLObjectType;
39
+ const isIgnoredType = introspectionQueries.includes(type);
40
+
41
+ if (!isGraphQLObjectType || isIgnoredType) {
42
+ return;
43
+ }
44
+
45
+ const fields = definition.getFields();
46
+ const fieldsToProcess = Object.entries(fields).filter(isValidFieldName);
47
+
48
+ for (const [fieldName, fieldDefinition] of fieldsToProcess) {
49
+ const defaultResolver = get(fieldName);
50
+
51
+ const path = `${type}.${fieldName}`;
52
+ const resolverConfig = getOr({}, path, resolversConfig);
53
+
54
+ const { resolve: baseResolver = defaultResolver } = fieldDefinition;
55
+
56
+ // Parse & initialize the middlewares
57
+ const middlewares = parseMiddlewares(resolverConfig, strapi);
58
+
59
+ // Generate the policy middleware
60
+ const policyMiddleware = createPoliciesMiddleware(resolverConfig, { strapi });
61
+
62
+ // Add the policyMiddleware at the end of the middlewares collection
63
+ middlewares.push(policyMiddleware);
64
+
65
+ // Bind every middleware to the next one
66
+ const boundMiddlewares = middlewares.map((middleware, index, collection) => {
67
+ return (...args) =>
68
+ middleware(
69
+ // Make sure the last middleware in the list calls the baseResolver
70
+ index >= collection.length - 1 ? baseResolver : boundMiddlewares[index + 1],
71
+ ...args
72
+ );
73
+ });
74
+
75
+ /**
76
+ * GraphQL authorization flow
77
+ * @param {object} context
78
+ * @return {Promise<void>}
79
+ */
80
+ const authorize = async ({ context }) => {
81
+ const authConfig = get('auth', resolverConfig);
82
+ const authContext = get('state.auth', context);
83
+
84
+ const isMutationOrQuery = ['Mutation', 'Query'].includes(type);
85
+ const hasConfig = !isNil(authConfig);
86
+
87
+ const isAuthDisabled = authConfig === false;
88
+
89
+ if ((isMutationOrQuery || hasConfig) && !isAuthDisabled) {
90
+ try {
91
+ await strapi.auth.verify(authContext, authConfig);
92
+ } catch (error) {
93
+ // TODO: [v4] Throw GraphQL Error instead
94
+ throw new Error('Forbidden access');
95
+ }
96
+ }
97
+ };
98
+
99
+ /**
100
+ * Base resolver wrapper that handles authorization, middlewares & policies
101
+ * @param {object} parent
102
+ * @param {object} args
103
+ * @param {object} context
104
+ * @param {object} info
105
+ * @return {Promise<any>}
106
+ */
107
+ fieldDefinition.resolve = async (parent, args, context, info) => {
108
+ await authorize({ context });
109
+
110
+ // Execute middlewares (including the policy middleware which will always be included)
111
+ return first(boundMiddlewares).call(null, parent, args, context, info);
112
+ };
113
+ }
114
+ });
115
+
116
+ return schema;
117
+ };
118
+
119
+ /**
120
+ * Get & parse middlewares definitions from the resolver's config
121
+ * @param {object} resolverConfig
122
+ * @param {object} strapi
123
+ * @return {function[]}
124
+ */
125
+ const parseMiddlewares = (resolverConfig, strapi) => {
126
+ const resolverMiddlewares = getOr([], 'middlewares', resolverConfig);
127
+
128
+ // TODO: [v4] to factorize with compose endpoints (routes)
129
+ return resolverMiddlewares.map(middleware => {
130
+ if (isFunction(middleware)) {
131
+ return middleware;
132
+ }
133
+
134
+ if (typeof middleware === 'string') {
135
+ return strapi.middleware(middleware);
136
+ }
137
+
138
+ if (typeof middleware === 'object') {
139
+ const { name, options = {} } = middleware;
140
+
141
+ return strapi.middleware(name)(options);
142
+ }
143
+ });
144
+ };
145
+
146
+ module.exports = { wrapResolvers };
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ const nexus = require('nexus');
4
+ const { merge } = require('lodash/fp');
5
+
6
+ const createShadowCRUDManager = require('./shadow-crud-manager');
7
+
8
+ /**
9
+ * @typedef StrapiGraphQLExtensionConfiguration
10
+ * @property {NexusGen[]} types - A collection of Nexus types
11
+ * @property {string} typeDefs - Type definitions (SDL format)
12
+ * @property {object} resolvers - A resolver map
13
+ * @property {object} resolversConfig - An object that bind a configuration to a resolver based on an absolute path (the key)
14
+ * @property {NexusPlugin[]} plugins - A collection of Nexus plugins
15
+ */
16
+
17
+ /**
18
+ * @typedef {function({ strapi: object, nexus: object, typeRegistry: object }): StrapiGraphQLExtensionConfiguration} StrapiGraphQLExtensionConfigurationFactory
19
+ */
20
+
21
+ const getDefaultState = () => ({
22
+ types: [],
23
+ typeDefs: [],
24
+ resolvers: {},
25
+ resolversConfig: {},
26
+ plugins: [],
27
+ });
28
+
29
+ const createExtension = ({ strapi } = {}) => {
30
+ const configs = [];
31
+
32
+ return {
33
+ shadowCRUD: createShadowCRUDManager({ strapi }),
34
+
35
+ /**
36
+ * Register a new extension configuration
37
+ * @param {StrapiGraphQLExtensionConfiguration | StrapiGraphQLExtensionConfigurationFactory} configuration
38
+ * @return {this}
39
+ */
40
+ use(configuration) {
41
+ configs.push(configuration);
42
+
43
+ return this;
44
+ },
45
+
46
+ /**
47
+ * Convert the registered configuration into a single extension object & return it
48
+ * @param {object} options
49
+ * @param {object} options.typeRegistry
50
+ * @return {object}
51
+ */
52
+ generate({ typeRegistry }) {
53
+ const resolveConfig = config => {
54
+ return typeof config === 'function' ? config({ strapi, nexus, typeRegistry }) : config;
55
+ };
56
+
57
+ // Evaluate & merge every registered configuration object, then return the result
58
+ return configs.reduce((acc, configuration) => {
59
+ const { types, typeDefs, resolvers, resolversConfig, plugins } = resolveConfig(
60
+ configuration
61
+ );
62
+
63
+ // Register type definitions
64
+ if (typeof typeDefs === 'string') {
65
+ acc.typeDefs.push(typeDefs);
66
+ }
67
+
68
+ // Register nexus types
69
+ if (Array.isArray(types)) {
70
+ acc.types.push(...types);
71
+ }
72
+
73
+ // Register nexus plugins
74
+ if (Array.isArray(plugins)) {
75
+ acc.plugins.push(...plugins);
76
+ }
77
+
78
+ // Register resolvers
79
+ if (typeof resolvers === 'object') {
80
+ acc.resolvers = merge(acc.resolvers, resolvers);
81
+ }
82
+
83
+ // Register resolvers configuration
84
+ if (typeof resolversConfig === 'object') {
85
+ // TODO: smarter merge for auth, middlewares & policies
86
+ acc.resolversConfig = merge(resolversConfig, acc.resolversConfig);
87
+ }
88
+
89
+ return acc;
90
+ }, getDefaultState());
91
+ },
92
+ };
93
+ };
94
+
95
+ module.exports = createExtension;
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ const createExtension = require('./extension');
4
+
5
+ module.exports = createExtension;
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ const getDefaultContentTypeConfig = () => ({
4
+ enabled: true,
5
+
6
+ mutations: true,
7
+ queries: true,
8
+
9
+ disabledActions: [],
10
+ fields: new Map(),
11
+ });
12
+
13
+ const getDefaultFieldConfig = () => ({
14
+ enabled: true,
15
+
16
+ input: true,
17
+ output: true,
18
+
19
+ filters: true,
20
+ });
21
+
22
+ const ALL_ACTIONS = '*';
23
+
24
+ module.exports = () => {
25
+ const configs = new Map();
26
+
27
+ return uid => {
28
+ if (!configs.has(uid)) {
29
+ configs.set(uid, getDefaultContentTypeConfig());
30
+ }
31
+
32
+ return {
33
+ isEnabled() {
34
+ return configs.get(uid).enabled;
35
+ },
36
+
37
+ isDisabled() {
38
+ return !this.isEnabled();
39
+ },
40
+
41
+ areQueriesEnabled() {
42
+ return configs.get(uid).queries;
43
+ },
44
+
45
+ areQueriesDisabled() {
46
+ return !this.areQueriesEnabled();
47
+ },
48
+
49
+ areMutationsEnabled() {
50
+ return configs.get(uid).mutations;
51
+ },
52
+
53
+ areMutationsDisabled() {
54
+ return !this.areMutationsEnabled();
55
+ },
56
+
57
+ isActionEnabled(action) {
58
+ const matchingActions = [action, ALL_ACTIONS];
59
+
60
+ return configs.get(uid).disabledActions.every(action => !matchingActions.includes(action));
61
+ },
62
+
63
+ isActionDisabled(action) {
64
+ return !this.isActionEnabled(action);
65
+ },
66
+
67
+ disable() {
68
+ configs.get(uid).enabled = false;
69
+
70
+ return this;
71
+ },
72
+
73
+ disableQueries() {
74
+ configs.get(uid).queries = false;
75
+
76
+ return this;
77
+ },
78
+
79
+ disableMutations() {
80
+ configs.get(uid).mutations = false;
81
+
82
+ return this;
83
+ },
84
+
85
+ disableAction(action) {
86
+ const config = configs.get(uid);
87
+
88
+ if (!config.disabledActions.includes(action)) {
89
+ config.disabledActions.push(action);
90
+ }
91
+
92
+ return this;
93
+ },
94
+
95
+ disableActions(actions = []) {
96
+ actions.forEach(action => this.disableAction(action));
97
+
98
+ return this;
99
+ },
100
+
101
+ field(fieldName) {
102
+ const { fields } = configs.get(uid);
103
+
104
+ if (!fields.has(fieldName)) {
105
+ fields.set(fieldName, getDefaultFieldConfig());
106
+ }
107
+
108
+ return {
109
+ isEnabled() {
110
+ return fields.get(fieldName).enabled;
111
+ },
112
+
113
+ hasInputEnabled() {
114
+ return fields.get(fieldName).input;
115
+ },
116
+
117
+ hasOutputEnabled() {
118
+ return fields.get(fieldName).output;
119
+ },
120
+
121
+ hasFiltersEnabeld() {
122
+ return fields.get(fieldName).filters;
123
+ },
124
+
125
+ disable() {
126
+ fields.set(fieldName, {
127
+ enabled: false,
128
+
129
+ output: false,
130
+ input: false,
131
+
132
+ filters: false,
133
+ });
134
+
135
+ return this;
136
+ },
137
+
138
+ disableOutput() {
139
+ fields.get(fieldName).output = false;
140
+
141
+ return this;
142
+ },
143
+
144
+ disableInput() {
145
+ fields.get(fieldName).input = false;
146
+
147
+ return this;
148
+ },
149
+
150
+ disableFilters() {
151
+ fields.get(fieldName).filters = false;
152
+
153
+ return this;
154
+ },
155
+ };
156
+ },
157
+ };
158
+ };
159
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const returnTypes = require('./return-types');
4
+
5
+ module.exports = context => ({
6
+ returnTypes: returnTypes(context),
7
+ });
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ module.exports = () => ({
4
+ /**
5
+ * @param {object} value
6
+ * @param {object} info
7
+ * @param {object} info.args
8
+ * @param {string} info.resourceUID
9
+ */
10
+ toEntityResponse(value, info = {}) {
11
+ const { args = {}, resourceUID } = info;
12
+
13
+ return { value, info: { args, resourceUID } };
14
+ },
15
+
16
+ /**
17
+ * @param {object[]} nodes
18
+ * @param {object} info
19
+ * @param {object} info.args
20
+ * @param {string} info.resourceUID
21
+ */
22
+ toEntityResponseCollection(nodes, info = {}) {
23
+ const { args = {}, resourceUID } = info;
24
+
25
+ return { nodes, info: { args, resourceUID } };
26
+ },
27
+ });
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ const contentAPI = require('./content-api');
4
+ const typeRegistry = require('./type-registry');
5
+ const utils = require('./utils');
6
+ const constants = require('./constants');
7
+ const internals = require('./internals');
8
+ const builders = require('./builders');
9
+ const extension = require('./extension');
10
+ const format = require('./format');
11
+
12
+ module.exports = {
13
+ builders,
14
+ 'content-api': contentAPI,
15
+ constants,
16
+ extension,
17
+ format,
18
+ internals,
19
+ 'type-registry': typeRegistry,
20
+ utils,
21
+ };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ const SortArg = require('./sort');
4
+ const publicationState = require('./publication-state');
5
+ const PaginationArg = require('./pagination');
6
+
7
+ module.exports = context => ({
8
+ SortArg,
9
+ PaginationArg,
10
+ PublicationStateArg: publicationState(context),
11
+ });
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const { arg, inputObjectType } = require('nexus');
4
+
5
+ const PaginationInputType = inputObjectType({
6
+ name: 'PaginationArg',
7
+
8
+ definition(t) {
9
+ t.int('page');
10
+ t.int('pageSize');
11
+ t.int('start');
12
+ t.int('limit');
13
+ },
14
+ });
15
+
16
+ module.exports = arg({
17
+ type: PaginationInputType,
18
+ default: {},
19
+ });
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const { arg } = require('nexus');
4
+
5
+ module.exports = ({ strapi }) => {
6
+ const { PUBLICATION_STATE_TYPE_NAME } = strapi.plugin('graphql').service('constants');
7
+
8
+ return arg({
9
+ type: PUBLICATION_STATE_TYPE_NAME,
10
+ default: 'live',
11
+ });
12
+ };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ const { arg, list } = require('nexus');
4
+
5
+ const SortArg = arg({
6
+ type: list('String'),
7
+ default: [],
8
+ });
9
+
10
+ module.exports = SortArg;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const { first } = require('lodash/fp');
4
+
5
+ module.exports = ({ strapi }) => () => {
6
+ const { GRAPHQL_SCALAR_OPERATORS } = strapi.plugin('graphql').service('constants');
7
+
8
+ return (
9
+ Object.entries(GRAPHQL_SCALAR_OPERATORS)
10
+ // To be valid, a GraphQL scalar must have at least one operator enabled
11
+ .filter(([, value]) => value.length > 0)
12
+ // Only keep the key (the scalar name)
13
+ .map(first)
14
+ );
15
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const getEnabledScalars = require('./get-enabled-scalars');
4
+
5
+ module.exports = context => ({
6
+ getEnabledScalars: getEnabledScalars(context),
7
+ });
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const args = require('./args');
4
+ const scalars = require('./scalars');
5
+ const types = require('./types');
6
+ const helpers = require('./helpers');
7
+
8
+ module.exports = context => ({
9
+ args: args(context),
10
+ scalars: scalars(context),
11
+ buildInternalTypes: types(context),
12
+ helpers: helpers(context),
13
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const GraphQLJSON = require('graphql-type-json');
4
+ const GraphQLLong = require('graphql-type-long');
5
+ const { GraphQLDateTime, GraphQLDate } = require('graphql-iso-date/dist');
6
+ const { GraphQLUpload } = require('graphql-upload');
7
+ const { asNexusMethod } = require('nexus');
8
+
9
+ const TimeScalar = require('./time');
10
+
11
+ module.exports = () => ({
12
+ JSON: asNexusMethod(GraphQLJSON, 'json'),
13
+ DateTime: asNexusMethod(GraphQLDateTime, 'dateTime'),
14
+ Time: asNexusMethod(TimeScalar, 'time'),
15
+ Date: asNexusMethod(GraphQLDate, 'date'),
16
+ Long: asNexusMethod(GraphQLLong, 'long'),
17
+ Upload: asNexusMethod(GraphQLUpload, 'upload'),
18
+ });
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ const { GraphQLScalarType } = require('graphql');
4
+ const { Kind } = require('graphql');
5
+ const { parseType } = require('@strapi/utils');
6
+
7
+ /**
8
+ * A GraphQL scalar used to store Time (HH:mm:ss.SSS) values
9
+ * @type {GraphQLScalarType}
10
+ */
11
+ const TimeScalar = new GraphQLScalarType({
12
+ name: 'Time',
13
+
14
+ description: 'A time string with format HH:mm:ss.SSS',
15
+
16
+ serialize(value) {
17
+ return parseType({ type: 'time', value });
18
+ },
19
+
20
+ parseValue(value) {
21
+ return parseType({ type: 'time', value });
22
+ },
23
+
24
+ parseLiteral(ast) {
25
+ if (ast.kind !== Kind.STRING) {
26
+ throw new TypeError('Time cannot represent non string type');
27
+ }
28
+
29
+ const value = ast.value;
30
+
31
+ return parseType({ type: 'time', value });
32
+ },
33
+ });
34
+
35
+ module.exports = TimeScalar;
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const { objectType } = require('nexus');
4
+ const { get } = require('lodash/fp');
5
+
6
+ /**
7
+ * Build an Error object type
8
+ * @return {Object<string, NexusObjectTypeDef>}
9
+ */
10
+ module.exports = ({ strapi }) => {
11
+ const { ERROR_CODES, ERROR_TYPE_NAME } = strapi.plugin('graphql').service('constants');
12
+
13
+ return objectType({
14
+ name: ERROR_TYPE_NAME,
15
+
16
+ definition(t) {
17
+ t.nonNull.string('code', {
18
+ resolve(parent) {
19
+ const code = get('code', parent);
20
+
21
+ const isValidPlaceholderCode = Object.values(ERROR_CODES).includes(code);
22
+ if (!isValidPlaceholderCode) {
23
+ throw new TypeError(`"${code}" is not a valid code value`);
24
+ }
25
+
26
+ return code;
27
+ },
28
+ });
29
+
30
+ t.string('message');
31
+ },
32
+ });
33
+ };
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const { inputObjectType } = require('nexus');
4
+
5
+ /**
6
+ * Build a map of filters type for every GraphQL scalars
7
+ * @return {Object<string, NexusInputTypeDef>}
8
+ */
9
+ const buildScalarFilters = ({ strapi }) => {
10
+ const { naming, mappers } = strapi.plugin('graphql').service('utils');
11
+ const { helpers } = strapi.plugin('graphql').service('internals');
12
+
13
+ return helpers.getEnabledScalars().reduce((acc, type) => {
14
+ const operators = mappers.graphqlScalarToOperators(type);
15
+ const typeName = naming.getScalarFilterInputTypeName(type);
16
+
17
+ if (!operators || operators.length === 0) {
18
+ return acc;
19
+ }
20
+
21
+ return {
22
+ ...acc,
23
+
24
+ [typeName]: inputObjectType({
25
+ name: typeName,
26
+
27
+ definition(t) {
28
+ for (const operator of operators) {
29
+ operator.add(t, type);
30
+ }
31
+ },
32
+ }),
33
+ };
34
+ }, {});
35
+ };
36
+
37
+ module.exports = context => ({
38
+ scalars: buildScalarFilters(context),
39
+ });