mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added custom join table names
This commit is contained in:
parent
e4647748c3
commit
6856af143d
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "typeorm",
|
||||
"private": true,
|
||||
"version": "0.0.2-alpha.9",
|
||||
"version": "0.0.2-alpha.10",
|
||||
"description": "Data-mapper ORM for Typescript",
|
||||
"license": "Apache-2.0",
|
||||
"readmeFilename": "README.md",
|
||||
|
||||
@ -24,4 +24,19 @@ export class CustomNamingStrategy implements NamingStrategyInterface {
|
||||
return "index" + columns.join("_");
|
||||
}
|
||||
|
||||
joinColumnInverseSideName(joinColumnName: string, propertyName: string): string {
|
||||
if (joinColumnName)
|
||||
return joinColumnName;
|
||||
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
joinTableName(firstTableName: string, secondTableName: string, firstColumnName: string, secondColumnName: string): string {
|
||||
return firstTableName + "_" + firstColumnName + "_" + secondTableName + "_" + secondColumnName;
|
||||
}
|
||||
|
||||
joinTableColumnName(tableName: string, columnName: string): string {
|
||||
return tableName + "_" + columnName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -27,15 +27,26 @@ createConnection(options).then(connection => {
|
||||
let author = new Author();
|
||||
author.name = "Umed";
|
||||
|
||||
let category1 = new Category();
|
||||
category1.name = "Category #1";
|
||||
|
||||
let category2 = new Category();
|
||||
category2.name = "Category #2";
|
||||
|
||||
let post = new Post();
|
||||
post.text = "Hello how are you?";
|
||||
post.title = "hello";
|
||||
post.author = author;
|
||||
post.categories = [category1, category2];
|
||||
|
||||
postRepository
|
||||
.persist(post)
|
||||
.then(post => {
|
||||
console.log("Post has been saved.");
|
||||
console.log("Post has been saved. Lets load it now.");
|
||||
return postRepository.find({ alias: "post", leftJoinAndSelect: { categories: "post.categories"} });
|
||||
})
|
||||
.then(loadedPosts => {
|
||||
console.log("loadedPosts: ", loadedPosts);
|
||||
})
|
||||
.catch(error => console.log(error.stack));
|
||||
|
||||
|
||||
@ -22,9 +22,9 @@ export class Post {
|
||||
@ManyToOne(type => Author, author => author.posts, {
|
||||
cascadeAll: true
|
||||
})
|
||||
@JoinColumn({
|
||||
@JoinColumn(/*{ // todo: not yet fixed
|
||||
name: "user"
|
||||
})
|
||||
}*/)
|
||||
author: Author;
|
||||
|
||||
@ManyToMany(type => Category, category => category.posts, {
|
||||
|
||||
@ -17,6 +17,10 @@ import {IndexMetadata} from "../metadata/IndexMetadata";
|
||||
import {CompositeIndexMetadata} from "../metadata/CompositeIndexMetadata";
|
||||
import {PropertyMetadataCollection} from "../metadata/collection/PropertyMetadataCollection";
|
||||
import {TargetMetadataCollection} from "../metadata/collection/TargetMetadataCollection";
|
||||
import {JoinTableMetadata} from "../metadata/JoinTableMetadata";
|
||||
import {JoinTableOptions} from "../metadata/options/JoinTableOptions";
|
||||
import {JoinColumnMetadata} from "../metadata/JoinColumnMetadata";
|
||||
import {JoinColumnOptions} from "../metadata/options/JoinColumnOptions";
|
||||
|
||||
/**
|
||||
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
|
||||
@ -91,19 +95,35 @@ export class EntityMetadataBuilder {
|
||||
mergedMetadata.relationMetadatas,
|
||||
mergedMetadata.compositeIndexMetadatas
|
||||
);
|
||||
entityMetadata.namingStrategy = this.namingStrategy;
|
||||
|
||||
// find entity's relations join tables
|
||||
entityMetadata.relations.forEach(relation => {
|
||||
// create entity's relations join tables
|
||||
entityMetadata.manyToManyRelations.forEach(relation => {
|
||||
const joinTable = mergedMetadata.joinTableMetadatas.findByProperty(relation.propertyName);
|
||||
if (joinTable)
|
||||
if (joinTable) {
|
||||
relation.joinTable = joinTable;
|
||||
joinTable.relation = relation;
|
||||
}
|
||||
});
|
||||
|
||||
// find entity's relations join columns
|
||||
// create entity's relations join columns
|
||||
entityMetadata.relations.forEach(relation => {
|
||||
const joinColumn = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
|
||||
if (joinColumn)
|
||||
if (joinColumn) {
|
||||
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 joinColumn = mergedMetadata.joinColumnMetadatas.findByProperty(relation.propertyName);
|
||||
if (!joinColumn) {
|
||||
joinColumn = new JoinColumnMetadata(relation.target, relation.propertyName, <JoinColumnOptions> {});
|
||||
relation.joinColumn = joinColumn;
|
||||
joinColumn.relation = relation;
|
||||
}
|
||||
});
|
||||
|
||||
return entityMetadata;
|
||||
@ -112,7 +132,7 @@ export class EntityMetadataBuilder {
|
||||
// after all metadatas created we set inverse side (related) entity metadatas for all relation metadatas
|
||||
entityMetadatas.forEach(entityMetadata => {
|
||||
entityMetadata.relations.forEach(relation => {
|
||||
relation.relatedEntityMetadata = entityMetadatas.find(m => m.target === relation.type);
|
||||
relation.inverseEntityMetadata = entityMetadatas.find(m => m.target === relation.type);
|
||||
});
|
||||
});
|
||||
|
||||
@ -124,11 +144,12 @@ export class EntityMetadataBuilder {
|
||||
metadata.relationsWithJoinColumns.forEach(relation => {
|
||||
|
||||
// find relational column and if it does not exist - add it
|
||||
const inverseSideColumn = relation.relatedEntityMetadata.primaryColumn;
|
||||
// todo: later add support for propertyInFunction
|
||||
const inverseSideColumn = relation.joinColumn.referencedColumn;
|
||||
let relationalColumn = metadata.columns.find(column => column.name === relation.name); // todo?: ColumnCollection.findByName
|
||||
if (!relationalColumn) {
|
||||
|
||||
const options: ColumnOptions = {
|
||||
name: relation.joinColumn.name,
|
||||
type: inverseSideColumn.type,
|
||||
oldColumnName: relation.oldColumnName,
|
||||
nullable: relation.isNullable
|
||||
@ -147,7 +168,7 @@ export class EntityMetadataBuilder {
|
||||
const foreignKey = new ForeignKeyMetadata(
|
||||
metadata.table,
|
||||
[relationalColumn],
|
||||
relation.relatedEntityMetadata.table,
|
||||
relation.inverseEntityMetadata.table,
|
||||
[inverseSideColumn],
|
||||
relation.onDelete
|
||||
);
|
||||
@ -159,36 +180,44 @@ export class EntityMetadataBuilder {
|
||||
const junctionEntityMetadatas: EntityMetadata[] = [];
|
||||
entityMetadatas.forEach(metadata => {
|
||||
metadata.ownerManyToManyRelations.map(relation => {
|
||||
const inverseSideMetadata = entityMetadatas.find(metadata => metadata.target === relation.type);
|
||||
const tableName = metadata.table.name + "_" + relation.name + "_" +
|
||||
inverseSideMetadata.table.name + "_" + inverseSideMetadata.primaryColumn.name;
|
||||
const inverseSideMetadata = relation.inverseEntityMetadata;
|
||||
// const inverseSideColumn = relation.inverseSideColumn;
|
||||
|
||||
// generate table name for junction table
|
||||
/*const tableName = this.namingStrategy.joinTableName(
|
||||
metadata.table.name,
|
||||
inverseSideMetadata.table.name,
|
||||
relation.name,
|
||||
inverseSideColumn.name
|
||||
);*/
|
||||
const tableMetadata = new JunctionTableMetadata(relation.joinTable.name);
|
||||
const column1 = relation.joinTable.referencedColumn;
|
||||
const column2 = relation.joinTable.inverseReferencedColumn;
|
||||
|
||||
const tableMetadata = new JunctionTableMetadata(tableName);
|
||||
const column1options: ColumnOptions = {
|
||||
length: metadata.primaryColumn.length,
|
||||
type: metadata.primaryColumn.type,
|
||||
name: metadata.table.name + "_" + metadata.primaryColumn.name + "_1"
|
||||
length: column1.length,
|
||||
type: column1.type,
|
||||
name: relation.joinTable.joinColumnName // metadata.table.name + "_" + column1.name
|
||||
};
|
||||
const column2options: ColumnOptions = {
|
||||
length: inverseSideMetadata.primaryColumn.length,
|
||||
type: inverseSideMetadata.primaryColumn.type,
|
||||
name: inverseSideMetadata.table.name + "_" + inverseSideMetadata.primaryColumn.name + "_2"
|
||||
length: column2.length,
|
||||
type: column2.type,
|
||||
name: relation.joinTable.inverseJoinColumnName // inverseSideMetadata.table.name + "_" + column2.name
|
||||
};
|
||||
const columns = [
|
||||
new ColumnMetadata({
|
||||
propertyType: inverseSideMetadata.primaryColumn.type,
|
||||
propertyType: column2.type,
|
||||
options: column1options
|
||||
}),
|
||||
new ColumnMetadata({
|
||||
propertyType: inverseSideMetadata.primaryColumn.type,
|
||||
propertyType: column2.type,
|
||||
options: column2options
|
||||
})
|
||||
];
|
||||
const junctionEntityMetadata = new EntityMetadata(tableMetadata, columns, [], []);
|
||||
junctionEntityMetadata.foreignKeys.push(
|
||||
new ForeignKeyMetadata(tableMetadata, [columns[0]], metadata.table, [metadata.primaryColumn]),
|
||||
new ForeignKeyMetadata(tableMetadata, [columns[1]], inverseSideMetadata.table, [inverseSideMetadata.primaryColumn])
|
||||
new ForeignKeyMetadata(tableMetadata, [columns[0]], metadata.table, [column1]),
|
||||
new ForeignKeyMetadata(tableMetadata, [columns[1]], inverseSideMetadata.table, [column2])
|
||||
);
|
||||
junctionEntityMetadatas.push(junctionEntityMetadata);
|
||||
relation.junctionEntityMetadata = junctionEntityMetadata;
|
||||
|
||||
@ -11,7 +11,7 @@ export class MissingJoinColumnError extends Error {
|
||||
super();
|
||||
if (relation.inverseRelation) {
|
||||
this.message = `JoinColumn is missing on both sides of ${entityMetadata.name}#${relation.name} and ` +
|
||||
`${relation.relatedEntityMetadata.name}#${relation.inverseRelation.name} one-to-one relationship. ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} 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.name} one-to-one relationship. ` +
|
||||
|
||||
@ -12,7 +12,7 @@ export class MissingJoinTableError extends Error {
|
||||
|
||||
if (relation.inverseRelation) {
|
||||
this.message = `JoinTable is missing on both sides of ${entityMetadata.name}#${relation.name} and ` +
|
||||
`${relation.relatedEntityMetadata.name}#${relation.inverseRelation.name} many-to-many relationship. ` +
|
||||
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} 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. ` +
|
||||
|
||||
@ -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.relatedEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`Both ${entityMetadata.name}#${relation.name} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`has JoinTable decorators. Choose one of them and left JoinTable decorator only on it.`;
|
||||
}
|
||||
|
||||
|
||||
@ -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.relatedEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`Both ${entityMetadata.name}#${relation.name} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.name} ` +
|
||||
`has JoinTable decorators. Choose one of them and left JoinColumn decorator only on it.`;
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,25 @@
|
||||
import {TableMetadata} from "./TableMetadata";
|
||||
import {ColumnMetadata} from "./ColumnMetadata";
|
||||
import {RelationMetadata} from "./RelationMetadata";
|
||||
import {IndexMetadata} from "./IndexMetadata";
|
||||
import {CompositeIndexMetadata} from "./CompositeIndexMetadata";
|
||||
import {RelationTypes} from "./types/RelationTypes";
|
||||
import {ForeignKeyMetadata} from "./ForeignKeyMetadata";
|
||||
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategy";
|
||||
|
||||
/**
|
||||
* Contains all entity metadata.
|
||||
*/
|
||||
export class EntityMetadata {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Public Properties
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Naming strategy used to generate and normalize column name.
|
||||
*/
|
||||
namingStrategy: NamingStrategyInterface;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Readonly Properties
|
||||
// -------------------------------------------------------------------------
|
||||
@ -34,7 +43,7 @@ export class EntityMetadata {
|
||||
this.relations = relations;
|
||||
this.compositeIndices = compositeIndices;
|
||||
|
||||
// this.relations.forEach(relation => relation.entityMetadata = this);
|
||||
this.relations.forEach(relation => relation.entityMetadata = this);
|
||||
this.compositeIndices.forEach(index => index.entityMetadata = this);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import {PropertyMetadata} from "./PropertyMetadata";
|
||||
import {JoinColumnOptions} from "./options/JoinColumnOptions";
|
||||
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategy";
|
||||
import {RelationMetadata} from "./RelationMetadata";
|
||||
import {ColumnMetadata} from "./ColumnMetadata";
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -10,26 +13,58 @@ export class JoinColumnMetadata extends PropertyMetadata {
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Naming strategy used to generate and normalize column name.
|
||||
* Relation - owner of this join column metadata.
|
||||
*/
|
||||
// namingStrategy: NamingStrategyInterface;
|
||||
relation: RelationMetadata;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Readonly Properties
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Join table options.
|
||||
* Join column name.
|
||||
*/
|
||||
readonly options: JoinColumnOptions;
|
||||
private readonly _name: string;
|
||||
|
||||
/**
|
||||
* Join column referenced column name.
|
||||
*/
|
||||
private readonly _referencedColumnName: string;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
constructor(target: Function, propertyName: string, options: JoinColumnOptions) {
|
||||
constructor(target: Function,
|
||||
propertyName: string,
|
||||
options: JoinColumnOptions) {
|
||||
super(target, propertyName);
|
||||
this.options = options;
|
||||
|
||||
if (options.name)
|
||||
this._name = options.name;
|
||||
if (options.referencedColumnName)
|
||||
this._referencedColumnName = options.referencedColumnName;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Accessors
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Join column name.
|
||||
*/
|
||||
get name() {
|
||||
return this.relation.entityMetadata.namingStrategy.joinColumnInverseSideName(this._name, this.relation.propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Referenced join column.
|
||||
*/
|
||||
get referencedColumn(): ColumnMetadata {
|
||||
if (this._referencedColumnName)
|
||||
return this.relation.inverseEntityMetadata.columns.find(column => column.name === this._referencedColumnName);
|
||||
|
||||
return this.relation.inverseEntityMetadata.primaryColumn;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
import {PropertyMetadata} from "./PropertyMetadata";
|
||||
import {JoinTableOptions} from "./options/JoinTableOptions";
|
||||
import {RelationMetadata} from "./RelationMetadata";
|
||||
import {ColumnMetadata} from "./ColumnMetadata";
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -10,18 +12,38 @@ export class JoinTableMetadata extends PropertyMetadata {
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Naming strategy used to generate and normalize column name.
|
||||
* Relation - owner of this join table metadata.
|
||||
*/
|
||||
// namingStrategy: NamingStrategyInterface;
|
||||
relation: RelationMetadata;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Readonly Properties
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Join table options.
|
||||
* Join table name.
|
||||
*/
|
||||
readonly options: JoinTableOptions;
|
||||
private readonly _name: string;
|
||||
|
||||
/**
|
||||
* Join column name.
|
||||
*/
|
||||
private readonly _joinColumnName: string;
|
||||
|
||||
/**
|
||||
* Join column referenced column name.
|
||||
*/
|
||||
private readonly _joinColumnReferencedColumnName: string;
|
||||
|
||||
/**
|
||||
* Join column name of the inverse side.
|
||||
*/
|
||||
private readonly _inverseJoinColumnName: string;
|
||||
|
||||
/**
|
||||
* Join column referenced column name of the inverse side.
|
||||
*/
|
||||
private readonly _inverseJoinColumnReferencedColumnName: string;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructor
|
||||
@ -29,7 +51,82 @@ export class JoinTableMetadata extends PropertyMetadata {
|
||||
|
||||
constructor(target: Function, propertyName: string, options: JoinTableOptions) {
|
||||
super(target, propertyName);
|
||||
this.options = options;
|
||||
|
||||
if (options.name)
|
||||
this._name = options.name;
|
||||
|
||||
if (options.joinColumn) {
|
||||
if (options.joinColumn.name)
|
||||
this._joinColumnName = options.joinColumn.name;
|
||||
if (options.joinColumn.referencedColumnName)
|
||||
this._joinColumnReferencedColumnName = options.joinColumn.referencedColumnName;
|
||||
}
|
||||
|
||||
if (options.inverseJoinColumn) {
|
||||
if (options.inverseJoinColumn.name)
|
||||
this._inverseJoinColumnName = options.inverseJoinColumn.name;
|
||||
if (options.inverseJoinColumn.referencedColumnName)
|
||||
this._inverseJoinColumnReferencedColumnName = options.inverseJoinColumn.referencedColumnName;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Accessors
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Join table name.
|
||||
*/
|
||||
get name() {
|
||||
if (this._name)
|
||||
return this._name;
|
||||
|
||||
return this.relation.entityMetadata.namingStrategy.joinTableName(
|
||||
this.relation.entityMetadata.table.name,
|
||||
this.relation.inverseEntityMetadata.table.name,
|
||||
this.referencedColumn.name,
|
||||
this.inverseReferencedColumn.name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join column name.
|
||||
*/
|
||||
get joinColumnName() {
|
||||
if (this._joinColumnName)
|
||||
return this._joinColumnName;
|
||||
|
||||
return this.relation.entityMetadata.namingStrategy.joinTableColumnName(this.relation.entityMetadata.table.name, this.referencedColumn.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join column name of the inverse side.
|
||||
*/
|
||||
get inverseJoinColumnName() {
|
||||
if (this._inverseJoinColumnName)
|
||||
return this._inverseJoinColumnName;
|
||||
|
||||
return this.relation.entityMetadata.namingStrategy.joinTableColumnName(this.relation.inverseEntityMetadata.table.name, this.inverseReferencedColumn.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Referenced join column.
|
||||
*/
|
||||
get referencedColumn(): ColumnMetadata {
|
||||
if (this._joinColumnReferencedColumnName)
|
||||
return this.relation.entityMetadata.columns.find(column => column.name === this._joinColumnReferencedColumnName);
|
||||
|
||||
return this.relation.entityMetadata.primaryColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Referenced join column of the inverse side.
|
||||
*/
|
||||
get inverseReferencedColumn(): ColumnMetadata {
|
||||
if (this._joinColumnReferencedColumnName)
|
||||
return this.relation.inverseEntityMetadata.columns.find(column => column.name === this._inverseJoinColumnReferencedColumnName);
|
||||
|
||||
return this.relation.inverseEntityMetadata.primaryColumn;
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {OnDeleteType} from "./ForeignKeyMetadata";
|
||||
import {JoinTableMetadata} from "./JoinTableMetadata";
|
||||
import {JoinColumnMetadata} from "./JoinColumnMetadata";
|
||||
import {RelationMetadataArgs} from "./args/RelationMetadataArgs";
|
||||
import {ColumnMetadata} from "./ColumnMetadata";
|
||||
|
||||
/**
|
||||
* Function that returns a type of the field. Returned value must be a class used on the relation.
|
||||
@ -32,10 +33,15 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
*/
|
||||
namingStrategy: NamingStrategyInterface;
|
||||
|
||||
/**
|
||||
* Its own entity metadata.
|
||||
*/
|
||||
entityMetadata: EntityMetadata;
|
||||
|
||||
/**
|
||||
* Related entity metadata.
|
||||
*/
|
||||
relatedEntityMetadata: EntityMetadata;
|
||||
inverseEntityMetadata: EntityMetadata;
|
||||
|
||||
/**
|
||||
* Junction entity metadata.
|
||||
@ -173,7 +179,7 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
}
|
||||
|
||||
get inverseRelation(): RelationMetadata {
|
||||
return this.relatedEntityMetadata.findRelationWithPropertyName(this.computeInverseSide(this._inverseSideProperty));
|
||||
return this.inverseEntityMetadata.findRelationWithPropertyName(this.computeInverseSide(this._inverseSideProperty));
|
||||
}
|
||||
|
||||
get isOneToOne(): boolean {
|
||||
@ -193,7 +199,7 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
}
|
||||
|
||||
get hasInverseSide(): boolean {
|
||||
return this.relatedEntityMetadata && !!this.inverseRelation;
|
||||
return this.inverseEntityMetadata && !!this.inverseRelation;
|
||||
}
|
||||
|
||||
get isLazy(): boolean {
|
||||
@ -205,7 +211,7 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private computeInverseSide(inverseSide: PropertyTypeInFunction<any>): string {
|
||||
const ownerEntityPropertiesMap = this.relatedEntityMetadata.createPropertiesMap();
|
||||
const ownerEntityPropertiesMap = this.inverseEntityMetadata.createPropertiesMap();
|
||||
if (typeof inverseSide === "function")
|
||||
return (<Function> inverseSide)(ownerEntityPropertiesMap);
|
||||
if (typeof inverseSide === "string")
|
||||
|
||||
@ -24,5 +24,20 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
|
||||
return "ind_" + columns.join("_");
|
||||
}
|
||||
|
||||
joinColumnInverseSideName(joinColumnName: string, propertyName: string): string {
|
||||
if (joinColumnName)
|
||||
return joinColumnName;
|
||||
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
joinTableName(firstTableName: string, secondTableName: string, firstColumnName: string, secondColumnName: string): string {
|
||||
return firstTableName + "_" + firstColumnName + "_" + secondTableName + "_" + secondColumnName;
|
||||
}
|
||||
|
||||
joinTableColumnName(tableName: string, columnName: string): string {
|
||||
return tableName + "_" + columnName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -24,4 +24,19 @@ export interface NamingStrategyInterface {
|
||||
*/
|
||||
indexName(target: Function, name: string, columns: string[]): string;
|
||||
|
||||
/**
|
||||
* Gets the name of the join column used in the one-to-one and many-to-one relations.
|
||||
*/
|
||||
joinColumnInverseSideName(joinColumnName: string|undefined, propertyName: string): string;
|
||||
|
||||
/**
|
||||
* Gets the name of the join table used in the many-to-many relations.
|
||||
*/
|
||||
joinTableName(firstTableName: string, secondTableName: string, firstColumnName: string, secondColumnName: string): string;
|
||||
|
||||
/**
|
||||
* Gets the name of the column used for columns in the junction tables.
|
||||
*/
|
||||
joinTableColumnName(tableName: string, columnName: string): string;
|
||||
|
||||
}
|
||||
@ -153,7 +153,7 @@ export class EntityPersistOperationBuilder {
|
||||
}
|
||||
|
||||
metadata.relations.forEach(relation => {
|
||||
const relMetadata = relation.relatedEntityMetadata;
|
||||
const relMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdColumnName = relMetadata.primaryColumn.name;
|
||||
const value = this.getEntityRelationValue(relation, newEntity);
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
@ -203,7 +203,7 @@ export class EntityPersistOperationBuilder {
|
||||
|
||||
metadata.relations.forEach(relation => {
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
const relMetadata = relation.relatedEntityMetadata;
|
||||
const relMetadata = relation.inverseEntityMetadata;
|
||||
if (!dbValue) return;
|
||||
|
||||
if (dbValue instanceof Array) {
|
||||
@ -275,7 +275,7 @@ export class EntityPersistOperationBuilder {
|
||||
.filter(relation => relation.isManyToMany)
|
||||
// .filter(relation => newEntity[relation.propertyName] instanceof Array)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.relatedEntityMetadata;
|
||||
const relationMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
const value = this.getEntityRelationValue(relation, newEntity);
|
||||
const dbValue = dbEntity ? this.getEntityRelationValue(relation, dbEntity.entity) : null;
|
||||
@ -313,7 +313,7 @@ export class EntityPersistOperationBuilder {
|
||||
.filter(relation => relation.isManyToMany)
|
||||
// .filter(relation => dbEntity[relation.propertyName] instanceof Array)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.relatedEntityMetadata;
|
||||
const relationMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
const value = newEntity ? this.getEntityRelationValue(relation, newEntity.entity) : null;
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
|
||||
@ -296,16 +296,16 @@ export class PersistOperationExecutor {
|
||||
.filter(column => entity.hasOwnProperty(column.propertyName))
|
||||
.map(column => this.driver.preparePersistentValue(entity[column.propertyName], column));
|
||||
const relationColumns = metadata.relations
|
||||
.filter(relation => relation.isOwning && !!relation.relatedEntityMetadata)
|
||||
.filter(relation => relation.isOwning && !!relation.inverseEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
.filter(relation => entity[relation.propertyName][relation.relatedEntityMetadata.primaryColumn.name])
|
||||
.filter(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.name])
|
||||
.map(relation => relation.name);
|
||||
|
||||
const relationValues = metadata.relations
|
||||
.filter(relation => relation.isOwning && !!relation.relatedEntityMetadata)
|
||||
.filter(relation => relation.isOwning && !!relation.inverseEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
.filter(relation => entity[relation.propertyName].hasOwnProperty(relation.relatedEntityMetadata.primaryColumn.name))
|
||||
.map(relation => entity[relation.propertyName][relation.relatedEntityMetadata.primaryColumn.name]);
|
||||
.filter(relation => entity[relation.propertyName].hasOwnProperty(relation.inverseEntityMetadata.primaryColumn.name))
|
||||
.map(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.name]);
|
||||
|
||||
const allColumns = columns.concat(relationColumns);
|
||||
const allValues = values.concat(relationValues);
|
||||
|
||||
@ -577,29 +577,33 @@ export class QueryBuilder<Entity> {
|
||||
const relation = parentMetadata.findRelationWithDbName(join.alias.parentPropertyName);
|
||||
const junctionMetadata = relation.junctionEntityMetadata;
|
||||
const joinMetadata = this.aliasMap.getEntityMetadataByAlias(join.alias);
|
||||
const joinTable = joinMetadata.table.name;
|
||||
const joinTableColumn = joinMetadata.primaryColumn.name;
|
||||
const joinTableName = joinMetadata.table.name;
|
||||
|
||||
if (relation.isManyToMany) {
|
||||
const junctionTable = junctionMetadata.table.name;
|
||||
const junctionAlias = join.alias.parentAliasName + "_" + join.alias.name;
|
||||
const joinAlias = join.alias.name;
|
||||
const joinTable = relation.isOwning ? relation.joinTable : relation.inverseRelation.joinTable; // not sure if this is correct
|
||||
const joinTableColumn = joinTable.referencedColumn.name; // not sure if this is correct
|
||||
const inverseJoinColumnName = joinTable.inverseReferencedColumn.name; // not sure if this is correct
|
||||
const condition1 = junctionAlias + "." + junctionMetadata.columns[0].name + "=" + parentAlias + "." + joinTableColumn; // todo: use column names from junction table somehow
|
||||
const condition2 = joinAlias + "." + joinTableColumn + "=" + junctionAlias + "." + junctionMetadata.columns[1].name;
|
||||
const condition2 = joinAlias + "." + inverseJoinColumnName + "=" + junctionAlias + "." + junctionMetadata.columns[1].name;
|
||||
|
||||
return " " + joinType + " JOIN " + junctionTable + " " + junctionAlias + " " + join.conditionType + " " + condition1 +
|
||||
" " + joinType + " JOIN " + joinTable + " " + joinAlias + " " + join.conditionType + " " + condition2 + appendedCondition;
|
||||
" " + joinType + " JOIN " + joinTableName + " " + joinAlias + " " + join.conditionType + " " + condition2 + appendedCondition;
|
||||
|
||||
} else if (relation.isManyToOne || (relation.isOneToOne && relation.isOwning)) {
|
||||
const joinTableColumn = relation.joinColumn.referencedColumn.name;
|
||||
const condition = join.alias.name + "." + joinTableColumn + "=" + parentAlias + "." + join.alias.parentPropertyName;
|
||||
return " " + joinType + " JOIN " + joinTable + " " + join.alias.name + " " + join.conditionType + " " + condition + appendedCondition;
|
||||
return " " + joinType + " JOIN " + joinTableName + " " + join.alias.name + " " + join.conditionType + " " + condition + appendedCondition;
|
||||
|
||||
} else if (relation.isOneToMany || (relation.isOneToOne && !relation.isOwning)) {
|
||||
const joinTableColumn = relation.inverseRelation.joinColumn.referencedColumn.name;
|
||||
const condition = join.alias.name + "." + relation.inverseSideProperty + "=" + parentAlias + "." + joinTableColumn;
|
||||
return " " + joinType + " JOIN " + joinTable + " " + join.alias.name + " " + join.conditionType + " " + condition + appendedCondition;
|
||||
return " " + joinType + " JOIN " + joinTableName + " " + join.alias.name + " " + join.conditionType + " " + condition + appendedCondition;
|
||||
|
||||
} else {
|
||||
return " " + joinType + " JOIN " + joinTable + " " + join.alias.name + " " + join.conditionType + " " + join.condition;
|
||||
return " " + joinType + " JOIN " + joinTableName + " " + join.alias.name + " " + join.conditionType + " " + join.condition;
|
||||
}
|
||||
}).join(" ");
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ export class AliasMap {
|
||||
if (!relation)
|
||||
throw new Error("Relation metadata for " + alias.parentAliasName + "#" + alias.parentPropertyName + " was not found.");
|
||||
|
||||
return relation.relatedEntityMetadata;
|
||||
return relation.inverseEntityMetadata;
|
||||
}
|
||||
|
||||
throw new Error("Cannot get entity metadata for the given alias " + alias.name);
|
||||
|
||||
@ -67,7 +67,7 @@ export class PlainObjectToDatabaseEntityTransformer<Entity> {
|
||||
if (value instanceof Array)
|
||||
value = Object.assign({}, ...value);
|
||||
|
||||
const child = value ? this.buildLoadMap(value, relation.relatedEntityMetadata) : [];
|
||||
const child = value ? this.buildLoadMap(value, relation.inverseEntityMetadata) : [];
|
||||
return <LoadMap> { name: relation.name, child: child };
|
||||
});
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ export class PlainObjectToNewEntityTransformer {
|
||||
metadata.relations
|
||||
.filter(relation => object.hasOwnProperty(relation.propertyName))
|
||||
.forEach(relation => {
|
||||
const relationMetadata = relation.relatedEntityMetadata;
|
||||
const relationMetadata = relation.inverseEntityMetadata;
|
||||
if (!relationMetadata)
|
||||
throw new Error("Relation metadata for the relation " + (<any> metadata.target).name + "#" + relation.propertyName + " is missing");
|
||||
|
||||
|
||||
@ -329,7 +329,7 @@ export class Repository<Entity> {
|
||||
const promises = metadata.relations
|
||||
// .filter(relation => !!entity[relation.propertyName])
|
||||
.map(relation => {
|
||||
const relMetadata = relation.relatedEntityMetadata;
|
||||
const relMetadata = relation.inverseEntityMetadata;
|
||||
// const value = ;
|
||||
|
||||
const value = (entity[relation.propertyName] instanceof Promise && relation.isLazy) ? entity["__" + relation.propertyName + "__"] : entity[relation.propertyName];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user