mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixed issues when update operations were not working correctly when new entity is attached and its inside things were changed + fixed issues with custom column name for relations + added tests for it
This commit is contained in:
parent
f513fc1ba7
commit
cf6ebe5c2e
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "typeorm",
|
||||
"private": true,
|
||||
"version": "0.0.2-alpha.24",
|
||||
"version": "0.0.2-alpha.25",
|
||||
"description": "Data-mapper ORM for Typescript",
|
||||
"license": "Apache-2.0",
|
||||
"readmeFilename": "README.md",
|
||||
|
||||
@ -85,7 +85,7 @@ export class ConnectionManager {
|
||||
if (existConnection)
|
||||
this.connections.splice(this.connections.indexOf(existConnection), 1);
|
||||
|
||||
const connection = new Connection(name, <Driver> driver, options);
|
||||
const connection = new Connection(name, driver, options);
|
||||
this.connections.push(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ export class EntityMetadataBuilder {
|
||||
entityMetadata.relations.forEach(relation => {
|
||||
const inverseEntityMetadata = entityMetadatas.find(m => m.target === relation.type);
|
||||
if (!inverseEntityMetadata)
|
||||
throw new Error("Entity metadata for " + entityMetadata.name + "#" + relation.name + " was not found.");
|
||||
throw new Error("Entity metadata for " + entityMetadata.name + "#" + relation.propertyName + " was not found.");
|
||||
|
||||
relation.inverseEntityMetadata = inverseEntityMetadata;
|
||||
});
|
||||
|
||||
@ -10,11 +10,11 @@ export class MissingJoinColumnError extends Error {
|
||||
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
|
||||
super();
|
||||
if (relation.hasInverseSide) {
|
||||
this.message = `JoinColumn is missing on both sides of ${entityMetadata.name}#${relation.name} and ` +
|
||||
this.message = `JoinColumn is missing on both sides of ${entityMetadata.name}#${relation.propertyName} and ` +
|
||||
`${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. ` +
|
||||
this.message = `JoinColumn is missing on ${entityMetadata.name}#${relation.propertyName} one-to-one relationship. ` +
|
||||
`You need to put JoinColumn decorator on it.`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +189,8 @@ export class EntityMetadata {
|
||||
|
||||
createPropertiesMap(): any {
|
||||
const entity: any = {};
|
||||
this.columns.forEach(column => entity[column.name] = column.name);
|
||||
this.relations.forEach(relation => entity[relation.name] = relation.name);
|
||||
this.columns.forEach(column => entity[column.propertyName] = column.propertyName);
|
||||
this.relations.forEach(relation => entity[relation.propertyName] = relation.propertyName);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@ -177,6 +177,13 @@ export class RelationMetadata extends PropertyMetadata {
|
||||
|
||||
return this.namingStrategy ? this.namingStrategy.relationName(this._name) : this._name;
|
||||
}
|
||||
|
||||
get referencedColumnName(): string {
|
||||
if (this.joinColumn && this.joinColumn.referencedColumn && this.joinColumn.referencedColumn.name)
|
||||
return this.joinColumn.referencedColumn.name;
|
||||
|
||||
return this.inverseEntityMetadata.primaryColumn.propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this side is an owner of this relation.
|
||||
|
||||
@ -73,11 +73,13 @@ export class EntityPersistOperationBuilder {
|
||||
persistOperation.inserts = this.findCascadeInsertedEntities(persistedEntity, dbEntities);
|
||||
persistOperation.updatesByRelations = this.updateRelations(persistOperation.inserts, persistedEntity);
|
||||
persistOperation.updatesByInverseRelations = this.updateInverseRelations(metadata, dbEntity, persistedEntity);
|
||||
persistOperation.updates = this.findCascadeUpdateEntities(persistOperation.updatesByRelations, metadata, dbEntity, persistedEntity);
|
||||
persistOperation.updates = this.findCascadeUpdateEntities(persistOperation.updatesByRelations, metadata, dbEntity, persistedEntity, dbEntities);
|
||||
persistOperation.junctionInserts = this.findJunctionInsertOperations(metadata, persistedEntity, dbEntities);
|
||||
persistOperation.removes = this.findCascadeRemovedEntities(metadata, dbEntity, allPersistedEntities, undefined, undefined, undefined);
|
||||
persistOperation.junctionRemoves = this.findJunctionRemoveOperations(metadata, dbEntity, allPersistedEntities);
|
||||
|
||||
// persistOperation.log();
|
||||
|
||||
return persistOperation;
|
||||
}
|
||||
|
||||
@ -113,7 +115,7 @@ export class EntityPersistOperationBuilder {
|
||||
operations: InsertOperation[] = []): InsertOperation[] {
|
||||
// const metadata = this.connection.getEntityMetadata(newEntity.constructor);
|
||||
const metadata = this.entityMetadatas.findByTarget(newEntity.constructor);
|
||||
const isObjectNew = !this.findEntityWithId(dbEntities, metadata.target, newEntity[metadata.primaryColumn.name]);
|
||||
const isObjectNew = !this.findEntityWithId(dbEntities, metadata.target, newEntity[metadata.primaryColumn.propertyName]);
|
||||
|
||||
// if object is new and should be inserted, we check if cascades are allowed before add it to operations list
|
||||
if (isObjectNew && fromRelation && !this.checkCascadesAllowed("insert", metadata, fromRelation)) {
|
||||
@ -141,6 +143,7 @@ export class EntityPersistOperationBuilder {
|
||||
metadata: EntityMetadata,
|
||||
dbEntity: any,
|
||||
newEntity: any,
|
||||
dbEntities: EntityWithId[],
|
||||
fromRelation?: RelationMetadata,
|
||||
operations: UpdateOperation[] = []): UpdateOperation[] {
|
||||
if (!dbEntity)
|
||||
@ -152,30 +155,39 @@ export class EntityPersistOperationBuilder {
|
||||
return operations;
|
||||
|
||||
} else if (diffColumns.length || diffRelations.length) {
|
||||
const entityId = newEntity[metadata.primaryColumn.name];
|
||||
const entityId = newEntity[metadata.primaryColumn.propertyName];
|
||||
if (entityId)
|
||||
operations.push(new UpdateOperation(newEntity, entityId, diffColumns, diffRelations));
|
||||
}
|
||||
|
||||
metadata.relations.forEach(relation => {
|
||||
const relMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdColumnName = relMetadata.primaryColumn.name;
|
||||
const relationIdColumnName = relMetadata.primaryColumn.propertyName;
|
||||
const value = this.getEntityRelationValue(relation, newEntity);
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
const referencedColumnName = relation.isOwning ? relation.referencedColumnName : relation.inverseRelation.referencedColumnName;
|
||||
// const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
|
||||
if (!value || !dbValue)
|
||||
if (!value/* || !dbValue*/)
|
||||
return;
|
||||
|
||||
if (value instanceof Array) {
|
||||
value.forEach((subEntity: any) => {
|
||||
const subDbEntity = dbValue.find((subDbEntity: any) => {
|
||||
/*const subDbEntity = dbValue.find((subDbEntity: any) => {
|
||||
return subDbEntity[relationIdColumnName] === subEntity[relationIdColumnName];
|
||||
});*/
|
||||
const dbValue = dbEntities.find(dbValue => {
|
||||
return dbValue.entity.constructor === subEntity.constructor && dbValue.entity[referencedColumnName] === subEntity[relationIdColumnName];
|
||||
});
|
||||
this.findCascadeUpdateEntities(updatesByRelations, relMetadata, subDbEntity, subEntity, relation, operations);
|
||||
if (dbValue)
|
||||
this.findCascadeUpdateEntities(updatesByRelations, relMetadata, dbValue.entity, subEntity, dbEntities, relation, operations);
|
||||
});
|
||||
|
||||
} else {
|
||||
this.findCascadeUpdateEntities(updatesByRelations, relMetadata, dbValue, value, relation, operations);
|
||||
const dbValue = dbEntities.find(dbValue => {
|
||||
return dbValue.entity.constructor === value.constructor && dbValue.entity[referencedColumnName] === value[relationIdColumnName];
|
||||
});
|
||||
if (dbValue)
|
||||
this.findCascadeUpdateEntities(updatesByRelations, relMetadata, dbValue.entity, value, dbEntities, relation, operations);
|
||||
}
|
||||
});
|
||||
|
||||
@ -193,7 +205,7 @@ export class EntityPersistOperationBuilder {
|
||||
if (!dbEntity)
|
||||
return operations;
|
||||
|
||||
const entityId = dbEntity[metadata.primaryColumn.name];
|
||||
const entityId = dbEntity[metadata.primaryColumn.propertyName];
|
||||
const isObjectRemoved = parentAlreadyRemoved || !this.findEntityWithId(allPersistedEntities, metadata.target, entityId);
|
||||
|
||||
// if object is removed and should be removed, we check if cascades are allowed before add it to operations list
|
||||
@ -211,11 +223,11 @@ export class EntityPersistOperationBuilder {
|
||||
|
||||
if (dbValue instanceof Array) {
|
||||
dbValue.forEach((subDbEntity: any) => {
|
||||
const relationOperations = this.findCascadeRemovedEntities(relMetadata, subDbEntity, allPersistedEntities, relation, metadata, dbEntity[metadata.primaryColumn.name], isObjectRemoved);
|
||||
const relationOperations = this.findCascadeRemovedEntities(relMetadata, subDbEntity, allPersistedEntities, relation, metadata, dbEntity[metadata.primaryColumn.propertyName], isObjectRemoved);
|
||||
relationOperations.forEach(o => operations.push(o));
|
||||
});
|
||||
} else {
|
||||
const relationOperations = this.findCascadeRemovedEntities(relMetadata, dbValue, allPersistedEntities, relation, metadata, dbEntity[metadata.primaryColumn.name], isObjectRemoved);
|
||||
const relationOperations = this.findCascadeRemovedEntities(relMetadata, dbValue, allPersistedEntities, relation, metadata, dbEntity[metadata.primaryColumn.propertyName], isObjectRemoved);
|
||||
relationOperations.forEach(o => operations.push(o));
|
||||
}
|
||||
}, []);
|
||||
@ -314,13 +326,13 @@ export class EntityPersistOperationBuilder {
|
||||
|
||||
private findJunctionInsertOperations(metadata: EntityMetadata, newEntity: any, dbEntities: EntityWithId[], isRoot = true): JunctionInsertOperation[] {
|
||||
const dbEntity = dbEntities.find(dbEntity => {
|
||||
return dbEntity.id === newEntity[metadata.primaryColumn.name] && dbEntity.entity.constructor === metadata.target;
|
||||
return dbEntity.id === newEntity[metadata.primaryColumn.propertyName] && dbEntity.entity.constructor === metadata.target;
|
||||
});
|
||||
return metadata.relations
|
||||
.filter(relation => newEntity[relation.propertyName] !== null && newEntity[relation.propertyName] !== undefined)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.propertyName;
|
||||
const value = this.getEntityRelationValue(relation, newEntity);
|
||||
const dbValue = dbEntity ? this.getEntityRelationValue(relation, dbEntity.entity) : null;
|
||||
|
||||
@ -360,13 +372,13 @@ export class EntityPersistOperationBuilder {
|
||||
return [];
|
||||
|
||||
const newEntity = newEntities.find(newEntity => {
|
||||
return newEntity.id === dbEntity[metadata.primaryColumn.name] && newEntity.entity.constructor === metadata.target;
|
||||
return newEntity.id === dbEntity[metadata.primaryColumn.propertyName] && newEntity.entity.constructor === metadata.target;
|
||||
});
|
||||
return metadata.relations
|
||||
.filter(relation => dbEntity[relation.propertyName] !== null && dbEntity[relation.propertyName] !== undefined)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.inverseEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.propertyName;
|
||||
const value = newEntity ? this.getEntityRelationValue(relation, newEntity.entity) : null;
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
|
||||
@ -404,7 +416,16 @@ export class EntityPersistOperationBuilder {
|
||||
private diffColumns(metadata: EntityMetadata, newEntity: any, dbEntity: any) {
|
||||
return metadata.columns
|
||||
.filter(column => !column.isVirtual && !column.isUpdateDate && !column.isVersion && !column.isCreateDate)
|
||||
.filter(column => newEntity[column.propertyName] !== dbEntity[column.propertyName]);
|
||||
.filter(column => newEntity[column.propertyName] !== dbEntity[column.propertyName])
|
||||
.filter(column => {
|
||||
// filter out "relational columns" only in the case if there is a relation object in entity
|
||||
if (metadata.hasRelationWithDbName(column.propertyName)) {
|
||||
const relation = metadata.findRelationWithDbName(column.propertyName);
|
||||
if (newEntity[relation.propertyName] !== null && newEntity[relation.propertyName] !== undefined)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private diffRelations(updatesByRelations: UpdateByRelationOperation[], metadata: EntityMetadata, newEntity: any, dbEntity: any) {
|
||||
|
||||
@ -248,7 +248,7 @@ export class PersistOperationExecutor {
|
||||
insertOperation.entity[metadata.versionColumn.propertyName]++;
|
||||
if (metadata.hasTreeLevelColumn) {
|
||||
// const parentEntity = insertOperation.entity[metadata.treeParentMetadata.propertyName];
|
||||
// const parentLevel = parentEntity ? (parentEntity[metadata.treeLevelColumn.name] || 0) : 0;
|
||||
// const parentLevel = parentEntity ? (parentEntity[metadata.treeLevelColumn.propertyName] || 0) : 0;
|
||||
insertOperation.entity[metadata.treeLevelColumn.propertyName] = insertOperation.treeLevel;
|
||||
}
|
||||
if (metadata.hasTreeChildrenCountColumn) {
|
||||
@ -273,7 +273,7 @@ export class PersistOperationExecutor {
|
||||
persistOperation.removes.forEach(removeOperation => {
|
||||
const metadata = this.entityMetadatas.findByTarget(removeOperation.entity.constructor);
|
||||
const removedEntity = persistOperation.allPersistedEntities.find(allNewEntity => {
|
||||
return allNewEntity.entity.constructor === removeOperation.entity.constructor && allNewEntity.id === removeOperation.entity[metadata.primaryColumn.name];
|
||||
return allNewEntity.entity.constructor === removeOperation.entity.constructor && allNewEntity.id === removeOperation.entity[metadata.primaryColumn.propertyName];
|
||||
});
|
||||
if (removedEntity)
|
||||
removedEntity.entity[metadata.primaryColumn.propertyName] = undefined;
|
||||
@ -290,11 +290,11 @@ export class PersistOperationExecutor {
|
||||
if (operation.updatedRelation.isOneToMany) {
|
||||
const metadata = this.entityMetadatas.findByTarget(operation.insertOperation.entity.constructor);
|
||||
if (operation.insertOperation.entity === target)
|
||||
updateMap[operation.updatedRelation.inverseRelation.name] = operation.targetEntity[metadata.primaryColumn.propertyName] || idInInserts;
|
||||
updateMap[operation.updatedRelation.inverseRelation.propertyName] = operation.targetEntity[metadata.primaryColumn.propertyName] || idInInserts;
|
||||
|
||||
} else {
|
||||
if (operation.targetEntity === target)
|
||||
updateMap[operation.updatedRelation.name] = operation.insertOperation.entityId;
|
||||
updateMap[operation.updatedRelation.propertyName] = operation.insertOperation.entityId;
|
||||
}
|
||||
});
|
||||
|
||||
@ -325,26 +325,6 @@ export class PersistOperationExecutor {
|
||||
}
|
||||
|
||||
private updateInverseRelation(operation: UpdateByInverseSideOperation, insertOperations: InsertOperation[]) {
|
||||
/*let tableName: string, relationName: string, relationId: any, idColumn: string, id: any;
|
||||
const relatedInsertOperation = insertOperations.find(o => o.entity === operation.targetEntity);
|
||||
const idInInserts = relatedInsertOperation ? relatedInsertOperation.entityId : null;
|
||||
if (operation.updatedRelation.isOneToMany) {
|
||||
const metadata = this.entityMetadatas.findByTarget(operation.insertOperation.entity.constructor);
|
||||
tableName = metadata.table.name;
|
||||
relationName = operation.updatedRelation.inverseRelation.name;
|
||||
relationId = operation.targetEntity[metadata.primaryColumn.propertyName] || idInInserts;
|
||||
idColumn = metadata.primaryColumn.name;
|
||||
id = operation.insertOperation.entityId;
|
||||
|
||||
} else {
|
||||
const metadata = this.entityMetadatas.findByTarget(operation.targetEntity.constructor);
|
||||
tableName = metadata.table.name;
|
||||
relationName = operation.updatedRelation.name;
|
||||
relationId = operation.insertOperation.entityId;
|
||||
idColumn = metadata.primaryColumn.name;
|
||||
id = operation.targetEntity[metadata.primaryColumn.propertyName] || idInInserts;
|
||||
}*/
|
||||
|
||||
const targetEntityMetadata = this.entityMetadatas.findByTarget(operation.targetEntity.constructor);
|
||||
const fromEntityMetadata = this.entityMetadatas.findByTarget(operation.fromEntity.constructor);
|
||||
const tableName = targetEntityMetadata.table.name;
|
||||
@ -424,14 +404,14 @@ export class PersistOperationExecutor {
|
||||
const relationColumns = metadata.relations
|
||||
.filter(relation => relation.isOwning && !!relation.inverseEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
.filter(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.name])
|
||||
.filter(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.propertyName])
|
||||
.map(relation => relation.name);
|
||||
|
||||
const relationValues = metadata.relations
|
||||
.filter(relation => relation.isOwning && !!relation.inverseEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
.filter(relation => entity[relation.propertyName].hasOwnProperty(relation.inverseEntityMetadata.primaryColumn.name))
|
||||
.map(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.name]);
|
||||
.filter(relation => entity[relation.propertyName].hasOwnProperty(relation.inverseEntityMetadata.primaryColumn.propertyName))
|
||||
.map(relation => entity[relation.propertyName][relation.inverseEntityMetadata.primaryColumn.propertyName]);
|
||||
|
||||
const allColumns = columns.concat(relationColumns);
|
||||
const allValues = values.concat(relationValues);
|
||||
@ -452,8 +432,8 @@ export class PersistOperationExecutor {
|
||||
}
|
||||
|
||||
if (metadata.hasTreeLevelColumn && metadata.hasTreeParentRelation) {
|
||||
const parentEntity = entity[metadata.treeParentRelation.propertyName];
|
||||
const parentLevel = parentEntity ? (parentEntity[metadata.treeLevelColumn.name] || 0) : 0;
|
||||
const parentEntity = entity[metadata.treeParentRelation.name]; // todo: are you sure here we should use name and not propertyName ?
|
||||
const parentLevel = parentEntity ? (parentEntity[metadata.treeLevelColumn.propertyName] || 0) : 0;
|
||||
|
||||
allColumns.push(metadata.treeLevelColumn.name);
|
||||
allValues.push(parentLevel + 1);
|
||||
@ -473,8 +453,9 @@ export class PersistOperationExecutor {
|
||||
const parentEntity = entity[metadata.treeParentRelation.propertyName];
|
||||
|
||||
let parentEntityId: any = 0;
|
||||
if (parentEntity && parentEntity[metadata.primaryColumn.name]) {
|
||||
parentEntityId = parentEntity[metadata.primaryColumn.name];
|
||||
if (parentEntity && parentEntity[metadata.primaryColumn.propertyName]) {
|
||||
parentEntityId = parentEntity[metadata.primaryColumn.propertyName];
|
||||
|
||||
} else if (updateMap && updateMap[metadata.treeParentRelation.propertyName]) { // todo: name or propertyName: depend how update will be implemented. or even find relation of this treeParent and use its name?
|
||||
parentEntityId = updateMap[metadata.treeParentRelation.propertyName];
|
||||
}
|
||||
@ -510,8 +491,8 @@ export class PersistOperationExecutor {
|
||||
const insertOperation1 = insertOperations.find(o => o.entity === junctionOperation.entity1);
|
||||
const insertOperation2 = insertOperations.find(o => o.entity === junctionOperation.entity2);
|
||||
|
||||
let id1 = junctionOperation.entity1[metadata1.primaryColumn.name];
|
||||
let id2 = junctionOperation.entity2[metadata2.primaryColumn.name];
|
||||
let id1 = junctionOperation.entity1[metadata1.primaryColumn.propertyName];
|
||||
let id2 = junctionOperation.entity2[metadata2.primaryColumn.propertyName];
|
||||
|
||||
if (!id1) {
|
||||
if (insertOperation1) {
|
||||
@ -545,8 +526,8 @@ export class PersistOperationExecutor {
|
||||
const metadata1 = this.entityMetadatas.findByTarget(junctionOperation.entity1.constructor);
|
||||
const metadata2 = this.entityMetadatas.findByTarget(junctionOperation.entity2.constructor);
|
||||
const columns = junctionMetadata.columns.map(column => column.name);
|
||||
const id1 = junctionOperation.entity1[metadata1.primaryColumn.name];
|
||||
const id2 = junctionOperation.entity2[metadata2.primaryColumn.name];
|
||||
const id1 = junctionOperation.entity1[metadata1.primaryColumn.propertyName];
|
||||
const id2 = junctionOperation.entity2[metadata2.primaryColumn.propertyName];
|
||||
return this.driver.delete(junctionMetadata.table.name, { [columns[0]]: id1, [columns[1]]: id2 });
|
||||
}
|
||||
|
||||
|
||||
@ -632,7 +632,7 @@ export class QueryBuilder<Entity> {
|
||||
const foundAlias = this.aliasMap.findAliasByName(parentAlias);
|
||||
if (!foundAlias)
|
||||
throw new Error(`Alias "${parentAlias}" was not found`);
|
||||
|
||||
|
||||
const parentMetadata = this.aliasMap.getEntityMetadataByAlias(foundAlias);
|
||||
const relation = parentMetadata.findRelationWithDbName(join.alias.parentPropertyName);
|
||||
const junctionMetadata = relation.junctionEntityMetadata;
|
||||
@ -735,9 +735,6 @@ export class QueryBuilder<Entity> {
|
||||
protected join(joinType: "INNER"|"LEFT", entityOrProperty: Function|string, alias: string, conditionType: "ON"|"WITH", condition: string, parameters?: { [key: string]: any }, mapToProperty?: string, isMappingMany?: boolean): this;
|
||||
protected join(joinType: "INNER"|"LEFT", entityOrProperty: Function|string, alias: string, conditionType: "ON"|"WITH" = "ON", condition: string = "", parameters?: { [key: string]: any }, mapToProperty?: string, isMappingMany: boolean = false): this {
|
||||
|
||||
if (!mapToProperty && typeof entityOrProperty === "string")
|
||||
mapToProperty = entityOrProperty;
|
||||
|
||||
let tableName = "";
|
||||
const aliasObj = new Alias(alias);
|
||||
this.aliasMap.addAlias(aliasObj);
|
||||
@ -747,8 +744,11 @@ export class QueryBuilder<Entity> {
|
||||
} else if (typeof entityOrProperty === "string" && entityOrProperty.indexOf(".") !== -1) {
|
||||
aliasObj.parentAliasName = entityOrProperty.split(".")[0];
|
||||
aliasObj.parentPropertyName = entityOrProperty.split(".")[1];
|
||||
|
||||
} else if (typeof entityOrProperty === "string") {
|
||||
tableName = entityOrProperty;
|
||||
if (!mapToProperty)
|
||||
mapToProperty = entityOrProperty;
|
||||
}
|
||||
|
||||
const join: Join = { type: joinType, alias: aliasObj, tableName: tableName, conditionType: conditionType, condition: condition, mapToProperty: mapToProperty, isMappingMany: isMappingMany };
|
||||
|
||||
@ -91,7 +91,7 @@ export class RawSqlResultsToEntityTransformer {
|
||||
if (joinMapping) {
|
||||
propertyName = joinMapping.propertyName;
|
||||
}
|
||||
|
||||
|
||||
if (relation.isLazy) {
|
||||
entity["__" + propertyName + "__"] = result;
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
|
||||
import {Post} from "./Post";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {OneToMany} from "../../../../../src/decorator/relations/OneToMany";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
import {JoinColumn} from "../../../../../src/decorator/relations/JoinColumn";
|
||||
import {CategoryMetadata} from "./CategoryMetadata";
|
||||
|
||||
@Table()
|
||||
export class Category {
|
||||
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: number;
|
||||
|
||||
@OneToMany(type => Post, post => post.category)
|
||||
posts: Post[];
|
||||
|
||||
@Column({ type: "int", nullable: true })
|
||||
metadataId: number;
|
||||
|
||||
@OneToOne(type => CategoryMetadata, metadata => metadata.category, {
|
||||
cascadeInsert: true
|
||||
})
|
||||
@JoinColumn({ name: "metadataId" })
|
||||
metadata: CategoryMetadata;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
import {Category} from "./Category";
|
||||
|
||||
@Table()
|
||||
export class CategoryMetadata {
|
||||
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
keyword: string;
|
||||
|
||||
@OneToOne(type => Category, category => category.metadata)
|
||||
category: Category;
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
import {Category} from "./Category";
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {JoinColumn} from "../../../../../src/decorator/relations/JoinColumn";
|
||||
|
||||
@Table()
|
||||
export class Post {
|
||||
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column("int", { nullable: true })
|
||||
categoryId: number;
|
||||
|
||||
@ManyToOne(type => Category, category => category.posts, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true
|
||||
})
|
||||
@JoinColumn({ name: "categoryId" })
|
||||
category: Category;
|
||||
|
||||
}
|
||||
@ -0,0 +1,273 @@
|
||||
import "reflect-metadata";
|
||||
import * as chai from "chai";
|
||||
import {expect} from "chai";
|
||||
import {Connection} from "../../../../src/connection/Connection";
|
||||
import {Repository} from "../../../../src/repository/Repository";
|
||||
import {Post} from "./entity/Post";
|
||||
import {Category} from "./entity/Category";
|
||||
import {CreateConnectionOptions} from "../../../../src/connection-manager/CreateConnectionOptions";
|
||||
import {createConnection} from "../../../../src/index";
|
||||
import {CategoryMetadata} from "./entity/CategoryMetadata";
|
||||
|
||||
chai.should();
|
||||
chai.use(require("sinon-chai"));
|
||||
chai.use(require("chai-as-promised"));
|
||||
|
||||
describe("persistence > custom-column-names", function() {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Configuration
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
const parameters: CreateConnectionOptions = {
|
||||
driver: "mysql",
|
||||
connection: {
|
||||
host: "192.168.99.100",
|
||||
port: 3306,
|
||||
username: "root",
|
||||
password: "admin",
|
||||
database: "test",
|
||||
autoSchemaCreate: true,
|
||||
logging: {
|
||||
logFailedQueryError: true
|
||||
}
|
||||
},
|
||||
entities: [Post, Category, CategoryMetadata]
|
||||
};
|
||||
// connect to db
|
||||
let connection: Connection;
|
||||
before(function() {
|
||||
return createConnection(parameters)
|
||||
.then(con => connection = con)
|
||||
.catch(e => {
|
||||
console.log("Error during connection to db: " + e);
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
|
||||
after(function() {
|
||||
connection.close();
|
||||
});
|
||||
|
||||
// clean up database before each test
|
||||
function reloadDatabase() {
|
||||
return connection.driver
|
||||
.clearDatabase()
|
||||
.then(() => connection.syncSchema())
|
||||
.catch(e => console.log("Error during schema re-creation: ", e));
|
||||
}
|
||||
|
||||
let postRepository: Repository<Post>;
|
||||
let categoryRepository: Repository<Category>;
|
||||
let metadataRepository: Repository<CategoryMetadata>;
|
||||
before(function() {
|
||||
postRepository = connection.getRepository(Post);
|
||||
categoryRepository = connection.getRepository(Category);
|
||||
metadataRepository = connection.getRepository(CategoryMetadata);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specifications
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("attach exist entity to exist entity with many-to-one relation", function() {
|
||||
let newPost: Post, newCategory: Category, loadedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
// save a new category
|
||||
before(function () {
|
||||
newCategory = categoryRepository.create();
|
||||
newCategory.name = "Animals";
|
||||
return categoryRepository.persist(newCategory);
|
||||
});
|
||||
|
||||
// save a new post
|
||||
before(function() {
|
||||
newPost = postRepository.create();
|
||||
newPost.title = "All about animals";
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// attach category to post and save it
|
||||
before(function() {
|
||||
newPost.category = newCategory;
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// load a post
|
||||
before(function() {
|
||||
return postRepository
|
||||
.findOneById(1, { alias: "post", leftJoinAndSelect: { category: "post.categoryId" } })
|
||||
.then(post => loadedPost = post);
|
||||
});
|
||||
|
||||
it("should contain attached category", function () {
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
expect(loadedPost.category).not.to.be.empty;
|
||||
expect(loadedPost.categoryId).not.to.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("attach new entity to exist entity with many-to-one relation", function() {
|
||||
let newPost: Post, newCategory: Category, loadedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
// save a new category
|
||||
before(function () {
|
||||
newCategory = categoryRepository.create();
|
||||
newCategory.name = "Animals";
|
||||
return categoryRepository.persist(newCategory);
|
||||
});
|
||||
|
||||
// save a new post and attach category
|
||||
before(function() {
|
||||
newPost = postRepository.create();
|
||||
newPost.title = "All about animals";
|
||||
newPost.category = newCategory;
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// load a post
|
||||
before(function() {
|
||||
return postRepository
|
||||
.findOneById(1, { alias: "post", leftJoinAndSelect: { category: "post.categoryId" } })
|
||||
.then(post => loadedPost = post);
|
||||
});
|
||||
|
||||
it("should contain attached category", function () {
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
expect(loadedPost.category).not.to.be.empty;
|
||||
expect(loadedPost.categoryId).not.to.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("attach new entity to new entity with many-to-one relation", function() {
|
||||
let newPost: Post, newCategory: Category, loadedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
// save a new category, post and attach category to post
|
||||
before(function () {
|
||||
newCategory = categoryRepository.create();
|
||||
newCategory.name = "Animals";
|
||||
newPost = postRepository.create();
|
||||
newPost.title = "All about animals";
|
||||
newPost.category = newCategory;
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// load a post
|
||||
before(function() {
|
||||
return postRepository
|
||||
.findOneById(1, { alias: "post", leftJoinAndSelect: { category: "post.categoryId" } })
|
||||
.then(post => loadedPost = post);
|
||||
});
|
||||
|
||||
it("should contain attached category", function () {
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
expect(loadedPost.category).not.to.be.empty;
|
||||
expect(loadedPost.categoryId).not.to.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("attach exist entity to exist entity with one-to-one relation", function() {
|
||||
let newPost: Post, newCategory: Category, newMetadata: CategoryMetadata, loadedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
// save a new post
|
||||
before(function() {
|
||||
newPost = postRepository.create();
|
||||
newPost.title = "All about animals";
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// save a new category
|
||||
before(function () {
|
||||
newCategory = categoryRepository.create();
|
||||
newCategory.name = "Animals";
|
||||
return categoryRepository.persist(newCategory);
|
||||
});
|
||||
|
||||
// save a new metadata
|
||||
before(function() {
|
||||
newMetadata = metadataRepository.create();
|
||||
newMetadata.keyword = "animals";
|
||||
return metadataRepository.persist(newMetadata);
|
||||
});
|
||||
|
||||
// attach metadata to category and category to post and save it
|
||||
before(function() {
|
||||
newCategory.metadata = newMetadata;
|
||||
newPost.category = newCategory;
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// load a post
|
||||
before(function() {
|
||||
return postRepository
|
||||
.findOneById(1, { alias: "post", leftJoinAndSelect: { category: "post.categoryId", metadata: "category.metadataId" } })
|
||||
.then(post => loadedPost = post);
|
||||
});
|
||||
|
||||
it("should contain attached category and metadata in the category", function () {
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
expect(loadedPost.category).not.to.be.empty;
|
||||
expect(loadedPost.categoryId).not.to.be.empty;
|
||||
expect(loadedPost.category.metadata).not.to.be.empty;
|
||||
expect(loadedPost.category.metadataId).not.to.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("attach new entity to exist entity with one-to-one relation", function() {
|
||||
let newPost: Post, newCategory: Category, newMetadata: CategoryMetadata, loadedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
// save a new post
|
||||
before(function() {
|
||||
newPost = postRepository.create();
|
||||
newPost.title = "All about animals";
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// save a new category and new metadata
|
||||
before(function () {
|
||||
newMetadata = metadataRepository.create();
|
||||
newMetadata.keyword = "animals";
|
||||
newCategory = categoryRepository.create();
|
||||
newCategory.name = "Animals";
|
||||
newCategory.metadata = newMetadata;
|
||||
return categoryRepository.persist(newCategory);
|
||||
});
|
||||
|
||||
// attach metadata to category and category to post and save it
|
||||
before(function() {
|
||||
newPost.category = newCategory;
|
||||
return postRepository.persist(newPost);
|
||||
});
|
||||
|
||||
// load a post
|
||||
before(function() {
|
||||
return postRepository
|
||||
.findOneById(1, { alias: "post", leftJoinAndSelect: { category: "post.categoryId", metadata: "category.metadataId" } })
|
||||
.then(post => loadedPost = post);
|
||||
});
|
||||
|
||||
it("should contain attached category and metadata in the category", function () {
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
expect(loadedPost.category).not.to.be.empty;
|
||||
expect(loadedPost.categoryId).not.to.be.empty;
|
||||
expect(loadedPost.category.metadata).not.to.be.empty;
|
||||
expect(loadedPost.category.metadataId).not.to.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user