TypeORM+ adds functionality to TypeORM intending to make the Repository and QueryBuilder more powerful.
TypeORM+ is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript (ES5, ES6, ES7, ES8).
TypeORM+ is a fork of TypeORM. TypeORM+ adds functionality to TypeORM intending to make the
Repositoryand
QueryBuildermore powerful. Since this is a fork we'll pull in changes from the original TypeORM regularly as they are released.
TypeORM+ is intended to replace TypeORM, so any changes in its interface are documented below.
Install the npm package:
yarn add typeorm-plus --save
You need to install
reflect-metadatashim, node typing, a database driver and so on. You can read more from here: http://typeorm.io.
After installed the npm packages, you can import modules from "typeorm-plus". But if you are using the third-party modules for TypeORM, such like nestjs/typeorm, you need to install
typeorm-pluswith the alias name
typeorm:
yarn add [email protected]:typeorm-plus --save
In addition to actually removing records from your database, TypeORM+ supports "soft delete". When entities are soft deleted, they are not actually removed from your database. Instead, an attribute that records the delete time is set on the entity and inserted into the database. If the attribute is a non-null value, the entity has been soft deleted. To enable soft deletes for an entity, use the
@DeleteDateColumnon the entity:
import { DeleteDateColumn } from 'typeorm-plus'export class Entity {
@DeleteDateColumn({ name: 'deleted_at' }) public deletedAt: Date
}
@DeleteDateColumnis a special column that is automatically set to the entity's delete time each time you call soft-delete of entity manager or repository. You don't need to set this column - it will be automatically set.
import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";createConnection(/.../).then(async connection => {
await connection .getRepository(Entity) .createQueryBuilder() .softDelete() // And You can restore it using restore; await connection .getRepository(Entity) .createQueryBuilder() .restore()
}).catch(error => console.log(error));
import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";createConnection(/.../).then(async connection => {
const repository = connection.getRepository(Entity); // Delete a entity await repository.softDelete(1); // And You can restore it using restore; await repository.restore(1); // Or You can soft-delete them using softRemove const entities = await repository.find(); const entitiesAfterSoftRemove = await repository.softRemove(entities); // And You can recover them using recover; await repository.recover(entitiesAfterSoftRemove);
}).catch(error => console.log(error));
This example show what the cascading soft deletes behaves in TypeORM+.
const category1 = new Category(); category1.name = "animals";const category2 = new Category(); category2.name = "zoo";
const question = new Question(); question.categories = [category1, category2]; const newQuestion = await connection.manager.save(question);
await connection.manager.softRemove(newQuestion);
As you can see in this example we did not call
saveor
softRemovefor category1 and category2. But They will be automatically saved and soft-deleted when the
cascadeof relation options is set to true like this:
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm-plus"; import {Category} from "./Category";@Entity() export class Question {
@PrimaryGeneratedColumn() id: number; @ManyToMany(type => Category, category => category.questions, { cascade: true }) @JoinTable() categories: Category[];
}
Query scopes allow you to add constraints to all queries for a given entity. You can register scopes in your entity:
import { DeleteDateColumn } from 'typeorm-plus'export class Entity {
static scope = { 'default': { deletedAt: IsNull() }, 'myScope': { deletedAt: Not(IsNull()) } }
}
When you are calling
queryBuilder, you can also apply the scope.
import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";createConnection(/.../).then(async connection => {
const repository = connection.getRepository(Entity); await repository.createQueryBuilder().setScope("myScope").getMany();
}).catch(error => console.log(error));
The param
scopeof the setScope function selects scope to apply to the repository. If it is false, none of the scopes will be applied. If it is undefined, the value will be "default".
When you are calling
repository, you can apply the scope. The scope mode supports these methods of
repository:
find,
findOne,
findOneOrFail,
count、
findByIdsAnd
findAndCount. ```TypeScript import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";
createConnection(/.../).then(async connection => {
const repository = connection.getRepository(Entity); // Delete a entity await repository.find({ scope: 'myScope' });
}).catch(error => console.log(error)); ``
The propertyscope` of the find options selects scope to apply to the repository. If it is false, none of the scopes will be applied. If it is undefined, the value will be "default".
TypeORM's own soft delete functionality utilizes global scopes to only pull "non-deleted" entities from the database.
If the
@DeleteDateColumnis set, the default scope will be "non-deleted".
TypeORM+'s paginator is integrated with the
query builderand
repositoryand provides convenient, easy-to-use pagination of database results out of the box.
In this example, the arguments passed to the paginate method is the current page number and the number of items you would like displayed "per page": ```TypeScript import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";
createConnection(/.../).then(async connection => {
await connection .getRepository(Entity) .createQueryBuilder() .paginate(1, 15) .getMany();
}).catch(error => console.log(error));
TypeORM+'s paginator also supports `raw` mode:TypeScript import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";
createConnection(/.../).then(async connection => {
await connection .getRepository(Entity) .createQueryBuilder() .paginateRaw(1, 15) .getRawMany();
}).catch(error => console.log(error)); ```
You may also paginate queries with the
repository.
import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";createConnection(/.../).then(async connection => {
await connection .getRepository(Entity) .findAndCount({ current: 1, size: 15 })
}).catch(error => console.log(error));
The property
currentof the find options defines an offset page (paginated) where from entities should be taken. And The property
sizeis the alias name for taking, just effected for the conditions that current and size are both defined.
Sometimes you may want clauses to apply to a query only when something else is true. For instance, you may only want to apply a where statement if a given input value is present on the incoming request. You may accomplish this using the when method:
import {createConnection} from "typeorm-plus"; import {Entity} from "./entity";createConnection(/.../).then(async connection => {
await connection .getRepository(Entity) .createQueryBuilder("it") .when(true, qb => qb.where('it.id = 1')) .getMany();
}).catch(error => console.log(error));
The when method only executes the given Closure when the first parameter is true. If the first parameter is false, the Closure will not be executed.
TypeORM+ is MIT licensed.