mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 18:08:11 +00:00 
			
		
		
		
	Add nested resolvers filtering & fix nested component load
This commit is contained in:
		
							parent
							
								
									5aece86258
								
							
						
					
					
						commit
						513f66ce9b
					
				| @ -3,8 +3,8 @@ | ||||
| const { extendType } = require('nexus'); | ||||
| 
 | ||||
| const { actionExists } = require('../../../old/utils'); | ||||
| const { utils, args } = require('../../../types'); | ||||
| const { transformArgs } = require('../utils'); | ||||
| const { utils } = require('../../../types'); | ||||
| const { transformArgs, getContentTypeArgs } = require('../utils'); | ||||
| const { buildQueriesResolvers } = require('../../resolvers'); | ||||
| 
 | ||||
| module.exports = ({ strapi }) => { | ||||
| @ -35,18 +35,10 @@ module.exports = ({ strapi }) => { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // todo[v4]: Don't allow to filter using every unique attributes for now
 | ||||
|     // Only authorize filtering using unique scalar fields for findOne queries
 | ||||
|     // const uniqueAttributes = getUniqueAttributesFiltersMap(attributes);
 | ||||
| 
 | ||||
|     t.field(findOneQueryName, { | ||||
|       type: responseTypeName, | ||||
| 
 | ||||
|       args: { | ||||
|         id: 'ID', | ||||
|         // todo[v4]: Don't allow to filter using every unique attributes for now
 | ||||
|         // ...uniqueAttributes,
 | ||||
|       }, | ||||
|       args: getContentTypeArgs(contentType, { multiple: false }), | ||||
| 
 | ||||
|       async resolve(source, args) { | ||||
|         const transformedArgs = transformArgs(args, { contentType }); | ||||
| @ -80,14 +72,7 @@ module.exports = ({ strapi }) => { | ||||
|     t.field(findQueryName, { | ||||
|       type: responseCollectionTypeName, | ||||
| 
 | ||||
|       args: { | ||||
|         publicationState: args.PublicationStateArg, | ||||
|         // todo[v4]: to add through i18n plugin
 | ||||
|         locale: 'String', | ||||
|         sort: args.SortArg, | ||||
|         pagination: args.PaginationArg, | ||||
|         filters: utils.getFiltersInputTypeName(contentType), | ||||
|       }, | ||||
|       args: getContentTypeArgs(contentType), | ||||
| 
 | ||||
|       async resolve(source, args) { | ||||
|         const transformedArgs = transformArgs(args, { contentType, usePagination: true }); | ||||
|  | ||||
| @ -6,7 +6,8 @@ const { objectType } = require('nexus'); | ||||
| const { contentTypes } = require('@strapi/utils'); | ||||
| 
 | ||||
| const { mappers, utils: typeUtils, constants } = require('../../types'); | ||||
| const { buildAssociationResolver } = require('../resolvers'); | ||||
| const { buildAssociationResolver, buildComponentResolver } = require('../resolvers'); | ||||
| const { getContentTypeArgs } = require('./utils'); | ||||
| 
 | ||||
| /** | ||||
|  * @typedef TypeBuildersOptions | ||||
| @ -160,22 +161,17 @@ const addComponentAttribute = ({ builder, attributeName, contentType, attribute, | ||||
|     builder = builder.list; | ||||
|   } | ||||
| 
 | ||||
|   builder.field(attributeName, { | ||||
|     type, | ||||
|   const targetComponent = strapi.getModel(attribute.component); | ||||
| 
 | ||||
|     // Move resolver to /resolvers/component.js
 | ||||
|     async resolve(source) { | ||||
|       const { [attributeName]: component } = await strapi.db.entityManager.populate( | ||||
|         contentType.uid, | ||||
|         source, | ||||
|         { | ||||
|           [attributeName]: true, | ||||
|         } | ||||
|       ); | ||||
| 
 | ||||
|       return component; | ||||
|     }, | ||||
|   const resolve = buildComponentResolver({ | ||||
|     contentTypeUID: contentType.uid, | ||||
|     attributeName, | ||||
|     strapi, | ||||
|   }); | ||||
| 
 | ||||
|   const args = getContentTypeArgs(targetComponent); | ||||
| 
 | ||||
|   builder.field(attributeName, { type, resolve, args }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
| @ -226,13 +222,15 @@ const addMediaAttribute = options => { | ||||
|   const fileContentType = strapi.getModel('plugins::upload.file'); | ||||
|   const type = typeUtils.getTypeName(fileContentType); | ||||
| 
 | ||||
|   const associationResolver = buildAssociationResolver({ | ||||
|   const resolve = buildAssociationResolver({ | ||||
|     contentTypeUID: contentType.uid, | ||||
|     attributeName, | ||||
|     strapi, | ||||
|   }); | ||||
| 
 | ||||
|   builder.field(attributeName, { type, resolve: associationResolver }); | ||||
|   const args = attribute.multiple ? getContentTypeArgs(fileContentType) : undefined; | ||||
| 
 | ||||
|   builder.field(attributeName, { type, resolve, args }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
| @ -255,7 +253,7 @@ const addPolymorphicRelationalAttribute = options => { | ||||
|     builder = builder.list; | ||||
|   } | ||||
| 
 | ||||
|   const associationResolver = buildAssociationResolver({ | ||||
|   const resolve = buildAssociationResolver({ | ||||
|     contentTypeUID: contentType.uid, | ||||
|     attributeName, | ||||
|     strapi, | ||||
| @ -265,7 +263,7 @@ const addPolymorphicRelationalAttribute = options => { | ||||
|   if (isUndefined(target)) { | ||||
|     builder.field(attributeName, { | ||||
|       type: constants.GENERIC_MORPH_TYPENAME, | ||||
|       resolve: associationResolver, | ||||
|       resolve, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
| @ -273,7 +271,7 @@ const addPolymorphicRelationalAttribute = options => { | ||||
|   else if (isArray(target) && target.every(isString)) { | ||||
|     const type = typeUtils.getMorphRelationTypeName(contentType, attributeName); | ||||
| 
 | ||||
|     builder.field(attributeName, { type, resolve: associationResolver }); | ||||
|     builder.field(attributeName, { type, resolve }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| @ -296,7 +294,7 @@ const addRegularRelationalAttribute = options => { | ||||
|     builder = builder.list; | ||||
|   } | ||||
| 
 | ||||
|   const associationResolver = buildAssociationResolver({ | ||||
|   const resolve = buildAssociationResolver({ | ||||
|     contentTypeUID: contentType.uid, | ||||
|     attributeName, | ||||
|     strapi, | ||||
| @ -305,7 +303,9 @@ const addRegularRelationalAttribute = options => { | ||||
|   const targetContentType = strapi.getModel(attribute.target); | ||||
|   const type = typeUtils.getTypeName(targetContentType); | ||||
| 
 | ||||
|   builder.field(attributeName, { type, resolve: associationResolver }); | ||||
|   const args = isToManyRelation ? getContentTypeArgs(targetContentType) : undefined; | ||||
| 
 | ||||
|   builder.field(attributeName, { type, resolve, args }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -6,8 +6,9 @@ const { | ||||
| } = require('@strapi/utils'); | ||||
| 
 | ||||
| const { | ||||
|   args, | ||||
|   mappers: { strapiScalarToGraphQLScalar, graphQLFiltersToStrapiQuery }, | ||||
|   utils: { isScalar, getScalarFilterInputTypeName }, | ||||
|   utils: { isScalar, getScalarFilterInputTypeName, getFiltersInputTypeName }, | ||||
| } = require('../../types'); | ||||
| 
 | ||||
| /** | ||||
| @ -38,7 +39,7 @@ const scalarAttributesToFiltersMap = mapValues(attribute => { | ||||
|  * Apply basic transform to GQL args | ||||
|  */ | ||||
| // todo[v4]: unify & move elsewhere
 | ||||
| const transformArgs = (args, { contentType, usePagination = false }) => { | ||||
| const transformArgs = (args, { contentType, usePagination = false } = {}) => { | ||||
|   const { pagination = {}, filters = {} } = args; | ||||
| 
 | ||||
|   // Init
 | ||||
| @ -60,7 +61,49 @@ const transformArgs = (args, { contentType, usePagination = false }) => { | ||||
|   return newArgs; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Get every args for a given content type | ||||
|  * @param {object} contentType | ||||
|  * @param {object} options | ||||
|  * @param {boolean} options.multiple | ||||
|  * @return {object} | ||||
|  */ | ||||
| const getContentTypeArgs = (contentType, { multiple = true } = {}) => { | ||||
|   const { kind, modelType } = contentType; | ||||
| 
 | ||||
|   // Components
 | ||||
|   if (modelType === 'component') { | ||||
|     return { | ||||
|       sort: args.SortArg, | ||||
|       pagination: args.PaginationArg, | ||||
|       filters: getFiltersInputTypeName(contentType), | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   // Collection Types
 | ||||
|   else if (kind === 'collectionType') { | ||||
|     return multiple | ||||
|       ? { | ||||
|           publicationState: args.PublicationStateArg, | ||||
|           // todo[v4]: to add through i18n plugin
 | ||||
|           locale: 'String', | ||||
|           sort: args.SortArg, | ||||
|           pagination: args.PaginationArg, | ||||
|           filters: getFiltersInputTypeName(contentType), | ||||
|         } | ||||
|       : { id: 'ID' }; | ||||
|   } | ||||
| 
 | ||||
|   // Single Types
 | ||||
|   else if (kind === 'singleType') { | ||||
|     return { | ||||
|       id: 'ID', | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| module.exports = { | ||||
|   getContentTypeArgs, | ||||
|   getUniqueScalarAttributes, | ||||
|   scalarAttributesToFiltersMap, | ||||
|   transformArgs, | ||||
|  | ||||
| @ -1,11 +1,41 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const { omit } = require('lodash/fp'); | ||||
| 
 | ||||
| const { transformArgs } = require('../builders/utils'); | ||||
| const { utils } = require('../../types'); | ||||
| 
 | ||||
| const buildAssociationResolver = ({ contentTypeUID, attributeName, strapi }) => { | ||||
|   const { entityManager } = strapi.db; | ||||
| 
 | ||||
|   const contentType = strapi.getModel(contentTypeUID); | ||||
|   const attribute = contentType.attributes[attributeName]; | ||||
| 
 | ||||
|   if (!attribute) { | ||||
|     throw new Error( | ||||
|       `Failed to build an association resolver for ${contentTypeUID}::${attributeName}` | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   // todo[v4]: make sure polymorphic relations aren't breaking here
 | ||||
|   const targetUID = utils.isMedia(attribute) ? 'plugins::upload.file' : attribute.target; | ||||
|   const targetContentType = strapi.getModel(targetUID); | ||||
| 
 | ||||
|   return (parent, args = {}) => { | ||||
|     const transformedArgs = transformArgs(args, { | ||||
|       contentType: targetContentType, | ||||
|       usePagination: true, | ||||
|     }); | ||||
| 
 | ||||
|     // todo[v4]: move the .load to the entity service?
 | ||||
|     const hotFixedArgs = { | ||||
|       ...omit(['start', 'filters'], transformedArgs), | ||||
|       where: transformedArgs.filters, | ||||
|       offset: transformedArgs.start, | ||||
|     }; | ||||
| 
 | ||||
|     // todo[v4]: Should we be able to run policies here too?
 | ||||
|     return entityManager.load(contentTypeUID, parent, attributeName, args); | ||||
|     return entityManager.load(contentTypeUID, parent, attributeName, hotFixedArgs); | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,22 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const { omit } = require('lodash/fp'); | ||||
| const { transformArgs } = require('../builders/utils'); | ||||
| 
 | ||||
| const buildComponentResolver = ({ contentTypeUID, attributeName, strapi }) => { | ||||
|   return async (source, args = {}) => { | ||||
|     const contentType = strapi.getModel(contentTypeUID); | ||||
|     const transformedArgs = transformArgs(args, { contentType, usePagination: true }); | ||||
| 
 | ||||
|     // todo[v4]: move the .load to the entity service?
 | ||||
|     const hotFixedArgs = { | ||||
|       ...omit(['start', 'filters'], transformedArgs), | ||||
|       where: transformedArgs.filters, | ||||
|       offset: transformedArgs.start, | ||||
|     }; | ||||
| 
 | ||||
|     return strapi.db.entityManager.load(contentTypeUID, source, attributeName, hotFixedArgs); | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| module.exports = { buildComponentResolver }; | ||||
| @ -3,6 +3,7 @@ | ||||
| const associationResolvers = require('./association'); | ||||
| const { buildQueriesResolvers } = require('./query'); | ||||
| const { buildMutationsResolvers } = require('./mutation'); | ||||
| const { buildComponentResolver } = require('./component'); | ||||
| 
 | ||||
| module.exports = { | ||||
|   // Generics
 | ||||
| @ -11,4 +12,5 @@ module.exports = { | ||||
|   // Builders
 | ||||
|   buildMutationsResolvers, | ||||
|   buildQueriesResolvers, | ||||
|   buildComponentResolver, | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Convly
						Convly