diff --git a/packages/graphql/src/schema/buildObjectType.ts b/packages/graphql/src/schema/buildObjectType.ts index 0ce88092e..f368f663b 100644 --- a/packages/graphql/src/schema/buildObjectType.ts +++ b/packages/graphql/src/schema/buildObjectType.ts @@ -11,6 +11,7 @@ export type ObjectTypeConfig = { type Args = { baseFields?: ObjectTypeConfig + collectionSlug?: string config: SanitizedConfig fields: Field[] forceNullable?: boolean @@ -23,6 +24,7 @@ type Args = { export function buildObjectType({ name, baseFields = {}, + collectionSlug, config, fields, forceNullable, @@ -43,6 +45,7 @@ export function buildObjectType({ return { ...objectTypeConfig, ...fieldSchema({ + collectionSlug, config, field, forceNullable, diff --git a/packages/graphql/src/schema/fieldToSchemaMap.ts b/packages/graphql/src/schema/fieldToSchemaMap.ts index 70ffc75ab..fc5750add 100644 --- a/packages/graphql/src/schema/fieldToSchemaMap.ts +++ b/packages/graphql/src/schema/fieldToSchemaMap.ts @@ -8,6 +8,7 @@ import type { DateField, EmailField, Field, + FlattenedJoinField, GraphQLInfo, GroupField, JoinField, @@ -68,6 +69,7 @@ function formattedNameResolver({ } type SharedArgs = { + collectionSlug?: string config: SanitizedConfig forceNullable?: boolean graphqlResult: GraphQLInfo @@ -340,7 +342,7 @@ export const fieldToSchemaMap: FieldToSchemaMap = { }, } }, - join: ({ field, graphqlResult, objectTypeConfig, parentName }) => { + join: ({ collectionSlug, field, graphqlResult, objectTypeConfig, parentName }) => { const joinName = combineParentName(parentName, toWords(field.name, true)) const joinType = { @@ -385,9 +387,23 @@ export const fieldToSchemaMap: FieldToSchemaMap = { const draft = Boolean(args.draft ?? context.req.query?.draft) - const fullWhere = combineQueries(where, { - [field.on]: { equals: parent._id ?? parent.id }, - }) + const targetField = (field as FlattenedJoinField).targetField + + const fullWhere = combineQueries( + where, + Array.isArray(targetField.relationTo) + ? { + [field.on]: { + equals: { + relationTo: collectionSlug, + value: parent._id ?? parent.id, + }, + }, + } + : { + [field.on]: { equals: parent._id ?? parent.id }, + }, + ) if (Array.isArray(collection)) { throw new Error('GraphQL with array of join.field.collection is not implemented') diff --git a/packages/graphql/src/schema/fieldToWhereInputSchemaMap.ts b/packages/graphql/src/schema/fieldToWhereInputSchemaMap.ts index db3f0e1f3..ab77eff03 100644 --- a/packages/graphql/src/schema/fieldToWhereInputSchemaMap.ts +++ b/packages/graphql/src/schema/fieldToWhereInputSchemaMap.ts @@ -29,6 +29,7 @@ import { recursivelyBuildNestedPaths } from './recursivelyBuildNestedPaths.js' import { withOperators } from './withOperators.js' type Args = { + collectionSlug?: string nestedFieldName?: string parentName: string } diff --git a/packages/graphql/src/schema/initCollections.ts b/packages/graphql/src/schema/initCollections.ts index 626a2a120..7dda78057 100644 --- a/packages/graphql/src/schema/initCollections.ts +++ b/packages/graphql/src/schema/initCollections.ts @@ -111,6 +111,7 @@ export function initCollections({ config, graphqlResult }: InitCollectionsGraphQ collection.graphQL.type = buildObjectType({ name: singularName, baseFields, + collectionSlug: collectionConfig.slug, config, fields, forceNullable: forceNullableObjectType, @@ -339,6 +340,7 @@ export function initCollections({ config, graphqlResult }: InitCollectionsGraphQ collection.graphQL.versionType = buildObjectType({ name: `${singularName}Version`, + collectionSlug: collectionConfig.slug, config, fields: versionCollectionFields, forceNullable: forceNullableObjectType, diff --git a/test/joins/int.spec.ts b/test/joins/int.spec.ts index f38248388..85b9bc76e 100644 --- a/test/joins/int.spec.ts +++ b/test/joins/int.spec.ts @@ -940,6 +940,94 @@ describe('Joins Field', () => { ) }) + it('should have simple paginate with page for joins polymorphic', async () => { + let queryWithLimit = `query { + Categories(where: { + name: { equals: "paginate example" } + }) { + docs { + polymorphic( + sort: "createdAt", + limit: 2 + ) { + docs { + title + } + hasNextPage + } + } + } + }` + let pageWithLimit = await restClient + .GRAPHQL_POST({ body: JSON.stringify({ query: queryWithLimit }) }) + .then((res) => res.json()) + + const queryUnlimited = `query { + Categories( + where: { + name: { equals: "paginate example" } + } + ) { + docs { + polymorphic( + sort: "createdAt", + limit: 0 + ) { + docs { + title + createdAt + } + hasNextPage + } + } + } + }` + + const unlimited = await restClient + .GRAPHQL_POST({ body: JSON.stringify({ query: queryUnlimited }) }) + .then((res) => res.json()) + + expect(pageWithLimit.data.Categories.docs[0].polymorphic.docs).toHaveLength(2) + expect(pageWithLimit.data.Categories.docs[0].polymorphic.docs[0].id).toStrictEqual( + unlimited.data.Categories.docs[0].polymorphic.docs[0].id, + ) + expect(pageWithLimit.data.Categories.docs[0].polymorphic.docs[1].id).toStrictEqual( + unlimited.data.Categories.docs[0].polymorphic.docs[1].id, + ) + + expect(pageWithLimit.data.Categories.docs[0].polymorphic.hasNextPage).toStrictEqual(true) + + queryWithLimit = `query { + Categories(where: { + name: { equals: "paginate example" } + }) { + docs { + polymorphic( + sort: "createdAt", + limit: 2, + page: 2, + ) { + docs { + title + } + hasNextPage + } + } + } + }` + + pageWithLimit = await restClient + .GRAPHQL_POST({ body: JSON.stringify({ query: queryWithLimit }) }) + .then((res) => res.json()) + + expect(pageWithLimit.data.Categories.docs[0].polymorphic.docs[0].id).toStrictEqual( + unlimited.data.Categories.docs[0].polymorphic.docs[2].id, + ) + expect(pageWithLimit.data.Categories.docs[0].polymorphic.docs[1].id).toStrictEqual( + unlimited.data.Categories.docs[0].polymorphic.docs[3].id, + ) + }) + it('should populate joins with hasMany when on both sides documents are in draft', async () => { const category = await payload.create({ collection: 'categories-versions',