上一篇文章详细了介绍nestjs 配置数据库,有不懂的小伙伴可以先查看上一篇文章【NestJs】使用连接mysql企业级开发规范在继续往下。
今天这一篇文章主要是针对配置数据库的重构,使用代码规范,方便后期维护。
当应用变得复杂 我们需要借用TypeORM CLI 非常方便的调整。
注意:
TypeORM 读取到extensions 结尾的文件
但是在根目录的文件 不能进行动态的修改,这样的话变量一旦很多的,修改极其麻烦。
当然 我们选择 ormconfig.ts
,不过因为我们环境不止一个。需要多多个环境校验。
使用 CLI
此 CLI 工具使用 javascript 编写,并在 node 上运行。如果你的实体文件是 TypeScript 编写,则需要在使用 CLI 之前将它们转换为 javascript。如果只使用 javascript,则可以跳过此部分。
全局安装 ts-node:
你可以在项目中设置 ts-node 以简化操作,如下所示:
npm install ts-node --save-dev
在 package.json 中的 scripts 下添加 typeorm 命令
"script" {
...
"typeorm": "typeorm-ts-node-commonjs"
}
注意:
typeorm 该版本使用的是 “typeorm”: “0.3.7” 要是版本不一致 需要查看官方文档最新使用方法。
根目录创建文件ormconfig.ts
,我们需要把app.module.ts
配置的数据库迁移:
import { User } from './src/user/user.entity';
import { Profile } from './src/user/profile.entity';
import { Logs } from './src/logs/logs.entity';
import { Roles } from './src/roles/roles.entity';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
export default {
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '123456',
database: 'testdb',
entities: [User, Profile, Logs, Roles],
// 同步本地的schema与数据库 -> 初始化的时候去使用
synchronize: true,
// logging: process.env.NODE_ENV === 'development',
logging: false,
} as TypeOrmModuleOptions;
app.module.ts
import { Global, Logger, Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LogsModule } from './logs/logs.module';
import { RolesModule } from './roles/roles.module';
import ormconfig from '../ormconfig';
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;
@Global()
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath,
load: [() => dotenv.config({ path: '.env' })],
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production')
.default('development'),
DB_PORT: Joi.number().default(3306),
DB_HOST: Joi.string().ip(),
DB_TYPE: Joi.string().valid('mysql', 'postgres'),
DB_DATABASE: Joi.string().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_SYNC: Joi.boolean().default(false),
}),
}),
TypeOrmModule.forRoot(ormconfig),
UserModule,
LogsModule,
RolesModule,
],
controllers: [],
providers: [Logger],
exports: [Logger],
})
export class AppModule {}
到这里 说明连接成功了。
初始化一个新的TypeORM项目
它使用 TypeORM 创建基本项目所需的所有文件:
- .gitignore
- package.json
- README.md
- tsconfig.json
- ormconfig.json
- src/entity/User.ts
- src/index.ts
然后你可以运行npm install来安装所有依赖项。 一旦安装了所有依赖项,你需要修改ormconfig.json并插入您自己的数据库设置。 之后,可以通过运行npm start来运行您的应用程序。
要指定使用的特定数据库,可以使用–database:
npx typeorm init --database mysql2
生成文件data-source.ts
文件结构和ormconfig 类似,
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { User } from './entity/User';
export const AppDataSource = new DataSource({
synchronize: true,
logging: false,
entities: [User],
migrations: [],
subscribers: [],
});
也会生成一个entity文件夹,暂时不用 我们可以先删掉,根据文档我们需要使用new DataSource
接下来需要修改 ormconnfig.ts 文件
import { User } from './src/user/user.entity';
import { Profile } from './src/user/profile.entity';
import { Logs } from './src/logs/logs.entity';
import { Roles } from './src/roles/roles.entity';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource, DataSourceOptions } from 'typeorm';
export const connectionParams = {
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '123456',
database: 'testdb',
entities: [User, Profile, Logs, Roles],
// 同步本地的schema与数据库 -> 初始化的时候去使用
synchronize: true,
// logging: process.env.NODE_ENV === 'development',
logging: false,
} as TypeOrmModuleOptions;
export default new DataSource({
...connectionParams,
migrations: ['src/migrations/**'],
} as DataSourceOptions);
测试:
修改index.ts
import AppDataSource from '../ormconfig';
import { User } from './user/user.entity';
AppDataSource.initialize()
.then(async () => {
const res = await AppDataSource.manager.find(User);
console.log(res);
})
.catch((error) => console.log(error));
npx ts-node src/index.ts
结果:
到此 我们已经完成了一半。
我们需要使用ormconfig 对接不同的环境?
通过环境变量读取不用的.env
文件, 通过dotENV来解析不同的配置:
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource, DataSourceOptions } from 'typeorm';
import * as fs from 'fs';
import * as dotenv from 'dotenv';
import { ConfigEnum } from './src/enum/config.enum';
// 通过环境变量读取不同的.env文件
function getEnv(env: string): Record<string, unknown> {
if (fs.existsSync(env)) {
return dotenv.parse(fs.readFileSync(env));
}
return {};
}
// 通过dotENV来解析不同的配置
function buildConnectionOptions() {
const defaultConfig = getEnv('.env');
const envConfig = getEnv(`.env.${process.env.NODE_ENV || 'development'}`);
// configService
const config = { ...defaultConfig, ...envConfig };
// 过多的实体 我们就不需要一个一个的导入加载
const entitiesDir =
process.env.NODE_ENV === 'test'
? [__dirname + '/**/*.entity.ts']
: [__dirname + '/**/*.entity{.js,.ts}'];
return {
type: config[ConfigEnum.DB_TYPE],
host: config[ConfigEnum.DB_HOST],
port: config[ConfigEnum.DB_PORT],
username: config[ConfigEnum.DB_USERNAME],
password: config[ConfigEnum.DB_PASSWORD],
database: config[ConfigEnum.DB_DATABASE],
entities: entitiesDir,
// 同步本地的schema与数据库 -> 初始化的时候去使用
synchronize: true,
// logging: process.env.NODE_ENV === 'development',
logging: false,
} as TypeOrmModuleOptions;
}
export const connectionParams = buildConnectionOptions();
export default new DataSource({
...connectionParams,
migrations: ['src/migrations/**'],
subscribers: [],
} as DataSourceOptions);
app.module.ts
Joi 的配置需要修改一下:
import { Global, Logger, Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LogsModule } from './logs/logs.module';
import { RolesModule } from './roles/roles.module';
import { connectionParams } from '../ormconfig';
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;
@Global()
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath,
load: [() => dotenv.config({ path: '.env' })],
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production')
.default('development'),
DB_PORT: Joi.number().default(3306),
// 生产环境和部署环境可能 HOST 一个是ip 一个是网址一样
DB_HOST: Joi.alternatives().try(
Joi.string().ip(),
Joi.string().domain(),
),
DB_TYPE: Joi.string().valid('mysql', 'postgres'),
DB_DATABASE: Joi.string().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_SYNC: Joi.boolean().default(false),
LOG_ON: Joi.boolean(),
LOG_LEVEL: Joi.string(),
}),
}),
TypeOrmModule.forRoot(connectionParams),
UserModule,
LogsModule,
RolesModule,
],
controllers: [],
providers: [Logger],
exports: [Logger],
})
export class AppModule {}
最后就是package.json
中 按照官方文档修改的配置:
"scripts": {
"prebuild": "rimraf dist",
"build": "cross-env NODE_ENV=production nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "ts-node src/index.ts",
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:debug": "cross-env NODE_ENV=development nest start --debug --watch",
"start:prod": "cross-env NODE_ENV=production node dist/src/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"typeorm": "typeorm-ts-node-commonjs -d ormconfig.ts",
"migration:generate": "f() { npm run typeorm migration:generate -p \"./src/migrations/$@\"; }; f",
"migration:create": "typeorm-ts-node-commonjs migration:create",
"migration:run": "npm run typeorm migration:run",
"migration:revert": "npm run typeorm migration:revert",
"schema:drop": "npm run typeorm schema:drop"
},
运行代码即可。