diff --git a/packages/drizzle/src/queries/getTableColumnFromPath.ts b/packages/drizzle/src/queries/getTableColumnFromPath.ts index 39f970329..1a51104df 100644 --- a/packages/drizzle/src/queries/getTableColumnFromPath.ts +++ b/packages/drizzle/src/queries/getTableColumnFromPath.ts @@ -1,4 +1,4 @@ -import type { SQL, Table } from 'drizzle-orm' +import type { SQL } from 'drizzle-orm' import type { SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core' import type { FlattenedBlock, @@ -8,7 +8,7 @@ import type { TextField, } from 'payload' -import { and, eq, getTableName, like, sql } from 'drizzle-orm' +import { and, eq, getTableName, like, or, sql, Table } from 'drizzle-orm' import { type PgTableWithColumns } from 'drizzle-orm/pg-core' import { APIError, getFieldByPath } from 'payload' import { fieldShouldBeLocalized, tabHasName } from 'payload/shared' @@ -499,27 +499,37 @@ export const getTableColumnFromPath = ({ columnName = 'number' } newTableName = `${rootTableName}_${tableType}` + + const existingTable = joins.find((e) => e.queryPath === `${constraintPath}${field.name}`) + + const table = (existingTable?.table ?? + getTableAlias({ adapter, tableName: newTableName }) + .newAliasTable) as PgTableWithColumns + const joinConstraints = [ - eq(adapter.tables[rootTableName].id, adapter.tables[newTableName].parent), - like(adapter.tables[newTableName].path, `${constraintPath}${field.name}`), + eq(adapter.tables[rootTableName].id, table.parent), + like(table.path, `${constraintPath}${field.name}`), ] if (locale && isFieldLocalized && adapter.payload.config.localization) { const conditions = [...joinConstraints] if (locale !== 'all') { - conditions.push(eq(adapter.tables[newTableName]._locale, locale)) + conditions.push(eq(table._locale, locale)) } + addJoinTable({ condition: and(...conditions), joins, - table: adapter.tables[newTableName], + queryPath: `${constraintPath}${field.name}`, + table, }) } else { addJoinTable({ condition: and(...joinConstraints), joins, - table: adapter.tables[newTableName], + queryPath: `${constraintPath}${field.name}`, + table, }) } @@ -527,7 +537,7 @@ export const getTableColumnFromPath = ({ columnName, constraints, field, - table: adapter.tables[newTableName], + table, } } break diff --git a/test/fields/collections/Text/index.ts b/test/fields/collections/Text/index.ts index 4d1d5f872..77444d895 100644 --- a/test/fields/collections/Text/index.ts +++ b/test/fields/collections/Text/index.ts @@ -127,6 +127,11 @@ const TextFields: CollectionConfig = { type: 'text', hasMany: true, }, + { + name: 'hasManySecond', + type: 'text', + hasMany: true, + }, { name: 'readOnlyHasMany', type: 'text', diff --git a/test/fields/int.spec.ts b/test/fields/int.spec.ts index 738a6950d..cc5eb0643 100644 --- a/test/fields/int.spec.ts +++ b/test/fields/int.spec.ts @@ -165,6 +165,43 @@ describe('Fields', () => { expect(missResult).toBeFalsy() }) + it('should query multiple hasMany fields', async () => { + await payload.delete({ collection: 'text-fields', where: {} }) + const hit = await payload.create({ + collection: 'text-fields', + data: { + hasMany: ['1', '2', '3'], + hasManySecond: ['4'], + text: 'required', + }, + }) + + const miss = await payload.create({ + collection: 'text-fields', + data: { + hasMany: ['6'], + hasManySecond: ['4'], + text: 'required', + }, + }) + + const { docs } = await payload.find({ + collection: 'text-fields', + where: { + hasMany: { equals: '3' }, + hasManySecond: { + equals: '4', + }, + }, + }) + + const hitResult = docs.find(({ id: findID }) => hit.id === findID) + const missResult = docs.find(({ id: findID }) => miss.id === findID) + + expect(hitResult).toBeDefined() + expect(missResult).toBeFalsy() + }) + it('should query like on value', async () => { const miss = await payload.create({ collection: 'text-fields', diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 50b383869..71b64bd19 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -769,6 +769,7 @@ export interface TextField { fieldWithDefaultValue?: string | null; dependentOnFieldWithDefaultValue?: string | null; hasMany?: string[] | null; + hasManySecond?: string[] | null; readOnlyHasMany?: string[] | null; validatesHasMany?: string[] | null; localizedHasMany?: string[] | null; @@ -3256,6 +3257,7 @@ export interface TextFieldsSelect { fieldWithDefaultValue?: T; dependentOnFieldWithDefaultValue?: T; hasMany?: T; + hasManySecond?: T; readOnlyHasMany?: T; validatesHasMany?: T; localizedHasMany?: T;