Skip to content

Commit 31ffc57

Browse files
authored
fix(drizzle): in query on polymorphic relations across ID types (#8240)
Fixes querying using `in` operator by polymorphic relationship value. The previous PR #8191 didn't handle the case when the incoming query value is an array and therefore each item of the array can have a different type. Ensures test coverage
1 parent 9035467 commit 31ffc57

File tree

3 files changed

+93
-10
lines changed

3 files changed

+93
-10
lines changed

packages/drizzle/src/queries/getTableColumnFromPath.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type Constraint = {
2323
type TableColumn = {
2424
columnName?: string
2525
columns?: {
26-
idType: 'number' | 'text'
26+
idType: 'number' | 'text' | 'uuid'
2727
rawColumn: SQL<unknown>
2828
}[]
2929
constraints: Constraint[]
@@ -521,17 +521,28 @@ export const getTableColumnFromPath = ({
521521

522522
const columns: TableColumn['columns'] = field.relationTo
523523
.map((relationTo) => {
524-
let idType: 'number' | 'text' = adapter.idType === 'uuid' ? 'text' : 'number'
524+
let idType: 'number' | 'text' | 'uuid' =
525+
adapter.idType === 'uuid' ? 'uuid' : 'number'
525526

526527
const { customIDType } = adapter.payload.collections[relationTo]
527528

528529
if (customIDType) {
529530
idType = customIDType
530531
}
531532

533+
const idTypeTextOrUuid = idType === 'text' || idType === 'uuid'
534+
532535
// Do not add the column to OR if we know that it can't match by the type
533536
// We can't do the same with idType: 'number' because `value` can be from the REST search query params
534-
if (typeof value === 'number' && idType === 'text') {
537+
if (typeof value === 'number' && idTypeTextOrUuid) {
538+
return null
539+
}
540+
541+
if (
542+
Array.isArray(value) &&
543+
value.every((val) => typeof val === 'number') &&
544+
idTypeTextOrUuid
545+
) {
535546
return null
536547
}
537548

@@ -540,15 +551,24 @@ export const getTableColumnFromPath = ({
540551
// We need this because Postgres throws an error if querying by UUID column with a value that isn't a valid UUID.
541552
if (
542553
value &&
543-
!customIDType &&
544-
adapter.idType === 'uuid' &&
554+
!Array.isArray(value) &&
555+
idType === 'uuid' &&
545556
hasCustomCollectionWithCustomID
546557
) {
547558
if (!uuidValidate(value)) {
548559
return null
549560
}
550561
}
551562

563+
if (
564+
Array.isArray(value) &&
565+
idType === 'uuid' &&
566+
hasCustomCollectionWithCustomID &&
567+
!value.some((val) => uuidValidate(val))
568+
) {
569+
return null
570+
}
571+
552572
const relationTableName = adapter.tableNameMap.get(
553573
toSnakeCase(adapter.payload.collections[relationTo].config.slug),
554574
)

packages/drizzle/src/queries/sanitizeQueryValue.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import type { SQL } from 'drizzle-orm'
22

33
import { APIError, createArrayFromCommaDelineated, type Field, type TabAsField } from 'payload'
44
import { fieldAffectsData } from 'payload/shared'
5+
import { validate as uuidValidate } from 'uuid'
56

67
import type { DrizzleAdapter } from '../types.js'
78

89
type SanitizeQueryValueArgs = {
910
adapter: DrizzleAdapter
1011
columns?: {
11-
idType: 'number' | 'text'
12+
idType: 'number' | 'text' | 'uuid'
1213
rawColumn: SQL<unknown>
1314
}[]
1415
field: Field | TabAsField
@@ -119,15 +120,37 @@ export const sanitizeQueryValue = ({
119120
} else {
120121
formattedColumns = columns
121122
.map(({ idType, rawColumn }) => {
122-
let formattedValue: number | string
123-
if (idType === 'number') {
123+
let formattedValue: number | number[] | string | string[]
124+
125+
if (Array.isArray(val)) {
126+
formattedValue = val
127+
.map((eachVal) => {
128+
let formattedValue: number | string
129+
130+
if (idType === 'number') {
131+
formattedValue = Number(eachVal)
132+
133+
if (Number.isNaN(formattedValue)) {
134+
return null
135+
}
136+
} else {
137+
if (idType === 'uuid' && !uuidValidate(eachVal)) {
138+
return null
139+
}
140+
141+
formattedValue = String(eachVal)
142+
}
143+
144+
return formattedValue
145+
})
146+
.filter(Boolean) as number[] | string[]
147+
} else if (idType === 'number') {
124148
formattedValue = Number(val)
125149

126150
if (Number.isNaN(formattedValue)) {
127151
return null
128152
}
129-
}
130-
if (idType === 'text') {
153+
} else {
131154
formattedValue = String(val)
132155
}
133156

test/relationships/int.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,46 @@ describe('Relationships', () => {
587587

588588
expect(customIDNumberResult.totalDocs).toBe(1)
589589
expect(customIDNumberResult.docs[0].id).toBe(relToCustomIdNumber.id)
590+
591+
const inResult_1 = await payload.find({
592+
collection: 'rels-to-pages-and-custom-text-ids',
593+
where: {
594+
'rel.value': {
595+
in: [page.id, customIDNumber.id],
596+
},
597+
},
598+
})
599+
600+
expect(inResult_1.totalDocs).toBe(2)
601+
expect(inResult_1.docs.some((each) => each.id === relToPage.id)).toBeTruthy()
602+
expect(inResult_1.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy()
603+
604+
const inResult_2 = await payload.find({
605+
collection: 'rels-to-pages-and-custom-text-ids',
606+
where: {
607+
'rel.value': {
608+
in: [customIDNumber.id, customIDText.id],
609+
},
610+
},
611+
})
612+
613+
expect(inResult_2.totalDocs).toBe(2)
614+
expect(inResult_2.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy()
615+
expect(inResult_2.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy()
616+
617+
const inResult_3 = await payload.find({
618+
collection: 'rels-to-pages-and-custom-text-ids',
619+
where: {
620+
'rel.value': {
621+
in: [customIDNumber.id, customIDText.id, page.id],
622+
},
623+
},
624+
})
625+
626+
expect(inResult_3.totalDocs).toBe(3)
627+
expect(inResult_3.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy()
628+
expect(inResult_3.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy()
629+
expect(inResult_3.docs.some((each) => each.id === relToPage.id)).toBeTruthy()
590630
})
591631
})
592632

0 commit comments

Comments
 (0)