Skip to content

Commit

Permalink
re-implemented update, updateById, removeById methods; added delete a…
Browse files Browse the repository at this point in the history
…nd insert methods
  • Loading branch information
Umed Khudoiberdiev committed Oct 16, 2017
1 parent 568db03 commit 6234501
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 72 deletions.
2 changes: 0 additions & 2 deletions .github/ISSUE_TEMPLATE.md

This file was deleted.

7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ feel free to ask us and community.

* added support for `pg-native` for postgres (#975). To use it you just need to install `npm i pg-native` and it will be picked up automatically.
* now Find Options support `-1` and `1` for `DESC` and `ASC` values. This is better user experience for MongoDB users.
* now inheritances in embeddeds are supported (#966)
* now inheritances in embeddeds are supported (#966).
* `isArray: boolean` in `ColumnOptions` is deprecated. Use `array: boolean` instead.
* deprecated `removeById` method, now use `deleteById` method instead.
* added `insert` and `delete` methods into repository and entity manager.
* fixed multiple issues with `update`, `updateById` and `removeById` methods in repository and entity manager. Now they do not use `save` and `remove` methods anymore - instead they are using QueryBuilder to build and execute their queries.
* removed opencollective dependency
* multiple small bugfixes

## 0.1.0

Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
"glob": "^7.1.2",
"js-yaml": "^3.8.4",
"mkdirp": "^0.5.1",
"opencollective": "^1.0.3",
"reflect-metadata": "^0.1.10",
"xml2js": "^0.4.17",
"yargonaut": "^1.1.2",
Expand All @@ -92,8 +91,7 @@
"test": "gulp ci-tests",
"compile": "tsc",
"setup:config": "gulp createTravisOrmConfig",
"package": "gulp package",
"postinstall": "opencollective postinstall"
"package": "gulp package"
},
"bin": {
"typeorm": "./cli.js"
Expand Down
122 changes: 87 additions & 35 deletions src/entity-manager/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {RepositoryFactory} from "../repository/RepositoryFactory";
import {EntityManagerFactory} from "./EntityManagerFactory";
import {TreeRepositoryNotSupportedError} from "../error/TreeRepositoryNotSupportedError";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {QueryPartialEntity} from "../query-builder/QueryPartialEntity";

/**
* Entity manager supposed to work with any entity, automatically find its repository and call its methods,
Expand Down Expand Up @@ -358,37 +359,59 @@ export class EntityManager {
}

/**
* Updates entity partially. Entity can be found by a given conditions.
* Inserts a given entity into the database.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient INSERT query.
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
* You can execute bulk inserts using this method.
*/
async update<Entity>(target: ObjectType<Entity>|string, conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void>;
async insert<Entity>(target: ObjectType<Entity>|string, entity: QueryPartialEntity<Entity>|QueryPartialEntity<Entity>[], options?: SaveOptions): Promise<void> {
// todo: in the future create InsertResult with query result information
// todo: think if subscribers and listeners can be executed here as well

/**
* Updates entity partially. Entity can be found by a given find options.
*/
async update<Entity>(target: ObjectType<Entity>|string, findOptions: FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void>;
await this.createQueryBuilder()
.insert()
.into(target)
.values(entity)
.execute();
}

/**
* Updates entity partially. Entity can be found by a given conditions.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient UPDATE query.
* Does not check if entity exist in the database.
*/
async update<Entity>(target: ObjectType<Entity>|string, conditionsOrFindOptions: Partial<Entity>|FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
const entity = await this.findOne(target, conditionsOrFindOptions as any); // this is temporary, in the future can be refactored to perform better
if (!entity)
throw new Error(`Cannot find entity to update by a given criteria`);
async update<Entity>(target: ObjectType<Entity>|string, conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
// todo: in the future create UpdateResult with query result information
// todo: think if subscribers and listeners can be executed here as well

const queryBuilder = this.createQueryBuilder()
.update(target)
.set(partialEntity);

Object.assign(entity, partialEntity);
await this.save(entity, options);
FindOptionsUtils.applyConditions(queryBuilder, conditions); // todo: move condition-like syntax into .where method of query builder?
await queryBuilder.execute();
}

/**
* Updates entity partially. Entity will be found by a given id.
*/
async updateById<Entity>(target: ObjectType<Entity>|string, id: any, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
const entity = await this.findOneById(target, id as any); // this is temporary, in the future can be refactored to perform better
if (!entity)
throw new Error(`Cannot find entity to update by a id`);

Object.assign(entity, partialEntity);
await this.save(entity, options);
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient UPDATE query.
* Does not check if entity exist in the database.
*/
async updateById<Entity>(target: ObjectType<Entity>|string, id: any|any[], partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
// todo: in the future create UpdateResult with query result information
// todo: think if subscribers and listeners can be executed here as well

await this.createQueryBuilder()
.update(target)
.set(partialEntity)
.whereInIds(id)
.execute();
}

/**
Expand Down Expand Up @@ -498,29 +521,58 @@ export class EntityManager {
}

/**
* Removes entity by a given entity id.
* Deletes entities by a given conditions.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
async removeById<Entity>(targetOrEntity: ObjectType<Entity>|string, id: any, options?: RemoveOptions): Promise<void> {
const entity = await this.findOneById<any>(targetOrEntity, id); // this is temporary, in the future can be refactored to perform better
if (!entity)
throw new Error(`Cannot find entity to remove by a given id`);
async delete<Entity>(targetOrEntity: ObjectType<Entity>|string, conditions: Partial<Entity>, options?: RemoveOptions): Promise<void> {
// todo: in the future create DeleteResult with query result information
// todo: think if subscribers and listeners can be executed here as well

const queryBuilder = this.createQueryBuilder()
.delete()
.from(targetOrEntity);

await this.remove(entity, options);
FindOptionsUtils.applyConditions(queryBuilder, conditions); // todo: move condition-like syntax into .where method of query builder?
await queryBuilder.execute();
}

/**
* Removes entity by a given entity ids.
* Deletes entities by a given entity id or ids.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
async removeByIds<Entity>(targetOrEntity: ObjectType<Entity>|string, ids: any[], options?: RemoveOptions): Promise<void> {
const promises = ids.map(async id => {
const entity = await this.findOneById<any>(targetOrEntity, id); // this is temporary, in the future can be refactored to perform better
if (!entity)
throw new Error(`Cannot find entity to remove by a given id`);
async deleteById<Entity>(targetOrEntity: ObjectType<Entity>|string, id: any|any[], options?: RemoveOptions): Promise<void> {
// todo: in the future create DeleteResult with query result information
// todo: think if subscribers and listeners can be executed here as well

await this.remove(entity, options);
});
await this.createQueryBuilder()
.delete()
.from(targetOrEntity)
.whereInIds(id)
.execute();
}

await Promise.all(promises);
/**
* Deletes entity by a given entity id.
*
* @deprecated use deleteById method instead.
*/
async removeById<Entity>(targetOrEntity: ObjectType<Entity>|string, id: any, options?: RemoveOptions): Promise<void> {
return this.deleteById(targetOrEntity, id, options);
}

/**
* Deletes entity by a given entity ids.
*
* @deprecated use deleteById method instead.
*/
async removeByIds<Entity>(targetOrEntity: ObjectType<Entity>|string, ids: any[], options?: RemoveOptions): Promise<void> {
return this.deleteById(targetOrEntity, ids, options);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/find-options/FindOptionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {FindManyOptions} from "./FindManyOptions";
import {FindOneOptions} from "./FindOneOptions";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder";
import {WhereExpression} from "../query-builder/WhereExpression";

/**
* Utilities to work with FindOptions.
Expand Down Expand Up @@ -161,7 +162,7 @@ export class FindOptionsUtils {
/**
* Applies given simple conditions set to a given query builder.
*/
static applyConditions<T>(qb: SelectQueryBuilder<T>, conditions: ObjectLiteral): SelectQueryBuilder<T> {
static applyConditions<QB extends WhereExpression & { alias: string, setParameter(name: string, value: any): QB }>(qb: QB, conditions: ObjectLiteral): QB {
Object.keys(conditions).forEach((key, index) => {
if (conditions![key] === null) {
qb.andWhere(`${qb.alias}.${key} IS NULL`);
Expand Down
14 changes: 2 additions & 12 deletions src/query-builder/InsertQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
/**
* Values needs to be inserted into table.
*/
values(values: QueryPartialEntity<Entity>): this;

/**
* Values needs to be inserted into table.
*/
values(values: QueryPartialEntity<Entity>[]): this;

/**
* Values needs to be inserted into table.
*/
values(values: ObjectLiteral|ObjectLiteral[]): this {
values(values: QueryPartialEntity<Entity>|QueryPartialEntity<Entity>[]): this {
this.expressionMap.valuesSet = values;
return this;
}
Expand Down Expand Up @@ -92,7 +82,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
const values = valueSets.map((valueSet, key) => {
const columnNames = insertColumns.map(column => {
const paramName = "_inserted_" + key + "_" + column.databaseName;
const value = valueSet[column.propertyName];
const value = column.getEntityValue(valueSet);

if (value instanceof Function) { // support for SQL expressions in update query
return value();
Expand Down
2 changes: 1 addition & 1 deletion src/repository/BaseEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export class BaseEntity {
* Removes entity by a given entity id.
*/
static removeById<T extends BaseEntity>(this: ObjectType<T>, id: any, options?: RemoveOptions): Promise<void> {
return (this as any).getRepository().removeById(id, options);
return (this as any).getRepository().deleteById(id, options);
}

/**
Expand Down
54 changes: 38 additions & 16 deletions src/repository/Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,25 +133,21 @@ export class Repository<Entity extends ObjectLiteral> {
}

/**
* Updates entity partially. Entity can be found by a given conditions.
*/
async update(conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void>;

/**
* Updates entity partially. Entity can be found by a given find options.
*/
async update(findOptions: FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void>;
* Inserts a given entity into the database.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient INSERT query.
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
*/
async insert(entity: Partial<Entity>|Partial<Entity>[], options?: SaveOptions): Promise<void> {
return this.manager.insert(this.metadata.target, entity, options);
}

/**
* Updates entity partially. Entity can be found by a given conditions.
*/
async update(conditionsOrFindOptions: Partial<Entity>|FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
const entity = await this.findOne(conditionsOrFindOptions as any); // this is temporary, in the future can be refactored to perform better
if (!entity)
throw new Error(`Cannot find entity to update by a given criteria`);

Object.assign(entity, partialEntity);
await this.save(entity, options);
async update(conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<void> {
return this.manager.update(this.metadata.target, conditions, partialEntity, options);
}

/**
Expand All @@ -178,15 +174,41 @@ export class Repository<Entity extends ObjectLiteral> {
return this.manager.remove(this.metadata.target, entityOrEntities as any, options);
}

/**
* Deletes entities by a given conditions.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
async delete(conditions: Partial<Entity>, options?: RemoveOptions): Promise<void> {
return this.manager.delete(this.metadata.target, conditions, options);
}

/**
* Deletes entities by a given conditions.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Does not modify source entity and does not execute listeners and subscribers.
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
async deleteById(id: any, options?: RemoveOptions): Promise<void> {
return this.manager.deleteById(this.metadata.target, id, options);
}

/**
* Removes entity by a given entity id.
*
* @deprecated use deleteById method instead.
*/
async removeById(id: any, options?: RemoveOptions): Promise<void> {
return this.manager.removeById(this.metadata.target, id, options);
return this.manager.deleteById(this.metadata.target, id, options);
}

/**
* Removes entity by a given entity id.
*
* @deprecated use deleteById method instead.
*/
async removeByIds(ids: any[], options?: RemoveOptions): Promise<void> {
return this.manager.removeByIds(this.metadata.target, ids, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe("repository > removeById and removeByIds methods", function() {
]);

// remove one
await postRepository.removeById(1);
await postRepository.deleteById(1);

// load to check
const loadedPosts = await postRepository.find();
Expand Down

0 comments on commit 6234501

Please sign in to comment.