diff --git a/docs/decorator-reference.md b/docs/decorator-reference.md index 6a6ede3fa3..c79cd069a8 100644 --- a/docs/decorator-reference.md +++ b/docs/decorator-reference.md @@ -10,6 +10,7 @@ * [`@ObjectIdColumn`](#objectidcolumn) * [`@CreateDateColumn`](#createdatecolumn) * [`@UpdateDateColumn`](#updatedatecolumn) + * [`@DeleteDateColumn`](#deletedatecolumn) * [`@VersionColumn`](#versioncolumn) * [`@Generated`](#generated) * [Relation decorators](#relation-decorators) @@ -93,7 +94,7 @@ View entity is a class that maps to a database view. `expression` can be string with properly escaped columns and tables, depend on database used (postgres in example): ```typescript -@ViewEntity({ +@ViewEntity({ expression: ` SELECT "post"."id" "id", "post"."name" AS "name", "category"."name" AS "categoryName" FROM "post" "post" @@ -106,7 +107,7 @@ export class PostCategory { or an instance of QueryBuilder ```typescript -@ViewEntity({ +@ViewEntity({ expression: (connection: Connection) => connection.createQueryBuilder() .select("post.id", "id") .addSelect("post.name", "name") @@ -120,7 +121,7 @@ export class PostCategory { **Note:** parameter binding is not supported due to drivers limitations. Use the literal parameters instead. ```typescript -@ViewEntity({ +@ViewEntity({ expression: (connection: Connection) => connection.createQueryBuilder() .select("post.id", "id") .addSelect("post.name", "name") @@ -240,7 +241,7 @@ There are two generation strategies: * `increment` - uses AUTO_INCREMENT / SERIAL / SEQUENCE (depend on database type) to generate incremental number. * `uuid` - generates unique `uuid` string. -* `rowid` - only for [CockroachDB](https://www.cockroachlabs.com/docs/stable/serial.html). Value is automatically generated using the `unique_rowid()` +* `rowid` - only for [CockroachDB](https://www.cockroachlabs.com/docs/stable/serial.html). Value is automatically generated using the `unique_rowid()` function. This produces a 64-bit integer from the current timestamp and ID of the node executing the `INSERT` or `UPSERT` operation. > Note: property with a `rowid` generation strategy must be a `string` data type @@ -309,6 +310,24 @@ export class User { } ``` +#### `@DeleteDateColumn` + +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. + +TypeORM's own soft delete functionality utilizes global scopes to only pull "non-deleted" entities from the database. + +If the @DeleteDateColumn is set, the default scope will be "non-deleted". + +```typescript +@Entity() +export class User { + + @DeleteDateColumn() + deletedDate: Date; + +} +``` + #### `@VersionColumn` Special column that is automatically set to the entity's version (incremental number) diff --git a/docs/delete-query-builder.md b/docs/delete-query-builder.md index 0611e7f0c7..8c679ca483 100644 --- a/docs/delete-query-builder.md +++ b/docs/delete-query-builder.md @@ -1,8 +1,15 @@ # Delete using Query Builder +* [Delete using Query Builder](#delete-using-query-builder) + * [`Delete`](#delete) + * [`Soft-Delete`](#soft-delete) + * [`Restore-Soft-Delete`](#restore-soft-delete) + +### `Delete` + You can create `DELETE` queries using `QueryBuilder`. Examples: - + ```typescript import {getConnection} from "typeorm"; @@ -14,4 +21,42 @@ await getConnection() .execute(); ``` -This is the most efficient way in terms of performance to delete entities from your database. +This is the most efficient way in terms of performance to delete entities from your database. + +--- + +### `Soft-Delete` + +Applying Soft Delete to QueryBuilder + +```typescript +import {createConnection} from "typeorm"; +import {Entity} from "./entity"; + +createConnection(/*...*/).then(async connection => { + + await connection + .getRepository(Entity) + .createQueryBuilder() + .softDelete() + +}).catch(error => console.log(error)); +``` + +### `Restore-Soft-Delete` + +Alternatively, You can recover the soft deleted rows by using the `restore()` method: + +```typescript +import {createConnection} from "typeorm"; +import {Entity} from "./entity"; + +createConnection(/*...*/).then(async connection => { + + await connection + .getRepository(Entity) + .createQueryBuilder() + .restore() + +}).catch(error => console.log(error)); +``` diff --git a/docs/many-to-many-relations.md b/docs/many-to-many-relations.md index ce522a43a6..77de926695 100644 --- a/docs/many-to-many-relations.md +++ b/docs/many-to-many-relations.md @@ -115,6 +115,45 @@ await connection.manager.save(question) This will only remove the record in the join table. The `question` and `categoryToRemove` records will still exist. +## Soft Deleting a relationship with cascade + +This example show what the cascading soft deletes behaves + +```typescript +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 save or softRemove for category1 and category2. But They will be automatically saved and soft-deleted when the cascade of relation options is set to true like this: + +```typescript +import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm"; +import {Category} from "./Category"; + +@Entity() +export class Question { + + @PrimaryGeneratedColumn() + id: number; + + @ManyToMany(type => Category, category => category.questions, { + cascade: true + }) + @JoinTable() + categories: Category[]; + +} +``` + ## Loading many-to-many relations To load question with categories inside you must specify relation in `FindOptions`: @@ -201,7 +240,7 @@ const categoriesWithQuestions = await connection ## many-to-many relations with custom properties -In case you need to have additional properties to your many-to-many relationship you have to create a new entity yourself. +In case you need to have additional properties to your many-to-many relationship you have to create a new entity yourself. For example if you would like entities `Post` and `Category` to have a many-to-many relationship with additional `order` column, you need to create entity `PostToCategory` with two `ManyToOne` relations pointing in both directions and custom columns in it: ```typescript @@ -216,10 +255,10 @@ export class PostToCategory { @Column() public postId!: number; - + @Column() public categoryId!: number; - + @Column() public order!: number; diff --git a/docs/repository-api.md b/docs/repository-api.md index 00a3d6fd7f..22c84794be 100644 --- a/docs/repository-api.md +++ b/docs/repository-api.md @@ -51,7 +51,7 @@ const users = await repository } ``` -* `getId` - Gets the primary column property values of the given entity. +* `getId` - Gets the primary column property values of the given entity. If entity has composite primary keys then the returned value will be an object with names and values of primary columns. ```typescript @@ -135,12 +135,12 @@ await repository.insert({ }); -await manager.insert(User, [{ - firstName: "Foo", - lastName: "Bar" -}, { - firstName: "Rizz", - lastName: "Rak" +await manager.insert(User, [{ + firstName: "Foo", + lastName: "Bar" +}, { + firstName: "Rizz", + lastName: "Rak" }]); ``` @@ -162,6 +162,27 @@ await repository.delete([1, 2, 3]); await repository.delete({ firstName: "Timber" }); ``` +* `softDelete` and `restore` - Soft deleting and restoring a row by id + +```typescript +const repository = connection.getRepository(Entity); +// Delete a entity +await repository.softDelete(1); +// And You can restore it using restore; +await repository.restore(1); +``` + +* `softRemove` and `recover` - This is alternative to `softDelete` and `restore`. +```typescript +// 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); +``` + + * `count` - Counts entities that match given options. Useful for pagination. ```typescript