entity metadata builder refactoring

This commit is contained in:
Umed Khudoiberdiev 2016-05-26 22:32:37 +05:00
parent 08a8062e66
commit b2c3fe0151
8 changed files with 155 additions and 72 deletions

View 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[];
}

View File

@ -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);

View File

@ -8,7 +8,7 @@ export interface TableMetadataArgs {
/**
* Class to which table is applied.
*/
readonly target: Function;
readonly target?: Function;
/**
* Table name.

View File

@ -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]);
}

View File

@ -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
// -------------------------------------------------------------------------
}

View 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;
}
}

View File

@ -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 || [];
}
// -------------------------------------------------------------------------

View File

@ -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;