updated update by relations algorith,

m
This commit is contained in:
Umed Khudoiberdiev 2016-02-29 12:35:52 +05:00
parent 35d363f887
commit 976d6fd10a
3 changed files with 142 additions and 9 deletions

View File

@ -47,7 +47,7 @@ TypeORM.createMysqlConnection(options, [Post, PostDetails, Image, ImageDetails,
postRepository.persist(post).then(result => {
const qb = postRepository.createQueryBuilder("post")
/*const qb = postRepository.createQueryBuilder("post")
.leftJoinAndSelect("post.details", "details")
.leftJoinAndSelect("post.images", "images")
// .leftJoinAndSelect("post.coverId", "coverId")
@ -80,7 +80,7 @@ TypeORM.createMysqlConnection(options, [Post, PostDetails, Image, ImageDetails,
})
.then(() => qb.getSingleResult())
.then(reloadedPost => console.log("reloadedPost: ", reloadedPost));
.then(reloadedPost => console.log("reloadedPost: ", reloadedPost));*/
})
.then(result => console.log(result))
.catch(error => console.log(error.stack ? error.stack : error));

View File

@ -2,6 +2,7 @@ import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
import {RelationMetadata} from "../metadata-builder/metadata/RelationMetadata";
import metadata = Reflect.metadata;
import {Connection} from "../connection/Connection";
export interface EntityWithId {
id: any;
@ -30,24 +31,34 @@ export interface JunctionRemoveOperation {
entity2: any;
}
export class UpdateByRelationOperation {
constructor(public targetEntity: any,
public insertOperation: InsertOperation,
public updatedRelation: RelationMetadata) {
}
}
export class PersistOperation {
inserts: InsertOperation[];
removes: any[];
updates: UpdateOperation[];
junctionInserts: JunctionInsertOperation[];
junctionRemoves: JunctionRemoveOperation[];
updatesByRelations: UpdateByRelationOperation[];
constructor(inserts: any[],
removes: any[],
updates: UpdateOperation[],
junctionInserts: JunctionInsertOperation[],
junctionRemoves: JunctionRemoveOperation[]) {
junctionRemoves: JunctionRemoveOperation[],
updatesByRelations: UpdateByRelationOperation[]) {
this.inserts = inserts;
this.removes = removes;
this.updates = updates;
this.junctionInserts = junctionInserts;
this.junctionRemoves = junctionRemoves;
this.updatesByRelations = updatesByRelations;
}
}
@ -81,6 +92,9 @@ export class EntityPersistOperationsBuilder {
// if relation has "update" it can only update related entity
// if relation has "remove" it can only remove related entity
constructor(private connection: Connection) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -96,6 +110,7 @@ export class EntityPersistOperationsBuilder {
const updateOperations = this.findCascadeUpdateEntities(metadata, entity1, entity2, null);
const junctionInsertOperations = this.findJunctionInsertOperations(metadata, entity2, dbEntities);
const junctionRemoveOperations = this.findJunctionRemoveOperations(metadata, entity1, allEntities);
const updatesByRelationsOperations = this.updateRelations(insertOperations, entity2);
//const insertJunctionOperations = ;//this.a();
console.log("---------------------------------------------------------");
console.log("DB ENTITIES");
@ -126,6 +141,10 @@ export class EntityPersistOperationsBuilder {
console.log("---------------------------------------------------------");
console.log(junctionRemoveOperations);
console.log("---------------------------------------------------------");
console.log("UPDATES BY RELATIONS");
console.log("---------------------------------------------------------");
console.log(updatesByRelationsOperations);
console.log("---------------------------------------------------------");
// now normalize inserted entities
// no need probably, since we cant rely on deepness because of recursion: insertOperations.sort((a, b) => a.deepness + b.deepness);
@ -149,7 +168,8 @@ export class EntityPersistOperationsBuilder {
removeOperations,
updateOperations,
junctionInsertOperations,
junctionRemoveOperations
junctionRemoveOperations,
updatesByRelationsOperations
);
}
@ -157,6 +177,92 @@ export class EntityPersistOperationsBuilder {
// Private Methods
// -------------------------------------------------------------------------
private updateIdsAfterPersist(insertOperations: InsertOperation[]) {
insertOperations.forEach(insertOperation => {
const metadata = this.connection.getMetadata(insertOperation.entity.constructor);
insertOperation.entity[metadata.primaryColumn.name] = insertOperation.entityId;
});
}
private findRelationsWithEntityInside(insertOperation: InsertOperation, entityToSearchIn: any) {
const metadata = this.connection.getMetadata(entityToSearchIn.constructor);
return metadata.relations.reduce((operations, relation) => {
const value = entityToSearchIn[relation.propertyName];
if (value instanceof Array) {
value.forEach((sub: any) => {
if (!relation.isManyToMany && sub === insertOperation.entity)
operations.push(new UpdateByRelationOperation(entityToSearchIn, insertOperation, relation));
const subOperations = this.findRelationsWithEntityInside(insertOperation, sub);
operations.concat(subOperations);
});
} else if (value) {
if (value === insertOperation.entity)
operations.push(new UpdateByRelationOperation(entityToSearchIn, insertOperation, relation));
const subOperations = this.findRelationsWithEntityInside(insertOperation, value);
operations.concat(subOperations);
}
return operations;
}, <UpdateByRelationOperation[]> []);
}
/**
* To update relation, you need:
* update table where this relation (owner side)
* set its relation property to inserted id
* where
*
*/
private updateRelations(insertOperations: InsertOperation[], newEntity: any): UpdateByRelationOperation[] {
return insertOperations.reduce((operations, insertOperation) => {
return operations.concat(this.findRelationsWithEntityInside(insertOperation, newEntity));
}, <UpdateByRelationOperation[]> []);
/*const entitiesWithoutIds = allEntities
.filter(entityWithId => !!entityWithId.id)
.map(entityWithId => entityWithId.entity);*/
/*
entitiesWithoutIds.find(entity => entity === insertOperation.entity);
metadata.relations.map(relation => {
});
const oneToOneManyToOneUpdates = Promise.all(meta.relations.map(relation => {
let insertOperationUpdates: Promise<any>, updateOperationUpdates: Promise<any>;
if (insertOperation.entity[relation.propertyName] instanceof Array && relation.isOneToMany) {
insertOperationUpdates = Promise.all(persistOperations.inserts.filter(o => {
return insertOperation.entity[relation.propertyName].indexOf(o.entity) !== -1;
}).map(o => {
const oMetadata = this.connection.getMetadata(o.entity.constructor);
const inverseRelation = relation.inverseRelation;
const query = `UPDATE ${oMetadata.table.name} SET ${inverseRelation.name}='${insertOperation.entityId}' WHERE ${oMetadata.primaryColumn.name}='${o.entityId}'`;
return this.connection.driver.query(query);
}));
updateOperationUpdates = Promise.all(persistOperations.updates.filter(o => {
return insertOperation.entity[relation.propertyName].indexOf(o.entity) !== -1;
}).map(o => {
const oMetadata = this.connection.getMetadata(o.entity.constructor);
const inverseRelation = relation.inverseRelation;
const id = insertOperation.entity[meta.primaryColumn.name];
const query = `UPDATE ${oMetadata.table.name} SET ${inverseRelation.name}='${insertOperation.entityId}' WHERE ${oMetadata.primaryColumn.name}='${id}'`;
return this.connection.driver.query(query);
}));
}
//return Promise.all([insertOperationUpdates, updateOperationUpdates]);
}));
});*/
}
private findJunctionInsertOperations(metadata: EntityMetadata, newEntity: any, dbEntities: EntityWithId[]): JunctionInsertOperation[] {
const dbEntity = dbEntities.find(dbEntity => {
return dbEntity.id === newEntity[metadata.primaryColumn.name] && dbEntity.entity.constructor.name === metadata.name;

View File

@ -4,10 +4,9 @@ import {OrmBroadcaster} from "../subscriber/OrmBroadcaster";
import {QueryBuilder} from "../query-builder/QueryBuilder";
import {PlainObjectToNewEntityTransformer} from "../query-builder/transformer/PlainObjectToNewEntityTransformer";
import {PlainObjectToDatabaseEntityTransformer} from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer";
import {RelationMetadata} from "../metadata-builder/metadata/RelationMetadata";
import {
EntityPersistOperationsBuilder, PersistOperation, JunctionInsertOperation,
InsertOperation, JunctionRemoveOperation, UpdateOperation
InsertOperation, JunctionRemoveOperation, UpdateOperation, UpdateByRelationOperation
} from "./EntityPersistOperationsBuilder";
// todo: think how we can implement queryCount, queryManyAndCount
@ -79,7 +78,7 @@ export class Repository<Entity> {
* Finds columns and relations from entity2 which does not exist or does not match in entity1.
*/
difference(entity1: Entity, entity2: Entity): PersistOperation {
const builder = new EntityPersistOperationsBuilder();
const builder = new EntityPersistOperationsBuilder(this.connection);
return builder.difference(this.metadata, entity1, entity2);
}
@ -105,7 +104,12 @@ export class Repository<Entity> {
}));
}).then(() => {
return Promise.all(persistOperations.inserts.map(operation => {
return Promise.all(persistOperations.updatesByRelations.map(updateByRelation => {
this.updateByRelation(updateByRelation, persistOperations.inserts);
}));
/*return Promise.all(persistOperations.inserts.map(operation => {
const meta = this.connection.getMetadata(operation.entity.constructor);
const oneToOneManyToOneUpdates = Promise.all(meta.relations.map(relation => {
@ -156,7 +160,7 @@ export class Repository<Entity> {
}));
return Promise.all([oneToOneManyToOneUpdates]);
}));
}));*/
}).then(() => { // perform updates
return Promise.all(persistOperations.updates.map(updateOperation => {
@ -176,6 +180,29 @@ export class Repository<Entity> {
//}
});
}
private updateByRelation(operation: UpdateByRelationOperation, insertOperations: InsertOperation[]) {
let tableName: string, relationName: string, relationId: any, idColumn: string, id: any;
const idInInserts = insertOperations.find(o => o.entity === operation.targetEntity).entityId;
if (operation.updatedRelation.isOneToMany) {
const metadata = this.connection.getMetadata(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.connection.getMetadata(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 query = `UPDATE ${tableName} SET ${relationName}='${relationId}' WHERE ${idColumn}='${id}'`;
return this.connection.driver.query(query);
}
private update(updateOperation: UpdateOperation) {
const entity = updateOperation.entity;