mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added remove tests
This commit is contained in:
parent
23458269df
commit
3c7ff278f6
@ -10,7 +10,7 @@ export class PostMetadata {
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
description: string;
|
||||
|
||||
@OneToOne<Post>(false, () => Post, post => post.metadata)
|
||||
post: Post;
|
||||
|
||||
@ -14,6 +14,13 @@ export interface InsertOperation {
|
||||
entityId: number;
|
||||
}
|
||||
|
||||
export interface RemoveOperation {
|
||||
entity: any;
|
||||
fromEntityId: any;
|
||||
metadata: EntityMetadata;
|
||||
relation: RelationMetadata;
|
||||
}
|
||||
|
||||
export interface UpdateOperation {
|
||||
entity: any;
|
||||
columns: ColumnMetadata[];
|
||||
@ -40,14 +47,14 @@ export class UpdateByRelationOperation {
|
||||
|
||||
export class PersistOperation {
|
||||
inserts: InsertOperation[];
|
||||
removes: any[];
|
||||
removes: RemoveOperation[];
|
||||
updates: UpdateOperation[];
|
||||
junctionInserts: JunctionInsertOperation[];
|
||||
junctionRemoves: JunctionRemoveOperation[];
|
||||
updatesByRelations: UpdateByRelationOperation[];
|
||||
|
||||
constructor(inserts: any[],
|
||||
removes: any[],
|
||||
constructor(inserts: InsertOperation[],
|
||||
removes: RemoveOperation[],
|
||||
updates: UpdateOperation[],
|
||||
junctionInserts: JunctionInsertOperation[],
|
||||
junctionRemoves: JunctionRemoveOperation[],
|
||||
@ -372,13 +379,18 @@ export class EntityPersistOperationsBuilder {
|
||||
.reduce((removedEntities, relation) => {
|
||||
const relationIdColumnName = relation.relatedEntityMetadata.primaryColumn.name;
|
||||
const relMetadata = relation.relatedEntityMetadata;
|
||||
if (dbEntity[relation.propertyName] instanceof Array) {
|
||||
if (dbEntity[relation.propertyName] instanceof Array) { // todo: propertyName or name here?
|
||||
dbEntity[relation.propertyName].forEach((subEntity: any) => {
|
||||
const isObjectRemoved = !newEntities.find(newEntity => {
|
||||
return newEntity.id === subEntity[relationIdColumnName] && newEntity.entity.constructor.name === relMetadata.name;
|
||||
});
|
||||
if (isObjectRemoved && relation.isCascadeRemove)
|
||||
removedEntities.push(subEntity);
|
||||
removedEntities.push({
|
||||
entity: subEntity,
|
||||
fromEntityId: dbEntity[metadata.primaryColumn.name],
|
||||
metadata: metadata,
|
||||
relation: relation
|
||||
});
|
||||
|
||||
removedEntities = removedEntities.concat(this.findCascadeRemovedEntities(relMetadata, subEntity, newEntities));
|
||||
});
|
||||
@ -388,7 +400,12 @@ export class EntityPersistOperationsBuilder {
|
||||
return newEntity.id === relationId && newEntity.entity.constructor.name === relMetadata.name;
|
||||
});
|
||||
if (isObjectRemoved && relation.isCascadeRemove)
|
||||
removedEntities.push(dbEntity[relation.propertyName]);
|
||||
removedEntities.push({
|
||||
entity: dbEntity[relation.propertyName],
|
||||
fromEntityId: dbEntity[metadata.primaryColumn.name],
|
||||
metadata: metadata,
|
||||
relation: relation
|
||||
});
|
||||
|
||||
removedEntities = removedEntities.concat(this.findCascadeRemovedEntities(relMetadata, dbEntity[relation.propertyName], newEntities));
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import {PlainObjectToNewEntityTransformer} from "../query-builder/transformer/Pl
|
||||
import {PlainObjectToDatabaseEntityTransformer} from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer";
|
||||
import {
|
||||
EntityPersistOperationsBuilder, PersistOperation, JunctionInsertOperation,
|
||||
InsertOperation, JunctionRemoveOperation, UpdateOperation, UpdateByRelationOperation
|
||||
InsertOperation, JunctionRemoveOperation, UpdateOperation, UpdateByRelationOperation, RemoveOperation
|
||||
} from "./EntityPersistOperationsBuilder";
|
||||
|
||||
// todo: think how we can implement queryCount, queryManyAndCount
|
||||
@ -88,11 +88,17 @@ export class Repository<Entity> {
|
||||
return promise.then(dbEntity => {
|
||||
const persistOperations = this.difference(dbEntity, entity);
|
||||
// create update queries based on diff map
|
||||
return Promise.all(persistOperations.inserts.map(operation => {
|
||||
return this.insert(operation.entity).then((result: any) => {
|
||||
operation.entityId = result.insertId;
|
||||
});
|
||||
})).then(() => { // insert junction table insertions
|
||||
// return Promise.resolve()
|
||||
return Promise.resolve()
|
||||
|
||||
.then(() => { // insert new relations
|
||||
return Promise.all(persistOperations.inserts.map(operation => {
|
||||
return this.insert(operation.entity).then((result: any) => {
|
||||
operation.entityId = result.insertId;
|
||||
});
|
||||
}));
|
||||
|
||||
}).then(() => { // insert junction table insertions
|
||||
|
||||
return Promise.all(persistOperations.junctionInserts.map(junctionOperation => {
|
||||
return this.insertJunctions(junctionOperation, persistOperations.inserts);
|
||||
@ -108,63 +114,21 @@ export class Repository<Entity> {
|
||||
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 => {
|
||||
|
||||
let insertOperationUpdates: Promise<any>, updateOperationUpdates: Promise<any>;
|
||||
|
||||
if (operation.entity[relation.propertyName] instanceof Array && relation.isOneToMany) {
|
||||
|
||||
insertOperationUpdates = Promise.all(persistOperations.inserts.filter(o => {
|
||||
return operation.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}='${operation.entityId}' WHERE ${oMetadata.primaryColumn.name}='${o.entityId}'`;
|
||||
return this.connection.driver.query(query);
|
||||
}));
|
||||
|
||||
updateOperationUpdates = Promise.all(persistOperations.updates.filter(o => {
|
||||
return operation.entity[relation.propertyName].indexOf(o.entity) !== -1;
|
||||
}).map(o => {
|
||||
const oMetadata = this.connection.getMetadata(o.entity.constructor);
|
||||
const inverseRelation = relation.inverseRelation;
|
||||
const id = operation.entity[meta.primaryColumn.name];
|
||||
const query = `UPDATE ${oMetadata.table.name} SET ${inverseRelation.name}='${operation.entityId}' WHERE ${oMetadata.primaryColumn.name}='${id}'`;
|
||||
return this.connection.driver.query(query);
|
||||
}));
|
||||
|
||||
} else {
|
||||
|
||||
insertOperationUpdates = Promise.all(persistOperations.inserts.filter(o => {
|
||||
return operation.entity[relation.propertyName] === o.entity; // only one-to-one and many-to-one
|
||||
}).map(o => {
|
||||
const query = `UPDATE ${meta.table.name} SET ${relation.name}='${o.entityId}' WHERE ${meta.primaryColumn.name}='${operation.entityId}'`;
|
||||
return this.connection.driver.query(query);
|
||||
}));
|
||||
|
||||
updateOperationUpdates = Promise.all(persistOperations.updates.filter(o => {
|
||||
return operation.entity[relation.propertyName] === o.entity; // only one-to-one and many-to-one
|
||||
}).map(o => {
|
||||
const reverseMeta = this.connection.getMetadata(o.entity.constructor);
|
||||
const id = o.entity[reverseMeta.primaryColumn.name];
|
||||
const query = `UPDATE ${meta.table.name} SET ${relation.name}='${id}' WHERE ${meta.primaryColumn.name}='${operation.entityId}'`;
|
||||
return this.connection.driver.query(query);
|
||||
}));
|
||||
}
|
||||
|
||||
return Promise.all([insertOperationUpdates, updateOperationUpdates]);
|
||||
}));
|
||||
|
||||
return Promise.all([oneToOneManyToOneUpdates]);
|
||||
}));*/
|
||||
}).then(() => { // perform updates
|
||||
|
||||
return Promise.all(persistOperations.updates.map(updateOperation => {
|
||||
return this.update(updateOperation);
|
||||
return Promise.all(persistOperations.updates.map(updateOperation => {
|
||||
return this.update(updateOperation);
|
||||
}));
|
||||
|
||||
}).then(() => { // remove removed relations
|
||||
return Promise.all(persistOperations.removes.map(operation => {
|
||||
return this.updateDeletedRelations(operation);
|
||||
}));
|
||||
|
||||
}).then(() => { // remove removed entities
|
||||
return Promise.all(persistOperations.removes.map(operation => {
|
||||
return this.delete(operation.entity);
|
||||
}));
|
||||
|
||||
}).then(() => { // update ids
|
||||
@ -177,16 +141,6 @@ export class Repository<Entity> {
|
||||
return entity;
|
||||
|
||||
});
|
||||
//} else {
|
||||
// do update
|
||||
/*return this.initialize(entity).then(dbEntity => {
|
||||
const persistOperations = this.difference(dbEntity, entity);
|
||||
// create update queries based on diff map
|
||||
return Promise.all(persistOperations.inserts.map(operation => {
|
||||
return this.insert(operation.entity);
|
||||
}));
|
||||
});*/
|
||||
//}
|
||||
});
|
||||
}
|
||||
|
||||
@ -223,6 +177,18 @@ export class Repository<Entity> {
|
||||
const query = `UPDATE ${metadata.table.name} SET ${values} WHERE ${metadata.primaryColumn.name}='${metadata.getEntityId(entity)}'` ;
|
||||
return this.connection.driver.query(query);
|
||||
}
|
||||
|
||||
private updateDeletedRelations(removeOperation: RemoveOperation) { // todo: check if both many-to-one deletions work too
|
||||
const value = removeOperation.relation.name + "=NULL";
|
||||
const query = `UPDATE ${removeOperation.metadata.table.name} SET ${value} WHERE ${removeOperation.metadata.primaryColumn.name}='${removeOperation.fromEntityId}'` ;
|
||||
return this.connection.driver.query(query);
|
||||
}
|
||||
|
||||
private delete(entity: any) {
|
||||
const metadata = this.connection.getMetadata(entity.constructor);
|
||||
const query = `DELETE FROM ${metadata.table.name} WHERE ${metadata.primaryColumn.name}='${entity[metadata.primaryColumn.propertyName]}'`;
|
||||
return this.connection.driver.query(query);
|
||||
}
|
||||
|
||||
private insert(entity: any) {
|
||||
const metadata = this.connection.getMetadata(entity.constructor);
|
||||
|
||||
@ -51,12 +51,14 @@ describe("insertion", function() {
|
||||
let postRepository: Repository<Post>,
|
||||
postDetailsRepository: Repository<PostDetails>,
|
||||
postCategoryRepository: Repository<PostCategory>,
|
||||
postImageRepository: Repository<PostImage>;
|
||||
postImageRepository: Repository<PostImage>,
|
||||
postMetadataRepository: Repository<PostMetadata>;
|
||||
before(function() {
|
||||
postRepository = connection.getRepository<Post>(Post);
|
||||
postDetailsRepository = connection.getRepository<PostDetails>(PostDetails);
|
||||
postCategoryRepository = connection.getRepository<PostCategory>(PostCategory);
|
||||
postImageRepository = connection.getRepository<PostImage>(PostImage);
|
||||
postMetadataRepository = connection.getRepository<PostMetadata>(PostMetadata);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -334,11 +336,11 @@ describe("insertion", function() {
|
||||
});
|
||||
|
||||
describe("cascade updates should be executed when cascadeUpdate option is set", function() {
|
||||
let newPost: Post, newImage: PostImage, savedPost: Post, savedImage: PostImage;
|
||||
let newPost: Post, newImage: PostImage, savedImage: PostImage;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
it("should ignore updates in the model and do not update the db when entity is updated", function () {
|
||||
it("should update a relation successfully when updated", function () {
|
||||
|
||||
newImage = new PostImage();
|
||||
newImage.url = "logo.png";
|
||||
@ -382,4 +384,53 @@ describe("insertion", function() {
|
||||
|
||||
});
|
||||
|
||||
describe("cascade remove should be executed when cascadeRemove option is set", function() {
|
||||
let newPost: Post, newMetadata: PostMetadata, savedMetadata: PostMetadata;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
it("should remove a relation entity successfully when removed", function () {
|
||||
|
||||
newMetadata = new PostMetadata();
|
||||
newMetadata.description = "this is post metadata";
|
||||
|
||||
newPost = new Post();
|
||||
newPost.text = "Hello post";
|
||||
newPost.title = "this is post title";
|
||||
|
||||
return postMetadataRepository
|
||||
.persist(newMetadata)
|
||||
.then(metadata => {
|
||||
savedMetadata = metadata;
|
||||
newPost.metadata = metadata;
|
||||
return postRepository.persist(newPost);
|
||||
|
||||
}).then(post => {
|
||||
newPost = post;
|
||||
return postRepository
|
||||
.createQueryBuilder("post")
|
||||
.leftJoinAndSelect("post.metadata", "metadata")
|
||||
.where("post.id=:id")
|
||||
.setParameter("id", post.id)
|
||||
.getSingleResult();
|
||||
|
||||
}).then(loadedPost => {
|
||||
loadedPost.metadata = null;
|
||||
return postRepository.persist(loadedPost);
|
||||
|
||||
}).then(() => {
|
||||
return postRepository
|
||||
.createQueryBuilder("post")
|
||||
.leftJoinAndSelect("post.metadata", "metadata")
|
||||
.where("post.id=:id")
|
||||
.setParameter("id", newPost.id)
|
||||
.getSingleResult();
|
||||
|
||||
}).then(reloadedPost => {
|
||||
expect(reloadedPost.metadata).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user