diff --git a/packages/drizzle/src/queries/getTableColumnFromPath.ts b/packages/drizzle/src/queries/getTableColumnFromPath.ts index ad92ee5ea..a03e44c6b 100644 --- a/packages/drizzle/src/queries/getTableColumnFromPath.ts +++ b/packages/drizzle/src/queries/getTableColumnFromPath.ts @@ -53,6 +53,7 @@ type Args = { fields: FlattenedField[] joins: BuildQueryJoinAliases locale?: string + parentAliasTable?: PgTableWithColumns | SQLiteTableWithColumns parentIsLocalized: boolean pathSegments: string[] rootTableName?: string @@ -83,6 +84,7 @@ export const getTableColumnFromPath = ({ fields, joins, locale: incomingLocale, + parentAliasTable, parentIsLocalized, pathSegments: incomingSegments, rootTableName: incomingRootTableName, @@ -162,6 +164,7 @@ export const getTableColumnFromPath = ({ table: adapter.tables[newTableName], }) } + return getTableColumnFromPath({ adapter, collectionPath, @@ -170,6 +173,7 @@ export const getTableColumnFromPath = ({ fields: field.flattenedFields, joins, locale, + parentAliasTable: aliasTable, parentIsLocalized: parentIsLocalized || field.localized, pathSegments: pathSegments.slice(1), rootTableName, @@ -548,7 +552,10 @@ export const getTableColumnFromPath = ({ // Join in the relationships table if (locale && isFieldLocalized && adapter.payload.config.localization) { const conditions = [ - eq((aliasTable || adapter.tables[rootTableName]).id, aliasRelationshipTable.parent), + eq( + (parentAliasTable || aliasTable || adapter.tables[rootTableName]).id, + aliasRelationshipTable.parent, + ), like(aliasRelationshipTable.path, `${constraintPath}${field.name}`), ] @@ -566,7 +573,10 @@ export const getTableColumnFromPath = ({ // Join in the relationships table addJoinTable({ condition: and( - eq((aliasTable || adapter.tables[rootTableName]).id, aliasRelationshipTable.parent), + eq( + (parentAliasTable || aliasTable || adapter.tables[rootTableName]).id, + aliasRelationshipTable.parent, + ), like(aliasRelationshipTable.path, `${constraintPath}${field.name}`), ), joins, diff --git a/test/joins/collections/Categories.ts b/test/joins/collections/Categories.ts index a87a9084d..c70dd42b4 100644 --- a/test/joins/collections/Categories.ts +++ b/test/joins/collections/Categories.ts @@ -111,6 +111,12 @@ export const Categories: CollectionConfig = { collection: 'posts', on: 'array.category', }, + { + name: 'arrayHasManyPosts', + type: 'join', + collection: 'posts', + on: 'arrayHasMany.category', + }, { name: 'localizedArrayPosts', type: 'join', diff --git a/test/joins/collections/Posts.ts b/test/joins/collections/Posts.ts index 7fc65e4a7..b4265f159 100644 --- a/test/joins/collections/Posts.ts +++ b/test/joins/collections/Posts.ts @@ -114,6 +114,18 @@ export const Posts: CollectionConfig = { }, ], }, + { + name: 'arrayHasMany', + type: 'array', + fields: [ + { + name: 'category', + type: 'relationship', + hasMany: true, + relationTo: categoriesSlug, + }, + ], + }, { name: 'localizedArray', type: 'array', diff --git a/test/joins/int.spec.ts b/test/joins/int.spec.ts index a14029f46..dccb033e3 100644 --- a/test/joins/int.spec.ts +++ b/test/joins/int.spec.ts @@ -115,6 +115,7 @@ describe('Joins Field', () => { camelCaseCategory: category.id, }, array: [{ category: category.id }], + arrayHasMany: [{ category: [category.id] }], localizedArray: [{ category: category.id }], blocks: [{ blockType: 'block', category: category.id }], }) @@ -247,6 +248,16 @@ describe('Joins Field', () => { expect(categoryWithPosts.arrayPosts.docs).toHaveLength(10) }) + it('should populate joins with array hasMany relationships', async () => { + const categoryWithPosts = await payload.findByID({ + id: category.id, + collection: categoriesSlug, + }) + + expect(categoryWithPosts.arrayHasManyPosts.docs).toBeDefined() + expect(categoryWithPosts.arrayHasManyPosts.docs).toHaveLength(10) + }) + it('should populate joins with localized array relationships', async () => { const categoryWithPosts = await payload.findByID({ id: category.id, diff --git a/test/joins/payload-types.ts b/test/joins/payload-types.ts index 8f467a089..4fca14e71 100644 --- a/test/joins/payload-types.ts +++ b/test/joins/payload-types.ts @@ -109,6 +109,7 @@ export interface Config { 'group.relatedPosts': 'posts'; 'group.camelCasePosts': 'posts'; arrayPosts: 'posts'; + arrayHasManyPosts: 'posts'; localizedArrayPosts: 'posts'; blocksPosts: 'posts'; polymorphic: 'posts'; @@ -240,6 +241,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -312,6 +320,12 @@ export interface Post { id?: string | null; }[] | null; + arrayHasMany?: + | { + category?: (string | Category)[] | null; + id?: string | null; + }[] + | null; localizedArray?: | { category?: (string | null) | Category; @@ -405,6 +419,11 @@ export interface Category { hasNextPage?: boolean; totalDocs?: number; }; + arrayHasManyPosts?: { + docs?: (string | Post)[]; + hasNextPage?: boolean; + totalDocs?: number; + }; localizedArrayPosts?: { docs?: (string | Post)[]; hasNextPage?: boolean; @@ -971,6 +990,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema @@ -1002,6 +1028,12 @@ export interface PostsSelect { category?: T; id?: T; }; + arrayHasMany?: + | T + | { + category?: T; + id?: T; + }; localizedArray?: | T | { @@ -1049,6 +1081,7 @@ export interface CategoriesSelect { camelCasePosts?: T; }; arrayPosts?: T; + arrayHasManyPosts?: T; localizedArrayPosts?: T; blocksPosts?: T; polymorphic?: T; diff --git a/test/relationships/config.ts b/test/relationships/config.ts index 861fa4ce8..c996471aa 100644 --- a/test/relationships/config.ts +++ b/test/relationships/config.ts @@ -240,6 +240,18 @@ export default buildConfigWithDefaults({ type: 'relationship', relationTo: 'directors', }, + { + type: 'array', + name: 'array', + fields: [ + { + name: 'director', + type: 'relationship', + relationTo: 'directors', + hasMany: true, + }, + ], + }, ], }, { diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index ddfc2bd9c..da6189c66 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -1151,6 +1151,29 @@ describe('Relationships', () => { expect(result.docs[0]!.id).toBe(doc.id) }) + it('should allow querying hasMany in array', async () => { + const director = await payload.create({ + collection: 'directors', + data: { name: 'Test Director1337' }, + }) + const movie = await payload.create({ + collection: 'movies', + data: { array: [{ director: [director.id] }] }, + }) + const res = await payload.find({ + collection: 'movies', + where: { 'array.director': { equals: director.id } }, + }) + expect(res.docs).toHaveLength(1) + expect(res.docs[0].id).toBe(movie.id) + const res2 = await payload.find({ + collection: 'movies', + where: { 'array.director.name': { equals: 'Test Director1337' } }, + }) + expect(res2.docs).toHaveLength(1) + expect(res2.docs[0].id).toBe(movie.id) + }) + describe('Nested Querying Separate Collections', () => { let director: Director diff --git a/test/relationships/payload-types.ts b/test/relationships/payload-types.ts index 66efbda92..2474724ab 100644 --- a/test/relationships/payload-types.ts +++ b/test/relationships/payload-types.ts @@ -268,6 +268,12 @@ export interface Movie { name?: string | null; select?: ('a' | 'b' | 'c')[] | null; director?: (string | null) | Director; + array?: + | { + director?: (string | Director)[] | null; + id?: string | null; + }[] + | null; updatedAt: string; createdAt: string; _status?: ('draft' | 'published') | null; @@ -313,6 +319,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -733,6 +746,12 @@ export interface MoviesSelect { name?: T; select?: T; director?: T; + array?: + | T + | { + director?: T; + id?: T; + }; updatedAt?: T; createdAt?: T; _status?: T; @@ -906,6 +925,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema