fix(graphql): population of joins that target relationship fields that have relationTo as an array (#12289)
Fixes population of joins that target relationship fields that have
`relationTo` as an array, for example:
```ts
// Posts collection
{
name: 'polymorphic',
type: 'relationship',
relationTo: ['categories', 'users'],
},
// Categories collection
{
name: 'polymorphic',
type: 'join',
collection: 'posts',
on: 'polymorphic',
}
```
Thanks @jaycetde for the integration test
https://github.com/payloadcms/payload/pull/12278!
---------
Co-authored-by: Jayce Pulsipher <jpulsipher@nav.com>
This commit is contained in:
@@ -11,6 +11,7 @@ export type ObjectTypeConfig = {
|
|||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
baseFields?: ObjectTypeConfig
|
baseFields?: ObjectTypeConfig
|
||||||
|
collectionSlug?: string
|
||||||
config: SanitizedConfig
|
config: SanitizedConfig
|
||||||
fields: Field[]
|
fields: Field[]
|
||||||
forceNullable?: boolean
|
forceNullable?: boolean
|
||||||
@@ -23,6 +24,7 @@ type Args = {
|
|||||||
export function buildObjectType({
|
export function buildObjectType({
|
||||||
name,
|
name,
|
||||||
baseFields = {},
|
baseFields = {},
|
||||||
|
collectionSlug,
|
||||||
config,
|
config,
|
||||||
fields,
|
fields,
|
||||||
forceNullable,
|
forceNullable,
|
||||||
@@ -43,6 +45,7 @@ export function buildObjectType({
|
|||||||
return {
|
return {
|
||||||
...objectTypeConfig,
|
...objectTypeConfig,
|
||||||
...fieldSchema({
|
...fieldSchema({
|
||||||
|
collectionSlug,
|
||||||
config,
|
config,
|
||||||
field,
|
field,
|
||||||
forceNullable,
|
forceNullable,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
DateField,
|
DateField,
|
||||||
EmailField,
|
EmailField,
|
||||||
Field,
|
Field,
|
||||||
|
FlattenedJoinField,
|
||||||
GraphQLInfo,
|
GraphQLInfo,
|
||||||
GroupField,
|
GroupField,
|
||||||
JoinField,
|
JoinField,
|
||||||
@@ -68,6 +69,7 @@ function formattedNameResolver({
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SharedArgs = {
|
type SharedArgs = {
|
||||||
|
collectionSlug?: string
|
||||||
config: SanitizedConfig
|
config: SanitizedConfig
|
||||||
forceNullable?: boolean
|
forceNullable?: boolean
|
||||||
graphqlResult: GraphQLInfo
|
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 joinName = combineParentName(parentName, toWords(field.name, true))
|
||||||
|
|
||||||
const joinType = {
|
const joinType = {
|
||||||
@@ -385,9 +387,23 @@ export const fieldToSchemaMap: FieldToSchemaMap = {
|
|||||||
|
|
||||||
const draft = Boolean(args.draft ?? context.req.query?.draft)
|
const draft = Boolean(args.draft ?? context.req.query?.draft)
|
||||||
|
|
||||||
const fullWhere = combineQueries(where, {
|
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 },
|
[field.on]: { equals: parent._id ?? parent.id },
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if (Array.isArray(collection)) {
|
if (Array.isArray(collection)) {
|
||||||
throw new Error('GraphQL with array of join.field.collection is not implemented')
|
throw new Error('GraphQL with array of join.field.collection is not implemented')
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { recursivelyBuildNestedPaths } from './recursivelyBuildNestedPaths.js'
|
|||||||
import { withOperators } from './withOperators.js'
|
import { withOperators } from './withOperators.js'
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
|
collectionSlug?: string
|
||||||
nestedFieldName?: string
|
nestedFieldName?: string
|
||||||
parentName: string
|
parentName: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export function initCollections({ config, graphqlResult }: InitCollectionsGraphQ
|
|||||||
collection.graphQL.type = buildObjectType({
|
collection.graphQL.type = buildObjectType({
|
||||||
name: singularName,
|
name: singularName,
|
||||||
baseFields,
|
baseFields,
|
||||||
|
collectionSlug: collectionConfig.slug,
|
||||||
config,
|
config,
|
||||||
fields,
|
fields,
|
||||||
forceNullable: forceNullableObjectType,
|
forceNullable: forceNullableObjectType,
|
||||||
@@ -339,6 +340,7 @@ export function initCollections({ config, graphqlResult }: InitCollectionsGraphQ
|
|||||||
|
|
||||||
collection.graphQL.versionType = buildObjectType({
|
collection.graphQL.versionType = buildObjectType({
|
||||||
name: `${singularName}Version`,
|
name: `${singularName}Version`,
|
||||||
|
collectionSlug: collectionConfig.slug,
|
||||||
config,
|
config,
|
||||||
fields: versionCollectionFields,
|
fields: versionCollectionFields,
|
||||||
forceNullable: forceNullableObjectType,
|
forceNullable: forceNullableObjectType,
|
||||||
|
|||||||
@@ -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 () => {
|
it('should populate joins with hasMany when on both sides documents are in draft', async () => {
|
||||||
const category = await payload.create({
|
const category = await payload.create({
|
||||||
collection: 'categories-versions',
|
collection: 'categories-versions',
|
||||||
|
|||||||
Reference in New Issue
Block a user