mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
updated update by relations algorith,
m
This commit is contained in:
parent
35d363f887
commit
976d6fd10a
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user