mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
metadata build refactoring
This commit is contained in:
parent
697178f3b7
commit
9465e2f1fe
@ -10,7 +10,8 @@ export function JoinColumn(options?: JoinColumnOptions): Function {
|
||||
const args: JoinColumnMetadataArgs = {
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
options: options
|
||||
name: options.name,
|
||||
referencedColumnName: options.referencedColumnName
|
||||
};
|
||||
getMetadataArgsStorage().joinColumns.add(args);
|
||||
};
|
||||
|
||||
@ -10,7 +10,9 @@ export function JoinTable(options?: JoinTableOptions): Function {
|
||||
const args: JoinTableMetadataArgs = {
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
options: options
|
||||
name: options.name,
|
||||
joinColumn: options.joinColumn,
|
||||
inverseJoinColumn: options.inverseJoinColumn
|
||||
};
|
||||
getMetadataArgsStorage().joinTables.add(args);
|
||||
};
|
||||
|
||||
@ -12,6 +12,9 @@ import {ColumnTypes} from "../metadata/types/ColumnTypes";
|
||||
import {getMetadataArgsStorage} from "../index";
|
||||
import {RelationMetadata} from "../metadata/RelationMetadata";
|
||||
import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
|
||||
import {JoinTableMetadataArgs} from "../metadata/args/JoinTableMetadataArgs";
|
||||
import {PropertyMetadataArgsCollection} from "../metadata/collection/PropertyMetadataArgsCollection";
|
||||
import {ColumnMetadataArgs} from "../metadata/args/ColumnMetadataArgs";
|
||||
|
||||
/**
|
||||
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
|
||||
@ -22,8 +25,10 @@ export class EntityMetadataBuilder {
|
||||
|
||||
// todo: type in function validation, inverse side function validation
|
||||
// todo: check on build for duplicate names, since naming checking was removed from MetadataStorage
|
||||
|
||||
// todo: duplicate name checking for: table, relation, column, index, naming strategy, join tables/columns?
|
||||
// todo: check if multiple tree parent metadatas in validator
|
||||
// todo: tree decorators can be used only on closure table (validation)
|
||||
// todo: throw error if parent tree metadata was not specified in a closure table
|
||||
|
||||
private entityValidator = new EntityMetadataValidator();
|
||||
|
||||
@ -34,49 +39,25 @@ export class EntityMetadataBuilder {
|
||||
/**
|
||||
* Builds a complete metadata aggregations for the given entity classes.
|
||||
*/
|
||||
build(namingStrategy: NamingStrategyInterface,
|
||||
entityClasses: Function[]): EntityMetadata[] {
|
||||
build(namingStrategy: NamingStrategyInterface, entityClasses: Function[]): EntityMetadata[] {
|
||||
|
||||
const allMetadataArgsStorage = getMetadataArgsStorage();
|
||||
const entityMetadatas = getMetadataArgsStorage().getMergedTableMetadatas(entityClasses).map(mergedArgs => {
|
||||
|
||||
// filter the only metadata we need - those which are bind to the given table classes
|
||||
const allTableMetadataArgs = allMetadataArgsStorage.tables.filterByClasses(entityClasses);
|
||||
const tableMetadatas = allTableMetadataArgs
|
||||
.filterByClasses(entityClasses)
|
||||
.filter(metadata => metadata.type !== "abstract");
|
||||
|
||||
// set naming strategy
|
||||
// allMetadataStorage.tableMetadatas.forEach(tableMetadata => tableMetadata.namingStrategy = namingStrategy);
|
||||
// allTableMetadatas.forEach(column => column.namingStrategy = namingStrategy);
|
||||
// entityMetadata.relations.forEach(relation => relation.namingStrategy = namingStrategy);
|
||||
|
||||
const entityMetadatas = tableMetadatas.map(tableMetadata => {
|
||||
|
||||
const mergedArgs = allMetadataArgsStorage.mergeWithAbstract(allTableMetadataArgs, tableMetadata);
|
||||
|
||||
// create layouts from metadatas
|
||||
const table = new TableMetadata(tableMetadata);
|
||||
// create metadatas from args
|
||||
const table = new TableMetadata(mergedArgs.table);
|
||||
const columns = mergedArgs.columns.map(args => new ColumnMetadata(args));
|
||||
const relations = mergedArgs.relations.map(args => new RelationMetadata(args));
|
||||
const indices = mergedArgs.indices.map(args => new IndexMetadata(args));
|
||||
|
||||
// todo no need to set naming strategy everywhere - childs can obtain it from their parents
|
||||
// tableMetadata.namingStrategy = namingStrategy;
|
||||
|
||||
// todo: check if multiple tree parent metadatas in validator
|
||||
// todo: tree decorators can be used only on closure table (validation)
|
||||
// todo: throw error if parent tree metadata was not specified in a closure table
|
||||
|
||||
// create a new entity metadata
|
||||
const entityMetadata = new EntityMetadata(
|
||||
namingStrategy,
|
||||
table,
|
||||
columns,
|
||||
relations,
|
||||
indices
|
||||
);
|
||||
|
||||
const entityMetadata = new EntityMetadata(namingStrategy, table, columns, relations, indices);
|
||||
|
||||
// set entity metadata everywhere its used
|
||||
table.entityMetadata = entityMetadata;
|
||||
columns.forEach(column => column.entityMetadata = entityMetadata);
|
||||
relations.forEach(relation => relation.entityMetadata = entityMetadata);
|
||||
indices.forEach(index => index.entityMetadata = entityMetadata);
|
||||
|
||||
// create entity's relations join tables
|
||||
entityMetadata.manyToManyRelations.forEach(relation => {
|
||||
const joinTableMetadata = mergedArgs.joinTables.findByProperty(relation.propertyName);
|
||||
@ -88,27 +69,27 @@ export class EntityMetadataBuilder {
|
||||
});
|
||||
|
||||
// create entity's relations join columns
|
||||
entityMetadata.relations.forEach(relation => {
|
||||
const joinColumnMetadata = mergedArgs.joinColumns.findByProperty(relation.propertyName);
|
||||
if (joinColumnMetadata) {
|
||||
const joinColumn = new JoinColumnMetadata(joinColumnMetadata);
|
||||
relation.joinColumn = joinColumn;
|
||||
joinColumn.relation = relation;
|
||||
}
|
||||
});
|
||||
entityMetadata.oneToOneRelations
|
||||
.concat(entityMetadata.manyToOneRelations)
|
||||
.forEach(relation => {
|
||||
|
||||
// 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
|
||||
let joinColumnMetadata = mergedArgs.joinColumns.findByProperty(relation.propertyName);
|
||||
if (!joinColumnMetadata && relation.isManyToOne) {
|
||||
joinColumnMetadata = {
|
||||
target: relation.target,
|
||||
propertyName: relation.propertyName
|
||||
};
|
||||
}
|
||||
|
||||
if (joinColumnMetadata) {
|
||||
const joinColumn = new JoinColumnMetadata(joinColumnMetadata);
|
||||
relation.joinColumn = joinColumn;
|
||||
joinColumn.relation = relation;
|
||||
}
|
||||
});
|
||||
|
||||
// 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 joinColumnMetadata = mergedArgs.joinColumns.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;
|
||||
}
|
||||
});
|
||||
|
||||
return entityMetadata;
|
||||
});
|
||||
|
||||
@ -171,45 +152,44 @@ export class EntityMetadataBuilder {
|
||||
const closureTableName = namingStrategy.closureJunctionTableName(metadata.table.name);
|
||||
const closureJunctionTableMetadata = new TableMetadata(undefined, closureTableName, "closureJunction");
|
||||
|
||||
const column1Args: ColumnMetadataArgs = {
|
||||
propertyType: metadata.primaryColumn.type,
|
||||
mode: "virtual",
|
||||
options: <ColumnOptions> {
|
||||
length: metadata.primaryColumn.length,
|
||||
type: metadata.primaryColumn.type,
|
||||
name: "ancestor"
|
||||
}
|
||||
};
|
||||
const column2Args: ColumnMetadataArgs = {
|
||||
propertyType: metadata.primaryColumn.type,
|
||||
mode: "virtual",
|
||||
options: <ColumnOptions> {
|
||||
length: metadata.primaryColumn.length,
|
||||
type: metadata.primaryColumn.type,
|
||||
name: "descendant"
|
||||
}
|
||||
};
|
||||
|
||||
const column3Args: ColumnMetadataArgs = {
|
||||
propertyType: ColumnTypes.INTEGER,
|
||||
mode: "virtual",
|
||||
options: {
|
||||
type: ColumnTypes.INTEGER,
|
||||
name: "level"
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
new ColumnMetadata(metadata, {
|
||||
target: Function, // todo: temp, fix it later
|
||||
propertyName: "", // todo: temp, fix it later
|
||||
propertyType: metadata.primaryColumn.type,
|
||||
mode: "regular", // or virtual?
|
||||
options: <ColumnOptions> {
|
||||
length: metadata.primaryColumn.length,
|
||||
type: metadata.primaryColumn.type,
|
||||
name: "ancestor"
|
||||
}
|
||||
}),
|
||||
new ColumnMetadata(metadata, {
|
||||
target: Function, // todo: temp, fix it later
|
||||
propertyName: "", // todo: temp, fix it later
|
||||
propertyType: metadata.primaryColumn.type,
|
||||
mode: "regular", // or virtual?
|
||||
options: <ColumnOptions> {
|
||||
length: metadata.primaryColumn.length,
|
||||
type: metadata.primaryColumn.type,
|
||||
name: "descendant"
|
||||
}
|
||||
})
|
||||
new ColumnMetadata(metadata, column1Args),
|
||||
new ColumnMetadata(metadata, column2Args)
|
||||
];
|
||||
|
||||
if (metadata.hasTreeLevelColumn) {
|
||||
columns.push(new ColumnMetadata(metadata, {
|
||||
target: Function, // todo: temp, fix it later
|
||||
propertyName: "", // todo: temp, fix it later
|
||||
propertyType: ColumnTypes.INTEGER,
|
||||
mode: "regular", // or virtual?
|
||||
options: {
|
||||
type: ColumnTypes.INTEGER,
|
||||
name: "level"
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (metadata.hasTreeLevelColumn)
|
||||
columns.push(new ColumnMetadata(metadata, column3Args));
|
||||
|
||||
const closureJunctionEntityMetadata = new EntityMetadata(namingStrategy, closureJunctionTableMetadata, columns, [], []);
|
||||
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])
|
||||
@ -258,6 +238,7 @@ export class EntityMetadataBuilder {
|
||||
})
|
||||
];
|
||||
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])
|
||||
|
||||
@ -1,15 +1,5 @@
|
||||
import {TableMetadata} from "../metadata/TableMetadata";
|
||||
import {RelationMetadata} from "../metadata/RelationMetadata";
|
||||
import {IndexMetadata} from "../metadata/IndexMetadata";
|
||||
import {ColumnMetadata} from "../metadata/ColumnMetadata";
|
||||
import {EventSubscriberMetadata} from "../metadata/EventSubscriberMetadata";
|
||||
import {EntityListenerMetadata} from "../metadata/EntityListenerMetadata";
|
||||
import {NamingStrategyMetadata} from "../metadata/NamingStrategyMetadata";
|
||||
import {JoinColumnMetadata} from "../metadata/JoinColumnMetadata";
|
||||
import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
|
||||
import {TargetMetadataCollection} from "../metadata/collection/TargetMetadataCollection";
|
||||
import {PropertyMetadataCollection} from "../metadata/collection/PropertyMetadataCollection";
|
||||
import {RelationsCountMetadata} from "../metadata/RelationsCountMetadata";
|
||||
import {TargetMetadataArgsCollection} from "../metadata/collection/TargetMetadataArgsCollection";
|
||||
import {PropertyMetadataArgsCollection} from "../metadata/collection/PropertyMetadataArgsCollection";
|
||||
import {RelationMetadataArgs} from "../metadata/args/RelationMetadataArgs";
|
||||
import {ColumnMetadataArgs} from "../metadata/args/ColumnMetadataArgs";
|
||||
import {RelationsCountMetadataArgs} from "../metadata/args/RelationsCountMetadataArgs";
|
||||
@ -37,27 +27,43 @@ export class MetadataArgsStorage {
|
||||
// Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
readonly tables = new TargetMetadataCollection<TableMetadataArgs>();
|
||||
readonly namingStrategies = new TargetMetadataCollection<NamingStrategyMetadataArgs>();
|
||||
readonly eventSubscribers = new TargetMetadataCollection<EventSubscriberMetadataArgs>();
|
||||
readonly indices = new TargetMetadataCollection<IndexMetadataArgs>();
|
||||
readonly columns = new PropertyMetadataCollection<ColumnMetadataArgs>();
|
||||
readonly relations = new PropertyMetadataCollection<RelationMetadataArgs>();
|
||||
readonly joinColumns = new PropertyMetadataCollection<JoinColumnMetadataArgs>();
|
||||
readonly joinTables = new PropertyMetadataCollection<JoinTableMetadataArgs>();
|
||||
readonly entityListeners = new PropertyMetadataCollection<EntityListenerMetadataArgs>();
|
||||
readonly relationCounts = new PropertyMetadataCollection<RelationsCountMetadataArgs>();
|
||||
readonly tables = new TargetMetadataArgsCollection<TableMetadataArgs>();
|
||||
readonly namingStrategies = new TargetMetadataArgsCollection<NamingStrategyMetadataArgs>();
|
||||
readonly eventSubscribers = new TargetMetadataArgsCollection<EventSubscriberMetadataArgs>();
|
||||
readonly indices = new TargetMetadataArgsCollection<IndexMetadataArgs>();
|
||||
readonly columns = new PropertyMetadataArgsCollection<ColumnMetadataArgs>();
|
||||
readonly relations = new PropertyMetadataArgsCollection<RelationMetadataArgs>();
|
||||
readonly joinColumns = new PropertyMetadataArgsCollection<JoinColumnMetadataArgs>();
|
||||
readonly joinTables = new PropertyMetadataArgsCollection<JoinTableMetadataArgs>();
|
||||
readonly entityListeners = new PropertyMetadataArgsCollection<EntityListenerMetadataArgs>();
|
||||
readonly relationCounts = new PropertyMetadataArgsCollection<RelationsCountMetadataArgs>();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets merged (with all abstract classes) table metadatas for the given classes.
|
||||
*/
|
||||
getMergedTableMetadatas(classes: Function[]) {
|
||||
const allTableMetadataArgs = this.tables.filterByClasses(classes);
|
||||
const tableMetadatas = this.tables.filterByClasses(classes).filter(table => table.type !== "abstract");
|
||||
|
||||
return tableMetadatas.map(tableMetadata => {
|
||||
return this.mergeWithAbstract(allTableMetadataArgs, tableMetadata);
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new copy of the MetadataStorage with same metadatas as in current metadata storage, but filtered
|
||||
* by classes.
|
||||
*/
|
||||
mergeWithAbstract(allTableMetadatas: TargetMetadataCollection<TableMetadataArgs>,
|
||||
tableMetadata: TableMetadataArgs) {
|
||||
private mergeWithAbstract(allTableMetadatas: TargetMetadataArgsCollection<TableMetadataArgs>,
|
||||
tableMetadata: TableMetadataArgs) {
|
||||
|
||||
const indices = this.indices.filterByClass(tableMetadata.target);
|
||||
const columns = this.columns.filterByClass(tableMetadata.target);
|
||||
@ -75,29 +81,30 @@ export class MetadataArgsStorage {
|
||||
metadatasFromAbstract.columns
|
||||
.filterRepeatedMetadatas(columns)
|
||||
.forEach(metadata => columns.push(metadata));
|
||||
|
||||
|
||||
metadatasFromAbstract.relations
|
||||
.filterRepeatedMetadatas(relations)
|
||||
.forEach(metadata => relations.push(metadata));
|
||||
|
||||
|
||||
metadatasFromAbstract.joinColumns
|
||||
.filterRepeatedMetadatas(joinColumns)
|
||||
.forEach(metadata => joinColumns.push(metadata));
|
||||
|
||||
|
||||
metadatasFromAbstract.joinTables
|
||||
.filterRepeatedMetadatas(joinTables)
|
||||
.forEach(metadata => joinTables.push(metadata));
|
||||
|
||||
|
||||
metadatasFromAbstract.entityListeners
|
||||
.filterRepeatedMetadatas(entityListeners)
|
||||
.forEach(metadata => entityListeners.push(metadata));
|
||||
|
||||
|
||||
metadatasFromAbstract.relationCounts
|
||||
.filterRepeatedMetadatas(relationCounts)
|
||||
.forEach(metadata => relationCounts.push(metadata));
|
||||
});
|
||||
|
||||
return {
|
||||
table: tableMetadata,
|
||||
indices: indices,
|
||||
columns: columns,
|
||||
relations: relations,
|
||||
@ -108,10 +115,6 @@ export class MetadataArgsStorage {
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks if this table is inherited from another table.
|
||||
*/
|
||||
@ -119,6 +122,8 @@ export class MetadataArgsStorage {
|
||||
// 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;
|
||||
if (!firstTargetMetadata.target)
|
||||
return false;
|
||||
return Object.getPrototypeOf(firstTargetMetadata.target.prototype).constructor === secondTargetMetadata.target;
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ export class MissingJoinColumnError extends Error {
|
||||
super();
|
||||
if (relation.hasInverseSide) {
|
||||
this.message = `JoinColumn is missing on both sides of ${entityMetadata.name}#${relation.propertyName} and ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} one-to-one relationship. ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} one-to-one relationship. ` +
|
||||
`You need to put JoinColumn decorator on one of the sides.`;
|
||||
} else {
|
||||
this.message = `JoinColumn is missing on ${entityMetadata.name}#${relation.propertyName} one-to-one relationship. ` +
|
||||
|
||||
@ -11,11 +11,11 @@ export class MissingJoinTableError extends Error {
|
||||
super();
|
||||
|
||||
if (relation.hasInverseSide) {
|
||||
this.message = `JoinTable is missing on both sides of ${entityMetadata.name}#${relation.name} and ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} many-to-many relationship. ` +
|
||||
this.message = `JoinTable is missing on both sides of ${entityMetadata.name}#${relation.propertyName} and ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} many-to-many relationship. ` +
|
||||
`You need to put decorator decorator on one of the sides.`;
|
||||
} else {
|
||||
this.message = `JoinTable is missing on ${entityMetadata.name}#${relation.name} many-to-many relationship. ` +
|
||||
this.message = `JoinTable is missing on ${entityMetadata.name}#${relation.propertyName} many-to-many relationship. ` +
|
||||
`You need to put JoinTable decorator on it.`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ export class UsingJoinColumnIsNotAllowedError extends Error {
|
||||
|
||||
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
|
||||
super();
|
||||
this.message = `Using JoinColumn on ${entityMetadata.name}#${relation.name} is wrong. ` +
|
||||
this.message = `Using JoinColumn on ${entityMetadata.name}#${relation.propertyName} is wrong. ` +
|
||||
`You can use JoinColumn only on one-to-one and many-to-one relations.`;
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ export class UsingJoinColumnOnlyOnOneSideAllowedError extends Error {
|
||||
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
|
||||
super();
|
||||
this.message = `Using JoinColumn is allowed only on one side of the one-to-one relationship. ` +
|
||||
`Both ${entityMetadata.name}#${relation.name} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} ` +
|
||||
`has JoinTable decorators. Choose one of them and left JoinTable decorator only on it.`;
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,8 @@ export class UsingJoinTableIsNotAllowedError extends Error {
|
||||
|
||||
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
|
||||
super();
|
||||
this.message = `Using JoinTable on ${entityMetadata.name}#${relation.name} is wrong. ` +
|
||||
`${entityMetadata.name}#${relation.name} has ${relation.relationType} relation, ` +
|
||||
this.message = `Using JoinTable on ${entityMetadata.name}#${relation.propertyName} is wrong. ` +
|
||||
`${entityMetadata.name}#${relation.propertyName} has ${relation.relationType} relation, ` +
|
||||
`however you can use JoinTable only on many-to-many relations.`;
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ export class UsingJoinTableOnlyOnOneSideAllowedError extends Error {
|
||||
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
|
||||
super();
|
||||
this.message = `Using JoinTable is allowed only on one side of the many-to-many relationship. ` +
|
||||
`Both ${entityMetadata.name}#${relation.name} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} ` +
|
||||
`has JoinTable decorators. Choose one of them and left JoinColumn decorator only on it.`;
|
||||
}
|
||||
|
||||
|
||||
@ -68,11 +68,6 @@ export class EntityMetadata {
|
||||
this.columns = columns;
|
||||
this.relations = relations;
|
||||
this.indices = indices;
|
||||
|
||||
table.entityMetadata = this;
|
||||
columns.forEach(column => column.entityMetadata = this);
|
||||
relations.forEach(relation => relation.entityMetadata = this);
|
||||
indices.forEach(index => index.entityMetadata = this);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -24,12 +24,12 @@ export class JoinColumnMetadata extends PropertyMetadata {
|
||||
/**
|
||||
* Join column name.
|
||||
*/
|
||||
private readonly _name: string;
|
||||
private readonly _name: string|undefined;
|
||||
|
||||
/**
|
||||
* Join column referenced column name.
|
||||
*/
|
||||
private readonly _referencedColumnName: string;
|
||||
private readonly referencedColumnName: string|undefined;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructor
|
||||
@ -37,11 +37,8 @@ export class JoinColumnMetadata extends PropertyMetadata {
|
||||
|
||||
constructor(args: JoinColumnMetadataArgs) {
|
||||
super(args.target, args.propertyName);
|
||||
|
||||
if (args.options.name)
|
||||
this._name = args.options.name;
|
||||
if (args.options.referencedColumnName)
|
||||
this._referencedColumnName = args.options.referencedColumnName;
|
||||
this._name = args.name;
|
||||
this.referencedColumnName = args.referencedColumnName;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
@ -59,10 +56,10 @@ export class JoinColumnMetadata extends PropertyMetadata {
|
||||
* Referenced join column.
|
||||
*/
|
||||
get referencedColumn(): ColumnMetadata {
|
||||
if (this._referencedColumnName) {
|
||||
const referencedColumn = this.relation.inverseEntityMetadata.columns.find(column => column.name === this._referencedColumnName);
|
||||
if (this.referencedColumnName) {
|
||||
const referencedColumn = this.relation.inverseEntityMetadata.columns.find(column => column.name === this.referencedColumnName);
|
||||
if (!referencedColumn)
|
||||
throw new Error(`Referenced column ${this._referencedColumnName} was not found in entity ${this.name}`);
|
||||
throw new Error(`Referenced column ${this.referencedColumnName} was not found in entity ${this.name}`);
|
||||
}
|
||||
|
||||
return this.relation.inverseEntityMetadata.primaryColumn;
|
||||
|
||||
@ -53,21 +53,21 @@ export class JoinTableMetadata extends PropertyMetadata {
|
||||
constructor(args: JoinTableMetadataArgs) {
|
||||
super(args.target, args.propertyName);
|
||||
|
||||
if (args.options.name)
|
||||
this._name = args.options.name;
|
||||
if (args.name)
|
||||
this._name = args.name;
|
||||
|
||||
if (args.options.joinColumn) {
|
||||
if (args.options.joinColumn.name)
|
||||
this._joinColumnName = args.options.joinColumn.name;
|
||||
if (args.options.joinColumn.referencedColumnName)
|
||||
this._joinColumnReferencedColumnName = args.options.joinColumn.referencedColumnName;
|
||||
if (args.joinColumn) {
|
||||
if (args.joinColumn.name)
|
||||
this._joinColumnName = args.joinColumn.name;
|
||||
if (args.joinColumn.referencedColumnName)
|
||||
this._joinColumnReferencedColumnName = args.joinColumn.referencedColumnName;
|
||||
}
|
||||
|
||||
if (args.options.inverseJoinColumn) {
|
||||
if (args.options.inverseJoinColumn.name)
|
||||
this._inverseJoinColumnName = args.options.inverseJoinColumn.name;
|
||||
if (args.options.inverseJoinColumn.referencedColumnName)
|
||||
this._inverseJoinColumnReferencedColumnName = args.options.inverseJoinColumn.referencedColumnName;
|
||||
if (args.inverseJoinColumn) {
|
||||
if (args.inverseJoinColumn.name)
|
||||
this._inverseJoinColumnName = args.inverseJoinColumn.name;
|
||||
if (args.inverseJoinColumn.referencedColumnName)
|
||||
this._inverseJoinColumnReferencedColumnName = args.inverseJoinColumn.referencedColumnName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -166,12 +166,7 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
if (!this.isOwning || this.isManyToMany)
|
||||
throw new Error(`Relation name cannot be retrieved for many-to-many relations or not owning relations.`);
|
||||
|
||||
// todo: maybe need to throw exception if its a many-to-many relation?
|
||||
|
||||
if (this.joinColumn && this.joinColumn.name)
|
||||
return this.entityMetadata.namingStrategy.relationNameCustomized(this.joinColumn.name);
|
||||
|
||||
return this.entityMetadata.namingStrategy.relationName(this.propertyName);
|
||||
return this.joinColumn.name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,11 +175,24 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
* Also only owning sides of the relations have this property.
|
||||
*/
|
||||
get referencedColumnName(): string {
|
||||
if (!this.isOwning)
|
||||
throw new Error(`Only owning side of the relations can have information about referenced column names.`);
|
||||
|
||||
// for many-to-one and owner one-to-one relations we get referenced column from join column
|
||||
if (this.joinColumn && this.joinColumn.referencedColumn && this.joinColumn.referencedColumn.name)
|
||||
return this.joinColumn.referencedColumn.name;
|
||||
|
||||
// todo: maybe join column should never be null, and this data should come from join column?
|
||||
return this.inverseEntityMetadata.primaryColumn.propertyName;
|
||||
// for many-to-many relation we give referenced column depend of owner side
|
||||
if (this.joinTable) { // need to check if this algorithm works correctly
|
||||
if (this.isOwning) {
|
||||
return this.joinTable.referencedColumn.name;
|
||||
} else {
|
||||
return this.joinTable.inverseReferencedColumn.name;
|
||||
}
|
||||
}
|
||||
|
||||
// this should not be possible, but anyway throw error
|
||||
throw new Error(`Cannot get referenced column name of the relation ${this.entityMetadata.name}#${this.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -9,12 +9,12 @@ export interface ColumnMetadataArgs {
|
||||
/**
|
||||
* Class to which column is applied.
|
||||
*/
|
||||
readonly target: Function;
|
||||
readonly target?: Function;
|
||||
|
||||
/**
|
||||
* Class's property name to which column is applied.
|
||||
*/
|
||||
readonly propertyName: string;
|
||||
readonly propertyName?: string;
|
||||
|
||||
/**
|
||||
* Class's property type (reflected) to which column is applied.
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import {JoinColumnOptions} from "../options/JoinColumnOptions";
|
||||
|
||||
/**
|
||||
* Arguments for JoinColumnMetadata class.
|
||||
*/
|
||||
@ -16,8 +14,13 @@ export interface JoinColumnMetadataArgs {
|
||||
readonly propertyName: string;
|
||||
|
||||
/**
|
||||
* Class's property type (reflected) to which join column is applied.
|
||||
* Name of the column.
|
||||
*/
|
||||
readonly options: JoinColumnOptions;
|
||||
readonly name?: string;
|
||||
|
||||
/**
|
||||
* Name of the column in the entity to which this column is referenced.
|
||||
*/
|
||||
readonly referencedColumnName?: string;
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {JoinTableOptions} from "../options/JoinTableOptions";
|
||||
import {JoinColumnOptions} from "../options/JoinColumnOptions";
|
||||
|
||||
/**
|
||||
* Arguments for JoinTableMetadata class.
|
||||
@ -16,8 +16,19 @@ export interface JoinTableMetadataArgs {
|
||||
readonly propertyName: string;
|
||||
|
||||
/**
|
||||
* Class's property type (reflected) to which this column is applied.
|
||||
* Name of the table that will be created to store values of the both tables (join table).
|
||||
* By default is auto generated.
|
||||
*/
|
||||
readonly options: JoinTableOptions;
|
||||
readonly name?: string;
|
||||
|
||||
/**
|
||||
* First column of the join table.
|
||||
*/
|
||||
readonly joinColumn?: JoinColumnOptions;
|
||||
|
||||
/**
|
||||
* Second (inverse) column of the join table.
|
||||
*/
|
||||
readonly inverseJoinColumn?: JoinColumnOptions;
|
||||
|
||||
}
|
||||
|
||||
@ -6,6 +6,6 @@ export interface TargetMetadataArgs {
|
||||
/**
|
||||
* Class to which this arguments is applied.
|
||||
*/
|
||||
readonly target: Function;
|
||||
readonly target?: Function;
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import {TargetMetadataCollection} from "./TargetMetadataCollection";
|
||||
import {PropertyMetadata} from "../PropertyMetadata";
|
||||
import {TargetMetadataArgsCollection} from "./TargetMetadataArgsCollection";
|
||||
|
||||
export class PropertyMetadataCollection<T extends PropertyMetadata> extends TargetMetadataCollection<T> {
|
||||
export class PropertyMetadataArgsCollection<T extends { target?: Function, propertyName?: string }> extends TargetMetadataArgsCollection<T> {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
@ -1,7 +1,7 @@
|
||||
import {MetadataAlreadyExistsError} from "../../metadata-storage/error/MetadataAlreadyExistsError";
|
||||
import {TargetMetadataArgs} from "../args/TargetMetadataArgs";
|
||||
|
||||
export class TargetMetadataCollection<T extends TargetMetadataArgs> extends Array<T> {
|
||||
export class TargetMetadataArgsCollection<T extends { target?: Function }> extends Array<T> {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
@ -13,21 +13,23 @@ export class TargetMetadataCollection<T extends TargetMetadataArgs> extends Arra
|
||||
|
||||
filterByClasses(classes: Function[]): this {
|
||||
const collection = new (<any> this.constructor)();
|
||||
this.filter(metadata => classes.indexOf(metadata.target) !== -1)
|
||||
this
|
||||
.filter(metadata => {
|
||||
if (!metadata.target) return false;
|
||||
return classes.indexOf(metadata.target) !== -1;
|
||||
})
|
||||
.forEach(metadata => collection.add(metadata));
|
||||
return collection;
|
||||
}
|
||||
|
||||
add(metadata: T, checkForDuplicateTargets = false) {
|
||||
if (checkForDuplicateTargets && this.hasWithTarget(metadata.target))
|
||||
throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
|
||||
if (checkForDuplicateTargets) {
|
||||
if (!metadata.target)
|
||||
throw new Error(`Target is not set in the given metadata.`);
|
||||
|
||||
this.push(metadata);
|
||||
}
|
||||
|
||||
addUniq(metadata: T) {
|
||||
if (this.hasWithTarget(metadata.target))
|
||||
throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
|
||||
if (this.hasWithTarget(metadata.target))
|
||||
throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
|
||||
}
|
||||
|
||||
this.push(metadata);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user