orginized persistent operations

This commit is contained in:
Umed Khudoiberdiev 2016-03-13 18:36:09 +05:00
parent 02e419aeb2
commit 74596edb0d
10 changed files with 182 additions and 148 deletions

View File

@ -1,105 +1,52 @@
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
import {RelationMetadata} from "../metadata-builder/metadata/RelationMetadata";
import {Connection} from "../connection/Connection";
import {PersistOperation} from "./operation/PersistOperation";
import {InsertOperation} from "./operation/InsertOperation";
import {UpdateByRelationOperation} from "./operation/UpdateByRelationOperation";
import {JunctionInsertOperation} from "./operation/JunctionInsertOperation";
import {UpdateOperation} from "./operation/UpdateOperation";
export interface EntityWithId {
interface EntityWithId {
id: any;
entity: any;
}
export interface InsertOperation {
entity: any;
entityId: number;
}
/**
* 1. collect all exist objects from the db entity
* 2. collect all objects from the new entity
* 3. first need to go throw all relations of the new entity and:
* 3.1. find all objects that are new (e.g. cascade="insert") by comparing ids from the exist objects
* 3.2. check if relation has rights to do cascade operation and throw exception if it cannot
* 3.3. save new objects for insert operation
* 4. second need to go throw all relations of the db entity and:
* 4.1. find all objects that are removed (e.g. cascade="remove") by comparing data with collected objects of the new entity
* 4.2. check if relation has rights to do cascade operation and throw exception if it cannot
* 4.3. save new objects for remove operation
* 5. third need to go throw collection of all new entities
* 5.1. compare with entities from the collection of db entities, find difference and generate a change set
* 5.2. check if relation has rights to do cascade operation and throw exception if it cannot
* 5.3.
* 6. go throw all relations and find junction
* 6.1.
*
* if relation has "all" then all of above:
* if relation has "insert" it can insert a new entity
* if relation has "update" it can only update related entity
* if relation has "remove" it can only remove related entity
*/
export class EntityPersistOperationBuilder {
export interface RemoveOperation {
entity: any;
fromEntityId: any;
metadata: EntityMetadata;
relation: RelationMetadata;
}
export interface UpdateOperation {
entity: any;
columns: ColumnMetadata[];
}
export interface JunctionInsertOperation {
metadata: EntityMetadata;
entity1: any;
entity2: any;
}
export interface JunctionRemoveOperation {
metadata: EntityMetadata;
entity1: any;
entity2: any;
}
export class UpdateByRelationOperation {
constructor(public targetEntity: any,
public insertOperation: InsertOperation,
public updatedRelation: RelationMetadata) {
}
}
export class PersistOperation {
inserts: InsertOperation[];
removes: RemoveOperation[];
updates: UpdateOperation[];
junctionInserts: JunctionInsertOperation[];
junctionRemoves: JunctionRemoveOperation[];
updatesByRelations: UpdateByRelationOperation[];
constructor(inserts: InsertOperation[],
removes: RemoveOperation[],
updates: UpdateOperation[],
junctionInserts: JunctionInsertOperation[],
junctionRemoves: JunctionRemoveOperation[],
updatesByRelations: UpdateByRelationOperation[]) {
this.inserts = inserts;
this.removes = removes;
this.updates = updates;
this.junctionInserts = junctionInserts;
this.junctionRemoves = junctionRemoves;
this.updatesByRelations = updatesByRelations;
}
}
/*export class JunctionEntity {
relation: RelationMetadata;
entity1: any;
entity2: any;
}*/
export class EntityPersistOperationsBuilder {
// 1. collect all exist objects from the db entity
// 2. collect all objects from the new entity
// 3. first need to go throw all relations of the new entity and:
// 3.1. find all objects that are new (e.g. cascade="insert") by comparing ids from the exist objects
// 3.2. check if relation has rights to do cascade operation and throw exception if it cannot
// 3.3. save new objects for insert operation
// 4. second need to go throw all relations of the db entity and:
// 4.1. find all objects that are removed (e.g. cascade="remove") by comparing data with collected objects of the new entity
// 4.2. check if relation has rights to do cascade operation and throw exception if it cannot
// 4.3. save new objects for remove operation
// 5. third need to go throw collection of all new entities
// 5.1. compare with entities from the collection of db entities, find difference and generate a change set
// 5.2. check if relation has rights to do cascade operation and throw exception if it cannot
// 5.3.
// 6. go throw all relations and find junction
// 6.1.
// if relation has "all" then all of above:
// if relation has "insert" it can insert a new entity
// if relation has "update" it can only update related entity
// if relation has "remove" it can only remove related entity
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
private strictCascadesMode = false;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(private connection: Connection) {
}
@ -119,51 +66,6 @@ export class EntityPersistOperationsBuilder {
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 ENTITY");
console.log("---------------------------------------------------------");
console.log(entity1);
console.log("---------------------------------------------------------");
console.log("NEW ENTITY");
console.log("---------------------------------------------------------");
console.log(entity2);
console.log("---------------------------------------------------------");
console.log("DB ENTITIES");
console.log("---------------------------------------------------------");
console.log(dbEntities);
console.log("---------------------------------------------------------");
console.log("ALL NEW ENTITIES");
console.log("---------------------------------------------------------");
console.log(allEntities);
console.log("---------------------------------------------------------");
console.log("INSERTED ENTITIES");
console.log("---------------------------------------------------------");
console.log(insertOperations);
console.log("---------------------------------------------------------");
console.log("REMOVED ENTITIES");
console.log("---------------------------------------------------------");
console.log(removeOperations);
console.log("---------------------------------------------------------");
console.log("UPDATED ENTITIES");
console.log("---------------------------------------------------------");
console.log(updateOperations);
console.log("---------------------------------------------------------");
console.log("JUNCTION INSERT ENTITIES");
console.log("---------------------------------------------------------");
console.log(junctionInsertOperations);
console.log("---------------------------------------------------------");
console.log("JUNCTION REMOVE ENTITIES");
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);
// todo: implement duplicates removal later
// remove duplicates from inserted entities (todo: shall we check if duplicates differ and throw exception?)
@ -208,8 +110,9 @@ export class EntityPersistOperationsBuilder {
operations.concat(subOperations);
});
} else if (value) {
if (value === insertOperation.entity)
if (value === insertOperation.entity) {
operations.push(new UpdateByRelationOperation(entityToSearchIn, insertOperation, relation));
}
const subOperations = this.findRelationsWithEntityInside(insertOperation, value);
operations.concat(subOperations);

View File

@ -1,16 +1,25 @@
import {
JunctionRemoveOperation,
InsertOperation,
JunctionInsertOperation,
PersistOperation, UpdateByRelationOperation, UpdateOperation, RemoveOperation
} from "./EntityPersistOperationsBuilder";
import {Connection} from "../connection/Connection";
import {PersistOperation} from "./operation/PersistOperation";
import {RemoveOperation} from "./operation/RemoveOperation";
import {UpdateOperation} from "./operation/UpdateOperation";
import {JunctionInsertOperation} from "./operation/JunctionInsertOperation";
import {InsertOperation} from "./operation/InsertOperation";
import {JunctionRemoveOperation} from "./operation/JunctionRemoveOperation";
import {UpdateByRelationOperation} from "./operation/UpdateByRelationOperation";
export class EntityPersister {
export class PersistOperationExecutor {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(private connection: Connection) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
executePersistOperation(persistOperation: PersistOperation) {
return Promise.resolve()
.then(() => { // insert new relations
@ -63,6 +72,10 @@ export class EntityPersister {
});
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
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;

View File

@ -0,0 +1,4 @@
export interface InsertOperation {
entity: any;
entityId: number;
}

View File

@ -0,0 +1,7 @@
import {EntityMetadata} from "../../metadata-builder/metadata/EntityMetadata";
export interface JunctionInsertOperation {
metadata: EntityMetadata;
entity1: any;
entity2: any;
}

View File

@ -0,0 +1,7 @@
import {EntityMetadata} from "../../metadata-builder/metadata/EntityMetadata";
export interface JunctionRemoveOperation {
metadata: EntityMetadata;
entity1: any;
entity2: any;
}

View File

@ -0,0 +1,75 @@
import {InsertOperation} from "./InsertOperation";
import {RemoveOperation} from "./RemoveOperation";
import {UpdateOperation} from "./UpdateOperation";
import {JunctionInsertOperation} from "./JunctionInsertOperation";
import {JunctionRemoveOperation} from "./JunctionRemoveOperation";
import {UpdateByRelationOperation} from "./UpdateByRelationOperation";
export class PersistOperation {
inserts: InsertOperation[];
removes: RemoveOperation[];
updates: UpdateOperation[];
junctionInserts: JunctionInsertOperation[];
junctionRemoves: JunctionRemoveOperation[];
updatesByRelations: UpdateByRelationOperation[];
constructor(inserts: InsertOperation[],
removes: RemoveOperation[],
updates: UpdateOperation[],
junctionInserts: JunctionInsertOperation[],
junctionRemoves: JunctionRemoveOperation[],
updatesByRelations: UpdateByRelationOperation[]) {
this.inserts = inserts;
this.removes = removes;
this.updates = updates;
this.junctionInserts = junctionInserts;
this.junctionRemoves = junctionRemoves;
this.updatesByRelations = updatesByRelations;
}
log() {
console.log("---------------------------------------------------------");
console.log("DB ENTITY");
console.log("---------------------------------------------------------");
// console.log(entity1);
console.log("---------------------------------------------------------");
console.log("NEW ENTITY");
console.log("---------------------------------------------------------");
// console.log(entity2);
console.log("---------------------------------------------------------");
console.log("DB ENTITIES");
console.log("---------------------------------------------------------");
// console.log(dbEntities);
console.log("---------------------------------------------------------");
console.log("ALL NEW ENTITIES");
console.log("---------------------------------------------------------");
// console.log(allEntities);
console.log("---------------------------------------------------------");
console.log("INSERTED ENTITIES");
console.log("---------------------------------------------------------");
console.log(this.inserts);
console.log("---------------------------------------------------------");
console.log("REMOVED ENTITIES");
console.log("---------------------------------------------------------");
console.log(this.removes);
console.log("---------------------------------------------------------");
console.log("UPDATED ENTITIES");
console.log("---------------------------------------------------------");
console.log(this.updates);
console.log("---------------------------------------------------------");
console.log("JUNCTION INSERT ENTITIES");
console.log("---------------------------------------------------------");
console.log(this.junctionInserts);
console.log("---------------------------------------------------------");
console.log("JUNCTION REMOVE ENTITIES");
console.log("---------------------------------------------------------");
console.log(this.junctionRemoves);
console.log("---------------------------------------------------------");
console.log("UPDATES BY RELATIONS");
console.log("---------------------------------------------------------");
console.log(this.updatesByRelations);
console.log("---------------------------------------------------------");
}
}

View File

@ -0,0 +1,9 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {EntityMetadata} from "../../metadata-builder/metadata/EntityMetadata";
export interface RemoveOperation {
entity: any;
fromEntityId: any;
metadata: EntityMetadata;
relation: RelationMetadata;
}

View File

@ -0,0 +1,9 @@
import {InsertOperation} from "./InsertOperation";
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
export class UpdateByRelationOperation {
constructor(public targetEntity: any,
public insertOperation: InsertOperation,
public updatedRelation: RelationMetadata) {
}
}

View File

@ -0,0 +1,6 @@
import {ColumnMetadata} from "../../metadata-builder/metadata/ColumnMetadata";
export interface UpdateOperation {
entity: any;
columns: ColumnMetadata[];
}

View File

@ -4,8 +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 {EntityPersistOperationsBuilder, PersistOperation} from "./EntityPersistOperationsBuilder";
import {EntityPersister} from "./EntityPersister";
import {PersistOperation} from "../persistment/operation/PersistOperation";
import {EntityPersistOperationBuilder} from "../persistment/EntityPersistOperationsBuilder";
import {PersistOperationExecutor} from "../persistment/PersistOperationExecutor";
// todo: think how we can implement queryCount, queryManyAndCount
// todo: extract non safe methods from repository (removeById, removeByConditions)
@ -110,7 +111,7 @@ export class Repository<Entity> {
* Persists (saves) a given entity in the database.
*/
persist(entity: Entity) {
const persister = new EntityPersister(this.connection);
const persister = new PersistOperationExecutor(this.connection);
const promise = !this.hasId(entity) ? Promise.resolve(null) : this.initialize(entity);
return promise.then(dbEntity => {
const persistOperation = this.difference(dbEntity, entity);
@ -122,7 +123,7 @@ export class Repository<Entity> {
* Removes a given entity from the database.
*/
remove(entity: Entity) {
const persister = new EntityPersister(this.connection);
const persister = new PersistOperationExecutor(this.connection);
return this.initialize(entity).then(dbEntity => {
// make this only to remove
const persistOperation = this.difference(dbEntity, entity);
@ -177,7 +178,7 @@ export class Repository<Entity> {
* that contains all information about what needs to be persisted.
*/
private difference(entity1: Entity, entity2: Entity): PersistOperation {
const builder = new EntityPersistOperationsBuilder(this.connection);
const builder = new EntityPersistOperationBuilder(this.connection);
return builder.difference(this.metadata, entity1, entity2);
}