fixed all issues related to metadata args changes

This commit is contained in:
Umed Khudoiberdiev 2016-05-24 20:06:17 +05:00
parent c5228e4978
commit 290204f573
11 changed files with 124 additions and 89 deletions

View File

@ -350,7 +350,7 @@ export class Connection {
getMetadataArgsStorage()
.namingStrategyMetadatas
.filterByClasses(this.namingStrategyClasses)
.forEach(namingStrategy => this.namingStrategyMetadatas.push(namingStrategy));
.forEach(metadata => this.namingStrategyMetadatas.push(new NamingStrategyMetadata(metadata)));
// take imported event subscribers
getMetadataArgsStorage()
@ -363,14 +363,14 @@ export class Connection {
getMetadataArgsStorage()
.entityListenerMetadatas
.filterByClasses(this.entityClasses)
.forEach(entityListener => this.entityListeners.push(entityListener));
.forEach(metadata => this.entityListeners.push(new EntityListenerMetadata(metadata)));
// build entity metadatas for the current connection
getFromContainer(EntityMetadataBuilder)
.build(this.createNamingStrategy(), this.entityClasses)
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.createRepository(metadata);
.forEach(layout => {
this.entityMetadatas.push(layout);
this.createRepository(layout);
});
}
@ -391,15 +391,15 @@ export class Connection {
/**
* Creates repository and reactive repository for the given entity metadata.
*/
private createRepository(metadata: EntityMetadata) {
private createRepository(entityLayout: EntityMetadata) {
const repositoryFactory = getFromContainer(RepositoryFactory);
if (metadata.table.isClosure) {
const repository = repositoryFactory.createRepository(this, this.entityMetadatas, metadata);
if (entityLayout.table.isClosure) {
const repository = repositoryFactory.createRepository(this, this.entityMetadatas, entityLayout);
const reactiveRepository = repositoryFactory.createReactiveRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(reactiveRepository);
} else {
const repository = repositoryFactory.createTreeRepository(this, this.entityMetadatas, metadata);
const repository = repositoryFactory.createTreeRepository(this, this.entityMetadatas, entityLayout);
const reactiveRepository = repositoryFactory.createReactiveTreeRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(reactiveRepository);

View File

@ -13,6 +13,8 @@ import {JoinColumnOptions} from "../metadata/options/JoinColumnOptions";
import {TableMetadata} from "../metadata/TableMetadata";
import {ColumnTypes} from "../metadata/types/ColumnTypes";
import {getMetadataArgsStorage} from "../index";
import {RelationMetadata} from "../metadata/RelationMetadata";
import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
/**
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
@ -31,17 +33,6 @@ export class EntityMetadataBuilder {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
private mergeIndicesAndCompositeIndices(indices: PropertyMetadataCollection<IndexMetadata>,
compositeIndices: TargetMetadataCollection<CompositeIndexMetadata>) {
indices.forEach(index => {
const compositeIndex = new CompositeIndexMetadata(index.target, index.name, [index.propertyName]);
compositeIndex.namingStrategy = index.namingStrategy;
compositeIndices.add(compositeIndex);
});
// later need to check if no duplicate keys in composite indices?
}
/**
* Builds a complete metadata aggregations for the given entity classes.
@ -53,7 +44,9 @@ export class EntityMetadataBuilder {
// filter the only metadata we need - those which are bind to the given table classes
const allTableMetadatas = allMetadataStorage.tableMetadatas.filterByClasses(entityClasses);
const tableMetadatas = allTableMetadatas.filterByClasses(entityClasses).filter(table => !table.isAbstract);
const tableMetadatas = allTableMetadatas
.filterByClasses(entityClasses)
.filter(metadata => metadata.type !== "abstract");
// set naming strategy
// allMetadataStorage.tableMetadatas.forEach(tableMetadata => tableMetadata.namingStrategy = namingStrategy);
@ -64,15 +57,22 @@ export class EntityMetadataBuilder {
const mergedMetadata = allMetadataStorage.mergeWithAbstract(allTableMetadatas, tableMetadata);
// set naming strategy
// tableMetadata.namingStrategy = namingStrategy;
mergedMetadata.columnMetadatas.forEach(column => column.namingStrategy = namingStrategy);
mergedMetadata.relationMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
mergedMetadata.indexMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
mergedMetadata.compositeIndexMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
// create layouts from metadatas
const columns = mergedMetadata.columnMetadatas.map(metadata => new ColumnMetadata(metadata));
const relations = mergedMetadata.relationMetadatas.map(metadata => new RelationMetadata(metadata));
const compositeIndices = mergedMetadata.compositeIndexMetadatas.map(metadata => new CompositeIndexMetadata(metadata));
// merge indices and composite indices because simple indices actually are compose indices with only one column
this.mergeIndicesAndCompositeIndices(mergedMetadata.indexMetadatas, mergedMetadata.compositeIndexMetadatas);
// todo: no need to create index layout for this, use index metadata instead
const indices = mergedMetadata.indexMetadatas.map(metadata => new IndexMetadata(metadata));
const compositeFromSimpleIndices = this.createCompositeIndicesFromSimpleIndices(indices);
compositeIndices.push(...compositeFromSimpleIndices);
// todo no need to set naming strategy everywhere - childs can obtain it from their parents
// tableMetadata.namingStrategy = namingStrategy;
columns.forEach(column => column.namingStrategy = namingStrategy);
relations.forEach(relation => relation.namingStrategy = namingStrategy);
compositeIndices.forEach(index => index.namingStrategy = namingStrategy);
// todo: check if multiple tree parent metadatas in validator
// todo: tree decorators can be used only on closure table (validation)
@ -81,16 +81,17 @@ export class EntityMetadataBuilder {
// create a new entity metadata
const entityMetadata = new EntityMetadata(
namingStrategy,
tableMetadata,
mergedMetadata.columnMetadatas,
mergedMetadata.relationMetadatas,
mergedMetadata.compositeIndexMetadatas
new TableMetadata(tableMetadata),
columns,
relations,
compositeIndices
);
// create entity's relations join tables
entityMetadata.manyToManyRelations.forEach(relation => {
const joinTable = mergedMetadata.joinTableMetadatas.findByProperty(relation.propertyName);
if (joinTable) {
const joinTableMetadata = mergedMetadata.joinTableMetadatas.findByProperty(relation.propertyName);
if (joinTableMetadata) {
const joinTable = new JoinTableMetadata(joinTableMetadata);
relation.joinTable = joinTable;
joinTable.relation = relation;
}
@ -98,8 +99,9 @@ export class EntityMetadataBuilder {
// create entity's relations join columns
entityMetadata.relations.forEach(relation => {
const joinColumn = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
if (joinColumn) {
const joinColumnMetadata = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
if (joinColumnMetadata) {
const joinColumn = new JoinColumnMetadata(joinColumnMetadata);
relation.joinColumn = joinColumn;
joinColumn.relation = relation;
}
@ -108,9 +110,10 @@ export class EntityMetadataBuilder {
// since for many-to-one relations having JoinColumn is not required on decorators level, we need to go
// throw all of them which don't have JoinColumn decorators and create it for them
entityMetadata.manyToOneRelations.forEach(relation => {
let joinColumn = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
if (!joinColumn) {
joinColumn = new JoinColumnMetadata(relation.target, relation.propertyName, <JoinColumnOptions> {});
let joinColumnMetadata = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
if (!joinColumnMetadata) {
joinColumnMetadata = { target: relation.target, propertyName: relation.propertyName, options: <JoinColumnOptions> {} };
const joinColumn = new JoinColumnMetadata(joinColumnMetadata);
relation.joinColumn = joinColumn;
joinColumn.relation = relation;
}
@ -179,16 +182,20 @@ export class EntityMetadataBuilder {
const columns = [
new ColumnMetadata({
target: Function, // todo: temp, fix it later
propertyName: "", // todo: temp, fix it later
propertyType: metadata.primaryColumn.type,
options: {
options: <ColumnOptions> {
length: metadata.primaryColumn.length,
type: metadata.primaryColumn.type,
name: "ancestor"
}
}),
new ColumnMetadata({
target: Function, // todo: temp, fix it later
propertyName: "", // todo: temp, fix it later
propertyType: metadata.primaryColumn.type,
options: {
options: <ColumnOptions> {
length: metadata.primaryColumn.length,
type: metadata.primaryColumn.type,
name: "descendant"
@ -198,6 +205,8 @@ export class EntityMetadataBuilder {
if (metadata.hasTreeLevelColumn) {
columns.push(new ColumnMetadata({
target: Function, // todo: temp, fix it later
propertyName: "", // todo: temp, fix it later
propertyType: ColumnTypes.INTEGER,
options: {
type: ColumnTypes.INTEGER,
@ -220,7 +229,11 @@ export class EntityMetadataBuilder {
const junctionEntityMetadatas: EntityMetadata[] = [];
entityMetadatas.forEach(metadata => {
metadata.ownerManyToManyRelations.map(relation => {
const tableMetadata = new TableMetadata(undefined, relation.joinTable.name, "junction");
const tableMetadata = new TableMetadata({
target: Function,
name: relation.joinTable.name,
type: "junction"
});
const column1 = relation.joinTable.referencedColumn;
const column2 = relation.joinTable.inverseReferencedColumn;
@ -236,10 +249,14 @@ export class EntityMetadataBuilder {
};
const columns = [
new ColumnMetadata({
target: Function, // todo: temp, fix it later
propertyName: "", // todo: temp, fix it later
propertyType: column2.type,
options: column1options
}),
new ColumnMetadata({
target: Function, // todo: temp, fix it later
propertyName: "", // todo: temp, fix it later
propertyType: column2.type,
options: column2options
})
@ -261,4 +278,20 @@ export class EntityMetadataBuilder {
.concat(closureJunctionEntityMetadatas);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private createCompositeIndicesFromSimpleIndices(indices: IndexMetadata[]) {
return indices.map(index => {
return new CompositeIndexMetadata({
name: index.name,
target: index.target,
columns: [index.propertyName]
});
});
// later need to check if no duplicate keys in composite indices?
}
}

View File

@ -22,6 +22,7 @@ import {NamingStrategyMetadataArgs} from "../metadata/args/NamingStrategyMetadat
import {EventSubscriberMetadataArgs} from "../metadata/args/EventSubscriberMetadataArgs";
import {JoinTableMetadataArgs} from "../metadata/args/JoinTableMetadataArgs";
import {JoinColumnMetadataArgs} from "../metadata/args/JoinColumnMetadataArgs";
import {TargetMetadataArgs} from "../metadata/args/TargetMetadataArgs";
/**
* Storage all metadatas of all available types: tables, fields, subscribers, relations, etc.
@ -65,8 +66,8 @@ export class MetadataArgsStorage {
* Creates a new copy of the MetadataStorage with same metadatas as in current metadata storage, but filtered
* by classes.
*/
mergeWithAbstract(allTableMetadatas: TargetMetadataCollection<TableMetadata>,
tableMetadata: TableMetadata) {
mergeWithAbstract(allTableMetadatas: TargetMetadataCollection<TableMetadataArgs>,
tableMetadata: TableMetadataArgs) {
const compositeIndexMetadatas = this.compositeIndexMetadatas.filterByClass(tableMetadata.target);
const columnMetadatas = this.columnMetadatas.filterByClass(tableMetadata.target);
@ -78,7 +79,7 @@ export class MetadataArgsStorage {
const relationCountMetadatas = this.relationCountMetadatas.filterByClass(tableMetadata.target);
allTableMetadatas
.filter(metadata => tableMetadata.isInherited(metadata))
.filter(metadata => this.isInherited(tableMetadata, metadata))
.forEach(parentMetadata => {
const metadatasFromAbstract = this.mergeWithAbstract(allTableMetadatas, parentMetadata);
@ -122,5 +123,16 @@ export class MetadataArgsStorage {
relationCountMetadatas: relationCountMetadatas
};
}
/**
* Checks if this table is inherited from another table.
*/
private isInherited(firstTargetMetadata: TargetMetadataArgs, secondTargetMetadata: TargetMetadataArgs) {
return Object.getPrototypeOf(firstTargetMetadata.target.prototype).constructor === secondTargetMetadata.target;
// we cannot use instanceOf in this method, because we need order of inherited tables, to ensure that
// properties get inherited in a right order. To achieve it we can only check a first parent of the class
// return this.target.prototype instanceof anotherTable.target;
}
}

View File

@ -169,13 +169,6 @@ export class RelationMetadata extends PropertyMetadata {
return this.namingStrategy ? this.namingStrategy.relationName(this.propertyName) : this.propertyName;
}
get referencedColumnName(): string {
if (this.joinColumn && this.joinColumn.referencedColumn && this.joinColumn.referencedColumn.name)
return this.joinColumn.referencedColumn.name;
return this.inverseEntityMetadata.primaryColumn.propertyName;
}
get referencedColumnName(): string {
if (this.joinColumn && this.joinColumn.referencedColumn && this.joinColumn.referencedColumn.name)
return this.joinColumn.referencedColumn.name;

View File

@ -39,12 +39,23 @@ export class TableMetadata extends TargetMetadata {
// Constructor
// ---------------------------------------------------------------------
constructor(metadata: TableMetadataArgs) {
super(metadata.target);
this.tableType = metadata.type;
if (metadata.name)
this._name = name;
constructor(target: Function|undefined, name: string, type: TableType);
constructor(metadata: TableMetadataArgs);
constructor(metadataOrTarget: TableMetadataArgs|Function|undefined, name?: string, type?: TableType) {
if (arguments.length === 1) {
const metadata = metadataOrTarget as TableMetadataArgs;
super(metadata.target);
this.tableType = metadata.type;
if (metadata.name)
this._name = metadata.name;
} else {
super(metadataOrTarget as Function);
if (name)
this._name = name;
if (type)
this.tableType = type;
}
}
// ---------------------------------------------------------------------
@ -81,19 +92,4 @@ export class TableMetadata extends TargetMetadata {
return this.entityMetadata.namingStrategy.tableName((<any>this.target).name);
}
// ---------------------------------------------------------------------
// Public Methods
// ---------------------------------------------------------------------
/**
* Checks if this table is inherited from another table.
*/
isInherited(anotherTable: TableMetadata) {
return Object.getPrototypeOf(this.target.prototype).constructor === anotherTable.target;
// we cannot use instanceOf in this method, because we need order of inherited tables, to ensure that
// properties get inherited in a right order. To achieve it we can only check a first parent of the class
// return this.target.prototype instanceof anotherTable.target;
}
}

View File

@ -1,17 +1,18 @@
import {CompositeIndexOptions} from "../options/CompositeIndexOptions";
import {TargetMetadataArgs} from "./TargetMetadataArgs";
/**
*/
export interface CompositeIndexMetadataArgs {
export interface CompositeIndexMetadataArgs extends TargetMetadataArgs {
/**
* Class to which this column is applied.
*/
target: Function;
name: string|undefined,
name?: string;
columns: ((object: any) => any[])|string[],
columns: ((object: any) => any[])|string[];
options?: CompositeIndexOptions;

View File

@ -1,6 +1,8 @@
import {TargetMetadataArgs} from "./TargetMetadataArgs";
/**
*/
export interface EventSubscriberMetadataArgs {
export interface EventSubscriberMetadataArgs extends TargetMetadataArgs {
/**
* Class to which this subscriber is applied.

View File

@ -1,10 +1,8 @@
import {TargetMetadataArgs} from "./TargetMetadataArgs";
/**
*/
export interface NamingStrategyMetadataArgs {
/**
*/
target: Function;
export interface NamingStrategyMetadataArgs extends TargetMetadataArgs {
/**
*/

View File

@ -1,7 +1,7 @@
/**
* Constructor arguments for ColumnMetadata class.
*/
export interface ColumnMetadataArgs {
export interface TargetMetadataArgs {
/**
* Class to which this column is applied.

View File

@ -1,7 +1,7 @@
import {MetadataAlreadyExistsError} from "../../metadata-storage/error/MetadataAlreadyExistsError";
import {TableMetadataArgs} from "../args/TableMetadataArgs";
import {TargetMetadataArgs} from "../args/TargetMetadataArgs";
export class TargetMetadataCollection<T extends TableMetadataArgs> extends Array<T> {
export class TargetMetadataCollection<T extends TargetMetadataArgs> extends Array<T> {
// -------------------------------------------------------------------------
// Public Methods

View File

@ -633,10 +633,10 @@ export class QueryBuilder<Entity> {
const metadata = this.aliasMap.getEntityMetadataByAlias(alias);
if (!metadata) return;
metadata.columns.forEach(column => {
statement = statement.replace(new RegExp(alias.name + "." + column.propertyName, 'g'), alias.name + "." + column.name);
statement = statement.replace(new RegExp(alias.name + "." + column.propertyName, "g"), alias.name + "." + column.name);
});
metadata.relations.forEach(relation => {
statement = statement.replace(new RegExp(alias.name + "." + relation.propertyName, 'g'), alias.name + "." + relation.name);
statement = statement.replace(new RegExp(alias.name + "." + relation.propertyName, "g"), alias.name + "." + relation.name);
});
});
return statement;