Files
klz-cables.com/.pnpm-store/v10/files/4b/d0415885837c8fdc28ccb8e223b3287dffa8cca16406dba5c40ed0ec777b37016944d9b14e070384a00ad2edc91ef466f1aecab9e1c09b33cfdec212ae878b
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

704 lines
24 KiB
Plaintext

import { InvalidConfiguration } from 'payload';
import toSnakeCase from 'to-snake-case';
import { createTableName } from '../createTableName.js';
import { buildForeignKeyName } from '../utilities/buildForeignKeyName.js';
import { buildIndexName } from '../utilities/buildIndexName.js';
import { traverseFields } from './traverseFields.js';
export const buildTable = ({ adapter, baseColumns = {}, baseForeignKeys = {}, baseIndexes = {}, blocksTableNameMap, compoundIndexes, disableNotNull, disableRelsTableUnique = false, disableUnique = false, fields, parentIsLocalized, rootRelationships, rootRelationsToBuild, rootTableIDColType, rootTableName: incomingRootTableName, rootUniqueRelationships, setColumnID, tableName, timestamps, versions, withinLocalizedArrayOrBlock })=>{
const isRoot = !incomingRootTableName;
const rootTableName = incomingRootTableName || tableName;
const columns = baseColumns;
const indexes = baseIndexes;
const localesColumns = {};
const localesIndexes = {};
let localesTable;
let textsTable;
let numbersTable;
// Relationships to the base collection
const relationships = rootRelationships || new Set();
// Unique relationships to the base collection
const uniqueRelationships = rootUniqueRelationships || new Set();
let relationshipsTable;
// Drizzle relations
const relationsToBuild = new Map();
const idColType = setColumnID({
adapter,
columns,
fields
});
const { hasLocalizedField, hasLocalizedManyNumberField, hasLocalizedManyTextField, hasLocalizedRelationshipField, hasManyNumberField, hasManyTextField } = traverseFields({
adapter,
blocksTableNameMap,
columns,
disableNotNull,
disableRelsTableUnique,
disableUnique,
fields,
indexes,
localesColumns,
localesIndexes,
newTableName: tableName,
parentIsLocalized,
parentTableName: tableName,
relationships,
relationsToBuild,
rootRelationsToBuild: rootRelationsToBuild || relationsToBuild,
rootTableIDColType: rootTableIDColType || idColType,
rootTableName,
setColumnID,
uniqueRelationships,
versions,
withinLocalizedArrayOrBlock
});
// split the relationsToBuild by localized and non-localized
const localizedRelations = new Map();
const nonLocalizedRelations = new Map();
relationsToBuild.forEach(({ type, localized, relationName, target }, key)=>{
const map = localized ? localizedRelations : nonLocalizedRelations;
map.set(key, {
type,
relationName,
target
});
});
if (timestamps) {
columns.createdAt = {
name: 'created_at',
type: 'timestamp',
defaultNow: true,
mode: 'string',
notNull: true,
precision: 3,
withTimezone: true
};
columns.updatedAt = {
name: 'updated_at',
type: 'timestamp',
defaultNow: true,
mode: 'string',
notNull: true,
precision: 3,
withTimezone: true
};
}
const table = {
name: tableName,
columns,
foreignKeys: baseForeignKeys,
indexes
};
adapter.rawTables[tableName] = table;
if (hasLocalizedField || localizedRelations.size) {
const localeTableName = `${tableName}${adapter.localesSuffix}`;
adapter.rawTables[localeTableName] = localesTable;
localesColumns.id = {
name: 'id',
type: 'serial',
primaryKey: true
};
localesColumns._locale = {
name: '_locale',
type: 'enum',
locale: true,
notNull: true
};
localesColumns._parentID = {
name: '_parent_id',
type: idColType,
notNull: true
};
localesIndexes._localeParent = {
name: buildIndexName({
name: `${localeTableName}_locale_parent_id_unique`,
adapter,
appendSuffix: false
}),
on: [
'_locale',
'_parentID'
],
unique: true
};
localesTable = {
name: localeTableName,
columns: localesColumns,
foreignKeys: {
_parentIdFk: {
name: buildForeignKeyName({
name: `${localeTableName}_parent_id`,
adapter
}),
columns: [
'_parentID'
],
foreignColumns: [
{
name: 'id',
table: tableName
}
],
onDelete: 'cascade'
}
},
indexes: localesIndexes
};
adapter.rawTables[localeTableName] = localesTable;
const localeRelations = {
_parentID: {
type: 'one',
fields: [
{
name: '_parentID',
table: localeTableName
}
],
references: [
'id'
],
relationName: '_locales',
to: tableName
}
};
localizedRelations.forEach(({ type, target }, key)=>{
if (type === 'one') {
localeRelations[key] = {
type: 'one',
fields: [
{
name: key,
table: localeTableName
}
],
references: [
'id'
],
relationName: key,
to: target
};
}
if (type === 'many') {
localeRelations[key] = {
type: 'many',
relationName: key,
to: target
};
}
});
adapter.rawRelations[localeTableName] = localeRelations;
}
if (compoundIndexes) {
for (const index of compoundIndexes){
let someLocalized = null;
const columns = [];
const getTableToUse = ()=>{
if (someLocalized) {
return localesTable;
}
return table;
};
for (const { path, pathHasLocalized } of index.fields){
if (someLocalized === null) {
someLocalized = pathHasLocalized;
}
if (someLocalized !== pathHasLocalized) {
throw new InvalidConfiguration(`Compound indexes within localized and non localized fields are not supported in SQL. Expected ${path} to be ${someLocalized ? 'non' : ''} localized.`);
}
const columnPath = path.replaceAll('.', '_');
if (!getTableToUse().columns[columnPath]) {
throw new InvalidConfiguration(`Column ${columnPath} for compound index on ${path} was not found in the ${getTableToUse().name} table.`);
}
columns.push(columnPath);
}
if (someLocalized) {
columns.push('_locale');
}
let name = columns.join('_');
// truncate against the limit, buildIndexName will handle collisions
if (name.length > 63) {
name = 'compound_index';
}
const indexName = buildIndexName({
name,
adapter
});
getTableToUse().indexes[indexName] = {
name: indexName,
on: columns,
unique: disableUnique ? false : index.unique
};
}
}
if (isRoot) {
if (hasManyTextField) {
const textsTableName = `${rootTableName}_texts`;
adapter.rawTables[textsTableName] = textsTable;
const columns = {
id: {
name: 'id',
type: 'serial',
primaryKey: true
},
order: {
name: 'order',
type: 'integer',
notNull: true
},
parent: {
name: 'parent_id',
type: idColType,
notNull: true
},
path: {
name: 'path',
type: 'varchar',
notNull: true
},
text: {
name: 'text',
type: 'varchar'
}
};
if (hasLocalizedManyTextField) {
columns.locale = {
name: 'locale',
type: 'enum',
locale: true
};
}
const textsTableIndexes = {
orderParentIdx: {
name: buildIndexName({
name: `${textsTableName}_order_parent`,
adapter,
appendSuffix: false
}),
on: [
'order',
'parent'
]
}
};
if (hasManyTextField === 'index') {
textsTableIndexes.text_idx = {
name: buildIndexName({
name: `${textsTableName}_text`,
adapter
}),
on: 'text'
};
}
if (hasLocalizedManyTextField) {
textsTableIndexes.localeParent = {
name: buildIndexName({
name: `${textsTableName}_locale_parent`,
adapter,
appendSuffix: false
}),
on: [
'locale',
'parent'
]
};
}
textsTable = {
name: textsTableName,
columns,
foreignKeys: {
parentFk: {
name: buildForeignKeyName({
name: `${textsTableName}_parent`,
adapter
}),
columns: [
'parent'
],
foreignColumns: [
{
name: 'id',
table: tableName
}
],
onDelete: 'cascade'
}
},
indexes: textsTableIndexes
};
adapter.rawTables[textsTableName] = textsTable;
adapter.rawRelations[textsTableName] = {
parent: {
type: 'one',
fields: [
{
name: 'parent',
table: textsTableName
}
],
references: [
'id'
],
relationName: '_texts',
to: tableName
}
};
}
if (hasManyNumberField) {
const numbersTableName = `${rootTableName}_numbers`;
adapter.rawTables[numbersTableName] = numbersTable;
const columns = {
id: {
name: 'id',
type: 'serial',
primaryKey: true
},
number: {
name: 'number',
type: 'numeric'
},
order: {
name: 'order',
type: 'integer',
notNull: true
},
parent: {
name: 'parent_id',
type: idColType,
notNull: true
},
path: {
name: 'path',
type: 'varchar',
notNull: true
}
};
if (hasLocalizedManyNumberField) {
columns.locale = {
name: 'locale',
type: 'enum',
locale: true
};
}
const numbersTableIndexes = {
orderParentIdx: {
name: buildIndexName({
name: `${numbersTableName}_order_parent`,
adapter
}),
on: [
'order',
'parent'
]
}
};
if (hasManyNumberField === 'index') {
numbersTableIndexes.numberIdx = {
name: buildIndexName({
name: `${numbersTableName}_number`,
adapter
}),
on: 'number'
};
}
if (hasLocalizedManyNumberField) {
numbersTableIndexes.localeParent = {
name: buildIndexName({
name: `${numbersTableName}_locale_parent`,
adapter,
appendSuffix: false
}),
on: [
'locale',
'parent'
]
};
}
numbersTable = {
name: numbersTableName,
columns,
foreignKeys: {
parentFk: {
name: buildForeignKeyName({
name: `${numbersTableName}_parent`,
adapter
}),
columns: [
'parent'
],
foreignColumns: [
{
name: 'id',
table: tableName
}
],
onDelete: 'cascade'
}
},
indexes: numbersTableIndexes
};
adapter.rawTables[numbersTableName] = numbersTable;
adapter.rawRelations[numbersTableName] = {
parent: {
type: 'one',
fields: [
{
name: 'parent',
table: numbersTableName
}
],
references: [
'id'
],
relationName: '_numbers',
to: tableName
}
};
}
if (relationships.size) {
const relationshipColumns = {
id: {
name: 'id',
type: 'serial',
primaryKey: true
},
order: {
name: 'order',
type: 'integer'
},
parent: {
name: 'parent_id',
type: idColType,
notNull: true
},
path: {
name: 'path',
type: 'varchar',
notNull: true
}
};
if (hasLocalizedRelationshipField) {
relationshipColumns.locale = {
name: 'locale',
type: 'enum',
locale: true
};
}
const relationshipsTableName = `${tableName}${adapter.relationshipsSuffix}`;
const relationshipIndexes = {
order: {
name: buildIndexName({
name: `${relationshipsTableName}_order`,
adapter
}),
on: 'order'
},
parentIdx: {
name: buildIndexName({
name: `${relationshipsTableName}_parent`,
adapter
}),
on: 'parent'
},
pathIdx: {
name: buildIndexName({
name: `${relationshipsTableName}_path`,
adapter
}),
on: 'path'
}
};
if (hasLocalizedRelationshipField) {
relationshipIndexes.localeIdx = {
name: buildIndexName({
name: `${relationshipsTableName}_locale`,
adapter
}),
on: 'locale'
};
}
const relationshipForeignKeys = {
parentFk: {
name: buildForeignKeyName({
name: `${relationshipsTableName}_parent`,
adapter
}),
columns: [
'parent'
],
foreignColumns: [
{
name: 'id',
table: tableName
}
],
onDelete: 'cascade'
}
};
relationships.forEach((relationTo)=>{
const relationshipConfig = adapter.payload.collections[relationTo].config;
const formattedRelationTo = createTableName({
adapter,
config: relationshipConfig,
throwValidationError: true
});
let colType = adapter.idType === 'uuid' ? 'uuid' : 'integer';
const relatedCollectionCustomIDType = adapter.payload.collections[relationshipConfig.slug]?.customIDType;
if (relatedCollectionCustomIDType === 'number') {
colType = 'numeric';
}
if (relatedCollectionCustomIDType === 'text') {
colType = 'varchar';
}
const colName = `${relationTo}ID`;
relationshipColumns[colName] = {
name: `${formattedRelationTo}_id`,
type: colType
};
relationshipForeignKeys[`${relationTo}IdFk`] = {
name: buildForeignKeyName({
name: `${relationshipsTableName}_${toSnakeCase(relationTo)}`,
adapter
}),
columns: [
colName
],
foreignColumns: [
{
name: 'id',
table: formattedRelationTo
}
],
onDelete: 'cascade'
};
const indexColumns = [
colName
];
const unique = !disableUnique && uniqueRelationships.has(relationTo);
if (unique) {
indexColumns.push('path');
}
if (hasLocalizedRelationshipField) {
indexColumns.push('locale');
}
const indexName = buildIndexName({
name: `${relationshipsTableName}_${formattedRelationTo}_id`,
adapter
});
relationshipIndexes[indexName] = {
name: indexName,
on: indexColumns,
unique
};
});
relationshipsTable = {
name: relationshipsTableName,
columns: relationshipColumns,
foreignKeys: relationshipForeignKeys,
indexes: relationshipIndexes
};
adapter.rawTables[relationshipsTableName] = relationshipsTable;
const relationshipsTableRelations = {
parent: {
type: 'one',
fields: [
{
name: 'parent',
table: relationshipsTableName
}
],
references: [
'id'
],
relationName: '_rels',
to: tableName
}
};
relationships.forEach((relationTo)=>{
const relatedTableName = createTableName({
adapter,
config: adapter.payload.collections[relationTo].config,
throwValidationError: true
});
const idColumnName = `${relationTo}ID`;
relationshipsTableRelations[idColumnName] = {
type: 'one',
fields: [
{
name: idColumnName,
table: relationshipsTableName
}
],
references: [
'id'
],
relationName: relationTo,
to: relatedTableName
};
});
adapter.rawRelations[relationshipsTableName] = relationshipsTableRelations;
}
}
const tableRelations = {};
nonLocalizedRelations.forEach(({ type, relationName, target }, key)=>{
if (type === 'one') {
tableRelations[key] = {
type: 'one',
fields: [
{
name: key,
table: tableName
}
],
references: [
'id'
],
relationName: key,
to: target
};
}
if (type === 'many') {
tableRelations[key] = {
type: 'many',
relationName: relationName || key,
to: target
};
}
});
if (hasLocalizedField) {
tableRelations._locales = {
type: 'many',
relationName: '_locales',
to: localesTable.name
};
}
if (isRoot && textsTable) {
tableRelations._texts = {
type: 'many',
relationName: '_texts',
to: textsTable.name
};
}
if (isRoot && numbersTable) {
tableRelations._numbers = {
type: 'many',
relationName: '_numbers',
to: numbersTable.name
};
}
if (relationships.size && relationshipsTable) {
tableRelations._rels = {
type: 'many',
relationName: '_rels',
to: relationshipsTable.name
};
}
adapter.rawRelations[tableName] = tableRelations;
return {
hasLocalizedManyNumberField,
hasLocalizedManyTextField,
hasLocalizedRelationshipField,
hasManyNumberField,
hasManyTextField,
relationsToBuild
};
};
//# sourceMappingURL=build.js.map