fix(db-postgres): alias already in use in this query (#8823)
Fixes https://github.com/payloadcms/payload/issues/8517 Reuses existing joins instead of adding new, duplicate ones which causes: ``` Error: Alias "" is already used in this query. ```
This commit is contained in:
25
packages/drizzle/src/queries/addJoinTable.ts
Normal file
25
packages/drizzle/src/queries/addJoinTable.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { SQL } from 'drizzle-orm'
|
||||
import type { PgTableWithColumns } from 'drizzle-orm/pg-core'
|
||||
|
||||
import type { GenericTable } from '../types.js'
|
||||
import type { BuildQueryJoinAliases } from './buildQuery.js'
|
||||
|
||||
import { getNameFromDrizzleTable } from '../utilities/getNameFromDrizzleTable.js'
|
||||
|
||||
export const addJoinTable = ({
|
||||
type,
|
||||
condition,
|
||||
joins,
|
||||
table,
|
||||
}: {
|
||||
condition: SQL
|
||||
joins: BuildQueryJoinAliases
|
||||
table: GenericTable | PgTableWithColumns<any>
|
||||
type?: 'innerJoin' | 'leftJoin' | 'rightJoin'
|
||||
}) => {
|
||||
const name = getNameFromDrizzleTable(table)
|
||||
|
||||
if (!joins.some((eachJoin) => getNameFromDrizzleTable(eachJoin.table) === name)) {
|
||||
joins.push({ type, condition, table })
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,6 @@ export const buildOrderBy = ({
|
||||
pathSegments: sortPath.replace(/__/g, '.').split('.'),
|
||||
selectFields,
|
||||
tableName,
|
||||
useAlias: true,
|
||||
value: sortPath,
|
||||
})
|
||||
orderBy.column = sortTable?.[sortTableColumnName]
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { DrizzleAdapter, GenericColumn } from '../types.js'
|
||||
import type { BuildQueryJoinAliases } from './buildQuery.js'
|
||||
|
||||
import { isPolymorphicRelationship } from '../utilities/isPolymorphicRelationship.js'
|
||||
import { addJoinTable } from './addJoinTable.js'
|
||||
import { getTableAlias } from './getTableAlias.js'
|
||||
|
||||
type Constraint = {
|
||||
@@ -53,7 +54,6 @@ type Args = {
|
||||
* If creating a new table name for arrays and blocks, this suffix should be appended to the table name
|
||||
*/
|
||||
tableNameSuffix?: string
|
||||
useAlias?: boolean
|
||||
/**
|
||||
* The raw value of the query before sanitization
|
||||
*/
|
||||
@@ -79,7 +79,6 @@ export const getTableColumnFromPath = ({
|
||||
selectFields,
|
||||
tableName,
|
||||
tableNameSuffix = '',
|
||||
useAlias,
|
||||
value,
|
||||
}: Args): TableColumn => {
|
||||
const fieldPath = incomingSegments[0]
|
||||
@@ -141,7 +140,6 @@ export const getTableColumnFromPath = ({
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
tableNameSuffix,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -162,7 +160,6 @@ export const getTableColumnFromPath = ({
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -181,7 +178,6 @@ export const getTableColumnFromPath = ({
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
tableNameSuffix,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -190,8 +186,9 @@ export const getTableColumnFromPath = ({
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
newTableName = `${tableName}${adapter.localesSuffix}`
|
||||
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: eq(adapter.tables[tableName].id, adapter.tables[newTableName]._parentID),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
if (locale !== 'all') {
|
||||
@@ -217,7 +214,6 @@ export const getTableColumnFromPath = ({
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -229,11 +225,12 @@ export const getTableColumnFromPath = ({
|
||||
)
|
||||
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: and(
|
||||
eq(adapter.tables[tableName].id, adapter.tables[newTableName].parent),
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
if (locale !== 'all') {
|
||||
@@ -244,8 +241,9 @@ export const getTableColumnFromPath = ({
|
||||
})
|
||||
}
|
||||
} else {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: eq(adapter.tables[tableName].id, adapter.tables[newTableName].parent),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
}
|
||||
@@ -276,8 +274,9 @@ export const getTableColumnFromPath = ({
|
||||
]
|
||||
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: and(...joinConstraints, eq(adapter.tables[newTableName]._locale, locale)),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
if (locale !== 'all') {
|
||||
@@ -288,8 +287,9 @@ export const getTableColumnFromPath = ({
|
||||
})
|
||||
}
|
||||
} else {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: and(...joinConstraints),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
}
|
||||
@@ -313,11 +313,12 @@ export const getTableColumnFromPath = ({
|
||||
|
||||
constraintPath = `${constraintPath}${field.name}.%.`
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: and(
|
||||
eq(arrayParentTable.id, adapter.tables[newTableName]._parentID),
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
if (locale !== 'all') {
|
||||
@@ -328,8 +329,9 @@ export const getTableColumnFromPath = ({
|
||||
})
|
||||
}
|
||||
} else {
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: eq(arrayParentTable.id, adapter.tables[newTableName]._parentID),
|
||||
joins,
|
||||
table: adapter.tables[newTableName],
|
||||
})
|
||||
}
|
||||
@@ -345,7 +347,6 @@ export const getTableColumnFromPath = ({
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -404,7 +405,6 @@ export const getTableColumnFromPath = ({
|
||||
rootTableName,
|
||||
selectFields: blockSelectFields,
|
||||
tableName: newTableName,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
} catch (error) {
|
||||
@@ -641,7 +641,6 @@ export const getTableColumnFromPath = ({
|
||||
rootTableName: newTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
} else if (
|
||||
@@ -694,7 +693,6 @@ export const getTableColumnFromPath = ({
|
||||
pathSegments: pathSegments.slice(1),
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
useAlias,
|
||||
value,
|
||||
})
|
||||
}
|
||||
@@ -716,12 +714,11 @@ export const getTableColumnFromPath = ({
|
||||
const parentTable = aliasTable || adapter.tables[tableName]
|
||||
newTableName = `${tableName}${adapter.localesSuffix}`
|
||||
|
||||
newTable = useAlias
|
||||
? getTableAlias({ adapter, tableName: newTableName }).newAliasTable
|
||||
: adapter.tables[newTableName]
|
||||
newTable = adapter.tables[newTableName]
|
||||
|
||||
joins.push({
|
||||
addJoinTable({
|
||||
condition: eq(parentTable.id, newTable._parentID),
|
||||
joins,
|
||||
table: newTable,
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Table } from 'drizzle-orm'
|
||||
|
||||
export const getNameFromDrizzleTable = (table: Table): string => {
|
||||
const symbol = Object.getOwnPropertySymbols(table).find((symb) =>
|
||||
symb.description.includes('Name'),
|
||||
)
|
||||
|
||||
return table[symbol]
|
||||
}
|
||||
@@ -23,6 +23,10 @@ const ArrayFields: CollectionConfig = {
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'anotherText',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
|
||||
@@ -1546,6 +1546,50 @@ describe('Fields', () => {
|
||||
expect(allLocales.localized.en[0].text).toStrictEqual(enText)
|
||||
expect(allLocales.localized.es[0].text).toStrictEqual(esText)
|
||||
})
|
||||
|
||||
it('should query by the same array', async () => {
|
||||
const doc = await payload.create({
|
||||
collection,
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
localizedText: 'test',
|
||||
text: 'required',
|
||||
anotherText: 'another',
|
||||
},
|
||||
],
|
||||
localized: [{ text: 'a' }],
|
||||
},
|
||||
})
|
||||
|
||||
// left join collection_items + left join collection_items_locales
|
||||
const {
|
||||
docs: [res],
|
||||
} = await payload.find({
|
||||
collection,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
'items.localizedText': {
|
||||
equals: 'test',
|
||||
},
|
||||
},
|
||||
{
|
||||
'items.anotherText': {
|
||||
equals: 'another',
|
||||
},
|
||||
},
|
||||
{
|
||||
'items.text': {
|
||||
equals: 'required',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.id).toBe(doc.id)
|
||||
})
|
||||
})
|
||||
|
||||
describe('group', () => {
|
||||
|
||||
@@ -353,6 +353,7 @@ export interface ArrayField {
|
||||
title?: string | null;
|
||||
items: {
|
||||
text: string;
|
||||
anotherText?: string | null;
|
||||
localizedText?: string | null;
|
||||
subArray?:
|
||||
| {
|
||||
|
||||
Reference in New Issue
Block a user