From a0a58e7fd20dff54d210c968f4d5defd67441bdd Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Wed, 7 Feb 2024 14:18:13 -0500 Subject: [PATCH] fix: query relationships by explicit id field (#5022) --- .../src/queries/getTableColumnFromPath.ts | 2 +- .../payload/src/database/getLocalizedPaths.ts | 11 +++ test/relationships/int.spec.ts | 72 ++++++++++++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/packages/db-postgres/src/queries/getTableColumnFromPath.ts b/packages/db-postgres/src/queries/getTableColumnFromPath.ts index f19349151f..2f01c0d906 100644 --- a/packages/db-postgres/src/queries/getTableColumnFromPath.ts +++ b/packages/db-postgres/src/queries/getTableColumnFromPath.ts @@ -349,7 +349,7 @@ export const getTableColumnFromPath = ({ table: newAliasTable, }) - if (newCollectionPath === '') { + if (newCollectionPath === '' || newCollectionPath === 'id') { return { columnName: `${field.relationTo}ID`, constraints, diff --git a/packages/payload/src/database/getLocalizedPaths.ts b/packages/payload/src/database/getLocalizedPaths.ts index 56d660a5bb..d3c51ae8b1 100644 --- a/packages/payload/src/database/getLocalizedPaths.ts +++ b/packages/payload/src/database/getLocalizedPaths.ts @@ -62,6 +62,17 @@ export async function getLocalizedPaths({ return paths } + if (!matchedField && currentPath === 'id' && i === pathSegments.length - 1) { + lastIncompletePath.path = currentPath + const idField: Field = { + name: 'id', + type: payload.db.defaultIDType as 'text', + } + lastIncompletePath.field = idField + lastIncompletePath.complete = true + return paths + } + if (matchedField) { if ('hidden' in matchedField && matchedField.hidden && !overrideAccess) { lastIncompletePath.invalid = true diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index e04640c9f9..40fd912cc5 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -273,6 +273,74 @@ describe('Relationships', () => { expect(query.totalDocs).toEqual(2) }) + // https://github.com/payloadcms/payload/issues/4240 + it('should allow querying by relationship id field', async () => { + /** + * This test shows something which breaks on postgres but not on mongodb. + */ + const someDirector = await payload.create({ + collection: 'directors', + data: { + name: 'Quentin Tarantino', + }, + }) + + await payload.create({ + collection: 'movies', + data: { + name: 'Pulp Fiction', + }, + }) + + await payload.create({ + collection: 'movies', + data: { + name: 'Pulp Fiction', + }, + }) + + await payload.create({ + collection: 'movies', + data: { + name: 'Harry Potter', + }, + }) + + await payload.create({ + collection: 'movies', + data: { + name: 'Lord of the Rings is boring', + director: someDirector.id, + }, + }) + + // This causes the following error: + // "Your "id" field references a column "directors"."id", but the table "directors" is not part of the query! Did you forget to join it?" + // This only happens on postgres, not on mongodb + const query = await payload.find({ + collection: 'movies', + depth: 5, + limit: 1, + where: { + or: [ + { + name: { + equals: 'Pulp Fiction', + }, + }, + { + 'director.id': { + equals: someDirector.id, + }, + }, + ], + }, + }) + + expect(query.totalDocs).toEqual(3) + expect(query.docs).toHaveLength(1) // Due to limit: 1 + }) + describe('Custom ID', () => { it('should query a custom id relation', async () => { const { doc } = await client.findByID({ id: post.id }) @@ -288,7 +356,7 @@ describe('Relationships', () => { await expect(async () => createPost({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Sending bad data to test error handling + // @ts-expect-error Sending bad data to test error handling customIdRelation: 1234, }), ).rejects.toThrow('The following field is invalid: customIdRelation') @@ -298,7 +366,7 @@ describe('Relationships', () => { await expect(async () => createPost({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Sending bad data to test error handling + // @ts-expect-error Sending bad data to test error handling customIdNumberRelation: 'bad-input', }), ).rejects.toThrow('The following field is invalid: customIdNumberRelation')