diff --git a/packages/core/database/src/metadata/index.ts b/packages/core/database/src/metadata/index.ts index be79936bd4..a50d72a34e 100644 --- a/packages/core/database/src/metadata/index.ts +++ b/packages/core/database/src/metadata/index.ts @@ -1,9 +1,8 @@ import _ from 'lodash/fp'; - +import * as identifiers from '../utils/identifiers'; import * as types from '../utils/types'; import { createRelation, - getJoinTableName, isPolymorphic, isBidirectional, isAnyToOne, @@ -17,7 +16,6 @@ import type { Attribute, Model } from '../types'; export type { Metadata, Meta }; export { - getJoinTableName, isPolymorphic, isBidirectional, isAnyToOne, @@ -87,6 +85,6 @@ export const createMetadata = (models: Model[] = []): Metadata => { }; const createAttribute = (attributeName: string, attribute: Attribute) => { - const columnName = _.snakeCase(attributeName); + const columnName = identifiers.getColumnName(attributeName); Object.assign(attribute, { columnName }); }; diff --git a/packages/core/database/src/metadata/relations.ts b/packages/core/database/src/metadata/relations.ts index 54a9345e29..7e30370720 100644 --- a/packages/core/database/src/metadata/relations.ts +++ b/packages/core/database/src/metadata/relations.ts @@ -1,5 +1,6 @@ import _ from 'lodash/fp'; +import * as identifiers from '../utils/identifiers'; import type { Meta, Metadata } from './metadata'; import type { RelationalAttribute, Relation, MorphJoinTable } from '../types'; @@ -15,6 +16,10 @@ interface JoinTableOptions { meta: Meta; } +const ID = identifiers.ID_COLUMN; +const ORDER = identifiers.ORDER_COLUMN; +const FIELD = identifiers.FIELD_COLUMN; + const hasInversedBy = ( attr: RelationalAttribute ): attr is RelationalAttribute & { inversedBy: boolean } => 'inversedBy' in attr; @@ -57,9 +62,6 @@ const isOwner = ( const shouldUseJoinTable = (attribute: RelationalAttribute) => !('useJoinTable' in attribute) || attribute.useJoinTable !== false; -export const getJoinTableName = (tableName: string, attributeName: string) => - _.snakeCase(`${tableName}_${attributeName}_links`); - export const hasOrderColumn = (attribute: RelationalAttribute) => isAnyToMany(attribute); export const hasInverseOrderColumn = (attribute: RelationalAttribute) => isBidirectional(attribute) && isManyToAny(attribute); @@ -209,8 +211,8 @@ const createManyToMany = ( * set info in the traget */ const createMorphToOne = (attributeName: string, attribute: Relation.MorphToOne) => { - const idColumnName = 'target_id'; - const typeColumnName = 'target_type'; + const idColumnName = identifiers.getJoinColumnAttributeIdName('target'); + const typeColumnName = identifiers.getMorphColumnTypeName('target'); if ('morphColumn' in attribute && attribute.morphColumn) { return; @@ -225,7 +227,7 @@ const createMorphToOne = (attributeName: string, attribute: Relation.MorphToOne) }, idColumn: { name: idColumnName, - referencedColumn: 'id', + referencedColumn: ID, }, }, }); @@ -246,19 +248,19 @@ const createMorphToMany = ( return; } - const joinTableName = _.snakeCase(`${meta.tableName}_${attributeName}_morphs`); + const joinTableName = identifiers.getMorphTableName(meta.tableName, attributeName); + const joinColumnName = identifiers.getMorphColumnJoinTableIdName(meta.singularName); + const idColumnName = identifiers.getMorphColumnAttributeIdName(attributeName); + const typeColumnName = identifiers.getMorphColumnTypeName(attributeName); - const joinColumnName = _.snakeCase(`${meta.singularName}_id`); - const morphColumnName = _.snakeCase(`${attributeName}`); - const idColumnName = `${morphColumnName}_id`; - const typeColumnName = `${morphColumnName}_type`; + const fkIndexName = identifiers.getFkIndexName(joinTableName); metadata.add({ singularName: joinTableName, uid: joinTableName, tableName: joinTableName, attributes: { - id: { + [ID]: { type: 'increments', }, [joinColumnName]: { @@ -276,10 +278,10 @@ const createMorphToMany = ( [typeColumnName]: { type: 'string', }, - field: { + [FIELD]: { type: 'string', }, - order: { + [ORDER]: { type: 'float', column: { unsigned: true, @@ -288,12 +290,12 @@ const createMorphToMany = ( }, indexes: [ { - name: `${joinTableName}_fk`, + name: fkIndexName, columns: [joinColumnName], }, { name: `${joinTableName}_order_index`, - columns: ['order'], + columns: [ORDER], }, { name: `${joinTableName}_id_column_index`, @@ -302,10 +304,10 @@ const createMorphToMany = ( ], foreignKeys: [ { - name: `${joinTableName}_fk`, + name: fkIndexName, columns: [joinColumnName], - referencedColumns: ['id'], - referencedTable: meta.tableName, + referencedColumns: [ID], + referencedTable: identifiers.getTableName(meta.tableName), onDelete: 'CASCADE', }, ], @@ -317,7 +319,7 @@ const createMorphToMany = ( name: joinTableName, joinColumn: { name: joinColumnName, - referencedColumn: 'id', + referencedColumn: ID, }, morphColumn: { typeColumn: { @@ -325,7 +327,7 @@ const createMorphToMany = ( }, idColumn: { name: idColumnName, - referencedColumn: 'id', + referencedColumn: ID, }, }, orderBy: { @@ -390,7 +392,7 @@ const createJoinColum = (metadata: Metadata, { attribute, attributeName }: JoinC const joinColumnName = _.snakeCase(`${attributeName}_id`); const joinColumn = { name: joinColumnName, - referencedColumn: 'id', + referencedColumn: ID, referencedTable: targetMeta.tableName, }; @@ -430,30 +432,34 @@ const createJoinTable = ( return; } - const joinTableName = getJoinTableName(meta.tableName, attributeName); + const joinTableName = identifiers.getJoinTableName(meta.tableName, attributeName); - const joinColumnName = _.snakeCase(`${meta.singularName}_id`); - let inverseJoinColumnName = _.snakeCase(`${targetMeta.singularName}_id`); + const joinColumnName = identifiers.getJoinColumnIdName(meta.singularName); + let inverseJoinColumnName = identifiers.getJoinColumnIdName(targetMeta.singularName); // if relation is self referencing if (joinColumnName === inverseJoinColumnName) { - inverseJoinColumnName = `inv_${inverseJoinColumnName}`; + inverseJoinColumnName = identifiers.getInverseJoinColumnIdName(targetMeta.singularName); } - const orderColumnName = _.snakeCase(`${targetMeta.singularName}_order`); - let inverseOrderColumnName = _.snakeCase(`${meta.singularName}_order`); + const orderColumnName = identifiers.getOrderColumnName(targetMeta.singularName); + // TODO: should this plus the conditional below be rolled into one method? + let inverseOrderColumnName = identifiers.getOrderColumnName(meta.singularName); // if relation is self referencing if (attribute.relation === 'manyToMany' && orderColumnName === inverseOrderColumnName) { - inverseOrderColumnName = `inv_${inverseOrderColumnName}`; + inverseOrderColumnName = identifiers.getInverseOrderColumnName(meta.singularName); } + const fkIndexName = identifiers.getFkIndexName(joinTableName); // TODO: joinTableName is multipart, can we re-use those parts instead of shortening the combined string? + const invFkIndexName = identifiers.getInverseFkIndexName(joinTableName); + const metadataSchema: Meta = { singularName: joinTableName, uid: joinTableName, tableName: joinTableName, attributes: { - id: { + [ID]: { type: 'increments', }, [joinColumnName]: { @@ -472,32 +478,32 @@ const createJoinTable = ( }, indexes: [ { - name: `${joinTableName}_fk`, + name: fkIndexName, columns: [joinColumnName], }, { - name: `${joinTableName}_inv_fk`, + name: invFkIndexName, columns: [inverseJoinColumnName], }, { - name: `${joinTableName}_unique`, + name: identifiers.getUniqueIndexName(joinTableName), columns: [joinColumnName, inverseJoinColumnName], type: 'unique', }, ], foreignKeys: [ { - name: `${joinTableName}_fk`, + name: fkIndexName, columns: [joinColumnName], - referencedColumns: ['id'], - referencedTable: meta.tableName, + referencedColumns: [ID], + referencedTable: meta.tableName, // TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version? onDelete: 'CASCADE', }, { - name: `${joinTableName}_inv_fk`, + name: invFkIndexName, columns: [inverseJoinColumnName], - referencedColumns: ['id'], - referencedTable: targetMeta.tableName, + referencedColumns: [ID], + referencedTable: targetMeta.tableName, // TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version? onDelete: 'CASCADE', }, ], @@ -509,11 +515,11 @@ const createJoinTable = ( name: joinTableName, joinColumn: { name: joinColumnName, - referencedColumn: 'id', + referencedColumn: ID, }, inverseJoinColumn: { name: inverseJoinColumnName, - referencedColumn: 'id', + referencedColumn: ID, }, pivotColumns: [joinColumnName, inverseJoinColumnName], } as any; @@ -528,7 +534,7 @@ const createJoinTable = ( }, }; metadataSchema.indexes.push({ - name: `${joinTableName}_order_fk`, + name: identifiers.getOrderFkIndexName(joinTableName), // TODO: should we send joinTableName as parts? columns: [orderColumnName], }); joinTable.orderColumnName = orderColumnName; @@ -546,7 +552,7 @@ const createJoinTable = ( }; metadataSchema.indexes.push({ - name: `${joinTableName}_order_inv_fk`, + name: identifiers.getOrderInverseFkIndexName(joinTableName), columns: [inverseOrderColumnName], }); diff --git a/packages/core/database/src/utils/identifiers/index.ts b/packages/core/database/src/utils/identifiers/index.ts index e10cde63af..cef2816080 100644 --- a/packages/core/database/src/utils/identifiers/index.ts +++ b/packages/core/database/src/utils/identifiers/index.ts @@ -38,7 +38,7 @@ export const getNameFromTokens = (tokens: NameToken[], max: number = MAX_DB_IDEN }; // Generic name handler used by all helper functions -export const getName = (names: NameInput, options: NameOptions) => { +export const getName = (names: NameInput, options: NameOptions = {}) => { const tokens = _.castArray(names).map((name) => { return { name, @@ -61,7 +61,6 @@ export const getName = (names: NameInput, options: NameOptions) => { * TABLES */ -// Get a base table name for a model export const getTableName = (name: string, options?: NameOptions) => { const tokens = [ { @@ -93,7 +92,10 @@ export const getMorphTableName = (collectionName: string, attributeName: string) * COLUMNS */ -// Regular relation join tables +export const getColumnName = (attributeName: string) => { + return getName(attributeName); +}; + export const getJoinColumnEntityIdName = () => { return getName(ENTITY, { suffix: 'id' }); }; @@ -102,7 +104,25 @@ export const getJoinColumnAttributeIdName = (attributeName: string) => { return getName(attributeName, { suffix: 'id' }); }; -// Morph Join Tables +export const getJoinColumnIdName = (singularName: string) => { + return getName(singularName, { suffix: 'id' }); +}; + +export const getInverseJoinColumnIdName = (singularName: string) => { + return getName(singularName, { suffix: 'id', prefix: 'inv' }); +}; + +export const getOrderColumnName = (singularName: string) => { + return getName(singularName, { suffix: 'order' }); +}; + +export const getInverseOrderColumnName = (singularName: string) => { + return getName(singularName, { suffix: 'order', prefix: 'inv' }); +}; + +/** + * Morph Join Tables + */ export const getMorphColumnJoinTableIdName = (singularName: string) => { return getName(singularName, { suffix: 'id' }); }; @@ -127,6 +147,18 @@ export const getFkIndexName = (names: NameInput) => { return getName(names, { suffix: 'fk' }); }; +export const getInverseFkIndexName = (names: NameInput) => { + return getName(names, { suffix: 'inv_fk' }); +}; + +export const getOrderFkIndexName = (names: NameInput) => { + return getName(names, { suffix: 'order_fk' }); +}; + +export const getOrderInverseFkIndexName = (names: NameInput) => { + return getName(names, { suffix: 'order_inv_fk' }); +}; + export const getUniqueIndexName = (names: NameInput) => { return getName(names, { suffix: 'unique' }); }; diff --git a/packages/core/database/src/validations/relations/bidirectional.ts b/packages/core/database/src/validations/relations/bidirectional.ts index e07b170cb6..9a78bea05b 100644 --- a/packages/core/database/src/validations/relations/bidirectional.ts +++ b/packages/core/database/src/validations/relations/bidirectional.ts @@ -1,7 +1,6 @@ -import { getJoinTableName } from '../../metadata'; - import type { Database } from '../..'; import type { Relation } from '../../types'; +import { getJoinTableName } from '../../utils/identifiers'; type Link = { relation: Relation.Bidirectional & { inversedBy: string };