1. 概述
DatabaseModule 是 FastbuildAI 后端应用的核心数据库模块,负责配置和管理与 PostgreSQL 数据库的连接。该模块使用 TypeORM 作为 ORM 框架,提供了完整的数据库初始化、实体管理、连接配置和日志记录功能。
主要职责
- 配置 PostgreSQL 数据库连接
- 管理实体注册和同步
- 提供数据库初始化服务
- 集成业务模块的数据访问层
- 实现自定义日志记录和监控
2. 模块装饰器分析
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
@Module({
imports: [
// DatabaseSyncModule,
TypeOrmModule.forRootAsync({
imports: [],
inject: [],
useFactory: () => {
return {
...appConfig.database,
logger: new CustomLogger(),
entities: [
"dist/common/**/*.entity.js",
"dist/modules/**/*.entity.js",
"dist/core/**/*.entity.js",
// "dist/plugins/**/*.entity.js",
],
synchronize: appConfig.database.synchronize,
};
},
dataSourceFactory: async (options: PostgresConnectionOptions) => {
const dataSource = await new DataSource({
...options,
logging: false,
}).initialize();
// 查询并打印数据库类型和版本信息
try {
const dbInfoResult = await dataSource.query("SELECT VERSION() as version");
const dbVersion = dbInfoResult[0]?.version;
TerminalLogger.info(
"PgSQL Version",
dbVersion
? dbVersion.match(/PostgreSQL\s+(\d+(?:\.\d+)?)/)[1]
: "Unknown version",
);
} catch (error) {
TerminalLogger.error("Database Error", `Get version failed: ${error.message}`);
}
TerminalLogger.success("PgSQL Status", "Connected");
TerminalLogger.log("Db Sync", options.synchronize ? "ON" : "OFF", {
color: "magenta",
});
if (process.env.LOG_DATABASE_SCHEMA === "true") {
printEntityTable(dataSource);
}
return dataSource;
},
}),
MenuModule,
PermissionModule,
DictModule,
DecorateModule,
TypeOrmModule.forFeature([User, Menu, Payconfig, Dict, AiProvider, AiModel, KeyTemplate]),
],
controllers: [],
providers: [DatabaseInitService],
exports: [DatabaseInitService],
})
export class DatabaseModule {}
配置说明
- imports: 导入 TypeORM 根模块和相关业务模块
- providers: 提供数据库初始化服务
- exports: 导出初始化服务供其他模块使用
3. TypeORM异步配置分析
3.1 配置工厂函数
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
useFactory: () => {
return {
...appConfig.database,
logger: new CustomLogger(),
entities: [
"dist/common/**/*.entity.js",
"dist/modules/**/*.entity.js",
"dist/core/**/*.entity.js",
],
synchronize: appConfig.database.synchronize,
};
}
关键配置项:
- ...appConfig.database - 从应用配置中获取数据库连接信息(主机、端口、用户名、密码等)
- logger: new CustomLogger() - 使用自定义日志记录器来记录 SQL 操作
- entities - 指定实体文件的路径模式,TypeORM 会自动扫描这些路径下的实体类
- synchronize - 控制是否自动同步数据库结构(开发环境通常为 true,生产环境为 false)
3.2 数据库配置接口
typescript
// 源码位置:apps/server/src/common/config/app.config.ts
export interface AppConfig {
database: {
type: "postgres";
host: string;
port: number;
username: string;
password: string;
database: string;
synchronize: boolean;
logging: boolean;
namingStrategy: NamingStrategyInterface;
};
}
export const appConfig: AppConfig = {
database: {
type: process.env.DB_TYPE as "postgres",
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
synchronize: process.env.DB_SYNCHRONIZE === "true",
logging: process.env.DB_LOGGING === "true",
namingStrategy: new SnakeNamingStrategy(),
},
};
4. 数据源工厂分析
4.1 数据源初始化
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
dataSourceFactory: async (options: PostgresConnectionOptions) => {
const dataSource = await new DataSource({
...options,
logging: false,
}).initialize();
// 查询并打印数据库版本信息
try {
const dbInfoResult = await dataSource.query("SELECT VERSION() as version");
const dbVersion = dbInfoResult[0]?.version;
TerminalLogger.info(
"PgSQL Version",
dbVersion
? dbVersion.match(/PostgreSQL\s+(\d+(?:\.\d+)?)/)[1]
: "Unknown version",
);
} catch (error) {
TerminalLogger.error("Database Error", `Get version failed: ${error.message}`);
}
TerminalLogger.success("PgSQL Status", "Connected");
TerminalLogger.log("Db Sync", options.synchronize ? "ON" : "OFF", {
color: "magenta",
});
if (process.env.LOG_DATABASE_SCHEMA === "true") {
printEntityTable(dataSource);
}
return dataSource;
}
功能说明:
- 创建 PostgreSQL 数据库连接
- 查询并显示数据库版本信息
- 输出连接状态和同步设置
- 根据环境变量决定是否打印数据库结构信息
4.2 功能特性
- 版本检测: 自动检测 PostgreSQL 版本
- 连接状态监控: 实时显示连接状态
- 同步状态显示: 显示数据库同步开关状态
- 实体表格打印: 可选的实体信息展示
5. 实体管理
5.1 实体扫描配置
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
entities: [
"dist/common/**/*.entity.js",
"dist/modules/**/*.entity.js",
"dist/core/**/*.entity.js",
]
5.2 特定实体注册
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
TypeOrmModule.forFeature([
User, // 用户实体
Menu, // 菜单实体
Payconfig, // 支付配置实体
Dict, // 字典配置实体
AiProvider, // AI提供商实体
AiModel, // AI模型实体
KeyTemplate // 密钥模板实体
])
TypeOrmModule.forFeature() 注册了具体的实体类,使这些实体可以在当前模块中使用。
5.3 实体示例
typescript
// 源码位置:apps/server/src/common/modules/dict/entities/dict.entity.ts
@AppEntity({ name: "config", comment: "系统配置字典" })
@Index("UQ_dict_key_group", ["key", "group"], { unique: true })
export class Dict {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column({ length: 100, comment: "配置键" })
key: string;
@Column({ type: "text", comment: "配置值(JSON格式)" })
value: string;
@Column({ length: 50, default: "default", comment: "配置分组" })
group: string;
@Column({ length: 255, nullable: true, comment: "配置描述" })
description: string;
@Column({ type: "int", default: 0, comment: "排序" })
sort: number;
@Column({ type: "boolean", default: true, comment: "是否启用" })
isEnabled: boolean;
@CreateDateColumn({ comment: "创建时间" })
createdAt: Date;
@UpdateDateColumn({ comment: "更新时间" })
updatedAt: Date;
}
6. 业务模块集成
6.1 导入的功能模块
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
imports: [
MenuModule, // 菜单管理模块
PermissionModule, // 权限管理模块
DictModule, // 字典配置模块
DecorateModule, // 装饰器模块
]
6.2 模块依赖关系
- MenuModule: 提供系统菜单管理功能
- PermissionModule: 提供权限控制和验证
- DictModule: 提供系统配置字典服务
- DecorateModule: 提供装饰器增强功能
7. 数据库初始化服务
7.1 服务概述
typescript
// 源码位置:apps/server/src/core/database/database-init.service.ts
@Injectable()
export class DatabaseInitService implements OnModuleInit {
private readonly logger = new Logger(DatabaseInitService.name);
constructor(
private readonly dataSource: DataSource,
private readonly permissionService: PermissionService,
private readonly dictService: DictService,
private readonly pageService: PageService,
@InjectRepository(User) private readonly userRepository: Repository<User>,
@InjectRepository(Menu) private readonly menuRepository: Repository<Menu>,
@InjectRepository(Payconfig) private readonly payConfigRepository: Repository<Payconfig>,
@InjectRepository(AiProvider) private readonly aiProviderRepository: Repository<AiProvider>,
@InjectRepository(AiModel) private readonly aiModelRepository: Repository<AiModel>,
@InjectRepository(KeyTemplate) private readonly keyTemplateRepository: Repository<KeyTemplate>,
) {}
}
7.2 初始化流程
typescript
// 源码位置:apps/server/src/core/database/database-init.service.ts
async onModuleInit() {
try {
// 检查是否已安装
const isInstalled = await this.checkInstallation();
if (!isInstalled) {
await this.initializeDatabase();
} else {
await this.checkAndUpgrade();
}
} catch (error) {
this.logger.error('数据库初始化失败', error);
}
}
private async initializeDatabase() {
await this.initializeUsers(); // 初始化用户
await this.syncPermissions(); // 同步权限
await this.initializeMenus(); // 初始化菜单
await this.initializePayConfigs(); // 初始化支付配置
await this.initializeAiProviders(); // 初始化AI提供商
await this.initializeKeyTemplates(); // 初始化密钥模板
}
8. 自定义日志记录器
8.1 CustomLogger 实现
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
class CustomLogger implements TypeOrmLogger {
log(level: "log" | "info" | "warn", message: any): void {
if (message && typeof message === "string" && message.includes("synchronize schema")) {
TerminalLogger.info("Database", "Starting database schema synchronization...");
}
}
logQuery(query: string): void {
// 检测创建表的查询
if (query.includes("CREATE TABLE")) {
const tableName = query.match(/CREATE TABLE "?([^\s"]+)"?/)?.[1];
if (tableName) {
TerminalLogger.log("Table", `${tableName} created or updated`);
}
}
// 检测添加外键的查询
else if (query.includes("ADD CONSTRAINT") && query.includes("FOREIGN KEY")) {
const match = query.match(
/ADD CONSTRAINT "?([^\s"]+)"? FOREIGN KEY.*REFERENCES "?([^\s"(]+)"?/s,
);
if (match && match.length >= 3) {
const constraintName = match[1];
const referencedTable = match[2];
TerminalLogger.log(
"Foreign Key",
`${constraintName} added, references table ${referencedTable}`,
);
}
}
// 检测添加索引的查询
else if (query.includes("CREATE INDEX")) {
const indexMatch = query.match(/CREATE INDEX "?([^\s"]+)"? ON "?([^\s"]+)"?/i);
if (indexMatch && indexMatch.length >= 3) {
const indexName = indexMatch[1];
const tableName = indexMatch[2];
TerminalLogger.log("Index", `${indexName} added to table ${tableName}`);
}
}
}
logQueryError(error: string | Error, query: string): void {
TerminalLogger.error("Query Error", error.toString());
TerminalLogger.error("Failed Query", query);
}
logQuerySlow(time: number, query: string): void {
TerminalLogger.warn("Slow Query", `(${time}ms): ${query}`);
}
logMigration(message: string): void {
TerminalLogger.info("Migration", message);
}
logSchemaBuild(message: string): void {
TerminalLogger.info("Schema Build", message);
}
}
8.2 日志功能特性
- 表创建监控: 实时显示表的创建和更新
- 外键约束跟踪: 监控外键约束的添加
- 索引创建记录: 记录索引的创建过程
- 慢查询警告: 标记执行时间过长的查询
- 错误详细记录: 详细记录查询错误信息
9. 实体信息展示功能
9.1 printEntityTable 函数
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
async function printEntityTable(dataSource: DataSource): Promise<void> {
const entities = dataSource.entityMetadatas;
if (entities.length === 0) {
TerminalLogger.warn(`Entities`, "No entities registered");
return;
}
// 创建表格
const table = new Table({
chars: table3BorderStyle,
head: ["表名", "实体名", "注释", "模块", "列数", "关系数", "索引数"],
style: {
head: ["cyan"],
border: ["gray"],
},
});
// 对实体按模块分组排序
const sortedEntities = [...entities].sort((a, b) => {
const moduleA = getEntityModule(a);
const moduleB = getEntityModule(b);
return moduleA.localeCompare(moduleB);
});
// 添加实体信息到表格
for (let i = 0; i < sortedEntities.length; i++) {
const entity = sortedEntities[i];
table.push([
chalk.magenta(entity.tableName),
entity.name,
entity.comment || "-",
getEntityModule(entity),
entity.columns.length.toString(),
entity.relations.length.toString(),
entity.indices.length.toString(),
]);
}
// 打印表格
TerminalLogger.log("", `DataSource(${entities.length}):`);
console.log(table.toString());
}
9.2 模块分类功能
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
function getEntityModule(entity: EntityMetadata): string {
return entity.tableName.startsWith(process.env.DB_TABLE_PREFIX) ? "系统" : "插件";
}
10. 技术特点和最佳实践
10.1 技术特点
- 异步配置 : 使用
forRootAsync支持动态配置 - 环境变量驱动: 所有配置通过环境变量管理
- 自定义日志: 提供详细的数据库操作日志
- 实体自动扫描: 支持多目录实体自动发现
- 模块化设计: 清晰的模块依赖关系
- 初始化服务: 完整的数据库初始化流程
10.2 最佳实践
- 配置分离: 数据库配置与业务逻辑分离
- 错误处理: 完善的错误捕获和日志记录
- 性能监控: 慢查询检测和性能优化
- 安全性: 使用环境变量保护敏感信息
- 可维护性: 清晰的代码结构和注释
11. 配置参数说明
11.1 环境变量配置
| 变量名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DB_TYPE |
string | postgres | 数据库类型 |
DB_HOST |
string | - | 数据库主机地址 |
DB_PORT |
number | 5432 | 数据库端口 |
DB_USERNAME |
string | - | 数据库用户名 |
DB_PASSWORD |
string | - | 数据库密码 |
DB_DATABASE |
string | - | 数据库名称 |
DB_SYNCHRONIZE |
boolean | false | 是否自动同步实体 |
DB_LOGGING |
boolean | false | 是否启用日志 |
LOG_DATABASE_SCHEMA |
boolean | false | 是否打印实体表格 |
DB_TABLE_PREFIX |
string | - | 系统表前缀 |
11.2 TypeORM 配置选项
typescript
// 源码位置:apps/server/src/core/database/database.module.ts
{
type: "postgres", // 数据库类型
host: string, // 主机地址
port: number, // 端口号
username: string, // 用户名
password: string, // 密码
database: string, // 数据库名
synchronize: boolean, // 自动同步
logging: boolean, // 启用日志
namingStrategy: SnakeNamingStrategy, // 命名策略
logger: CustomLogger, // 自定义日志器
entities: string[], // 实体路径
}
12. 启动流程图
否 是 应用启动 加载DatabaseModule 读取环境变量配置 创建TypeORM配置 初始化数据源 连接PostgreSQL数据库 检查数据库版本 执行实体同步 注册自定义日志器 打印实体信息表格 启动DatabaseInitService 检查安装状态 是否已安装? 执行初始化流程 检查版本升级 初始化用户 同步权限 初始化菜单 初始化支付配置 初始化AI提供商 初始化密钥模板 数据库模块启动完成
13. 总结
DatabaseModule 是 FastbuildAI 后端应用的数据访问层核心,通过 TypeORM 提供了完整的数据库管理功能。该模块具有以下优势:
- 配置灵活: 支持环境变量驱动的动态配置
- 监控完善: 提供详细的数据库操作日志和性能监控
- 初始化完整: 包含完整的数据库初始化和升级流程
- 模块化设计: 清晰的依赖关系和职责分离
- 扩展性强: 支持插件实体和自定义配置
该模块为整个应用提供了稳定可靠的数据持久化基础,是系统架构中的重要组成部分。