Skip to content

Commit

Permalink
fix: return correct DeleteResult and UpdateResult for mongo (#7884)
Browse files Browse the repository at this point in the history
this updates the mongo entity manager to return the correct
values for both UpdateResult and DeleteResult instead of an
empty object
  • Loading branch information
imnotjames authored Jul 11, 2021
1 parent d31c2fd commit 7a646a2
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 52 deletions.
29 changes: 23 additions & 6 deletions src/entity-manager/MongoEntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,26 @@ export class MongoEntityManager extends EntityManager {
* Does not check if entity exist in the database.
*/
async update<Entity>(target: EntityTarget<Entity>, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions<Entity>, partialEntity: QueryDeepPartialEntity<Entity>): Promise<UpdateResult> {
const result = new UpdateResult();

if (Array.isArray(criteria)) {
await Promise.all((criteria as any[]).map(criteriaItem => {
const updateResults = await Promise.all((criteria as any[]).map(criteriaItem => {
return this.update(target, criteriaItem, partialEntity);
}));

result.raw = updateResults.map(r => r.raw);
result.affected = updateResults.map(r => (r.affected || 0)).reduce(( c, r) => c + r, 0);
result.generatedMaps = updateResults.reduce((c, r) => c.concat(r.generatedMaps), [] as ObjectLiteral[]);

} else {
const metadata = this.connection.getMetadata(target);
await this.updateMany(target, this.convertMixedCriteria(metadata, criteria), { $set: partialEntity });
const mongoResult = await this.updateMany(target, this.convertMixedCriteria(metadata, criteria), { $set: partialEntity });

result.raw = mongoResult;
result.affected = mongoResult.modifiedCount;
}

return new UpdateResult();
return result;
}

/**
Expand All @@ -245,16 +254,24 @@ export class MongoEntityManager extends EntityManager {
* Does not check if entity exist in the database.
*/
async delete<Entity>(target: EntityTarget<Entity>, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions<Entity>): Promise<DeleteResult> {
const result = new DeleteResult();

if (Array.isArray(criteria)) {
await Promise.all((criteria as any[]).map(criteriaItem => {
const deleteResults = await Promise.all((criteria as any[]).map(criteriaItem => {
return this.delete(target, criteriaItem);
}));

result.raw = deleteResults.map(r => r.raw);
result.affected = deleteResults.map(r => (r.affected || 0)).reduce((c, r) => c + r, 0);

} else {
await this.deleteMany(target, this.convertMixedCriteria(this.connection.getMetadata(target), criteria));
const mongoResult = await this.deleteMany(target, this.convertMixedCriteria(this.connection.getMetadata(target), criteria));

result.raw = mongoResult;
result.affected = mongoResult.deletedCount;
}

return new DeleteResult();
return result;
}

// -------------------------------------------------------------------------
Expand Down
100 changes: 54 additions & 46 deletions src/persistence/SubjectExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {NestedSetSubjectExecutor} from "./tree/NestedSetSubjectExecutor";
import {ClosureSubjectExecutor} from "./tree/ClosureSubjectExecutor";
import {MaterializedPathSubjectExecutor} from "./tree/MaterializedPathSubjectExecutor";
import {OrmUtils} from "../util/OrmUtils";
import { UpdateResult } from "../query-builder/result/UpdateResult";

/**
* Executes all database operations (inserts, updated, deletes) that must be executed
Expand Down Expand Up @@ -561,6 +562,8 @@ export class SubjectExecutor {
if (!subject.identifier)
throw new SubjectWithoutIdentifierError(subject);

let updateResult: UpdateResult;

// for mongodb we have a bit different updation logic
if (this.queryRunner instanceof MongoQueryRunner) {
const partialEntity = this.cloneMongoSubjectEntity(subject);
Expand All @@ -582,7 +585,7 @@ export class SubjectExecutor {

const manager = this.queryRunner.manager as MongoEntityManager;

await manager.update(subject.metadata.target, subject.identifier, partialEntity);
updateResult = await manager.update(subject.metadata.target, subject.identifier, partialEntity);

} else {

Expand All @@ -605,30 +608,31 @@ export class SubjectExecutor {
softDeleteQueryBuilder.where(subject.identifier);
}

const updateResult = await softDeleteQueryBuilder.execute();
subject.generatedMap = updateResult.generatedMaps[0];
if (subject.generatedMap) {
subject.metadata.columns.forEach(column => {
const value = column.getEntityValue(subject.generatedMap!);
if (value !== undefined && value !== null) {
const preparedValue = this.queryRunner.connection.driver.prepareHydratedValue(value, column);
column.setEntityValue(subject.generatedMap!, preparedValue);
}
});
}
updateResult = await softDeleteQueryBuilder.execute();
}

// experiments, remove probably, need to implement tree tables children removal
// if (subject.updatedRelationMaps.length > 0) {
// await Promise.all(subject.updatedRelationMaps.map(async updatedRelation => {
// if (!updatedRelation.relation.isTreeParent) return;
// if (!updatedRelation.value !== null) return;
//
// if (subject.metadata.treeType === "closure-table") {
// await new ClosureSubjectExecutor(this.queryRunner).deleteChildrenOf(subject);
// }
// }));
// }
subject.generatedMap = updateResult.generatedMaps[0];
if (subject.generatedMap) {
subject.metadata.columns.forEach(column => {
const value = column.getEntityValue(subject.generatedMap!);
if (value !== undefined && value !== null) {
const preparedValue = this.queryRunner.connection.driver.prepareHydratedValue(value, column);
column.setEntityValue(subject.generatedMap!, preparedValue);
}
});
}

// experiments, remove probably, need to implement tree tables children removal
// if (subject.updatedRelationMaps.length > 0) {
// await Promise.all(subject.updatedRelationMaps.map(async updatedRelation => {
// if (!updatedRelation.relation.isTreeParent) return;
// if (!updatedRelation.value !== null) return;
//
// if (subject.metadata.treeType === "closure-table") {
// await new ClosureSubjectExecutor(this.queryRunner).deleteChildrenOf(subject);
// }
// }));
// }
}));
}

Expand All @@ -641,6 +645,8 @@ export class SubjectExecutor {
if (!subject.identifier)
throw new SubjectWithoutIdentifierError(subject);

let updateResult: UpdateResult;

// for mongodb we have a bit different updation logic
if (this.queryRunner instanceof MongoQueryRunner) {
const partialEntity = this.cloneMongoSubjectEntity(subject);
Expand All @@ -662,7 +668,7 @@ export class SubjectExecutor {

const manager = this.queryRunner.manager as MongoEntityManager;

await manager.update(subject.metadata.target, subject.identifier, partialEntity);
updateResult = await manager.update(subject.metadata.target, subject.identifier, partialEntity);

} else {

Expand All @@ -685,30 +691,32 @@ export class SubjectExecutor {
softDeleteQueryBuilder.where(subject.identifier);
}

const updateResult = await softDeleteQueryBuilder.execute();
subject.generatedMap = updateResult.generatedMaps[0];
if (subject.generatedMap) {
subject.metadata.columns.forEach(column => {
const value = column.getEntityValue(subject.generatedMap!);
if (value !== undefined && value !== null) {
const preparedValue = this.queryRunner.connection.driver.prepareHydratedValue(value, column);
column.setEntityValue(subject.generatedMap!, preparedValue);
}
});
}
updateResult = await softDeleteQueryBuilder.execute();
}

// experiments, remove probably, need to implement tree tables children removal
// if (subject.updatedRelationMaps.length > 0) {
// await Promise.all(subject.updatedRelationMaps.map(async updatedRelation => {
// if (!updatedRelation.relation.isTreeParent) return;
// if (!updatedRelation.value !== null) return;
//
// if (subject.metadata.treeType === "closure-table") {
// await new ClosureSubjectExecutor(this.queryRunner).deleteChildrenOf(subject);
// }
// }));
// }
subject.generatedMap = updateResult.generatedMaps[0];
if (subject.generatedMap) {
subject.metadata.columns.forEach(column => {
const value = column.getEntityValue(subject.generatedMap!);
if (value !== undefined && value !== null) {
const preparedValue = this.queryRunner.connection.driver.prepareHydratedValue(value, column);
column.setEntityValue(subject.generatedMap!, preparedValue);
}
});
}

// experiments, remove probably, need to implement tree tables children removal
// if (subject.updatedRelationMaps.length > 0) {
// await Promise.all(subject.updatedRelationMaps.map(async updatedRelation => {
// if (!updatedRelation.relation.isTreeParent) return;
// if (!updatedRelation.value !== null) return;
//
// if (subject.metadata.treeType === "closure-table") {
// await new ClosureSubjectExecutor(this.queryRunner).deleteChildrenOf(subject);
// }
// }));
// }

}));
}

Expand Down

0 comments on commit 7a646a2

Please sign in to comment.