220 changes: 117 additions & 103 deletions docs/find-options.md

Large diffs are not rendered by default.

89 changes: 39 additions & 50 deletions docs/indices.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Indices

* [Column indices](#column-indices)
* [Unique indices](#unique-indices)
* [Indices with multiple columns](#indices-with-multiple-columns)
* [Spatial Indices](#spatial-indices)
* [Disabling synchronization](#disabling-synchronization)
- [Column indices](#column-indices)
- [Unique indices](#unique-indices)
- [Indices with multiple columns](#indices-with-multiple-columns)
- [Spatial Indices](#spatial-indices)
- [Disabling synchronization](#disabling-synchronization)

## Column indices

Expand All @@ -13,42 +13,40 @@ You can create indices for any columns of your entity.
Example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, Index} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column, Index } from "typeorm"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Index()
@Column()
firstName: string;
firstName: string

@Column()
@Index()
lastName: string;
lastName: string
}
```

You can also specify an index name:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, Index} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column, Index } from "typeorm"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Index("name1-idx")
@Column()
firstName: string;
firstName: string

@Column()
@Index("name2-idx")
lastName: string;
lastName: string
}
```

Expand All @@ -59,21 +57,20 @@ To create an unique index you need to specify `{ unique: true }` in the index op
> Note: CockroachDB stores unique indices as `UNIQUE` constraints
```typescript
import {Entity, PrimaryGeneratedColumn, Column, Index} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column, Index } from "typeorm"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Index({ unique: true })
@Column()
firstName: string;
firstName: string

@Column()
@Index({ unique: true })
lastName: string;
lastName: string
}
```

Expand All @@ -84,34 +81,31 @@ and specify all column property names which should be included in the index.
Example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, Index} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column, Index } from "typeorm"

@Entity()
@Index(["firstName", "lastName"])
@Index(["firstName", "middleName", "lastName"], { unique: true })
export class User {

@PrimaryGeneratedColumn()
id: number;

@Column()
firstName: string;
id: number

@Column()
middleName: string;
firstName: string

@Column()
lastName: string;
middleName: string

@Column()
lastName: string
}
```

## Spatial Indices

MySQL and PostgreSQL (when PostGIS is available) both support spatial indices.

To create a spatial index on a column in MySQL, add an `Index` with `spatial:
true` on a column that uses a spatial type (`geometry`, `point`, `linestring`,
To create a spatial index on a column in MySQL, add an `Index` with `spatial: true` on a column that uses a spatial type (`geometry`, `point`, `linestring`,
`polygon`, `multipoint`, `multilinestring`, `multipolygon`,
`geometrycollection`):

Expand All @@ -120,26 +114,26 @@ true` on a column that uses a spatial type (`geometry`, `point`, `linestring`,
export class Thing {
@Column("point")
@Index({ spatial: true })
point: string;
point: string
}
```

To create a spatial index on a column in PostgreSQL, add an `Index` with `spatial: true` on a column that uses a spatial type (`geometry`, `geography`):

```typescript
export interface Geometry {
type: "Point";
coordinates: [Number, Number];
type: "Point"
coordinates: [Number, Number]
}

@Entity()
export class Thing {
@Column("geometry", {
spatialFeatureType: "Point",
srid: 4326
spatialFeatureType: "Point",
srid: 4326,
})
@Index({ spatial: true })
point: Geometry;
point: Geometry
}
```

Expand All @@ -162,15 +156,10 @@ after that, you should disable synchronization for this index to avoid deletion
@Entity()
@Index("POST_NAME_INDEX", { synchronize: false })
export class Post {

@PrimaryGeneratedColumn()
id: number;

@Column()
name: string;
id: number

@Column()
name: string
}
```



27 changes: 11 additions & 16 deletions docs/insert-query-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,34 @@ You can create `INSERT` queries using `QueryBuilder`.
Examples:

```typescript
import {getConnection} from "typeorm";

await getConnection()
await dataSource
.createQueryBuilder()
.insert()
.into(User)
.values([
{ firstName: "Timber", lastName: "Saw" },
{ firstName: "Phantom", lastName: "Lancer" }
])
.execute();
{ firstName: "Timber", lastName: "Saw" },
{ firstName: "Phantom", lastName: "Lancer" },
])
.execute()
```

This is the most efficient way in terms of performance to insert rows into your database.
You can also perform bulk insertions this way.

### Raw SQL support
### Raw SQL support

In some cases when you need to execute SQL queries you need to use function style value:


```typescript
import {getConnection} from "typeorm";

await getConnection()
await dataSource
.createQueryBuilder()
.insert()
.into(User)
.values({
firstName: "Timber",
lastName: () => "CONCAT('S', 'A', 'W')"
.values({
firstName: "Timber",
lastName: () => "CONCAT('S', 'A', 'W')",
})
.execute();
.execute()
```

This syntax doesn't escape your values, you need to handle escape on your own.
4 changes: 2 additions & 2 deletions docs/internals.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Internals

This guide explains how things are working in TypeORM.
This guide explains how things are working in TypeORM.
It will be useful for our contributors.

TBD.
TBD.
106 changes: 53 additions & 53 deletions docs/listeners-and-subscribers.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Entity Listeners and Subscribers

- [Entity Listeners and Subscribers](#entity-listeners-and-subscribers)
- [What is an Entity Listener](#what-is-an-entity-listener)
- [`@AfterLoad`](#afterload)
- [`@BeforeInsert`](#beforeinsert)
- [`@AfterInsert`](#afterinsert)
- [`@BeforeUpdate`](#beforeupdate)
- [`@AfterUpdate`](#afterupdate)
- [`@BeforeRemove`](#beforeremove)
- [`@AfterRemove`](#afterremove)
- [`@BeforeSoftRemove`](#beforesoftremove)
- [`@AfterSoftRemove`](#aftersoftremove)
- [`@BeforeRecover`](#beforerecover)
- [`@AfterRecover`](#afterrecover)
- [What is a Subscriber](#what-is-a-subscriber)
- [`Event Object`](#event-object)
- [Entity Listeners and Subscribers](#entity-listeners-and-subscribers)
- [What is an Entity Listener](#what-is-an-entity-listener)
- [`@AfterLoad`](#afterload)
- [`@BeforeInsert`](#beforeinsert)
- [`@AfterInsert`](#afterinsert)
- [`@BeforeUpdate`](#beforeupdate)
- [`@AfterUpdate`](#afterupdate)
- [`@BeforeRemove`](#beforeremove)
- [`@AfterRemove`](#afterremove)
- [`@BeforeSoftRemove`](#beforesoftremove)
- [`@AfterSoftRemove`](#aftersoftremove)
- [`@BeforeRecover`](#beforerecover)
- [`@AfterRecover`](#afterrecover)
- [What is a Subscriber](#what-is-a-subscriber)
- [`Event Object`](#event-object)

## What is an Entity Listener

Expand All @@ -35,7 +35,7 @@ Example:
export class Post {
@AfterLoad()
updateCounters() {
if (this.likesCount === undefined) this.likesCount = 0;
if (this.likesCount === undefined) this.likesCount = 0
}
}
```
Expand All @@ -51,7 +51,7 @@ Example:
export class Post {
@BeforeInsert()
updateDates() {
this.createdDate = new Date();
this.createdDate = new Date()
}
}
```
Expand All @@ -67,7 +67,7 @@ Example:
export class Post {
@AfterInsert()
resetCounters() {
this.counters = 0;
this.counters = 0
}
}
```
Expand All @@ -83,7 +83,7 @@ Example:
export class Post {
@BeforeUpdate()
updateDates() {
this.updatedDate = new Date();
this.updatedDate = new Date()
}
}
```
Expand All @@ -99,7 +99,7 @@ Example:
export class Post {
@AfterUpdate()
updateCounters() {
this.counter = 0;
this.counter = 0
}
}
```
Expand All @@ -115,7 +115,7 @@ Example:
export class Post {
@BeforeRemove()
updateStatus() {
this.status = "removed";
this.status = "removed"
}
}
```
Expand All @@ -131,7 +131,7 @@ Example:
export class Post {
@AfterRemove()
updateStatus() {
this.status = "removed";
this.status = "removed"
}
}
```
Expand All @@ -147,7 +147,7 @@ Example:
export class Post {
@BeforeSoftRemove()
updateStatus() {
this.status = "soft-removed";
this.status = "soft-removed"
}
}
```
Expand All @@ -163,7 +163,7 @@ Example:
export class Post {
@AfterSoftRemove()
updateStatus() {
this.status = "soft-removed";
this.status = "soft-removed"
}
}
```
Expand All @@ -179,7 +179,7 @@ Example:
export class Post {
@BeforeRecover()
updateStatus() {
this.status = "recovered";
this.status = "recovered"
}
}
```
Expand All @@ -195,7 +195,7 @@ Example:
export class Post {
@AfterSoftRemove()
updateStatus() {
this.status = "recovered";
this.status = "recovered"
}
}
```
Expand All @@ -213,14 +213,14 @@ export class PostSubscriber implements EntitySubscriberInterface<Post> {
* Indicates that this subscriber only listen to Post events.
*/
listenTo() {
return Post;
return Post
}

/**
* Called before post insertion.
*/
beforeInsert(event: InsertEvent<Post>) {
console.log(`BEFORE POST INSERTED: `, event.entity);
console.log(`BEFORE POST INSERTED: `, event.entity)
}
}
```
Expand All @@ -235,35 +235,35 @@ export class PostSubscriber implements EntitySubscriberInterface {
* Called after entity is loaded.
*/
afterLoad(entity: any) {
console.log(`AFTER ENTITY LOADED: `, entity);
console.log(`AFTER ENTITY LOADED: `, entity)
}

/**
* Called before post insertion.
*/
beforeInsert(event: InsertEvent<any>) {
console.log(`BEFORE POST INSERTED: `, event.entity);
console.log(`BEFORE POST INSERTED: `, event.entity)
}

/**
* Called after entity insertion.
*/
afterInsert(event: InsertEvent<any>) {
console.log(`AFTER ENTITY INSERTED: `, event.entity);
console.log(`AFTER ENTITY INSERTED: `, event.entity)
}

/**
* Called before entity update.
*/
beforeUpdate(event: UpdateEvent<any>) {
console.log(`BEFORE ENTITY UPDATED: `, event.entity);
console.log(`BEFORE ENTITY UPDATED: `, event.entity)
}

/**
* Called after entity update.
*/
afterUpdate(event: UpdateEvent<any>) {
console.log(`AFTER ENTITY UPDATED: `, event.entity);
console.log(`AFTER ENTITY UPDATED: `, event.entity)
}

/**
Expand All @@ -272,8 +272,8 @@ export class PostSubscriber implements EntitySubscriberInterface {
beforeRemove(event: RemoveEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `,
event.entity
);
event.entity,
)
}

/**
Expand All @@ -282,8 +282,8 @@ export class PostSubscriber implements EntitySubscriberInterface {
afterRemove(event: RemoveEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `,
event.entity
);
event.entity,
)
}

/**
Expand All @@ -292,8 +292,8 @@ export class PostSubscriber implements EntitySubscriberInterface {
beforeSoftRemove(event: SoftRemoveEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} SOFT REMOVED: `,
event.entity
);
event.entity,
)
}

/**
Expand All @@ -302,8 +302,8 @@ export class PostSubscriber implements EntitySubscriberInterface {
afterSoftRemove(event: SoftRemoveEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} SOFT REMOVED: `,
event.entity
);
event.entity,
)
}

/**
Expand All @@ -312,8 +312,8 @@ export class PostSubscriber implements EntitySubscriberInterface {
beforeRecover(event: RecoverEvent<any>) {
console.log(
`BEFORE ENTITY WITH ID ${event.entityId} RECOVERED: `,
event.entity
);
event.entity,
)
}

/**
Expand All @@ -322,61 +322,61 @@ export class PostSubscriber implements EntitySubscriberInterface {
afterRecover(event: RecoverEvent<any>) {
console.log(
`AFTER ENTITY WITH ID ${event.entityId} RECOVERED: `,
event.entity
);
event.entity,
)
}

/**
* Called before transaction start.
*/
beforeTransactionStart(event: TransactionStartEvent) {
console.log(`BEFORE TRANSACTION STARTED: `, event);
console.log(`BEFORE TRANSACTION STARTED: `, event)
}

/**
* Called after transaction start.
*/
afterTransactionStart(event: TransactionStartEvent) {
console.log(`AFTER TRANSACTION STARTED: `, event);
console.log(`AFTER TRANSACTION STARTED: `, event)
}

/**
* Called before transaction commit.
*/
beforeTransactionCommit(event: TransactionCommitEvent) {
console.log(`BEFORE TRANSACTION COMMITTED: `, event);
console.log(`BEFORE TRANSACTION COMMITTED: `, event)
}

/**
* Called after transaction commit.
*/
afterTransactionCommit(event: TransactionCommitEvent) {
console.log(`AFTER TRANSACTION COMMITTED: `, event);
console.log(`AFTER TRANSACTION COMMITTED: `, event)
}

/**
* Called before transaction rollback.
*/
beforeTransactionRollback(event: TransactionRollbackEvent) {
console.log(`BEFORE TRANSACTION ROLLBACK: `, event);
console.log(`BEFORE TRANSACTION ROLLBACK: `, event)
}

/**
* Called after transaction rollback.
*/
afterTransactionRollback(event: TransactionRollbackEvent) {
console.log(`AFTER TRANSACTION ROLLBACK: `, event);
console.log(`AFTER TRANSACTION ROLLBACK: `, event)
}
}
```

Make sure your `subscribers` property is set in your [Connection Options](./connection-options.md#common-connection-options) so TypeORM loads your subscriber.
Make sure your `subscribers` property is set in your [DataSourceOptions](./data-source-options.md#common-data-source-options) so TypeORM loads your subscriber.

### `Event Object`

Excluding `listenTo`, all `EntitySubscriberInterface` methods are passed an event object that has the following base properties:

- `connection: Connection` - Connection used in the event.
- `dataSource: DataSource` - DataSource used in the event.
- `queryRunner: QueryRunner` - QueryRunner used in the event transaction.
- `manager: EntityManager` - EntityManager used in the event transaction.

Expand Down
79 changes: 30 additions & 49 deletions docs/logging.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Logging

* [Enabling logging](#enabling-logging)
* [Logging options](#logging-options)
* [Log long-running queries](#log-long-running-queries)
* [Changing default logger](#changing-default-logger)
* [Using custom logger](#using-custom-logger)
- [Enabling logging](#enabling-logging)
- [Logging options](#logging-options)
- [Log long-running queries](#log-long-running-queries)
- [Changing default logger](#changing-default-logger)
- [Using custom logger](#using-custom-logger)

## Enabling logging

You can enable logging of all queries and errors by simply setting `logging: true` in your connection options:
You can enable logging of all queries and errors by simply setting `logging: true` in data source options:

```typescript
{
Expand All @@ -26,10 +26,10 @@ You can enable logging of all queries and errors by simply setting `logging: tru

## Logging options

You can enable different types of logging in connection options:
You can enable different types of logging in data source options:

```typescript
{
{
host: "localhost",
...
logging: ["query", "error"]
Expand All @@ -48,14 +48,14 @@ If you want to enable logging of failed queries only then only add `error`:

There are other options you can use:

* `query` - logs all queries.
* `error` - logs all failed queries and errors.
* `schema` - logs the schema build process.
* `warn` - logs internal orm warnings.
* `info` - logs internal orm informative messages.
* `log` - logs internal orm log messages.
- `query` - logs all queries.
- `error` - logs all failed queries and errors.
- `schema` - logs the schema build process.
- `warn` - logs internal orm warnings.
- `info` - logs internal orm informative messages.
- `log` - logs internal orm log messages.

You can specify as many options as needed.
You can specify as many options as needed.
If you want to enable all logging you can simply specify `logging: "all"`:

```typescript
Expand All @@ -69,7 +69,7 @@ If you want to enable all logging you can simply specify `logging: "all"`:
## Log long-running queries

If you have performance issues, you can log queries that take too much time to execute
by setting `maxQueryExecutionTime` in connection options:
by setting `maxQueryExecutionTime` in data source options:

```typescript
{
Expand All @@ -85,14 +85,14 @@ This code will log all queries which run more then `1 second`.

TypeORM ships with 4 different types of logger:

* `advanced-console` - this is the default logger which logs all messages into the console using color
and sql syntax highlighting (using [chalk](https://github.com/chalk/chalk)).
* `simple-console` - this is a simple console logger which is exactly the same as the advanced logger, but it does not use any color highlighting.
This logger can be used if you have problems / or don't like colorized logs.
* `file` - this logger writes all logs into `ormlogs.log` in the root folder of your project (near `package.json` and `ormconfig.json`).
* `debug` - this logger uses [debug package](https://github.com/visionmedia/debug), to turn on logging set your env variable `DEBUG=typeorm:*` (note logging option has no effect on this logger).
- `advanced-console` - this is the default logger which logs all messages into the console using color
and sql syntax highlighting (using [chalk](https://github.com/chalk/chalk)).
- `simple-console` - this is a simple console logger which is exactly the same as the advanced logger, but it does not use any color highlighting.
This logger can be used if you have problems / or don't like colorized logs.
- `file` - this logger writes all logs into `ormlogs.log` in the root folder of your project (near `package.json`).
- `debug` - this logger uses [debug package](https://github.com/visionmedia/debug), to turn on logging set your env variable `DEBUG=typeorm:*` (note logging option has no effect on this logger).

You can enable any of them in connection options:
You can enable any of them in data source options:

```typescript
{
Expand All @@ -108,48 +108,29 @@ You can enable any of them in connection options:
You can create your own logger class by implementing the `Logger` interface:

```typescript
import {Logger} from "typeorm";
import { Logger } from "typeorm"

export class MyCustomLogger implements Logger {

// implement all methods from logger class

}
```

And specify it in connection options:
And specify it in data source options:

```typescript
import {createConnection} from "typeorm";
import {MyCustomLogger} from "./logger/MyCustomLogger";
import { DataSource } from "typeorm"
import { MyCustomLogger } from "./logger/MyCustomLogger"

createConnection({
const dataSource = new DataSource({
name: "mysql",
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
logger: new MyCustomLogger()
});
```

If you defined your connection options in the `ormconfig` file,
then you can use it and override it in the following way:

```typescript
import {createConnection, getConnectionOptions} from "typeorm";
import {MyCustomLogger} from "./logger/MyCustomLogger";

// getConnectionOptions will read options from your ormconfig file
// and return it in connectionOptions object
// then you can simply append additional properties to it
getConnectionOptions().then(connectionOptions => {
return createConnection(Object.assign(connectionOptions, {
logger: new MyCustomLogger()
}))
});
logger: new MyCustomLogger(),
})
```

Logger methods can accept `QueryRunner` when it's available. It's helpful if you want to log additional data.
Expand Down
172 changes: 97 additions & 75 deletions docs/many-to-many-relations.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Many-to-many relations

* [What are many-to-many relations](#what-are-many-to-many-relations)
* [Saving many-to-many relations](#saving-many-to-many-relations)
* [Deleting many-to-many relations](#deleting-many-to-many-relations)
* [Loading many-to-many relations](#loading-many-to-many-relations)
* [Bi-directional relations](#bi-directional-relations)
* [Many-to-many relations with custom properties](#many-to-many-relations-with-custom-properties)
- [What are many-to-many relations](#what-are-many-to-many-relations)
- [Saving many-to-many relations](#saving-many-to-many-relations)
- [Deleting many-to-many relations](#deleting-many-to-many-relations)
- [Loading many-to-many relations](#loading-many-to-many-relations)
- [Bi-directional relations](#bi-directional-relations)
- [Many-to-many relations with custom properties](#many-to-many-relations-with-custom-properties)

## What are many-to-many relations

Expand All @@ -14,36 +14,42 @@ Let's take for example `Question` and `Category` entities.
A question can have multiple categories, and each category can have multiple questions.

```typescript
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
name: string
}
```

```typescript
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
import { Category } from "./Category";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;
text: string

@ManyToMany(() => Category)
@JoinTable()
categories: Category[];
categories: Category[]
}
```

Expand Down Expand Up @@ -81,19 +87,19 @@ This example will produce following tables:
With [cascades](./relations.md#cascades) enabled, you can save this relation with only one `save` call.

```typescript
const category1 = new Category();
category1.name = "animals";
await connection.manager.save(category1);

const category2 = new Category();
category2.name = "zoo";
await connection.manager.save(category2);

const question = new Question();
question.title = "dogs";
question.text = "who let the dogs out?";
question.categories = [category1, category2];
await connection.manager.save(question);
const category1 = new Category()
category1.name = "animals"
await dataSource.manager.save(category1)

const category2 = new Category()
category2.name = "zoo"
await dataSource.manager.save(category2)

const question = new Question()
question.title = "dogs"
question.text = "who let the dogs out?"
question.categories = [category1, category2]
await dataSource.manager.save(question)
```

## Deleting many-to-many relations
Expand All @@ -103,11 +109,11 @@ With [cascades](./relations.md#cascades) enabled, you can delete this relation w
To delete a many-to-many relationship between two records, remove it from the corresponding field and save the record.

```typescript
const question = getRepository(Question);
question.categories = question.categories.filter(category => {
const question = dataSource.getRepository(Question)
question.categories = question.categories.filter((category) => {
return category.id !== categoryToRemove.id
})
await connection.manager.save(question)
await dataSource.manager.save(question)
```

This will only remove the record in the join table. The `question` and `categoryToRemove` records will still exist.
Expand All @@ -117,35 +123,41 @@ This will only remove the record in the join table. The `question` and `category
This example shows how the cascading soft delete behaves:

```typescript
const category1 = new Category();
category1.name = "animals";
const category1 = new Category()
category1.name = "animals"

const category2 = new Category();
category2.name = "zoo";
const category2 = new Category()
category2.name = "zoo"

const question = new Question();
question.categories = [category1, category2];
const newQuestion = await connection.manager.save(question);
const question = new Question()
question.categories = [category1, category2]
const newQuestion = await dataSource.manager.save(question)

await connection.manager.softRemove(newQuestion);
await dataSource.manager.softRemove(newQuestion)
```

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";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
id: number

@ManyToMany(() => Category, category => category.questions, {
cascade: true
@ManyToMany(() => Category, (category) => category.questions, {
cascade: true,
})
@JoinTable()
categories: Category[];
categories: Category[]
}
```

Expand All @@ -154,18 +166,22 @@ export class Question {
To load questions with categories inside you must specify the relation in `FindOptions`:

```typescript
const questionRepository = connection.getRepository(Question);
const questions = await questionRepository.find({ relations: ["categories"] });
const questionRepository = dataSource.getRepository(Question)
const questions = await questionRepository.find({
relations: {
categories: true,
},
})
```

Or using `QueryBuilder` you can join them:

```typescript
const questions = await connection
const questions = await dataSource
.getRepository(Question)
.createQueryBuilder("question")
.leftJoinAndSelect("question.categories", "category")
.getMany();
.getMany()
```

With eager loading enabled on a relation, you don't have to specify relations in the find command as it will ALWAYS be loaded automatically. If you use QueryBuilder eager relations are disabled, you have to use `leftJoinAndSelect` to load the relation.
Expand All @@ -179,40 +195,46 @@ Bi-directional relations are relations with decorators on both sides of a relati
We just created a uni-directional relation. Let's make it bi-directional:

```typescript
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm";
import { Question } from "./Question";
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm"
import { Question } from "./Question"

@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
name: string

@ManyToMany(() => Question, question => question.categories)
questions: Question[];
@ManyToMany(() => Question, (question) => question.categories)
questions: Question[]
}
```

```typescript
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
import { Category } from "./Category";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;
text: string

@ManyToMany(() => Category, category => category.questions)
@ManyToMany(() => Category, (category) => category.questions)
@JoinTable()
categories: Category[];
categories: Category[]
}
```

Expand All @@ -222,11 +244,11 @@ We just made our relation bi-directional. Note that the inverse relation does no
Bi-directional relations allow you to join relations from both sides using `QueryBuilder`:

```typescript
const categoriesWithQuestions = await connection
const categoriesWithQuestions = await dataSource
.getRepository(Category)
.createQueryBuilder("category")
.leftJoinAndSelect("category.questions", "question")
.getMany();
.getMany()
```

## Many-to-many relations with custom properties
Expand All @@ -235,29 +257,29 @@ In case you need to have additional properties in your many-to-many relationship
For example, if you would like entities `Post` and `Category` to have a many-to-many relationship with an additional `order` column, then you need to create an entity `PostToCategory` with two `ManyToOne` relations pointing in both directions and with custom columns in it:

```typescript
import { Entity, Column, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { Post } from "./post";
import { Category } from "./category";
import { Entity, Column, ManyToOne, PrimaryGeneratedColumn } from "typeorm"
import { Post } from "./post"
import { Category } from "./category"

@Entity()
export class PostToCategory {
@PrimaryGeneratedColumn()
public postToCategoryId!: number;
public postToCategoryId!: number

@Column()
public postId!: number;
public postId!: number

@Column()
public categoryId!: number;
public categoryId!: number

@Column()
public order!: number;
public order!: number

@ManyToOne(() => Post, post => post.postToCategories)
public post!: Post;
@ManyToOne(() => Post, (post) => post.postToCategories)
public post!: Post

@ManyToOne(() => Category, category => category.postToCategories)
public category!: Category;
@ManyToOne(() => Category, (category) => category.postToCategories)
public category!: Category
}
```

Expand Down
102 changes: 53 additions & 49 deletions docs/many-to-one-one-to-many-relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,36 @@ Let's take for example `User` and `Photo` entities.
User can have multiple photos, but each photo is owned by only one single user.

```typescript
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "typeorm";
import {User} from "./User";
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm"
import { User } from "./User"

@Entity()
export class Photo {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
url: string;

@ManyToOne(() => User, user => user.photos)
user: User;
url: string

@ManyToOne(() => User, (user) => user.photos)
user: User
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "typeorm";
import {Photo} from "./Photo";
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"
import { Photo } from "./Photo"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;

@OneToMany(() => Photo, photo => photo.user)
photos: Photo[];
name: string

@OneToMany(() => Photo, (photo) => photo.user)
photos: Photo[]
}
```

Expand Down Expand Up @@ -70,68 +66,76 @@ This example will produce following tables:
Example how to save such relation:

```typescript
const photo1 = new Photo();
photo1.url = "me.jpg";
await connection.manager.save(photo1);

const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await connection.manager.save(photo2);

const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
await connection.manager.save(user);
const photo1 = new Photo()
photo1.url = "me.jpg"
await dataSource.manager.save(photo1)

const photo2 = new Photo()
photo2.url = "me-and-bears.jpg"
await dataSource.manager.save(photo2)

const user = new User()
user.name = "John"
user.photos = [photo1, photo2]
await dataSource.manager.save(user)
```

or alternatively you can do:

```typescript
const user = new User();
user.name = "Leo";
await connection.manager.save(user);

const photo1 = new Photo();
photo1.url = "me.jpg";
photo1.user = user;
await connection.manager.save(photo1);

const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
photo2.user = user;
await connection.manager.save(photo2);
const user = new User()
user.name = "Leo"
await dataSource.manager.save(user)

const photo1 = new Photo()
photo1.url = "me.jpg"
photo1.user = user
await dataSource.manager.save(photo1)

const photo2 = new Photo()
photo2.url = "me-and-bears.jpg"
photo2.user = user
await dataSource.manager.save(photo2)
```

With [cascades](./relations.md#cascades) enabled you can save this relation with only one `save` call.

To load a user with photos inside you must specify the relation in `FindOptions`:

```typescript
const userRepository = connection.getRepository(User);
const users = await userRepository.find({ relations: ["photos"] });
const userRepository = dataSource.getRepository(User)
const users = await userRepository.find({
relations: {
photos: true,
},
})

// or from inverse side

const photoRepository = connection.getRepository(Photo);
const photos = await photoRepository.find({ relations: ["user"] });
const photoRepository = dataSource.getRepository(Photo)
const photos = await photoRepository.find({
relations: {
user: true,
},
})
```

Or using `QueryBuilder` you can join them:

```typescript
const users = await connection
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.photos", "photo")
.getMany();
.getMany()

// or from inverse side

const photos = await connection
const photos = await dataSource
.getRepository(Photo)
.createQueryBuilder("photo")
.leftJoinAndSelect("photo.user", "user")
.getMany();
.getMany()
```

With eager loading enabled on a relation, you don't have to specify relations in the find command as it will ALWAYS be loaded automatically.
Expand Down
434 changes: 230 additions & 204 deletions docs/migrations.md

Large diffs are not rendered by default.

244 changes: 104 additions & 140 deletions docs/mongodb.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,51 @@
# MongoDB

* [MongoDB support](#mongodb-support)
* [Defining entities and columns](#defining-entities-and-columns)
* [Defining subdocuments (embed documents)](#defining-subdocuments-embed-documents)
* [Using `MongoEntityManager` and `MongoRepository`](#using-mongoentitymanager-and-mongorepository)
- [MongoDB support](#mongodb-support)
- [Defining entities and columns](#defining-entities-and-columns)
- [Defining subdocuments (embed documents)](#defining-subdocuments-embed-documents)
- [Using `MongoEntityManager` and `MongoRepository`](#using-mongoentitymanager-and-mongorepository)

## MongoDB support

TypeORM has basic MongoDB support.
Most of TypeORM functionality is RDBMS-specific,
Most of TypeORM functionality is RDBMS-specific,
this page contains all MongoDB-specific functionality documentation.

## Defining entities and columns

Defining entities and columns is almost the same as in relational databases,
the main difference is that you must use `@ObjectIdColumn`
Defining entities and columns is almost the same as in relational databases,
the main difference is that you must use `@ObjectIdColumn`
instead of `@PrimaryColumn` or `@PrimaryGeneratedColumn`.

Simple entity example:

```typescript
import {Entity, ObjectID, ObjectIdColumn, Column} from "typeorm";
import { Entity, ObjectID, ObjectIdColumn, Column } from "typeorm"

@Entity()
export class User {

@ObjectIdColumn()
id: ObjectID;
id: ObjectID

@Column()
firstName: string;
firstName: string

@Column()
lastName: string;

lastName: string
}
```

And this is how you bootstrap the app:

```typescript
import {createConnection, Connection} from "typeorm";
import { DataSource } from "typeorm"

const connection: Connection = await createConnection({
const myDataSource = new DataSource({
type: "mongodb",
host: "localhost",
port: 27017,
database: "test"
});
database: "test",
})
```

## Defining subdocuments (embed documents)
Expand All @@ -56,88 +54,82 @@ Since MongoDB stores objects and objects inside objects (or documents inside doc
you can do the same in TypeORM:

```typescript
import {Entity, ObjectID, ObjectIdColumn, Column} from "typeorm";
import { Entity, ObjectID, ObjectIdColumn, Column } from "typeorm"

export class Profile {

@Column()
about: string;
about: string

@Column()
education: string;
education: string

@Column()
career: string;

career: string
}
```

```typescript
import {Entity, ObjectID, ObjectIdColumn, Column} from "typeorm";
import { Entity, ObjectID, ObjectIdColumn, Column } from "typeorm"

export class Photo {

@Column()
url: string;
url: string

@Column()
description: string;
description: string

@Column()
size: number;
size: number

constructor(url: string, description: string, size: number) {
this.url = url;
this.description = description;
this.size = size;
this.url = url
this.description = description
this.size = size
}

}
```

```typescript
import {Entity, ObjectID, ObjectIdColumn, Column} from "typeorm";
import { Entity, ObjectID, ObjectIdColumn, Column } from "typeorm"

@Entity()
export class User {

@ObjectIdColumn()
id: ObjectID;
id: ObjectID

@Column()
firstName: string;
firstName: string

@Column()
lastName: string;

@Column(type => Profile)
profile: Profile;

@Column(type => Photo)
photos: Photo[];

lastName: string

@Column((type) => Profile)
profile: Profile

@Column((type) => Photo)
photos: Photo[]
}
```

If you save this entity:

```typescript
import {getMongoManager} from "typeorm";

const user = new User();
user.firstName = "Timber";
user.lastName = "Saw";
user.profile = new Profile();
user.profile.about = "About Trees and Me";
user.profile.education = "Tree School";
user.profile.career = "Lumberjack";
import { getMongoManager } from "typeorm"

const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.profile = new Profile()
user.profile.about = "About Trees and Me"
user.profile.education = "Tree School"
user.profile.career = "Lumberjack"
user.photos = [
new Photo("me-and-trees.jpg", "Me and Trees", 100),
new Photo("me-and-chakram.jpg", "Me and Chakram", 200),
];
]

const manager = getMongoManager();
await manager.save(user);
const manager = getMongoManager()
await manager.save(user)
```

Following document will be saved in the database:
Expand Down Expand Up @@ -172,130 +164,103 @@ You can use the majority of methods inside the `EntityManager` (except for RDBMS
For example:

```typescript
import {getManager} from "typeorm";

const manager = getManager(); // or connection.manager
const timber = await manager.findOne(User, { firstName: "Timber", lastName: "Saw" });
const timber = await myDataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
```

For MongoDB there is also a separate `MongoEntityManager` which extends `EntityManager`.

```typescript
import {getMongoManager} from "typeorm";

const manager = getMongoManager(); // or connection.mongoManager
const timber = await manager.findOne(User, { firstName: "Timber", lastName: "Saw" });
const timber = await myDataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
```

Just like separate like `MongoEntityManager` there is a `MongoRepository` with extended `Repository`:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User); // or connection.getMongoRepository
const timber = await userRepository.findOne({ firstName: "Timber", lastName: "Saw" });
const timber = await myDataSource.getMongoRepository(User).findOneBy({
firstName: "Timber",
lastName: "Saw",
})
```

Use Advanced options in find():

Equal:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
const timber = await userRepository.find({
where: {
firstName: {$eq: "Timber"},
}
});
const timber = await myDataSource.getMongoRepository(User).find({
where: {
firstName: { $eq: "Timber" },
},
})
```

LessThan:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
const timber = await userRepository.find({
where: {
age: {$lt: 60},
}
});
const timber = await myDataSource.getMongoRepository(User).find({
where: {
age: { $lt: 60 },
},
})
```

In:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
const timber = await userRepository.find({
where: {
firstName: {$in: ["Timber","Zhang"]},
}
});
const timber = await myDataSource.getMongoRepository(User).find({
where: {
firstName: { $in: ["Timber", "Zhang"] },
},
})
```

Not in:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
const timber = await userRepository.find({
where: {
firstName: {$not: {$in: ["Timber","Zhang"]}},
}
});
const timber = await myDataSource.getMongoRepository(User).find({
where: {
firstName: { $not: { $in: ["Timber", "Zhang"] } },
},
})
```

Or:

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
const timber = await userRepository.find({
where: {
$or: [
{firstName:"Timber"},
{firstName:"Zhang"}
]
}
});
const timber = await myDataSource.getMongoRepository(User).find({
where: {
$or: [{ firstName: "Timber" }, { firstName: "Zhang" }],
},
})
```

Querying subdocuments

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
// Query users with education Tree School
const users = await userRepository.find({
where: {
'profile.education': { $eq: "Tree School"}
}
});
const users = await myDataSource.getMongoRepository(User).find({
where: {
"profile.education": { $eq: "Tree School" },
},
})
```

Querying Array of subdocuments

```typescript
import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User);
// Query users with photos of size less than 500
const users = await userRepository.find({
where: {
'photos.size': { $lt: 500}
}
});

const users = await myDataSource.getMongoRepository(User).find({
where: {
"photos.size": { $lt: 500 },
},
})
```


Both `MongoEntityManager` and `MongoRepository` contain lot of useful MongoDB-specific methods:

#### `createCursor`
Expand Down Expand Up @@ -439,4 +404,3 @@ Updates multiple documents within the collection based on the filter.
#### `updateOne`

Updates a single document within the collection based on the filter.

172 changes: 63 additions & 109 deletions docs/multiple-connections.md
Original file line number Diff line number Diff line change
@@ -1,130 +1,87 @@
# Multiple connections, databases, schemas and replication setup
# Multiple data sources, databases, schemas and replication setup

* [Using multiple connections](#using-multiple-connections)
* [Using multiple databases in a single connection](#using-multiple-databases-in-a-single-connection)
* [Using multiple schemas in a single connection](#using-multiple-schemas-in-a-single-connection)
* [Replication](#replication)
- [Using multiple data sources](#using-multiple-data-sources)
- [Using multiple databases in a single data source](#using-multiple-databases-within-a-single-data-source)
- [Using multiple schemas in a single data source](#using-multiple-schemas-within-a-single-data-source)
- [Replication](#replication)

## Using multiple data sources

## Using multiple connections

The simplest way to use multiple databases is to create different connections:
To use multiple data sources connected to different databases, simply create multiple DataSource instances:

```typescript
import {createConnections} from "typeorm";
import { DataSource } from "typeorm"

const connections = await createConnections([{
name: "db1Connection",
const db1DataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "db1",
entities: [__dirname + "/entity/*{.js,.ts}"],
synchronize: true
}, {
name: "db2Connection",
synchronize: true,
})

const db2DataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "db2",
entities: [__dirname + "/entity/*{.js,.ts}"],
synchronize: true
}]);
```

This approach allows you to connect to any number of databases you have
and each database will have its own configuration, own entities and overall ORM scope and settings.

For each connection a new `Connection` instance will be created.
You must specify a unique name for each connection you create.

The connection options can also be loaded from an ormconfig file. You can load all connections from
the ormconfig file:
```typescript
import {createConnections} from "typeorm";

const connections = await createConnections();
```

or you can specify which connection to create by name:
```typescript
import {createConnection} from "typeorm";

const connection = await createConnection("db2Connection");
```

When working with connections you must specify a connection name to get a specific connection:

```typescript
import {getConnection} from "typeorm";

const db1Connection = getConnection("db1Connection");
// you can work with "db1" database now...

const db2Connection = getConnection("db2Connection");
// you can work with "db2" database now...
synchronize: true,
})
```

Benefit of using this approach is that you can configure multiple connections with different login credentials,
host, port and even database type itself.
Downside for might be that you'll need to manage and work with multiple connection instances.
## Using multiple databases within a single data source

## Using multiple databases in a single connection

If you don't want to create multiple connections,
but want to use multiple databases in a single connection,
you can specify database name per-entity you use:
To use multiple databases in a single data source,
you can specify database name per-entity:

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ database: "secondDB" })
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
firstName: string;
firstName: string

@Column()
lastName: string;

lastName: string
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ database: "thirdDB" })
export class Photo {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
url: string;

url: string
}
```

`User` entity will be created inside `secondDB` database and `Photo` entity inside `thirdDB` database.
All other entities will be created in default connection database.
All other entities will be created in a default database defined in the data source options.

If you want to select data from a different database you only need to provide an entity:

```typescript
const users = await connection
const users = await dataSource
.createQueryBuilder()
.select()
.from(User, "user")
.addFrom(Photo, "photo")
.andWhere("photo.userId = user.id")
.getMany(); // userId is not a foreign key since its cross-database request
.getMany() // userId is not a foreign key since its cross-database request
```

This code will produce following SQL query (depend on database type):
Expand All @@ -137,67 +94,63 @@ SELECT * FROM "secondDB"."user" "user", "thirdDB"."photo" "photo"
You can also specify a table path instead of the entity:

```typescript
const users = await connection
const users = await dataSource
.createQueryBuilder()
.select()
.from("secondDB.user", "user")
.addFrom("thirdDB.photo", "photo")
.andWhere("photo.userId = user.id")
.getMany(); // userId is not a foreign key since its cross-database request
.getMany() // userId is not a foreign key since its cross-database request
```

This feature is supported only in mysql and mssql databases.

## Using multiple schemas in a single connection
## Using multiple schemas within a single data source

You can use multiple schemas in your applications, just set `schema` on each entity:
To use multiple schemas in your applications, just set `schema` on each entity:

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ schema: "secondSchema" })
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
firstName: string;
firstName: string

@Column()
lastName: string;

lastName: string
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ schema: "thirdSchema" })
export class Photo {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
url: string;

url: string
}
```

`User` entity will be created inside `secondSchema` schema and `Photo` entity inside `thirdSchema` schema.
All other entities will be created in default connection schema.
All other entities will be created in a default database defined in the data source options.

If you want to select data from a different schema you only need to provide an entity:

```typescript
const users = await connection
const users = await dataSource
.createQueryBuilder()
.select()
.from(User, "user")
.addFrom(Photo, "photo")
.andWhere("photo.userId = user.id")
.getMany(); // userId is not a foreign key since its cross-database request
.getMany() // userId is not a foreign key since its cross-database request
```

This code will produce following SQL query (depend on database type):
Expand All @@ -207,43 +160,41 @@ SELECT * FROM "secondSchema"."question" "question", "thirdSchema"."photo" "photo
WHERE "photo"."userId" = "user"."id"
```

You can also specify a table path instead of the entity:
You can also specify a table path instead of entity:

```typescript
const users = await connection
const users = await dataSource
.createQueryBuilder()
.select()
.from("secondSchema.user", "user") // in mssql you can even specify a database: secondDB.secondSchema.user
.addFrom("thirdSchema.photo", "photo") // in mssql you can even specify a database: thirdDB.thirdSchema.photo
.andWhere("photo.userId = user.id")
.getMany();
.getMany()
```

This feature is supported only in postgres and mssql databases.
In mssql you can also combine schemas and databases, for example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ database: "secondDB", schema: "public" })
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
firstName: string;
firstName: string

@Column()
lastName: string;

lastName: string
}
```

## Replication

You can setup read/write replication using TypeORM.
Example of replication connection settings:
You can set up read/write replication using TypeORM.
Example of replication options:

```typescript
{
Expand Down Expand Up @@ -281,26 +232,29 @@ All queries performed by query method are performed using the `master` instance.
If you want to explicitly use master in SELECT created by query builder, you can use the following code:

```typescript
const masterQueryRunner = connection.createQueryRunner("master");
const masterQueryRunner = dataSource.createQueryRunner("master")
try {
const postsFromMaster = await connection.createQueryBuilder(Post, "post")
const postsFromMaster = await dataSource
.createQueryBuilder(Post, "post")
.setQueryRunner(masterQueryRunner)
.getMany();
.getMany()
} finally {
await masterQueryRunner.release();
await masterQueryRunner.release()
}

```

If you want to use `slave` in raw queries, you also need to explicitly specify the query runner.

```typescript

const slaveQueryRunner = connection.createQueryRunner("slave");
const slaveQueryRunner = dataSource.createQueryRunner("slave")
try {
const userFromSlave = await slaveQueryRunner.query('SELECT * FROM users WHERE id = $1', [userId], slaveQueryRunner);
const userFromSlave = await slaveQueryRunner.query(
"SELECT * FROM users WHERE id = $1",
[userId],
slaveQueryRunner,
)
} finally {
return slaveQueryRunner.release();
return slaveQueryRunner.release()
}
```

Expand Down
29 changes: 0 additions & 29 deletions docs/naming-strategy.md

This file was deleted.

99 changes: 53 additions & 46 deletions docs/one-to-one-relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,42 @@ Let's take for example `User` and `Profile` entities.
User can have only a single profile, and a single profile is owned by only a single user.

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class Profile {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
gender: string;
gender: string

@Column()
photo: string;

photo: string
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
import {Profile} from "./Profile";
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
name: string

@OneToOne(() => Profile)
@JoinColumn()
profile: Profile;

profile: Profile
}
```

Expand Down Expand Up @@ -71,34 +73,37 @@ Again, `@JoinColumn` must be set only on one side of relation - the side that mu
Example how to save such a relation:

```typescript
const profile = new Profile();
profile.gender = "male";
profile.photo = "me.jpg";
await connection.manager.save(profile);

const user = new User();
user.name = 'Joe Smith';
user.profile = profile;
await connection.manager.save(user);
const profile = new Profile()
profile.gender = "male"
profile.photo = "me.jpg"
await dataSource.manager.save(profile)

const user = new User()
user.name = "Joe Smith"
user.profile = profile
await dataSource.manager.save(user)
```

With [cascades](./relations.md#cascades) enabled you can save this relation with only one `save` call.

To load user with profile inside you must specify relation in `FindOptions`:

```typescript
const userRepository = connection.getRepository(User);
const users = await userRepository.find({ relations: ["profile"] });
const users = await dataSource.getRepository(User).find({
relations: {
profile: true,
},
})
```

Or using `QueryBuilder` you can join them:

```typescript
const users = await connection
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.profile", "profile")
.getMany();
.getMany()
```

With eager loading enabled on a relation, you don't have to specify relations in the find command as it will ALWAYS be loaded automatically. If you use QueryBuilder eager relations are disabled, you have to use `leftJoinAndSelect` to load the relation.
Expand All @@ -110,56 +115,58 @@ Bi-directional are relations with decorators on both sides of a relation.
We just created a uni-directional relation. Let's make it bi-directional:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToOne} from "typeorm";
import {User} from "./User";
import { Entity, PrimaryGeneratedColumn, Column, OneToOne } from "typeorm"
import { User } from "./User"

@Entity()
export class Profile {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
gender: string;
gender: string

@Column()
photo: string;

@OneToOne(() => User, user => user.profile) // specify inverse side as a second parameter
user: User;
photo: string

@OneToOne(() => User, (user) => user.profile) // specify inverse side as a second parameter
user: User
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
import {Profile} from "./Profile";
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
name: string

@OneToOne(() => Profile, profile => profile.user) // specify inverse side as a second parameter
@OneToOne(() => Profile, (profile) => profile.user) // specify inverse side as a second parameter
@JoinColumn()
profile: Profile;

profile: Profile
}
```

We just made our relation bi-directional. Note, inverse relation does not have a `@JoinColumn`.
`@JoinColumn` must only be on one side of the relation - on the table that will own the foreign key.
`@JoinColumn` must only be on one side of the relation - on the table that will own the foreign key.

Bi-directional relations allow you to join relations from both sides using `QueryBuilder`:

```typescript
const profiles = await connection
const profiles = await dataSource
.getRepository(Profile)
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.user", "user")
.getMany();
.getMany()
```
79 changes: 29 additions & 50 deletions docs/query-runner.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,52 @@
# Working with Query Runner

* [What is `QueryRunner`](#what-is-queryrunner)
* [Creating a queryRunner](#creating-a-new-queryrunner)
* [Using queryRunner](#using-queryrunner)
* [Working with `QueryRunner`](#working-with-queryrunner)

## What is `QueryRunner`
- [What is `QueryRunner`](#what-is-queryrunner)
- [Creating a new `QueryRunner` instance](#creating-a-new-queryrunner-instance)
- [Using `QueryRunner`](#using-queryrunner)

Your interaction with the database is only possible once you setup a connection.
TypeORM's `Connection` does not setup a database connection as it might seem, instead it sets up a connection pool.
If you are interested in a real database connection, you should use `QueryRunner`.
Each instance of `QueryRunner` is a separate isolated database connection. Using query runners you can control your queries to execute using single database connection and manually control your database transaction.
## What is `QueryRunner`

## Creating a new queryRunner
Each new `QueryRunner` instance takes a single connection from connection pool, if RDBMS supports connection pooling.
For databases not supporting connection pools, it uses the same connection across data source.

To create a new instance of `QueryRunner` you should first create a connection pool, in any of the ways described on the `Connection` documentation. Once a connection has established, use the `createQueryRunner` function to create an isolated connection.
## Creating a new `QueryRunner` instance

`createQueryRunner` Creates a query runner used to perform queries on a single database connection.

Use `createQueryRunner` method to create a new `QueryRunner`:

```typescript
import { getConnection, QueryRunner } from 'typeorm';
// can be used once createConnection is called and is resolved
const connection: Connection = getConnection();

const queryRunner: QueryRunner = connection.createQueryRunner();
const queryRunner = dataSource.createQueryRunner()
```
## Using queryRunner

After creating an instance of `QueryRunner` use connect to activate the connection.
## Using `QueryRunner`

```typescript
import { getConnection, QueryRunner } from 'typeorm';
// can be used once createConnection is called and is resolved
const connection: Connection = getConnection();

const queryRunner: QueryRunner = connection.createQueryRunner();
After you create a new instance of `QueryRunner` use `connect` method to actually obtain a connection from the connection pool:

await queryRunner.connect(); // performs connection
```typescript
const queryRunner = dataSource.createQueryRunner()
await queryRunner.connect()
```

Since the `QueryRunner` is used to manage an isolated database connection, make sure to release it when it is not needed anymore to make it available to the connection pool again. After connection is released it is not possible to use the query runner methods.

## Working with `QueryRunner`

Once you set your queryRunner up, you can use it with an interface similar to the `Connection` interface:
**Important**: make sure to release it when it is not needed anymore to make it available to the connection pool again:

```typescript
import { getConnection, QueryRunner } from 'typeorm';
import { User } from "../entity/User";

export class UserController {
await queryRunner.release()
```

After connection is released it is not possible to use the query runner methods.

@Get("/users")
getAll(): Promise<User[]> {
// can be used once createConnection is called and is resolved
const connection: Connection = getConnection();
`QueryRunner` has bunch of methods you can use, it also has it's own `EntityManager` instance,
which you can use through `manager` property in order to run `EntityManager` methods on a particular database connection
used by `QueryRunner` instance:

const queryRunner: QueryRunner = connection.createQueryRunner();
```typescript
const queryRunner = connection.createQueryRunner()

await queryRunner.connect(); // performs connection
// take a connection from the connection pool
await queryRunner.connect()

const users = await queryRunner.manager.find(User);

await queryRunner.release(); // release connection

return users;
}
// use this particular connection to execut queries
const users = await queryRunner.manager.find(User)

}
// don't forget to release connection after you are done using it
await queryRunner.release()
```
79 changes: 34 additions & 45 deletions docs/relational-query-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,36 @@ or you can load related entities easily.

For example, we have a `Post` entity and it has a many-to-many relation to `Category` called `categories`.
Let's add a new category to this many-to-many relation:

```typescript
import {getConnection} from "typeorm";

await getConnection()
```typescript
await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of(post)
.add(category);
.add(category)
```

This code is equivalent to doing this:

```typescript
import {getRepository} from "typeorm";

const postRepository = getRepository(Post);
const post = await postRepository.findOne(1, { relations: ["categories"] });
post.categories.push(category);
await postRepository.save(post);
```typescript
const postRepository = dataSource.manager.getRepository(Post)
const post = await postRepository.findOne({
where: {
id: 1,
},
relations: {
categories: true,
},
})
post.categories.push(category)
await postRepository.save(post)
```

But more efficient, because it does a minimal number of operations, and binds entities in the database,
unlike calling a bulky `save` method call.

Also, another benefit of such an approach is that you don't need to load every related entity before pushing into it.
For example, if you have ten thousand categories inside a single post, adding new posts to this list may become problematic for you,
For example, if you have ten thousand categories inside a single post, adding new posts to this list may become problematic for you,
because the standard way of doing this is to load the post with all ten thousand categories, push a new category,
and save it. This results in very heavy performance costs and is basically inapplicable in production results.
However, using `RelationQueryBuilder` solves this problem.
Expand All @@ -41,85 +44,71 @@ Also, there is no real need to use entities when you "bind" things, since you ca
For example, let's add a category with id = 3 into post with id = 1:

```typescript
import {getConnection} from "typeorm";

await getConnection()
.createQueryBuilder()
.relation(Post, "categories")
.of(1)
.add(3);
await dataSource.createQueryBuilder().relation(Post, "categories").of(1).add(3)
```

If you are using composite primary keys, you have to pass them as an id map, for example:

```typescript
import {getConnection} from "typeorm";

await getConnection()
await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of({ firstPostId: 1, secondPostId: 3 })
.add({ firstCategoryId: 2, secondCategoryId: 4 });
.add({ firstCategoryId: 2, secondCategoryId: 4 })
```

You can remove entities the same way you add them:

```typescript
import {getConnection} from "typeorm";
You can remove entities the same way you add them:

```typescript
// this code removes a category from a given post
await getConnection()
await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of(post) // you can use just post id as well
.remove(category); // you can use just category id as well
.remove(category) // you can use just category id as well
```

Adding and removing related entities works in `many-to-many` and `one-to-many` relations.
For `one-to-one` and `many-to-one` relations use `set` instead:

```typescript
import {getConnection} from "typeorm";

// this code sets category of a given post
await getConnection()
await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of(post) // you can use just post id as well
.set(category); // you can use just category id as well
.set(category) // you can use just category id as well
```

If you want to unset a relation (set it to null), simply pass `null` to a `set` method:

```typescript
import {getConnection} from "typeorm";

// this code unsets category of a given post
await getConnection()
await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of(post) // you can use just post id as well
.set(null);
.set(null)
```

Besides updating relations, the relational query builder also allows you to load relational entities.
For example, lets say inside a `Post` entity we have a many-to-many `categories` relation and a many-to-one `user` relation,
to load those relations you can use following code:

```typescript
import {getConnection} from "typeorm";

const post = await getConnection().manager.findOne(Post, 1);
const post = await dataSource.manager.findOneBy(Post, {
id: 1,
})

post.categories = await getConnection()
post.categories = await dataSource
.createQueryBuilder()
.relation(Post, "categories")
.of(post) // you can use just post id as well
.loadMany();
.loadMany()

post.author = await getConnection()
post.author = await dataSource
.createQueryBuilder()
.relation(Post, "user")
.of(post) // you can use just post id as well
.loadOne();
.loadOne()
```
180 changes: 99 additions & 81 deletions docs/relations-faq.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Relations FAQ

* [How to create self referencing relation](#how-to-create-self-referencing-relation)
* [How to use relation id without joining relation](#how-to-use-relation-id-without-joining-relation)
* [How to load relations in entities](#how-to-load-relations-in-entities)
* [Avoid relation property initializers](#avoid-relation-property-initializers)
* [Avoid foreign key constraint creation](#avoid-foreign-key-constraint-creation)
- [How to create self referencing relation](#how-to-create-self-referencing-relation)
- [How to use relation id without joining relation](#how-to-use-relation-id-without-joining-relation)
- [How to load relations in entities](#how-to-load-relations-in-entities)
- [Avoid relation property initializers](#avoid-relation-property-initializers)
- [Avoid foreign key constraint creation](#avoid-foreign-key-constraint-creation)

## How to create self referencing relation

Expand All @@ -13,78 +13,84 @@ This is useful when you are storing entities in a tree-like structures.
Also "adjacency list" pattern is implemented using self-referenced relations.
For example, you want to create categories tree in your application.
Categories can nest categories, nested categories can nest other categories, etc.
Self-referencing relations come handy here.
Self-referencing relations come handy here.
Basically self-referencing relations are just regular relations that targets entity itself.
Example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany} from "typeorm";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
OneToMany,
} from "typeorm"

@Entity()
export class Category {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;

@ManyToOne(type => Category, category => category.childCategories)
parentCategory: Category;

@OneToMany(type => Category, category => category.parentCategory)
childCategories: Category[];

text: string

@ManyToOne((type) => Category, (category) => category.childCategories)
parentCategory: Category

@OneToMany((type) => Category, (category) => category.parentCategory)
childCategories: Category[]
}
```

## How to use relation id without joining relation

Sometimes you want to have, in your object, the id of the related object without loading it.
Sometimes you want to have, in your object, the id of the related object without loading it.
For example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class Profile {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
gender: string;
gender: string

@Column()
photo: string;

photo: string
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
import {Profile} from "./Profile";
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
@OneToOne(type => Profile)
name: string

@OneToOne((type) => Profile)
@JoinColumn()
profile: Profile;

profile: Profile
}
```

When you load a user without `profile` joined you won't have any information about profile in your user object,
When you load a user without `profile` joined you won't have any information about profile in your user object,
even profile id:

```javascript
Expand All @@ -99,25 +105,29 @@ To do this you just need to add another property to your entity with `@Column`
named exactly as the column created by your relation. Example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
import {Profile} from "./Profile";
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;
name: string

@Column({ nullable: true })
profileId: number;
@OneToOne(type => Profile)
profileId: number

@OneToOne((type) => Profile)
@JoinColumn()
profile: Profile;

profile: Profile
}
```

Expand All @@ -134,24 +144,30 @@ User {
## How to load relations in entities

The easiest way to load your entity relations is to use `relations` option in `FindOptions`:

```typescript
const users = await connection.getRepository(User).find({ relations: ["profile", "photos", "videos"] });
const users = await dataSource.getRepository(User).find({
relations: {
profile: true,
photos: true,
videos: true,
},
})
```

Alternative and more flexible way is to use `QueryBuilder`:

```typescript
const user = await connection
const user = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.profile", "profile")
.leftJoinAndSelect("user.photos", "photo")
.leftJoinAndSelect("user.videos", "video")
.getMany();
.getMany()
```

Using `QueryBuilder` you can do `innerJoinAndSelect` instead of `leftJoinAndSelect`
Using `QueryBuilder` you can do `innerJoinAndSelect` instead of `leftJoinAndSelect`
(to learn the difference between `LEFT JOIN` and `INNER JOIN` refer to your SQL documentation),
you can join relation data by a condition, make ordering, etc.

Expand All @@ -162,25 +178,29 @@ Learn more about [`QueryBuilder`](select-query-builder.md).
Sometimes it is useful to initialize your relation properties, for example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm";
import {Category} from "./Category";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;
@ManyToMany(type => Category, category => category.questions)
text: string

@ManyToMany((type) => Category, (category) => category.questions)
@JoinTable()
categories: Category[] = []; // see = [] initialization here

categories: Category[] = [] // see = [] initialization here
}
```

Expand Down Expand Up @@ -210,7 +230,7 @@ Question {
When you save the object it will check if there are any categories in the database bind to the question -
and it will detach all of them. Why? Because relation equal to `[]` or any items inside it will be considered
like something was removed from it, there is no other way to check if an object was removed from entity or not.

Therefore, saving an object like this will bring you problems - it will remove all previously set categories.

How to avoid this behaviour? Simply don't initialize arrays in your entities.
Expand All @@ -222,25 +242,23 @@ Sometimes for performance reasons you might want to have a relation between enti
You can define if foreign key constraint should be created with `createForeignKeyConstraints` option (default: true).

```typescript
import {Entity, PrimaryColumn, Column, ManyToOne} from "typeorm";
import {Person} from "./Person";
import { Entity, PrimaryColumn, Column, ManyToOne } from "typeorm"
import { Person } from "./Person"

@Entity()
export class ActionLog {

@PrimaryColumn()
id: number;
id: number

@Column()
date: Date;
date: Date

@Column()
action: string;
@ManyToOne(type => Person, {
createForeignKeyConstraints: false
action: string

@ManyToOne((type) => Person, {
createForeignKeyConstraints: false,
})
person: Person;

person: Person
}
```
116 changes: 58 additions & 58 deletions docs/relations.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,93 @@
# Relations

* [What are relations](#what-are-relations)
* [Relation options](#relation-options)
* [Cascades](#cascades)
* [`@JoinColumn` options](#joincolumn-options)
* [`@JoinTable` options](#jointable-options)
- [What are relations](#what-are-relations)
- [Relation options](#relation-options)
- [Cascades](#cascades)
- [`@JoinColumn` options](#joincolumn-options)
- [`@JoinTable` options](#jointable-options)

## What are relations

Relations helps you to work with related entities easily.
There are several types of relations:

* [one-to-one](./one-to-one-relations.md) using `@OneToOne`
* [many-to-one](./many-to-one-one-to-many-relations.md) using `@ManyToOne`
* [one-to-many](./many-to-one-one-to-many-relations.md) using `@OneToMany`
* [many-to-many](./many-to-many-relations.md) using `@ManyToMany`
- [one-to-one](./one-to-one-relations.md) using `@OneToOne`
- [many-to-one](./many-to-one-one-to-many-relations.md) using `@ManyToOne`
- [one-to-many](./many-to-one-one-to-many-relations.md) using `@OneToMany`
- [many-to-many](./many-to-many-relations.md) using `@ManyToMany`

## Relation options

There are several options you can specify for relations:

* `eager: boolean` - If set to true, the relation will always be loaded with the main entity when using `find*` methods or `QueryBuilder` on this entity
* `cascade: boolean | ("insert" | "update")[]` - If set to true, the related object will be inserted and updated in the database. You can also specify an array of [cascade options](#cascade-options).
* `onDelete: "RESTRICT"|"CASCADE"|"SET NULL"` - specifies how foreign key should behave when referenced object is deleted
* `primary: boolean` - Indicates whether this relation's column will be a primary column or not.
* `nullable: boolean` - Indicates whether this relation's column is nullable or not. By default it is nullable.
* `orphanedRowAction: "nullify" | "delete" | "soft-delete"` - When a child row is removed from its parent, determines if the child row should be orphaned (default) or deleted (delete or soft delete).
- `eager: boolean` - If set to true, the relation will always be loaded with the main entity when using `find*` methods or `QueryBuilder` on this entity
- `cascade: boolean | ("insert" | "update")[]` - If set to true, the related object will be inserted and updated in the database. You can also specify an array of [cascade options](#cascade-options).
- `onDelete: "RESTRICT"|"CASCADE"|"SET NULL"` - specifies how foreign key should behave when referenced object is deleted
- `nullable: boolean` - Indicates whether this relation's column is nullable or not. By default it is nullable.
- `orphanedRowAction: "nullify" | "delete" | "soft-delete"` - When a child row is removed from its parent, determines if the child row should be orphaned (default) or deleted (delete or soft delete).

## Cascades

Cascades example:

```typescript
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany} from "typeorm";
import {Question} from "./Question";
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm"
import { Question } from "./Question"

@Entity()
export class Category {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
name: string;

@ManyToMany(type => Question, question => question.categories)
questions: Question[];
name: string

@ManyToMany((type) => Question, (question) => question.categories)
questions: Question[]
}
```

```typescript
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm";
import {Category} from "./Category";
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;
text: string

@ManyToMany(type => Category, category => category.questions, {
cascade: true
@ManyToMany((type) => Category, (category) => category.questions, {
cascade: true,
})
@JoinTable()
categories: Category[];

categories: Category[]
}
```

```typescript
const category1 = new Category();
category1.name = "ORMs";
const category1 = new Category()
category1.name = "ORMs"

const category2 = new Category();
category2.name = "Programming";
const category2 = new Category()
category2.name = "Programming"

const question = new Question();
question.title = "How to ask questions?";
question.text = "Where can I ask TypeORM-related questions?";
question.categories = [category1, category2];
await connection.manager.save(question);
const question = new Question()
question.title = "How to ask questions?"
question.text = "Where can I ask TypeORM-related questions?"
question.categories = [category1, category2]
await dataSource.manager.save(question)
```

As you can see in this example we did not call `save` for `category1` and `category2`.
Expand All @@ -108,47 +109,46 @@ For example:
```typescript
@Entity(Post)
export class Post {

@PrimaryGeneratedColumn()
id: number;
id: number

@Column()
title: string;
title: string

@Column()
text: string;
text: string

// Full cascades on categories.
@ManyToMany(type => PostCategory, {
cascade: true
@ManyToMany((type) => PostCategory, {
cascade: true,
})
@JoinTable()
categories: PostCategory[];
categories: PostCategory[]

// Cascade insert here means if there is a new PostDetails instance set
// on this relation, it will be inserted automatically to the db when you save this Post entity
@ManyToMany(type => PostDetails, details => details.posts, {
cascade: ["insert"]
@ManyToMany((type) => PostDetails, (details) => details.posts, {
cascade: ["insert"],
})
@JoinTable()
details: PostDetails[];
details: PostDetails[]

// Cascade update here means if there are changes to an existing PostImage, it
// will be updated automatically to the db when you save this Post entity
@ManyToMany(type => PostImage, image => image.posts, {
cascade: ["update"]
@ManyToMany((type) => PostImage, (image) => image.posts, {
cascade: ["update"],
})
@JoinTable()
images: PostImage[];
images: PostImage[]

// Cascade insert & update here means if there are new PostInformation instances
// or an update to an existing one, they will be automatically inserted or updated
// when you save this Post entity
@ManyToMany(type => PostInformation, information => information.posts, {
cascade: ["insert", "update"]
@ManyToMany((type) => PostInformation, (information) => information.posts, {
cascade: ["insert", "update"],
})
@JoinTable()
informations: PostInformation[];
informations: PostInformation[]
}
```

Expand Down
Loading