Skip to content

Commit 2b7fd20

Browse files
Merge pull request #2327 from nestjs/docs/typeorm-v0.3
docs(): update to the latest version of typeorm
2 parents b0d05e1 + d974699 commit 2b7fd20

File tree

1 file changed

+48
-126
lines changed

1 file changed

+48
-126
lines changed

content/techniques/sql.md

Lines changed: 48 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@ For integrating with SQL and NoSQL databases, Nest provides the `@nestjs/typeorm
1313
To begin using it, we first install the required dependencies. In this chapter, we'll demonstrate using the popular [MySQL](https://www.mysql.com/) Relational DBMS, but TypeORM provides support for many relational databases, such as PostgreSQL, Oracle, Microsoft SQL Server, SQLite, and even NoSQL databases like MongoDB. The procedure we walk through in this chapter will be the same for any database supported by TypeORM. You'll simply need to install the associated client API libraries for your selected database.
1414

1515
```bash
16-
$ npm install --save @nestjs/typeorm typeorm@0.2 mysql2
16+
$ npm install --save @nestjs/typeorm typeorm mysql2
1717
```
1818

19-
> warning **Warning** Note that we're using TypeORM v0.2, which isn't the latest version of TypeORM. The latter has substantial modifications and duplicate methods which are used on this page. You can read about `[email protected]` changes [on their repository](https://github.com/typeorm/typeorm/releases/tag/0.3.0).
20-
2119
Once the installation process is complete, we can import the `TypeOrmModule` into the root `AppModule`.
2220

2321
```typescript
@@ -44,7 +42,7 @@ export class AppModule {}
4442

4543
> warning **Warning** Setting `synchronize: true` shouldn't be used in production - otherwise you can lose production data.
4644
47-
The `forRoot()` method supports all the configuration properties exposed by the `createConnection()` function from the [TypeORM](https://typeorm.io/#/connection-options) package. In addition, there are several extra configuration properties described below.
45+
The `forRoot()` method supports all the configuration properties exposed by the `DataSource` constructor from the [TypeORM](https://typeorm.io/data-source-options#common-data-source-options) package. In addition, there are several extra configuration properties described below.
4846

4947
<table>
5048
<tr>
@@ -65,78 +63,37 @@ The `forRoot()` method supports all the configuration properties exposed by the
6563
</tr>
6664
</table>
6765

68-
> info **Hint** Learn more about the connection options [here](https://typeorm.io/#/connection-options).
69-
70-
Alternatively, rather than passing a configuration object to `forRoot()`, we can create an `ormconfig.json` file in the project root directory.
71-
72-
```json
73-
{
74-
"type": "mysql",
75-
"host": "localhost",
76-
"port": 3306,
77-
"username": "root",
78-
"password": "root",
79-
"database": "test",
80-
"entities": ["dist/**/*.entity{.ts,.js}"],
81-
"synchronize": true
82-
}
83-
```
84-
85-
Then, we can call `forRoot()` without any options:
86-
87-
```typescript
88-
@@filename(app.module)
89-
import { Module } from '@nestjs/common';
90-
import { TypeOrmModule } from '@nestjs/typeorm';
91-
92-
@Module({
93-
imports: [TypeOrmModule.forRoot()],
94-
})
95-
export class AppModule {}
96-
```
97-
98-
> warning **Warning** Static glob paths (e.g., `dist/**/*.entity{{ '{' }} .ts,.js{{ '}' }}`) won't work properly with [webpack](https://webpack.js.org/).
66+
> info **Hint** Learn more about the data source options [here](https://typeorm.io/data-source-options).
9967
100-
> info **Hint** Note that the `ormconfig.json` file is loaded by the `typeorm` library. Thus, any of the extra properties described above (which are supported internally by way of the `forRoot()` method - for example, `autoLoadEntities` and `retryDelay`) won't be applied. Luckily, TypeORM provides the [`getConnectionOptions`](https://typeorm.io/#/using-ormconfig/overriding-options-defined-in-ormconfig) function that reads connection options from the `ormconfig` file or environment variables. With this, you can still use the configuration file and set Nest-specific options, as follows:
101-
>
102-
> ```typescript
103-
> TypeOrmModule.forRootAsync({
104-
> useFactory: async () =>
105-
> Object.assign(await getConnectionOptions(), {
106-
> autoLoadEntities: true,
107-
> }),
108-
> });
109-
> ```
110-
111-
Once this is done, the TypeORM `Connection` and `EntityManager` objects will be available to inject across the entire project (without needing to import any modules), for example:
68+
Once this is done, the TypeORM `DataSource` and `EntityManager` objects will be available to inject across the entire project (without needing to import any modules), for example:
11269

11370
```typescript
11471
@@filename(app.module)
115-
import { Connection } from 'typeorm';
72+
import { DataSource } from 'typeorm';
11673

11774
@Module({
11875
imports: [TypeOrmModule.forRoot(), UsersModule],
11976
})
12077
export class AppModule {
121-
constructor(private connection: Connection) {}
78+
constructor(private dataSource: DataSource) {}
12279
}
12380
@@switch
124-
import { Connection } from 'typeorm';
81+
import { DataSource } from 'typeorm';
12582

126-
@Dependencies(Connection)
83+
@Dependencies(DataSource)
12784
@Module({
12885
imports: [TypeOrmModule.forRoot(), UsersModule],
12986
})
13087
export class AppModule {
131-
constructor(connection) {
132-
this.connection = connection;
88+
constructor(dataSource) {
89+
this.dataSource = dataSource;
13390
}
13491
}
13592
```
13693

13794
#### Repository pattern
13895

139-
[TypeORM](https://github.com/typeorm/typeorm) supports the **repository design pattern**, so each entity has its own repository. These repositories can be obtained from the database connection.
96+
[TypeORM](https://github.com/typeorm/typeorm) supports the **repository design pattern**, so each entity has its own repository. These repositories can be obtained from the database data source.
14097

14198
To continue the example, we need at least one entity. Let's define the `User` entity.
14299

@@ -347,9 +304,7 @@ export class User {
347304
348305
#### Auto-load entities
349306

350-
Manually adding entities to the `entities` array of the connection options can be tedious. In addition, referencing entities from the root module breaks application domain boundaries and causes leaking implementation details to other parts of the application. To solve this issue, static glob paths can be used (e.g., `dist/**/*.entity{{ '{' }} .ts,.js{{ '}' }}`).
351-
352-
Note, however, that glob paths are not supported by webpack, so if you are building your application within a monorepo, you won't be able to use them. To address this issue, an alternative solution is provided. To automatically load entities, set the `autoLoadEntities` property of the configuration object (passed into the `forRoot()` method) to `true`, as shown below:
307+
Manually adding entities to the `entities` array of the data source options can be tedious. In addition, referencing entities from the root module breaks application domain boundaries and causes leaking implementation details to other parts of the application. To address this issue, an alternative solution is provided. To automatically load entities, set the `autoLoadEntities` property of the configuration object (passed into the `forRoot()` method) to `true`, as shown below:
353308

354309
```typescript
355310
@@filename(app.module)
@@ -434,22 +389,22 @@ A database transaction symbolizes a unit of work performed within a database man
434389

435390
There are many different strategies to handle [TypeORM transactions](https://typeorm.io/#/transactions). We recommend using the `QueryRunner` class because it gives full control over the transaction.
436391

437-
First, we need to inject the `Connection` object into a class in the normal way:
392+
First, we need to inject the `DataSource` object into a class in the normal way:
438393

439394
```typescript
440395
@Injectable()
441396
export class UsersService {
442-
constructor(private connection: Connection) {}
397+
constructor(private dataSource: DataSource) {}
443398
}
444399
```
445400

446-
> info **Hint** The `Connection` class is imported from the `typeorm` package.
401+
> info **Hint** The `DataSource` class is imported from the `typeorm` package.
447402
448403
Now, we can use this object to create a transaction.
449404

450405
```typescript
451406
async createMany(users: User[]) {
452-
const queryRunner = this.connection.createQueryRunner();
407+
const queryRunner = this.dataSource.createQueryRunner();
453408

454409
await queryRunner.connect();
455410
await queryRunner.startTransaction();
@@ -468,13 +423,13 @@ async createMany(users: User[]) {
468423
}
469424
```
470425

471-
> info **Hint** Note that the `connection` is used only to create the `QueryRunner`. However, to test this class would require mocking the entire `Connection` object (which exposes several methods). Thus, we recommend using a helper factory class (e.g., `QueryRunnerFactory`) and defining an interface with a limited set of methods required to maintain transactions. This technique makes mocking these methods pretty straightforward.
426+
> info **Hint** Note that the `dataSource` is used only to create the `QueryRunner`. However, to test this class would require mocking the entire `DataSource` object (which exposes several methods). Thus, we recommend using a helper factory class (e.g., `QueryRunnerFactory`) and defining an interface with a limited set of methods required to maintain transactions. This technique makes mocking these methods pretty straightforward.
472427
473-
Alternatively, you can use the callback-style approach with the `transaction` method of the `Connection` object ([read more](https://typeorm.io/#/transactions/creating-and-using-transactions)).
428+
Alternatively, you can use the callback-style approach with the `transaction` method of the `DataSource` object ([read more](https://typeorm.io/#/transactions/creating-and-using-transactions)).
474429

475430
```typescript
476431
async createMany(users: User[]) {
477-
await this.connection.transaction(async manager => {
432+
await this.dataSource.transaction(async manager => {
478433
await manager.save(users[0]);
479434
await manager.save(users[1]);
480435
});
@@ -491,7 +446,7 @@ With TypeORM [subscribers](https://typeorm.io/#/listeners-and-subscribers/what-i
491446

492447
```typescript
493448
import {
494-
Connection,
449+
DataSource,
495450
EntitySubscriberInterface,
496451
EventSubscriber,
497452
InsertEvent,
@@ -500,8 +455,8 @@ import { User } from './user.entity';
500455

501456
@EventSubscriber()
502457
export class UserSubscriber implements EntitySubscriberInterface<User> {
503-
constructor(connection: Connection) {
504-
connection.subscribers.push(this);
458+
constructor(dataSource: DataSource) {
459+
dataSource.subscribers.push(this);
505460
}
506461

507462
listenTo() {
@@ -544,7 +499,7 @@ Migration classes are separate from the Nest application source code. Their life
544499

545500
#### Multiple databases
546501

547-
Some projects require multiple database connections. This can also be achieved with this module. To work with multiple connections, first create the connections. In this case, connection naming becomes **mandatory**.
502+
Some projects require multiple database connections. This can also be achieved with this module. To work with multiple connections, first create the connections. In this case, data source naming becomes **mandatory**.
548503

549504
Suppose you have an `Album` entity stored in its own database.
550505

@@ -576,9 +531,9 @@ const defaultOptions = {
576531
export class AppModule {}
577532
```
578533

579-
> warning **Notice** If you don't set the `name` for a connection, its name is set to `default`. Please note that you shouldn't have multiple connections without a name, or with the same name, otherwise they will get overridden.
534+
> warning **Notice** If you don't set the `name` for a data source, its name is set to `default`. Please note that you shouldn't have multiple connections without a name, or with the same name, otherwise they will get overridden.
580535
581-
At this point, you have `User` and `Album` entities registered with their own connection. With this setup, you have to tell the `TypeOrmModule.forFeature()` method and the `@InjectRepository()` decorator which connection should be used. If you do not pass any connection name, the `default` connection is used.
536+
At this point, you have `User` and `Album` entities registered with their own data source. With this setup, you have to tell the `TypeOrmModule.forFeature()` method and the `@InjectRepository()` decorator which data source should be used. If you do not pass any data source name, the `default` data source is used.
582537

583538
```typescript
584539
@Module({
@@ -590,31 +545,31 @@ At this point, you have `User` and `Album` entities registered with their own co
590545
export class AppModule {}
591546
```
592547

593-
You can also inject the `Connection` or `EntityManager` for a given connection:
548+
You can also inject the `DataSource` or `EntityManager` for a given data source:
594549

595550
```typescript
596551
@Injectable()
597552
export class AlbumsService {
598553
constructor(
599554
@InjectConnection('albumsConnection')
600-
private connection: Connection,
555+
private dataSource: DataSource,
601556
@InjectEntityManager('albumsConnection')
602557
private entityManager: EntityManager,
603558
) {}
604559
}
605560
```
606561

607-
It's also possible to inject any `Connection` to the providers:
562+
It's also possible to inject any `DataSource` to the providers:
608563

609564
```typescript
610565
@Module({
611566
providers: [
612567
{
613568
provide: AlbumsService,
614-
useFactory: (albumsConnection: Connection) => {
569+
useFactory: (albumsConnection: DataSource) => {
615570
return new AlbumsService(albumsConnection);
616571
},
617-
inject: [getConnectionToken('albumsConnection')],
572+
inject: [getDataSourceToken('albumsConnection')],
618573
},
619574
],
620575
})
@@ -623,7 +578,7 @@ export class AlbumsModule {}
623578

624579
#### Testing
625580

626-
When it comes to unit testing an application, we usually want to avoid making a database connection, keeping our test suites independent and their execution process as fast as possible. But our classes might depend on repositories that are pulled from the connection instance. How do we handle that? The solution is to create mock repositories. In order to achieve that, we set up [custom providers](/fundamentals/custom-providers). Each registered repository is automatically represented by an `<EntityName>Repository` token, where `EntityName` is the name of your entity class.
581+
When it comes to unit testing an application, we usually want to avoid making a database connection, keeping our test suites independent and their execution process as fast as possible. But our classes might depend on repositories that are pulled from the data source (connection) instance. How do we handle that? The solution is to create mock repositories. In order to achieve that, we set up [custom providers](/fundamentals/custom-providers). Each registered repository is automatically represented by an `<EntityName>Repository` token, where `EntityName` is the name of your entity class.
627582

628583
The `@nestjs/typeorm` package exposes the `getRepositoryToken()` function which returns a prepared token based on a given entity.
629584

@@ -642,39 +597,6 @@ export class UsersModule {}
642597

643598
Now a substitute `mockRepository` will be used as the `UsersRepository`. Whenever any class asks for `UsersRepository` using an `@InjectRepository()` decorator, Nest will use the registered `mockRepository` object.
644599

645-
#### Custom repository
646-
647-
TypeORM provides a feature called **custom repositories**. Custom repositories allow you to extend a base repository class, and enrich it with several special methods. To learn more about this feature, visit [this page](https://typeorm.io/#/custom-repository). Be aware that custom repositories are outside of NestJS's Dependency Injection system, thus you can't inject any values into them.
648-
649-
In order to create your custom repository, use the `@EntityRepository()` decorator and extend the `Repository` class.
650-
651-
```typescript
652-
@EntityRepository(Author)
653-
export class AuthorRepository extends Repository<Author> {}
654-
```
655-
656-
> info **Hint** Both `@EntityRepository()` and `Repository` are imported from the `typeorm` package.
657-
658-
Once the class is created, the next step is to delegate instantiation responsibility to Nest. For this, we have to pass the`AuthorRepository` class to the `TypeOrm.forFeature()` method.
659-
660-
```typescript
661-
@Module({
662-
imports: [TypeOrmModule.forFeature([AuthorRepository])],
663-
controller: [AuthorController],
664-
providers: [AuthorService],
665-
})
666-
export class AuthorModule {}
667-
```
668-
669-
Afterward, simply inject the repository using the following construction:
670-
671-
```typescript
672-
@Injectable()
673-
export class AuthorService {
674-
constructor(private authorRepository: AuthorRepository) {}
675-
}
676-
```
677-
678600
#### Async configuration
679601

680602
You may want to pass your repository module options asynchronously instead of statically. In this case, use the `forRootAsync()` method, which provides several ways to deal with async configuration.
@@ -690,7 +612,7 @@ TypeOrmModule.forRootAsync({
690612
username: 'root',
691613
password: 'root',
692614
database: 'test',
693-
entities: [__dirname + '/**/*.entity{.ts,.js}'],
615+
entities: [],
694616
synchronize: true,
695617
}),
696618
});
@@ -704,11 +626,11 @@ TypeOrmModule.forRootAsync({
704626
useFactory: (configService: ConfigService) => ({
705627
type: 'mysql',
706628
host: configService.get('HOST'),
707-
port: +configService.get<number>('PORT'),
629+
port: +configService.get('PORT'),
708630
username: configService.get('USERNAME'),
709631
password: configService.get('PASSWORD'),
710632
database: configService.get('DATABASE'),
711-
entities: [__dirname + '/**/*.entity{.ts,.js}'],
633+
entities: [],
712634
synchronize: true,
713635
}),
714636
inject: [ConfigService],
@@ -736,7 +658,7 @@ class TypeOrmConfigService implements TypeOrmOptionsFactory {
736658
username: 'root',
737659
password: 'root',
738660
database: 'test',
739-
entities: [__dirname + '/**/*.entity{.ts,.js}'],
661+
entities: [],
740662
synchronize: true,
741663
};
742664
}
@@ -754,40 +676,40 @@ TypeOrmModule.forRootAsync({
754676

755677
This construction works the same as `useClass` with one critical difference - `TypeOrmModule` will lookup imported modules to reuse an existing `ConfigService` instead of instantiating a new one.
756678

757-
> info **Hint** Make sure that the `name` property is defined at the same level as the `useFactory`, `useClass`, or `useValue` property. This will allow Nest to properly register the connection under the appropriate injection token.
679+
> info **Hint** Make sure that the `name` property is defined at the same level as the `useFactory`, `useClass`, or `useValue` property. This will allow Nest to properly register the data source under the appropriate injection token.
758680
759-
#### Custom Connection Factory
681+
#### Custom DataSource Factory
760682

761-
In conjunction with async configuration using `useFactory`, `useClass`, or `useExisting`, you can optionally specify a `connectionFactory` function which will allow you to provide your own TypeORM connection rather than allowing `TypeOrmModule` to create the connection.
683+
In conjunction with async configuration using `useFactory`, `useClass`, or `useExisting`, you can optionally specify a `dataSourceFactory` function which will allow you to provide your own TypeORM data source rather than allowing `TypeOrmModule` to create the data source.
762684

763-
`connectionFactory` receives the TypeORM `ConnectionOptions` configured during async configuration using `useFactory`, `useClass`, or `useExisting` and returns a `Promise` that resolves a TypeORM `Connection`.
685+
`dataSourceFactory` receives the TypeORM `DataSourceOptions` configured during async configuration using `useFactory`, `useClass`, or `useExisting` and returns a `Promise` that resolves a TypeORM `DataSource`.
764686

765687
```typescript
766688
TypeOrmModule.forRootAsync({
767689
imports: [ConfigModule],
768690
inject: [ConfigService],
769691
// Use useFactory, useClass, or useExisting
770-
// to configure the ConnectionOptions.
692+
// to configure the DataSourceOptions.
771693
useFactory: (configService: ConfigService) => ({
772694
type: 'mysql',
773695
host: configService.get('HOST'),
774-
port: +configService.get<number>('PORT'),
696+
port: +configService.get('PORT'),
775697
username: configService.get('USERNAME'),
776698
password: configService.get('PASSWORD'),
777699
database: configService.get('DATABASE'),
778-
entities: [__dirname + '/**/*.entity{.ts,.js}'],
700+
entities: [],
779701
synchronize: true,
780702
}),
781-
// connectionFactory receives the configured ConnectionOptions
782-
// and returns a Promise<Connection>.
783-
connectionFactory: async (options) => {
784-
const connection = await createConnection(options);
785-
return connection;
703+
// dataSource receives the configured DataSourceOptions
704+
// and returns a Promise<DataSource>.
705+
dataSourceFactory: async (options) => {
706+
const dataSource = await new DataSource(options).initialize();
707+
return dataSource;
786708
},
787709
});
788710
```
789711

790-
> info **Hint** The `createConnection` function is imported from the `typeorm` package.
712+
> info **Hint** The `DataSource` class is imported from the `typeorm` package.
791713
792714
#### Example
793715

0 commit comments

Comments
 (0)