From bd464990eac41c2efda7e2507596f53fac7dc5b3 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 2 Aug 2023 21:37:06 -0400 Subject: [PATCH] chore: handles blocks --- packages/db-postgres/src/schema/build.ts | 52 +++++++++++- .../db-postgres/src/schema/traverseFields.ts | 84 ++++++++++++++++++- 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/packages/db-postgres/src/schema/build.ts b/packages/db-postgres/src/schema/build.ts index 9c1dbef363..ec1b9f8ce1 100644 --- a/packages/db-postgres/src/schema/build.ts +++ b/packages/db-postgres/src/schema/build.ts @@ -30,19 +30,22 @@ type Args = { tableName: string } +type Result = { + arrayBlockRelations: Map +} + export const buildTable = ({ adapter, baseColumns = {}, buildRelationships, fields, tableName, -}: Args): void => { +}: Args): Result => { const formattedTableName = toSnakeCase(tableName); const columns: Record = baseColumns; const indexes: Record IndexBuilder> = {}; let hasLocalizedField = false; - const localesColumns: Record = {}; const localesIndexes: Record IndexBuilder> = {}; let localesTable: GenericTable; @@ -50,6 +53,8 @@ export const buildTable = ({ const relationships: Set = new Set(); let relationshipsTable: GenericTable; + const arrayBlockRelations: Map = new Map(); + const idField = fields.find((field) => fieldAffectsData(field) && field.name === 'id'); if (idField) { @@ -60,6 +65,7 @@ export const buildTable = ({ ({ hasLocalizedField } = traverseFields({ adapter, + arrayBlockRelations, buildRelationships, columns, fields, @@ -93,6 +99,15 @@ export const buildTable = ({ }); adapter.tables[localeTableName] = localesTable; + + const localesTableRelations = relations(localesTable, ({ one }) => ({ + _parentID: one(table, { + fields: [localesTable._parentID], + references: [table.id], + }), + })); + + adapter.relations[localeTableName] = localesTableRelations; } if (buildRelationships) { @@ -109,15 +124,42 @@ export const buildTable = ({ relationshipColumns[`${relationTo}ID`] = integer(`${formattedRelationTo}_id`).references(() => adapter.tables[formattedRelationTo].id); }); - relationshipsTable = pgTable(`${formattedTableName}_relationships`, relationshipColumns); + const relationshipsTableName = `${formattedTableName}_relationships`; + relationshipsTable = pgTable(relationshipsTableName, relationshipColumns); + adapter.tables[relationshipsTableName] = relationshipsTable; - adapter.tables[`${formattedTableName}_relationships`] = relationshipsTable; + const relationshipsTableRelations = relations(relationshipsTable, ({ one, many }) => { + const result: Record> = { + parent: one(table, { + relationName: '_relationships', + fields: [relationshipsTable.parent], + references: [table.id], + }), + }; + + relationships.forEach((relationTo) => { + const relatedTableName = toSnakeCase(relationTo); + const idColumnName = `${relationTo}ID`; + result[idColumnName] = one(adapter.tables[relatedTableName], { + fields: [relationshipsTable[idColumnName]], + references: [adapter.tables[relatedTableName].id], + }); + }); + + return result; + }); + + adapter.relations[relationshipsTableName] = relationshipsTableRelations; } } const tableRelations = relations(table, ({ many }) => { const result: Record> = {}; + arrayBlockRelations.forEach((val, key) => { + result[key] = many(adapter.tables[val]); + }); + if (hasLocalizedField) { result._locales = many(localesTable); } @@ -132,4 +174,6 @@ export const buildTable = ({ }); adapter.relations[`${formattedTableName}`] = tableRelations; + + return { arrayBlockRelations }; }; diff --git a/packages/db-postgres/src/schema/traverseFields.ts b/packages/db-postgres/src/schema/traverseFields.ts index 590effd211..2123d7ce2a 100644 --- a/packages/db-postgres/src/schema/traverseFields.ts +++ b/packages/db-postgres/src/schema/traverseFields.ts @@ -3,12 +3,14 @@ import { AnyPgColumnBuilder, integer, pgEnum, pgTable, serial, uniqueIndex, text import { Field } from 'payload/types'; import toSnakeCase from 'to-snake-case'; import { fieldAffectsData } from 'payload/dist/fields/config/types'; +import { Relation, relations } from 'drizzle-orm'; import { GenericColumns, PostgresAdapter } from '../types'; import { createIndex } from './createIndex'; import { buildTable } from './build'; type Args = { adapter: PostgresAdapter + arrayBlockRelations: Map buildRelationships: boolean columns: Record columnPrefix?: string @@ -23,6 +25,7 @@ type Args = { export const traverseFields = ({ adapter, + arrayBlockRelations, buildRelationships, columnPrefix, columns, @@ -82,11 +85,86 @@ export const traverseFields = ({ baseColumns._locale = adapter.enums._locales('_locale').notNull(); } - buildTable({ + const arrayTableName = `${tableName}_${toSnakeCase(field.name)}`; + + const { arrayBlockRelations: subArrayBlockRelations } = buildTable({ adapter, baseColumns, fields: field.fields, - tableName: `${tableName}_${toSnakeCase(field.name)}`, + tableName: arrayTableName, + }); + + arrayBlockRelations.set(`${fieldPrefix || ''}${field.name}`, arrayTableName); + + const arrayTableRelations = relations(adapter.tables[arrayTableName], ({ many, one }) => { + const result: Record> = { + _parentID: one(adapter.tables[tableName], { + fields: [adapter.tables[arrayTableName]._parentID], + references: [adapter.tables[tableName].id], + }), + }; + + if (field.localized) { + result._locales = many(adapter.tables[`${arrayTableName}_locales`]); + } + + subArrayBlockRelations.forEach((val, key) => { + result[key] = many(adapter.tables[val]); + }); + + return result; + }); + + adapter.relations[arrayTableName] = arrayTableRelations; + + break; + } + + case 'blocks': { + field.blocks.forEach((block) => { + const baseColumns: Record = { + _order: integer('_order').notNull(), + _path: text('_path').notNull(), + _parentID: integer('_parent_id').references(() => adapter.tables[tableName].id).notNull(), + }; + + if (field.localized && adapter.payload.config.localization) { + baseColumns._locale = adapter.enums._locales('_locale').notNull(); + } + + const blockTableName = `${tableName}_${toSnakeCase(block.slug)}`; + + if (!adapter.tables[blockTableName]) { + const { arrayBlockRelations: subArrayBlockRelations } = buildTable({ + adapter, + baseColumns, + fields: block.fields, + tableName: blockTableName, + }); + + const blockTableRelations = relations(adapter.tables[blockTableName], ({ many, one }) => { + const result: Record> = { + _parentID: one(adapter.tables[tableName], { + fields: [adapter.tables[blockTableName]._parentID], + references: [adapter.tables[tableName].id], + }), + }; + + if (field.localized) { + result._locales = many(adapter.tables[`${blockTableName}_locales`]); + } + + subArrayBlockRelations.forEach((val, key) => { + result[key] = many(adapter.tables[val]); + }); + + return result; + }); + + adapter.relations[blockTableName] = blockTableRelations; + } + + arrayBlockRelations.set(`_${fieldPrefix || ''}${field.name}`, blockTableName); }); break; @@ -96,6 +174,7 @@ export const traverseFields = ({ // Todo: determine what should happen if groups are set to localized const { hasLocalizedField: groupHasLocalizedField } = traverseFields({ adapter, + arrayBlockRelations, buildRelationships, columnPrefix: `${columnName}_`, columns, @@ -116,6 +195,7 @@ export const traverseFields = ({ case 'row': ({ hasLocalizedField } = traverseFields({ adapter, + arrayBlockRelations, buildRelationships, columns, fields: field.fields,