diff --git a/packages/drizzle/src/deleteOne.ts b/packages/drizzle/src/deleteOne.ts index f9bdef788..afafde7cc 100644 --- a/packages/drizzle/src/deleteOne.ts +++ b/packages/drizzle/src/deleteOne.ts @@ -72,6 +72,7 @@ export const deleteOne: DeleteOne = async function deleteOne( data: docToDelete, fields: collection.flattenedFields, joinQuery: false, + tableName, }) await this.deleteWhere({ diff --git a/packages/drizzle/src/find/findMany.ts b/packages/drizzle/src/find/findMany.ts index d2ba6e129..2c0304617 100644 --- a/packages/drizzle/src/find/findMany.ts +++ b/packages/drizzle/src/find/findMany.ts @@ -158,6 +158,7 @@ export const findMany = async function find({ data, fields, joinQuery, + tableName, }) }) diff --git a/packages/drizzle/src/find/traverseFields.ts b/packages/drizzle/src/find/traverseFields.ts index 4bb2aae2f..5d1c1bd17 100644 --- a/packages/drizzle/src/find/traverseFields.ts +++ b/packages/drizzle/src/find/traverseFields.ts @@ -196,7 +196,8 @@ export const traverseFields = ({ } } - currentArgs.with[`${path}${field.name}`] = withArray + const relationName = field.dbName ? `_${arrayTableName}` : `${path}${field.name}` + currentArgs.with[relationName] = withArray traverseFields({ _locales: withArray.with._locales, diff --git a/packages/drizzle/src/schema/traverseFields.ts b/packages/drizzle/src/schema/traverseFields.ts index f82bd3433..a10c09e70 100644 --- a/packages/drizzle/src/schema/traverseFields.ts +++ b/packages/drizzle/src/schema/traverseFields.ts @@ -2,6 +2,7 @@ import type { CompoundIndex, FlattenedField } from 'payload' import { InvalidConfiguration } from 'payload' import { + array, fieldAffectsData, fieldIsVirtual, fieldShouldBeLocalized, @@ -287,7 +288,9 @@ export const traverseFields = ({ } } - relationsToBuild.set(fieldName, { + const relationName = field.dbName ? `_${arrayTableName}` : fieldName + + relationsToBuild.set(relationName, { type: 'many', // arrays have their own localized table, independent of the base table. localized: false, @@ -304,7 +307,7 @@ export const traverseFields = ({ }, ], references: ['id'], - relationName: fieldName, + relationName, to: parentTableName, }, } diff --git a/packages/drizzle/src/transform/read/index.ts b/packages/drizzle/src/transform/read/index.ts index 0d677c0db..2f5baab9a 100644 --- a/packages/drizzle/src/transform/read/index.ts +++ b/packages/drizzle/src/transform/read/index.ts @@ -15,6 +15,7 @@ type TransformArgs = { joinQuery?: JoinQuery locale?: string parentIsLocalized?: boolean + tableName: string } // This is the entry point to transform Drizzle output data @@ -26,6 +27,7 @@ export const transform = | TypeWithID>({ fields, joinQuery, parentIsLocalized, + tableName, }: TransformArgs): T => { let relationships: Record[]> = {} let texts: Record[]> = {} @@ -53,6 +55,7 @@ export const transform = | TypeWithID>({ adapter, blocks, config, + currentTableName: tableName, dataRef: { id: data.id, }, @@ -65,7 +68,9 @@ export const transform = | TypeWithID>({ path: '', relationships, table: data, + tablePath: '', texts, + topLevelTableName: tableName, }) deletions.forEach((deletion) => deletion()) diff --git a/packages/drizzle/src/transform/read/traverseFields.ts b/packages/drizzle/src/transform/read/traverseFields.ts index 68a5c64d2..43fbf0539 100644 --- a/packages/drizzle/src/transform/read/traverseFields.ts +++ b/packages/drizzle/src/transform/read/traverseFields.ts @@ -1,6 +1,7 @@ import type { FlattenedBlock, FlattenedField, JoinQuery, SanitizedConfig } from 'payload' import { fieldIsVirtual, fieldShouldBeLocalized } from 'payload/shared' +import toSnakeCase from 'to-snake-case' import type { DrizzleAdapter } from '../../types.js' import type { BlocksMap } from '../../utilities/createBlocksMap.js' @@ -22,6 +23,7 @@ type TraverseFieldsArgs = { * The full Payload config */ config: SanitizedConfig + currentTableName: string /** * The data reference to be mutated within this recursive function */ @@ -59,10 +61,12 @@ type TraverseFieldsArgs = { * Data structure representing the nearest table from db */ table: Record + tablePath: string /** * All hasMany text fields, as returned by Drizzle, keyed on an object by field path */ texts: Record[]> + topLevelTableName: string /** * Set to a locale if this group of fields is within a localized array or block. */ @@ -75,6 +79,7 @@ export const traverseFields = >({ adapter, blocks, config, + currentTableName, dataRef, deletions, fieldPrefix, @@ -85,7 +90,9 @@ export const traverseFields = >({ path, relationships, table, + tablePath, texts, + topLevelTableName, withinArrayOrBlockLocale, }: TraverseFieldsArgs): T => { const sanitizedPath = path ? `${path}.` : path @@ -110,6 +117,14 @@ export const traverseFields = >({ const isLocalized = fieldShouldBeLocalized({ field, parentIsLocalized }) if (field.type === 'array') { + const arrayTableName = adapter.tableNameMap.get( + `${currentTableName}_${tablePath}${toSnakeCase(field.name)}`, + ) + + if (field.dbName) { + fieldData = table[`_${arrayTableName}`] + } + if (Array.isArray(fieldData)) { if (isLocalized) { result[field.name] = fieldData.reduce((arrayResult, row) => { @@ -129,6 +144,7 @@ export const traverseFields = >({ adapter, blocks, config, + currentTableName: arrayTableName, dataRef: data, deletions, fieldPrefix: '', @@ -138,7 +154,9 @@ export const traverseFields = >({ path: `${sanitizedPath}${field.name}.${row._order - 1}`, relationships, table: row, + tablePath: '', texts, + topLevelTableName, withinArrayOrBlockLocale: locale, }) @@ -175,6 +193,7 @@ export const traverseFields = >({ adapter, blocks, config, + currentTableName: arrayTableName, dataRef: row, deletions, fieldPrefix: '', @@ -184,7 +203,9 @@ export const traverseFields = >({ path: `${sanitizedPath}${field.name}.${i}`, relationships, table: row, + tablePath: '', texts, + topLevelTableName, withinArrayOrBlockLocale, }), ) @@ -228,11 +249,16 @@ export const traverseFields = >({ (block) => typeof block !== 'string' && block.slug === row.blockType, ) as FlattenedBlock | undefined) + const tableName = adapter.tableNameMap.get( + `${topLevelTableName}_blocks_${toSnakeCase(block.slug)}`, + ) + if (block) { const blockResult = traverseFields({ adapter, blocks, config, + currentTableName: tableName, dataRef: row, deletions, fieldPrefix: '', @@ -242,7 +268,9 @@ export const traverseFields = >({ path: `${blockFieldPath}.${row._order - 1}`, relationships, table: row, + tablePath: '', texts, + topLevelTableName, withinArrayOrBlockLocale: locale, }) @@ -300,11 +328,16 @@ export const traverseFields = >({ delete row._index } + const tableName = adapter.tableNameMap.get( + `${topLevelTableName}_blocks_${toSnakeCase(block.slug)}`, + ) + acc.push( traverseFields({ adapter, blocks, config, + currentTableName: tableName, dataRef: row, deletions, fieldPrefix: '', @@ -314,7 +347,9 @@ export const traverseFields = >({ path: `${blockFieldPath}.${i}`, relationships, table: row, + tablePath: '', texts, + topLevelTableName, withinArrayOrBlockLocale, }), ) @@ -614,6 +649,7 @@ export const traverseFields = >({ adapter, blocks, config, + currentTableName, dataRef: groupData as Record, deletions, fieldPrefix: groupFieldPrefix, @@ -624,7 +660,9 @@ export const traverseFields = >({ path: `${sanitizedPath}${field.name}`, relationships, table, + tablePath: `${tablePath}${toSnakeCase(field.name)}_`, texts, + topLevelTableName, withinArrayOrBlockLocale: locale || withinArrayOrBlockLocale, }) diff --git a/packages/drizzle/src/upsertRow/index.ts b/packages/drizzle/src/upsertRow/index.ts index 71d0b50ab..84d8d80cd 100644 --- a/packages/drizzle/src/upsertRow/index.ts +++ b/packages/drizzle/src/upsertRow/index.ts @@ -467,6 +467,7 @@ export const upsertRow = async | TypeWithID>( data: doc, fields, joinQuery: false, + tableName, }) return result diff --git a/test/database/config.ts b/test/database/config.ts index b7e73aed6..b8331c695 100644 --- a/test/database/config.ts +++ b/test/database/config.ts @@ -604,6 +604,29 @@ export default buildConfigWithDefaults({ }, ], }, + { + slug: 'aliases', + fields: [ + { + name: 'thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName', + dbName: 'shortname', + type: 'array', + fields: [ + { + name: 'nestedArray', + type: 'array', + dbName: 'short_nested_1', + fields: [ + { + type: 'text', + name: 'text', + }, + ], + }, + ], + }, + ], + }, ], globals: [ { diff --git a/test/database/int.spec.ts b/test/database/int.spec.ts index 46dc4b93a..f4e6263e6 100644 --- a/test/database/int.spec.ts +++ b/test/database/int.spec.ts @@ -21,6 +21,7 @@ import { killTransaction, QueryError, } from 'payload' +import { assert } from 'ts-essentials' import { fileURLToPath } from 'url' import type { Global2 } from './payload-types.js' @@ -783,6 +784,28 @@ describe('database', () => { expect(doc.blocks[0].text).toStrictEqual('hello') expect(doc.blocks[0].localizedText).toStrictEqual('goodbye') }) + + it('arrays should work with both long field names and dbName', async () => { + const { id } = await payload.create({ + collection: 'aliases', + data: { + thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName: [ + { + nestedArray: [{ text: 'some-text' }], + }, + ], + }, + }) + const res = await payload.findByID({ collection: 'aliases', id }) + expect( + res.thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName, + ).toHaveLength(1) + const item = + res.thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName?.[0] + assert(item) + expect(item.nestedArray).toHaveLength(1) + expect(item.nestedArray?.[0]?.text).toBe('some-text') + }) }) describe('transactions', () => { diff --git a/test/database/payload-types.ts b/test/database/payload-types.ts index 470a03a4a..f2692eaaa 100644 --- a/test/database/payload-types.ts +++ b/test/database/payload-types.ts @@ -80,6 +80,7 @@ export interface Config { 'fake-custom-ids': FakeCustomId; 'relationships-migration': RelationshipsMigration; 'compound-indexes': CompoundIndex; + aliases: Alias; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -100,6 +101,7 @@ export interface Config { 'fake-custom-ids': FakeCustomIdsSelect | FakeCustomIdsSelect; 'relationships-migration': RelationshipsMigrationSelect | RelationshipsMigrationSelect; 'compound-indexes': CompoundIndexesSelect | CompoundIndexesSelect; + aliases: AliasesSelect | AliasesSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -419,6 +421,26 @@ export interface CompoundIndex { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "aliases". + */ +export interface Alias { + id: string; + thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName?: + | { + nestedArray?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + id?: string | null; + }[] + | null; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -495,6 +517,10 @@ export interface PayloadLockedDocument { relationTo: 'compound-indexes'; value: string | CompoundIndex; } | null) + | ({ + relationTo: 'aliases'; + value: string | Alias; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -795,6 +821,25 @@ export interface CompoundIndexesSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "aliases_select". + */ +export interface AliasesSelect { + thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName?: + | T + | { + nestedArray?: + | T + | { + text?: T; + id?: T; + }; + id?: T; + }; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select".