diff --git a/src/collections/graphql/resolvers/getFindByID.js b/src/collections/graphql/resolvers/getFindByID.js index 6cb5c4acdb..a15f86fba7 100644 --- a/src/collections/graphql/resolvers/getFindByID.js +++ b/src/collections/graphql/resolvers/getFindByID.js @@ -3,7 +3,9 @@ const findByIDQuery = require('../../queries/findByID'); const findByID = ({ config, model }) => withPolicy( config.policies.read, - async (_, { id }, context) => { + async (parent, { id }, context) => { + console.log(parent); + const options = { depth: 0, model, diff --git a/src/collections/queries/findByID.js b/src/collections/queries/findByID.js index 7d0eaa9549..2b16df19bc 100644 --- a/src/collections/queries/findByID.js +++ b/src/collections/queries/findByID.js @@ -1,3 +1,4 @@ +const mongoose = require('mongoose'); const { NotFound } = require('../../errors'); const findByID = async (options) => { @@ -6,6 +7,8 @@ const findByID = async (options) => { depth, locale, fallbackLocale, model, id, } = options; + const hasMultipleIDs = Array.isArray(id); + if (depth) { mongooseOptions.autopopulate = { maxDepth: depth, @@ -13,21 +16,32 @@ const findByID = async (options) => { } try { - // Await pre findOne hook here + // Await pre find hook here - const doc = await model.findOne({ _id: id }, {}, mongooseOptions); + let result; - if (!doc) { - throw new NotFound(); + if (hasMultipleIDs) { + result = await model.find({ + _id: { + $in: id.map(id => mongoose.Types.ObjectId(id)), + }, + }, {}, mongooseOptions); + } else { + result = await model.findOne({ _id: id }, {}, mongooseOptions); } - if (locale && doc.setLocale) { - doc.setLocale(locale, fallbackLocale); - } + if (result.length === 0) throw new NotFound(); - // Await post findOne hook here + if (hasMultipleIDs) { + result = result.map((doc) => { + if (locale && doc.setLocale) doc.setLocale(locale, fallbackLocale); + return doc.toJSON({ virtuals: true }); + }); + } else if (locale && result.setLocale) result = result.setLocale(locale, fallbackLocale); - return doc.toJSON({ virtuals: true }); + // Await post find hook here + + return result.toJSON({ virtuals: true }); } catch (err) { throw err; } diff --git a/src/graphql/index.js b/src/graphql/index.js index 123ec130ac..8963f82fc8 100644 --- a/src/graphql/index.js +++ b/src/graphql/index.js @@ -21,7 +21,7 @@ class GraphQL { this.init = this.init.bind(this); this.registerUser = this.registerUser.bind(this); this.registerCollections = this.registerCollections.bind(this); - this.addBlockType = this.addBlockType.bind(this); + this.buildBlockTypeIfMissing = this.buildBlockTypeIfMissing.bind(this); this.config = config; this.collections = collections; @@ -81,11 +81,32 @@ class GraphQL { } registerCollections() { - Object.keys(this.collections).forEach((collectionKey) => { - const collection = this.collections[collectionKey]; + Object.keys(this.collections).forEach((slug) => { + const { + config: { + labels: { + singular, + }, + fields, + }, + } = this.collections[slug]; + + const singularLabel = formatName(singular); + + this.collections[slug].graphQLType = this.buildObjectType( + singularLabel, + fields, + singularLabel, + getFindByID(this.collections[slug]), + ); + }); + + Object.keys(this.collections).forEach((collectionSlug) => { + const collection = this.collections[collectionSlug]; const { config: { + slug, fields, labels: { singular, @@ -97,8 +118,6 @@ class GraphQL { const singularLabel = formatName(singular); const pluralLabel = formatName(plural); - collection.graphQLType = this.buildObjectType(singularLabel, fields, singularLabel); - collection.graphQLWhereInputType = buildWhereInputType({ name: singularLabel, fields, @@ -106,7 +125,7 @@ class GraphQL { }); this.Query.fields[singularLabel] = { - type: collection.graphQLType, + type: this.collections[slug].graphQLType, args: { id: { type: GraphQLString }, }, @@ -140,8 +159,32 @@ class GraphQL { }); } - addBlockType(blockType, slug) { - this.types.blockTypes[slug] = blockType; + buildBlockTypeIfMissing(block) { + const { + slug, + labels: { + singular, + }, + } = block; + + if (!this.types.blockTypes[slug]) { + const formattedBlockName = formatName(singular); + this.types.blockTypes[slug] = this.buildObjectType( + formattedBlockName, + [ + ...block.fields, + { + name: 'blockName', + type: 'text', + }, + { + name: 'blockType', + type: 'text', + }, + ], + formattedBlockName, + ); + } } } diff --git a/src/graphql/schema/getBuildObjectType.js b/src/graphql/schema/getBuildObjectType.js index 66fd377e1e..0bcbc2f819 100644 --- a/src/graphql/schema/getBuildObjectType.js +++ b/src/graphql/schema/getBuildObjectType.js @@ -33,7 +33,7 @@ function getBuildObjectType(context) { return type; }; - const buildObjectType = (name, fields, parent) => { + const buildObjectType = (name, fields, parent, resolver) => { const fieldToSchemaMap = { number: (field) => { return { @@ -139,10 +139,31 @@ function getBuildObjectType(context) { }; }, relationship: (field) => { - const type = GraphQLString; + const { relationTo, label } = field; + let relationshipType; + + if (Array.isArray(relationTo)) { + const types = relationTo.map((relation) => { + return context.collections[relation].graphQLType; + }); + + relationshipType = new GraphQLUnionType({ + name: combineParentName(parent, label), + types, + resolveType(data) { + return context.types.blockTypes[data.blockType]; + }, + }); + } else { + relationshipType = context.collections[relationTo].graphQLType; + } + + // eslint-disable-next-line no-use-before-define + relationshipType = relationshipType || blockType; + const typeWithLocale = withLocalizedType( field, - withNullableType(field, type), + withNullableType(field, relationshipType), ); return { @@ -170,29 +191,9 @@ function getBuildObjectType(context) { }; }, flexible: (field) => { - const blockTypeOptions = field.blocks.map(block => block.slug); - - field.blocks.forEach((block) => { - if (context.types.blockTypes[block.slug] === undefined) { - const formattedBlockName = formatName(block.labels.singular); - - context.addBlockType(buildObjectType( - formattedBlockName, - [ - ...block.fields, - { - name: 'blockName', - type: 'text', - }, - { - name: 'blockType', - type: 'select', - options: blockTypeOptions, - }, - ], - formattedBlockName, - ), block.slug); - } + const types = field.blocks.map((block) => { + context.buildBlockTypeIfMissing(block); + return context.types.blockTypes[block.slug]; }); return { @@ -201,7 +202,7 @@ function getBuildObjectType(context) { new GraphQLList( new GraphQLUnionType({ name: combineParentName(parent, field.label), - types: field.blocks.map(blockType => context.types.blockTypes[blockType.slug]), + types, resolveType(data) { return context.types.blockTypes[data.blockType]; }, @@ -212,9 +213,9 @@ function getBuildObjectType(context) { }, }; - return new GraphQLObjectType({ + const objectSchema = { name, - fields: fields.reduce((schema, field) => { + fields: () => fields.reduce((schema, field) => { const fieldSchema = fieldToSchemaMap[field.type]; if (fieldSchema) { return { @@ -225,7 +226,15 @@ function getBuildObjectType(context) { return schema; }, {}), - }); + }; + + if (resolver) { + objectSchema.resolve = resolver; + } + + const blockType = new GraphQLObjectType(objectSchema); + + return blockType; }; return buildObjectType;