Skip to content

Commit d03658d

Browse files
authored
feat: join field with polymorphic relationships (#9990)
### What? The join field had a limitation imposed that prevents it from targeting polymorphic relationship fields. With this change we can support any relationship fields. ### Why? Improves the functionality of join field. ### How? Extended the database adapters and removed the config sanitization that would throw an error when polymorphic relationships were used. Fixes #
1 parent 07be617 commit d03658d

File tree

19 files changed

+330
-40
lines changed

19 files changed

+330
-40
lines changed

packages/db-mongodb/src/utilities/buildJoinAggregation.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ export const buildJoinAggregation = async ({
8181
})
8282
}
8383

84+
let polymorphicSuffix = ''
85+
if (Array.isArray(join.targetField.relationTo)) {
86+
polymorphicSuffix = '.value'
87+
}
88+
8489
if (adapter.payload.config.localization && locale === 'all') {
8590
adapter.payload.config.localization.localeCodes.forEach((code) => {
8691
const as = `${versions ? `version.${join.joinPath}` : join.joinPath}${code}`
@@ -89,7 +94,7 @@ export const buildJoinAggregation = async ({
8994
{
9095
$lookup: {
9196
as: `${as}.docs`,
92-
foreignField: `${join.field.on}${code}`,
97+
foreignField: `${join.field.on}${code}${polymorphicSuffix}`,
9398
from: adapter.collections[slug].collection.name,
9499
localField: versions ? 'parent' : '_id',
95100
pipeline,
@@ -130,7 +135,7 @@ export const buildJoinAggregation = async ({
130135
{
131136
$lookup: {
132137
as: `${as}.docs`,
133-
foreignField: `${join.field.on}${localeSuffix}`,
138+
foreignField: `${join.field.on}${localeSuffix}${polymorphicSuffix}`,
134139
from: adapter.collections[slug].collection.name,
135140
localField: versions ? 'parent' : '_id',
136141
pipeline,

packages/drizzle/src/find.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const find: Find = async function find(
1717

1818
return findMany({
1919
adapter: this,
20+
collectionSlug: collectionConfig.slug,
2021
fields: collectionConfig.flattenedFields,
2122
joins,
2223
limit,

packages/drizzle/src/find/buildFindManyArgs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { traverseFields } from './traverseFields.js'
99

1010
type BuildFindQueryArgs = {
1111
adapter: DrizzleAdapter
12+
collectionSlug?: string
1213
depth: number
1314
fields: FlattenedField[]
1415
joinQuery?: JoinQuery
@@ -32,6 +33,7 @@ export type Result = {
3233
// a collection field structure
3334
export const buildFindManyArgs = ({
3435
adapter,
36+
collectionSlug,
3537
depth,
3638
fields,
3739
joinQuery,
@@ -74,6 +76,7 @@ export const buildFindManyArgs = ({
7476
traverseFields({
7577
_locales,
7678
adapter,
79+
collectionSlug,
7780
currentArgs: result,
7881
currentTableName: tableName,
7982
depth,

packages/drizzle/src/find/findMany.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ import { buildFindManyArgs } from './buildFindManyArgs.js'
1313

1414
type Args = {
1515
adapter: DrizzleAdapter
16+
collectionSlug?: string
1617
fields: FlattenedField[]
1718
tableName: string
1819
versions?: boolean
1920
} & Omit<FindArgs, 'collection'>
2021

2122
export const findMany = async function find({
2223
adapter,
24+
collectionSlug,
2325
fields,
2426
joins: joinQuery,
2527
limit: limitArg,
@@ -70,6 +72,7 @@ export const findMany = async function find({
7072

7173
const findManyArgs = buildFindManyArgs({
7274
adapter,
75+
collectionSlug,
7376
depth: 0,
7477
fields,
7578
joinQuery,

packages/drizzle/src/find/traverseFields.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { chainMethods } from './chainMethods.js'
1616
type TraverseFieldArgs = {
1717
_locales: Result
1818
adapter: DrizzleAdapter
19+
collectionSlug?: string
1920
currentArgs: Result
2021
currentTableName: string
2122
depth?: number
@@ -42,6 +43,7 @@ type TraverseFieldArgs = {
4243
export const traverseFields = ({
4344
_locales,
4445
adapter,
46+
collectionSlug,
4547
currentArgs,
4648
currentTableName,
4749
depth,
@@ -292,6 +294,7 @@ export const traverseFields = ({
292294
traverseFields({
293295
_locales,
294296
adapter,
297+
collectionSlug,
295298
currentArgs,
296299
currentTableName,
297300
depth,
@@ -357,13 +360,26 @@ export const traverseFields = ({
357360
? adapter.tables[currentTableName].parent
358361
: adapter.tables[currentTableName].id
359362

360-
let joinQueryWhere: Where = {
361-
[field.on]: {
362-
equals: rawConstraint(currentIDColumn),
363-
},
363+
let joinQueryWhere: Where
364+
365+
if (Array.isArray(field.targetField.relationTo)) {
366+
joinQueryWhere = {
367+
[field.on]: {
368+
equals: {
369+
relationTo: collectionSlug,
370+
value: rawConstraint(currentIDColumn),
371+
},
372+
},
373+
}
374+
} else {
375+
joinQueryWhere = {
376+
[field.on]: {
377+
equals: rawConstraint(currentIDColumn),
378+
},
379+
}
364380
}
365381

366-
if (where) {
382+
if (where && Object.keys(where).length) {
367383
joinQueryWhere = {
368384
and: [joinQueryWhere, where],
369385
}

packages/drizzle/src/findOne.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function findOne<T extends TypeWithID>(
1616

1717
const { docs } = await findMany({
1818
adapter: this,
19+
collectionSlug: collection,
1920
fields: collectionConfig.flattenedFields,
2021
joins,
2122
limit: 1,

packages/drizzle/src/queries/sanitizeQueryValue.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ export const sanitizeQueryValue = ({
142142
collection: adapter.payload.collections[val.relationTo],
143143
})
144144

145+
if (isRawConstraint(val.value)) {
146+
return {
147+
operator,
148+
value: val.value.value,
149+
}
150+
}
145151
return {
146152
operator,
147153
value: idType === 'number' ? Number(val.value) : String(val.value),

packages/drizzle/src/queryDrafts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
2121

2222
const result = await findMany({
2323
adapter: this,
24+
collectionSlug: collection,
2425
fields,
2526
joins,
2627
limit,

packages/payload/src/fields/config/client.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
ClientField,
99
Field,
1010
FieldBase,
11+
JoinFieldClient,
1112
LabelsClient,
1213
RadioFieldClient,
1314
RowFieldClient,
@@ -229,6 +230,16 @@ export const createClientField = ({
229230
break
230231
}
231232

233+
case 'join': {
234+
const field = clientField as JoinFieldClient
235+
236+
field.targetField = {
237+
relationTo: field.targetField.relationTo,
238+
}
239+
240+
break
241+
}
242+
232243
case 'radio':
233244
// falls through
234245
case 'select': {

packages/payload/src/fields/config/sanitizeJoinField.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SanitizedJoin, SanitizedJoins } from '../../collections/config/types.js'
22
import type { Config } from '../../config/types.js'
3-
import type { JoinField, RelationshipField, UploadField } from './types.js'
3+
import type { FlattenedJoinField, JoinField, RelationshipField, UploadField } from './types.js'
44

55
import { APIError } from '../../errors/index.js'
66
import { InvalidFieldJoin } from '../../errors/InvalidFieldJoin.js'
@@ -12,7 +12,7 @@ export const sanitizeJoinField = ({
1212
joins,
1313
}: {
1414
config: Config
15-
field: JoinField
15+
field: FlattenedJoinField | JoinField
1616
joinPath?: string
1717
joins?: SanitizedJoins
1818
}) => {
@@ -74,9 +74,6 @@ export const sanitizeJoinField = ({
7474
if (!joinRelationship) {
7575
throw new InvalidFieldJoin(join.field)
7676
}
77-
if (Array.isArray(joinRelationship.relationTo)) {
78-
throw new APIError('Join fields cannot be used with polymorphic relationships.')
79-
}
8077

8178
join.targetField = joinRelationship
8279

@@ -85,6 +82,9 @@ export const sanitizeJoinField = ({
8582
// override the join field hasMany property to use whatever the relationship field has
8683
field.hasMany = joinRelationship.hasMany
8784

85+
// @ts-expect-error converting JoinField to FlattenedJoinField to track targetField
86+
field.targetField = join.targetField
87+
8888
if (!joins[field.collection]) {
8989
joins[field.collection] = [join]
9090
} else {

0 commit comments

Comments
 (0)