mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
entity metadata builder refactoring
This commit is contained in:
parent
08a8062e66
commit
b2c3fe0151
20
src/metadata-args/EntityMetadataArgs.ts
Normal file
20
src/metadata-args/EntityMetadataArgs.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {ColumnMetadata} from "../metadata/ColumnMetadata";
|
||||
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
|
||||
import {TableMetadata} from "../metadata/TableMetadata";
|
||||
import {RelationMetadata} from "../metadata/RelationMetadata";
|
||||
import {IndexMetadata} from "../metadata/IndexMetadata";
|
||||
import {ForeignKeyMetadata} from "../metadata/ForeignKeyMetadata";
|
||||
|
||||
/**
|
||||
* Arguments for EntityMetadata class.
|
||||
*/
|
||||
export interface EntityMetadataArgs {
|
||||
|
||||
readonly namingStrategy: NamingStrategyInterface;
|
||||
readonly tableMetadata: TableMetadata;
|
||||
readonly columnMetadatas?: ColumnMetadata[];
|
||||
readonly relationMetadatas?: RelationMetadata[];
|
||||
readonly indexMetadatas?: IndexMetadata[];
|
||||
readonly foreignKeyMetadatas?: ForeignKeyMetadata[];
|
||||
|
||||
}
|
||||
@ -73,7 +73,10 @@ export class MetadataArgsStorage {
|
||||
const relationCounts = this.relationCounts.filterByClass(tableMetadata.target);
|
||||
|
||||
allTableMetadatas
|
||||
.filter(metadata => this.isInherited(tableMetadata.target, metadata.target))
|
||||
.filter(metadata => {
|
||||
if (!tableMetadata.target || !metadata.target) return false;
|
||||
return this.isInherited(tableMetadata.target, metadata.target);
|
||||
})
|
||||
.forEach(parentMetadata => {
|
||||
const metadatasFromAbstract = this.mergeWithAbstract(allTableMetadatas, parentMetadata);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ export interface TableMetadataArgs {
|
||||
/**
|
||||
* Class to which table is applied.
|
||||
*/
|
||||
readonly target: Function;
|
||||
readonly target?: Function;
|
||||
|
||||
/**
|
||||
* Table name.
|
||||
|
||||
@ -6,7 +6,12 @@ export class TargetMetadataArgsCollection<T extends { target?: Function }> exten
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
filterByClass(cls: Function): this {
|
||||
filterByClass(cls?: Function): this {
|
||||
|
||||
// if no class specified then simply return empty collection
|
||||
if (!cls)
|
||||
return new (<any> this.constructor)();
|
||||
|
||||
return this.filterByClasses([cls]);
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
|
||||
import {JoinTableMetadataArgs} from "../metadata-args/JoinTableMetadataArgs";
|
||||
import {PropertyMetadataArgsCollection} from "../metadata-args/collection/PropertyMetadataArgsCollection";
|
||||
import {ColumnMetadataArgs} from "../metadata-args/ColumnMetadataArgs";
|
||||
import {JunctionEntityMetadataBuilder} from "./JunctionEntityMetadataBuilder";
|
||||
|
||||
/**
|
||||
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
|
||||
@ -31,6 +32,7 @@ export class EntityMetadataBuilder {
|
||||
// todo: throw error if parent tree metadata was not specified in a closure table
|
||||
|
||||
private entityValidator = new EntityMetadataValidator();
|
||||
private junctionEntityMetadataBuilder = new JunctionEntityMetadataBuilder();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
@ -50,7 +52,13 @@ export class EntityMetadataBuilder {
|
||||
const indices = mergedArgs.indices.map(args => new IndexMetadata(args));
|
||||
|
||||
// create a new entity metadata
|
||||
const entityMetadata = new EntityMetadata(namingStrategy, table, columns, relations, indices);
|
||||
const entityMetadata = new EntityMetadata({
|
||||
namingStrategy: namingStrategy,
|
||||
tableMetadata: table,
|
||||
columnMetadatas: columns,
|
||||
relationMetadatas: relations,
|
||||
indexMetadatas: indices
|
||||
});
|
||||
|
||||
// set entity metadata everywhere its used
|
||||
table.entityMetadata = entityMetadata;
|
||||
@ -133,13 +141,13 @@ export class EntityMetadataBuilder {
|
||||
|
||||
// create and add foreign key
|
||||
const foreignKey = new ForeignKeyMetadata(
|
||||
metadata,
|
||||
metadata.table,
|
||||
[relationalColumn],
|
||||
relation.inverseEntityMetadata.table,
|
||||
[inverseSideColumn],
|
||||
relation.onDelete
|
||||
);
|
||||
foreignKey.entityMetadata = metadata;
|
||||
metadata.foreignKeys.push(foreignKey);
|
||||
});
|
||||
});
|
||||
@ -180,20 +188,28 @@ export class EntityMetadataBuilder {
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
new ColumnMetadata(metadata, column1Args),
|
||||
new ColumnMetadata(metadata, column2Args)
|
||||
];
|
||||
const closureJunctionColumn1 = new ColumnMetadata(column1Args);
|
||||
const closureJunctionColumn2 = new ColumnMetadata(column2Args);
|
||||
const closureJunctionColumn3 = new ColumnMetadata(column3Args);
|
||||
|
||||
const columns = [closureJunctionColumn1, closureJunctionColumn2];
|
||||
if (metadata.hasTreeLevelColumn)
|
||||
columns.push(new ColumnMetadata(metadata, column3Args));
|
||||
|
||||
const closureJunctionEntityMetadata = new EntityMetadata(namingStrategy, closureJunctionTableMetadata, columns, [], []);
|
||||
columns.push(closureJunctionColumn3);
|
||||
|
||||
const foreignKey1 = new ForeignKeyMetadata(closureJunctionTableMetadata, [columns[0]], metadata.table, [metadata.primaryColumn]);
|
||||
const foreignKey2 = new ForeignKeyMetadata(closureJunctionTableMetadata, [columns[1]], metadata.table, [metadata.primaryColumn]);
|
||||
const foreignKeys = [foreignKey1, foreignKey2];
|
||||
|
||||
const closureJunctionEntityMetadata = new EntityMetadata({
|
||||
namingStrategy: namingStrategy,
|
||||
tableMetadata: closureJunctionTableMetadata,
|
||||
columnMetadatas: columns,
|
||||
foreignKeyMetadatas: foreignKeys
|
||||
});
|
||||
columns.forEach(column => column.entityMetadata = closureJunctionEntityMetadata);
|
||||
foreignKeys.forEach(foreignKey => foreignKey.entityMetadata = closureJunctionEntityMetadata);
|
||||
|
||||
closureJunctionTableMetadata.entityMetadata = closureJunctionEntityMetadata;
|
||||
closureJunctionEntityMetadata.foreignKeys.push(
|
||||
new ForeignKeyMetadata(closureJunctionEntityMetadata, closureJunctionTableMetadata, [columns[0]], metadata.table, [metadata.primaryColumn]),
|
||||
new ForeignKeyMetadata(closureJunctionEntityMetadata, closureJunctionTableMetadata, [columns[1]], metadata.table, [metadata.primaryColumn])
|
||||
);
|
||||
closureJunctionEntityMetadatas.push(closureJunctionEntityMetadata);
|
||||
|
||||
metadata.closureJunctionTable = closureJunctionEntityMetadata;
|
||||
@ -202,47 +218,13 @@ export class EntityMetadataBuilder {
|
||||
// generate junction tables with its columns and foreign keys
|
||||
const junctionEntityMetadatas: EntityMetadata[] = [];
|
||||
entityMetadatas.forEach(metadata => {
|
||||
metadata.ownerManyToManyRelations.map(relation => {
|
||||
const tableMetadata = new TableMetadata({
|
||||
target: Function,
|
||||
name: relation.joinTable.name,
|
||||
type: "junction"
|
||||
metadata.ownerManyToManyRelations.forEach(relation => {
|
||||
const junctionEntityMetadata = this.junctionEntityMetadataBuilder.createJunctionEntityMetadata({
|
||||
namingStrategy: namingStrategy,
|
||||
firstTable: metadata.table,
|
||||
secondTable: relation.inverseEntityMetadata.table,
|
||||
joinTable: relation.joinTable
|
||||
});
|
||||
const column1 = relation.joinTable.referencedColumn;
|
||||
const column2 = relation.joinTable.inverseReferencedColumn;
|
||||
|
||||
const column1options: ColumnOptions = {
|
||||
length: column1.length,
|
||||
type: column1.type,
|
||||
name: relation.joinTable.joinColumnName // metadata.table.name + "_" + column1.name
|
||||
};
|
||||
const column2options: ColumnOptions = {
|
||||
length: column2.length,
|
||||
type: column2.type,
|
||||
name: relation.joinTable.inverseJoinColumnName // inverseSideMetadata.table.name + "_" + column2.name
|
||||
};
|
||||
const columns = [
|
||||
new ColumnMetadata(metadata, {
|
||||
target: Function, // todo: temp, fix it later
|
||||
propertyName: "", // todo: temp, fix it later
|
||||
propertyType: column2.type,
|
||||
mode: "regular", // or virtual?
|
||||
options: column1options
|
||||
}),
|
||||
new ColumnMetadata(metadata, {
|
||||
target: Function, // todo: temp, fix it later
|
||||
propertyName: "", // todo: temp, fix it later
|
||||
propertyType: column2.type,
|
||||
mode: "regular", // or virtual?
|
||||
options: column2options
|
||||
})
|
||||
];
|
||||
const junctionEntityMetadata = new EntityMetadata(namingStrategy, tableMetadata, columns, [], []);
|
||||
tableMetadata.entityMetadata = junctionEntityMetadata;
|
||||
junctionEntityMetadata.foreignKeys.push(
|
||||
new ForeignKeyMetadata(junctionEntityMetadata, tableMetadata, [columns[0]], metadata.table, [column1]),
|
||||
new ForeignKeyMetadata(junctionEntityMetadata, tableMetadata, [columns[1]], relation.inverseEntityMetadata.table, [column2])
|
||||
);
|
||||
junctionEntityMetadatas.push(junctionEntityMetadata);
|
||||
relation.junctionEntityMetadata = junctionEntityMetadata;
|
||||
if (relation.hasInverseSide)
|
||||
@ -259,5 +241,4 @@ export class EntityMetadataBuilder {
|
||||
// Private Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
|
||||
}
|
||||
74
src/metadata-builder/JunctionEntityMetadataBuilder.ts
Normal file
74
src/metadata-builder/JunctionEntityMetadataBuilder.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import {EntityMetadata} from "../metadata/EntityMetadata";
|
||||
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
|
||||
import {ColumnMetadata} from "../metadata/ColumnMetadata";
|
||||
import {ColumnOptions} from "../decorator/options/ColumnOptions";
|
||||
import {ForeignKeyMetadata} from "../metadata/ForeignKeyMetadata";
|
||||
import {TableMetadata} from "../metadata/TableMetadata";
|
||||
import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
|
||||
|
||||
/**
|
||||
* Helps to create EntityMetadatas for junction tables.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface JunctionEntityMetadataBuilderArgs {
|
||||
namingStrategy: NamingStrategyInterface;
|
||||
firstTable: TableMetadata;
|
||||
secondTable: TableMetadata;
|
||||
joinTable: JoinTableMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to create EntityMetadatas for junction tables.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class JunctionEntityMetadataBuilder {
|
||||
|
||||
createJunctionEntityMetadata(args: JunctionEntityMetadataBuilderArgs) {
|
||||
|
||||
const column1 = args.joinTable.referencedColumn;
|
||||
const column2 = args.joinTable.inverseReferencedColumn;
|
||||
|
||||
const tableMetadata = new TableMetadata({
|
||||
name: args.joinTable.name,
|
||||
type: "junction"
|
||||
});
|
||||
|
||||
const junctionColumn1 = new ColumnMetadata({
|
||||
propertyType: column1.type,
|
||||
mode: "virtual",
|
||||
options: <ColumnOptions> {
|
||||
length: column1.length,
|
||||
type: column1.type,
|
||||
name: args.joinTable.joinColumnName
|
||||
}
|
||||
});
|
||||
const junctionColumn2 = new ColumnMetadata({
|
||||
propertyType: column2.type,
|
||||
mode: "virtual",
|
||||
options: <ColumnOptions> {
|
||||
length: column2.length,
|
||||
type: column2.type,
|
||||
name: args.joinTable.inverseJoinColumnName
|
||||
}
|
||||
});
|
||||
const junctionColumns = [junctionColumn1, junctionColumn2];
|
||||
|
||||
const foreignKey1 = new ForeignKeyMetadata(tableMetadata, [junctionColumns[0]], args.firstTable, [column2]);
|
||||
const foreignKey2 = new ForeignKeyMetadata(tableMetadata, [junctionColumns[1]], args.secondTable, [column2]);
|
||||
const foreignKeys = [foreignKey1, foreignKey2];
|
||||
|
||||
const junctionEntityMetadata = new EntityMetadata({
|
||||
namingStrategy: args.namingStrategy,
|
||||
tableMetadata: tableMetadata,
|
||||
columnMetadatas: junctionColumns,
|
||||
foreignKeyMetadatas: foreignKeys,
|
||||
});
|
||||
junctionColumns.forEach(column => column.entityMetadata = junctionEntityMetadata);
|
||||
foreignKeys.forEach(column => column.entityMetadata = junctionEntityMetadata);
|
||||
tableMetadata.entityMetadata = junctionEntityMetadata;
|
||||
return junctionEntityMetadata;
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,6 +5,7 @@ import {IndexMetadata} from "./IndexMetadata";
|
||||
import {RelationTypes} from "./types/RelationTypes";
|
||||
import {ForeignKeyMetadata} from "./ForeignKeyMetadata";
|
||||
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
|
||||
import {EntityMetadataArgs} from "../metadata-args/EntityMetadataArgs";
|
||||
|
||||
/**
|
||||
* Contains all entity metadata.
|
||||
@ -58,16 +59,13 @@ export class EntityMetadata {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(namingStrategy: NamingStrategyInterface,
|
||||
table: TableMetadata,
|
||||
columns: ColumnMetadata[],
|
||||
relations: RelationMetadata[],
|
||||
indices: IndexMetadata[]) {
|
||||
this.namingStrategy = namingStrategy;
|
||||
this.table = table;
|
||||
this.columns = columns;
|
||||
this.relations = relations;
|
||||
this.indices = indices;
|
||||
constructor(args: EntityMetadataArgs) {
|
||||
this.namingStrategy = args.namingStrategy;
|
||||
this.table = args.tableMetadata;
|
||||
this.columns = args.columnMetadatas || [];
|
||||
this.relations = args.relationMetadatas || [];
|
||||
this.indices = args.indexMetadatas || [];
|
||||
this.foreignKeys = args.foreignKeyMetadatas || [];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -13,13 +13,17 @@ export type OnDeleteType = "RESTRICT"|"CASCADE"|"SET NULL";
|
||||
export class ForeignKeyMetadata {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Readonly Properties
|
||||
// Public Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Entity metadata where this foreign key is.
|
||||
*/
|
||||
readonly entityMetadata: EntityMetadata;
|
||||
entityMetadata: EntityMetadata;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Readonly Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Table to which this foreign key is applied.
|
||||
@ -50,13 +54,11 @@ export class ForeignKeyMetadata {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(entityMetadata: EntityMetadata,
|
||||
table: TableMetadata,
|
||||
constructor(table: TableMetadata,
|
||||
columns: ColumnMetadata[],
|
||||
referencedTable: TableMetadata,
|
||||
referencedColumns: ColumnMetadata[],
|
||||
onDelete?: OnDeleteType) {
|
||||
this.entityMetadata = entityMetadata;
|
||||
this.table = table;
|
||||
this.columns = columns;
|
||||
this.referencedTable = referencedTable;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user