Skip to content

Commit 88548fc

Browse files
authored
fix(db-postgres): querying other collections via relationships inside blocks (#11255)
### What? Previously, in postgres query like: ```ts const result = await payload.find({ collection: 'blocks', where: { 'blocks.director.name': { equals: 'Test Director' } }, }) ``` where `blocks` is a blocks field, `director` is a relationship field and `name` is a text field inside `directors`, failed with: ![image](https://github.com/user-attachments/assets/f4b62b69-bd17-4ef0-9f0c-08057e9f2d57) ### Why? The generated query before was a bit wrong. Before: ```sql select distinct "blocks"."id", "blocks"."created_at", "blocks"."created_at" from "blocks" left join "directors" "a5ad426a_eda4_4067_af7e_5b294d7f0968" on "a5ad426a_eda4_4067_af7e_5b294d7f0968"."id" = "blocks_blocks_some"."director_id" left join "blocks_blocks_some" on "blocks"."id" = "blocks_blocks_some"."_parent_id" where "a5ad426a_eda4_4067_af7e_5b294d7f0968"."name" = 'Test Director' order by "blocks"."created_at" desc limit 10 ``` Notice `left join directors` _before_ join of `blocks_blocks_some`. `blocks_blocks_some` doesn't exist yet, this PR changes so now we generate ```sql select distinct "blocks"."id", "blocks"."created_at", "blocks"."created_at" from "blocks" left join "blocks_blocks_some" on "blocks"."id" = "blocks_blocks_some"."_parent_id" left join "directors" "a5ad426a_eda4_4067_af7e_5b294d7f0968" on "a5ad426a_eda4_4067_af7e_5b294d7f0968"."id" = "blocks_blocks_some"."director_id" where "a5ad426a_eda4_4067_af7e_5b294d7f0968"."name" = 'Test Director' order by "blocks"."created_at" desc limit 10 ```
1 parent 06debf5 commit 88548fc

File tree

4 files changed

+131
-23
lines changed

4 files changed

+131
-23
lines changed

packages/drizzle/src/queries/getTableColumnFromPath.ts

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,45 @@ export const getTableColumnFromPath = ({
220220
let result: TableColumn
221221
const blockConstraints = []
222222
const blockSelectFields = {}
223+
224+
let blockJoin: BuildQueryJoinAliases[0]
225+
if (isFieldLocalized && adapter.payload.config.localization) {
226+
const conditions = [
227+
eq(
228+
(aliasTable || adapter.tables[tableName]).id,
229+
adapter.tables[newTableName]._parentID,
230+
),
231+
]
232+
233+
if (locale !== 'all') {
234+
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
235+
}
236+
237+
blockJoin = {
238+
condition: and(...conditions),
239+
table: adapter.tables[newTableName],
240+
}
241+
} else {
242+
blockJoin = {
243+
condition: eq(
244+
(aliasTable || adapter.tables[tableName]).id,
245+
adapter.tables[newTableName]._parentID,
246+
),
247+
table: adapter.tables[newTableName],
248+
}
249+
}
250+
251+
// Create a new reference for nested joins
252+
const newJoins = [...joins]
253+
223254
try {
224255
result = getTableColumnFromPath({
225256
adapter,
226257
collectionPath,
227258
constraintPath,
228259
constraints: blockConstraints,
229260
fields: block.flattenedFields,
230-
joins,
261+
joins: newJoins,
231262
locale,
232263
parentIsLocalized: parentIsLocalized || field.localized,
233264
pathSegments: pathSegments.slice(1),
@@ -246,30 +277,14 @@ export const getTableColumnFromPath = ({
246277
blockTableColumn = result
247278
constraints = constraints.concat(blockConstraints)
248279
selectFields = { ...selectFields, ...blockSelectFields }
249-
if (isFieldLocalized && adapter.payload.config.localization) {
250-
const conditions = [
251-
eq(
252-
(aliasTable || adapter.tables[tableName]).id,
253-
adapter.tables[newTableName]._parentID,
254-
),
255-
]
256280

257-
if (locale !== 'all') {
258-
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
281+
const previousLength = joins.length
282+
joins.push(blockJoin)
283+
// Append new joins AFTER the block join to prevent errors with missing FROM clause.
284+
if (newJoins.length > previousLength) {
285+
for (let i = previousLength; i < newJoins.length; i++) {
286+
joins.push(newJoins[i])
259287
}
260-
261-
joins.push({
262-
condition: and(...conditions),
263-
table: adapter.tables[newTableName],
264-
})
265-
} else {
266-
joins.push({
267-
condition: eq(
268-
(aliasTable || adapter.tables[tableName]).id,
269-
adapter.tables[newTableName]._parentID,
270-
),
271-
table: adapter.tables[newTableName],
272-
})
273288
}
274289
return true
275290
})

test/relationships/config.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,27 @@ export default buildConfigWithDefaults({
460460
},
461461
],
462462
},
463+
{
464+
slug: 'blocks',
465+
fields: [
466+
{
467+
type: 'blocks',
468+
name: 'blocks',
469+
blocks: [
470+
{
471+
slug: 'some',
472+
fields: [
473+
{
474+
type: 'relationship',
475+
relationTo: 'directors',
476+
name: 'director',
477+
},
478+
],
479+
},
480+
],
481+
},
482+
],
483+
},
463484
],
464485
onInit: async (payload) => {
465486
await payload.create({

test/relationships/int.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,36 @@ describe('Relationships', () => {
11301130
})
11311131
})
11321132

1133+
it('should allow querying within block nesting', async () => {
1134+
const director = await payload.create({
1135+
collection: 'directors',
1136+
data: { name: 'Test Director' },
1137+
})
1138+
1139+
const director_false = await payload.create({
1140+
collection: 'directors',
1141+
data: { name: 'False Director' },
1142+
})
1143+
1144+
const doc = await payload.create({
1145+
collection: 'blocks',
1146+
data: { blocks: [{ blockType: 'some', director: director.id }] },
1147+
})
1148+
1149+
await payload.create({
1150+
collection: 'blocks',
1151+
data: { blocks: [{ blockType: 'some', director: director_false.id }] },
1152+
})
1153+
1154+
const result = await payload.find({
1155+
collection: 'blocks',
1156+
where: { 'blocks.director.name': { equals: 'Test Director' } },
1157+
})
1158+
1159+
expect(result.totalDocs).toBe(1)
1160+
expect(result.docs[0]!.id).toBe(doc.id)
1161+
})
1162+
11331163
describe('Nested Querying Separate Collections', () => {
11341164
let director: Director
11351165

test/relationships/payload-types.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export interface Config {
8686
'deep-nested': DeepNested;
8787
relations: Relation1;
8888
items: Item;
89+
blocks: Block;
8990
users: User;
9091
'payload-locked-documents': PayloadLockedDocument;
9192
'payload-preferences': PayloadPreference;
@@ -117,6 +118,7 @@ export interface Config {
117118
'deep-nested': DeepNestedSelect<false> | DeepNestedSelect<true>;
118119
relations: RelationsSelect<false> | RelationsSelect<true>;
119120
items: ItemsSelect<false> | ItemsSelect<true>;
121+
blocks: BlocksSelect<false> | BlocksSelect<true>;
120122
users: UsersSelect<false> | UsersSelect<true>;
121123
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
122124
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -464,6 +466,23 @@ export interface Item {
464466
updatedAt: string;
465467
createdAt: string;
466468
}
469+
/**
470+
* This interface was referenced by `Config`'s JSON-Schema
471+
* via the `definition` "blocks".
472+
*/
473+
export interface Block {
474+
id: string;
475+
blocks?:
476+
| {
477+
director?: (string | null) | Director;
478+
id?: string | null;
479+
blockName?: string | null;
480+
blockType: 'some';
481+
}[]
482+
| null;
483+
updatedAt: string;
484+
createdAt: string;
485+
}
467486
/**
468487
* This interface was referenced by `Config`'s JSON-Schema
469488
* via the `definition` "payload-locked-documents".
@@ -551,6 +570,10 @@ export interface PayloadLockedDocument {
551570
relationTo: 'items';
552571
value: string | Item;
553572
} | null)
573+
| ({
574+
relationTo: 'blocks';
575+
value: string | Block;
576+
} | null)
554577
| ({
555578
relationTo: 'users';
556579
value: string | User;
@@ -840,6 +863,25 @@ export interface ItemsSelect<T extends boolean = true> {
840863
updatedAt?: T;
841864
createdAt?: T;
842865
}
866+
/**
867+
* This interface was referenced by `Config`'s JSON-Schema
868+
* via the `definition` "blocks_select".
869+
*/
870+
export interface BlocksSelect<T extends boolean = true> {
871+
blocks?:
872+
| T
873+
| {
874+
some?:
875+
| T
876+
| {
877+
director?: T;
878+
id?: T;
879+
blockName?: T;
880+
};
881+
};
882+
updatedAt?: T;
883+
createdAt?: T;
884+
}
843885
/**
844886
* This interface was referenced by `Config`'s JSON-Schema
845887
* via the `definition` "users_select".

0 commit comments

Comments
 (0)