Skip to content

Commit f2cde67

Browse files
authored
feat(Feat/typeorm migration available): Implement TypeORM migration (#39)
* Chore: Add NODE_ENV to env type * feat: Refactor TypeORM configuration and integrate with ConfigModule * Feat: Add TypeORM migration scripts to package.json * Chore: Add example env file * Chore: Remove useless remark * Docs: Update migration setup and usage instructions * Docs: Add README for migration files location
1 parent e47dbfe commit f2cde67

File tree

9 files changed

+880
-780
lines changed

9 files changed

+880
-780
lines changed

.example.env

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
DB_HOST =
2+
DB_PORT =
3+
DB_USER =
4+
DB_PASSWORD =
5+
DB_NAME =
6+
PORT =
7+
JWT_PRIVATE_KEY =
8+
JWT_PUBLIC_KEY =
9+
JWT_REFRESH_TOKEN_PRIVATE_KEY =

README.md

+55
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,61 @@ Base NestJS, We like it
1616
We use [Nestjs/TypeORM](https://docs.nestjs.com/techniques/database)
1717
In this template, We've been trying not to use `Pure SQL` to make the most of TypeORM.
1818

19+
### Migration setup and usage
20+
21+
This project uses TypeORM's migration feature to manage database schema changes. Follow the steps below to generate and apply migrations.
22+
23+
> **Note**
24+
>
25+
> 1. The custom `typeorm` command defined in `package.json` is configured for `NODE_ENV=production`.
26+
> 2. Migrations are intended for production use, while `typeorm synchronize` should be used for development purposes.
27+
> 3. You can see the detailed configuration code [here](/src/common/config/ormconfig.ts)
28+
> 4. As you can see from the configuration code, migration files must be located in the subdirectory of `/src/common/database/migrations/${name}`.
29+
30+
#### 1. Generate a migration file
31+
32+
To reflect new changes in the database, you need to first generate a migration file.
33+
34+
```bash
35+
yarn migration:generate ./src/common/database/migrations/init
36+
```
37+
38+
you can change the name of migration by replacing `init`
39+
40+
#### 2. Run the Migration
41+
42+
To apply the generated migration to the database, run the following command:
43+
44+
```bash
45+
yarn migration:run
46+
```
47+
48+
#### 3. Revert a Migration
49+
50+
To roll back the last applied migration, use the following command:
51+
52+
```bash
53+
yarn migration:revert
54+
```
55+
56+
#### 4. Check Migration Status
57+
58+
To view the current status of your migrations, run:
59+
60+
```bash
61+
yarn migration:show
62+
```
63+
64+
#### Create Migration Command
65+
66+
You can also directly create a migration file using the following `typeorm` command:
67+
68+
```bash
69+
yarn migration:create ./src/common/database/migrations/init
70+
```
71+
72+
This command generates an empty migration file where you can manually add your schema changes.
73+
1974
## [PostgresQL Database](https://www.postgresql.org/)
2075

2176
We use postgresQL for backend database, The default database taht will be used is named 'postgres'

additional.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
declare namespace NodeJS {
22
interface ProcessEnv {
3+
NODE_ENV: 'development' | 'production' | 'test';
34
DB_HOST: string;
45
DB_PORT: string;
56
DB_USER: string;

package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@
2828
"test:e2e": "rm -rf dist && jest --config ./test/jest-e2e.json",
2929
"test:e2e:docker": "rm -rf dist && docker-compose -f docker-compose.e2e.yml --env-file ./.test.env up --exit-code-from app",
3030
"g": "plop --plopfile ./generator/plopfile.mjs",
31-
"prepare": "husky"
31+
"prepare": "husky",
32+
"typeorm": "export NODE_ENV=production&& ts-node ./node_modules/typeorm/cli.js -d ./src/common/config/ormconfig.ts",
33+
"migration:create": "typeorm-ts-node-commonjs migration:create",
34+
"migration:generate": "yarn typeorm migration:generate",
35+
"migration:show": "yarn typeorm migration:show",
36+
"migration:run": "yarn build && yarn typeorm migration:run",
37+
"migration:revert": "yarn typeorm migration:revert"
3238
},
3339
"dependencies": {
3440
"@apollo/server": "^4.11.3",

src/app.module.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
22
import { Module } from '@nestjs/common';
3-
import { ConfigModule } from '@nestjs/config';
3+
import { ConfigModule, ConfigService } from '@nestjs/config';
44
import { GraphQLModule } from '@nestjs/graphql';
55
import { TypeOrmModule } from '@nestjs/typeorm';
66

77
import { AuthModule } from './auth/auth.module';
88
import { CustomCacheModule } from './cache/custom-cache.module';
9+
import {
10+
typeormConfigKey,
11+
typeormConfigLoader,
12+
} from './common/config/ormconfig';
913
import { getEnvPath } from './common/helper/env.helper';
1014
import { envValidation } from './common/helper/env.validation';
1115
import { SettingModule } from './common/shared/setting/setting.module';
@@ -19,6 +23,7 @@ import { UserModule } from './user/user.module';
1923
ConfigModule.forRoot({
2024
envFilePath: getEnvPath(`${__dirname}/..`),
2125
validate: envValidation,
26+
load: [typeormConfigLoader],
2227
}),
2328
GraphQLModule.forRootAsync<ApolloDriverConfig>({
2429
driver: ApolloDriver,
@@ -28,10 +33,10 @@ import { UserModule } from './user/user.module';
2833
settingService.graphqlUseFactory,
2934
}),
3035
TypeOrmModule.forRootAsync({
31-
imports: [SettingModule],
32-
inject: [SettingService],
33-
useFactory: (settingService: SettingService) =>
34-
settingService.typeOrmUseFactory,
36+
imports: [ConfigModule],
37+
inject: [ConfigService],
38+
useFactory: (configService: ConfigService) =>
39+
configService.get(typeormConfigKey),
3540
}),
3641
UserModule,
3742
AuthModule,

src/common/config/ormconfig.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { registerAs } from '@nestjs/config';
2+
3+
import { config } from 'dotenv';
4+
import { join } from 'path';
5+
import { cwd, env } from 'process';
6+
import { DataSource, DataSourceOptions } from 'typeorm';
7+
8+
import { getEnvPath } from '../helper/env.helper';
9+
10+
config({
11+
path: getEnvPath(cwd()),
12+
});
13+
14+
const typeormConfig: DataSourceOptions = {
15+
type: 'postgres',
16+
host: env.DB_HOST,
17+
port: Number(env.DB_PORT),
18+
username: env.DB_USER,
19+
password: env.DB_PASSWORD,
20+
database: env.DB_NAME,
21+
entities:
22+
env.NODE_ENV === 'test'
23+
? [join(cwd(), 'src', '**', '*.entity.{ts,js}')]
24+
: [join(cwd(), 'dist', '**', '*.entity.js')],
25+
synchronize: env.NODE_ENV !== 'production',
26+
dropSchema: env.NODE_ENV === 'test',
27+
migrations: [
28+
join(cwd(), 'dist', 'common', 'database', 'migrations', '*{.ts,.js}'),
29+
],
30+
migrationsRun: false,
31+
logging: false,
32+
};
33+
34+
export const typeormConfigKey = 'typeorm';
35+
export const typeormConfigLoader = registerAs(
36+
typeormConfigKey,
37+
() => typeormConfig,
38+
);
39+
export default new DataSource(typeormConfig);
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Migration files should be located here

src/common/shared/setting/setting.service.ts

-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { ApolloDriverConfig } from '@nestjs/apollo';
22
import { Injectable } from '@nestjs/common';
3-
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
43

54
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
65
import GraphQLJSON from 'graphql-type-json';
@@ -34,25 +33,4 @@ export class SettingService {
3433
formatError,
3534
};
3635
}
37-
38-
get typeOrmUseFactory():
39-
| TypeOrmModuleOptions
40-
| Promise<TypeOrmModuleOptions> {
41-
return {
42-
type: 'postgres',
43-
host: this.utilService.getString('DB_HOST'),
44-
port: this.utilService.getNumber('DB_PORT'),
45-
username: this.utilService.getString('DB_USER'),
46-
password: this.utilService.getString('DB_PASSWORD'),
47-
database: this.utilService.getString('DB_NAME'),
48-
entities:
49-
this.utilService.nodeEnv === 'test'
50-
? [join(process.cwd(), 'src', '**', '*.entity.{ts,js}')]
51-
: ['dist/**/*.entity.js'],
52-
synchronize: this.utilService.nodeEnv !== 'production',
53-
autoLoadEntities: true,
54-
dropSchema: this.utilService.nodeEnv === 'test',
55-
logging: false, // if you want to see the query log, change it to true
56-
};
57-
}
5836
}

0 commit comments

Comments
 (0)