npm package: @lark-apaas/nestjs-datapaas
Description: FullStack Nestjs DataPaas
Latest version: 1.0.18

# DataPaas 数据库模块

基于 Drizzle ORM 封装的 PostgreSQL 数据库连接模块，提供连接池、请求上下文注入与事务等能力。

## 功能特性

- 🚀 基于 Drizzle Postgres ORM 的高性能数据库操作
- 🔄 自动在 pg session 执行层面注入 user_id 环境变量以无感支持 RLS 功能，数据库实例方法完全兼容 drizzle-orm/postgres-js
- 🛡️ 连接池管理和健康检查
- 🎯 NestJS 模块化集成
- 🎨 装饰器支持，简化使用
- 🔧 丰富的工具函数

## 安装依赖

```bash
npm install @lark-apaas/nestjs-datapaas
```

## 基本使用

### 1. 模块注册

#### 方式 1：同步配置（forRoot）

适用于配置可以直接从环境变量或常量获取的场景：

```typescript
import { Module } from '@nestjs/common';
import { DataPaasModule } from '@lark-apaas/nestjs-datapaas';

@Module({
  imports: [
    DataPaasModule.forRoot({
      // PostgreSQL 连接串，如：postgres://user:pass@host:port/dbname
      connectionString: process.env.DATABASE_URL!,
      schema: yourSchema,               // 可选，Drizzle schema
      logger: true,                     // 可选，启用日志
      timeout: 10000,                   // 可选，请求超时（ms）
      idleTimeout: 20,                  // 可选，空闲连接超时（s）
      connectionTimeout: 10,            // 可选，连接超时（s）
      ssl: false,                       // 可选，是否启用 SSL
      autoContext: true,                // 可选，为 SQL 执行自动设置 user_id 环境变量
    }),
  ],
})
export class AppModule {}
```

#### 方式 2：异步配置（forRootAsync）

**推荐使用**，适用于需要从 `ConfigModule` 等异步配置源获取配置的场景：

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { DataPaasModule } from '@lark-apaas/nestjs-datapaas';
import * as schema from './database/schema';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    DataPaasModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        connectionString: configService.get<string>('DATABASE_URL')!,
        schema,
        logger: configService.get<boolean>('DATABASE_LOGGER') || false,
        timeout: configService.get<number>('DATABASE_TIMEOUT') || 10000,
        maxConnections: configService.get<number>('DATABASE_MAX_CONNECTIONS') || 1,
        ssl: configService.get<boolean>('DATABASE_SSL') || false,
        autoContext: true,
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}
```

> **提示**: 
> - 使用 `forRootAsync` 时，配置会在应用启动时从 `ConfigService` 异步获取
> - 支持 `useFactory`、`useClass` 和 `useExisting` 三种配置方式
> - 详细的异步配置使用方法请参考 [ASYNC_USAGE.md](./ASYNC_USAGE.md)

> **注意**: 新版本使用标准的 NestJS 依赖注入模式，所有服务都会自动初始化和管理。


### 2. 在服务/控制器中使用

```typescript
import { Injectable, Inject } from '@nestjs/common';
import { 
  DataPaasDatabaseService,
  DrizzleDatabaseManager,
  Database,
  DatabaseManager,
  DatabaseService,
  DRIZZLE_DATABASE,
  type PostgresJsDatabase
} from '@lark-apaas/nestjs-datapaas';

@Injectable()
export class UserService {
  constructor(
    private readonly databaseService: DataPaasDatabaseService,
    private readonly databaseManager: DrizzleDatabaseManager,
    @Inject(DRIZZLE_DATABASE) private readonly db: PostgresJsDatabase,
  ) {}

  // 方式一：构造函数注入数据库实例
  async getUsersByCtor() {
    return this.db.select().from(users);
  }

  // 方式二：方法参数装饰器（请求上下文友好）
  async getUsers(@Database() db: PostgresJsDatabase) {
    return db.select().from(users);
  }

  // 使用装饰器注入数据库管理器
  async getConnectionStatus(@DatabaseManager() manager: DrizzleDatabaseManager) {
    return manager.getConnectionPoolStatus();
  }

  // 使用装饰器注入数据库服务
  async getHealthStatus(@DatabaseService() service: DataPaasDatabaseService) {
    return service.isConnected();
  }

  // 健康检查
  async checkHealth() {
    return this.databaseService.testConnection();
  }

  // 获取连接池状态
  async getPoolStatus() {
    return this.databaseManager.getConnectionPoolStatus();
  }
}


## API 参考

### DataPaasModule

#### forRoot(options)

同步配置方法。

**参数：**
- `connectionString`: PostgreSQL 连接串（必填）
- `schema`: Drizzle schema（可选）
- `logger`: 是否启用日志（可选，默认 false）
- `timeout`: 请求超时（ms，可选，默认 10000）
- `maxConnections`: 最大连接数（可选，默认 1）
- `idleTimeout`: 空闲连接超时（秒，可选，默认 20）
- `connectionTimeout`: 连接超时（秒，可选，默认 10）
- `ssl`: 是否启用 SSL（可选，默认 false）
- `autoContext`: 是否为请求自动设置上下文（可选，默认 true）

#### forRootAsync(options)

异步配置方法，支持从 ConfigModule 等异步源获取配置。

**参数：**
- `imports`: 需要导入的模块（例如 `[ConfigModule]`）
- `inject`: 工厂函数需要注入的依赖
- `useExisting`: 已存在的配置 provider
- **useFactory**: 工厂函数，返回配置对象
```typescript
DataPaasModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (configService: ConfigService) => ({
    connectionString: configService.get('DATABASE_URL')!,
  }),
  inject: [ConfigService],
})
```


### DataPaasDatabaseService

- `testConnection()`: 测试数据库连接
- `isConnected()`: 检查连接状态
- `getConnectionPoolStatus()`: 获取连接池状态

### 装饰器

- `@Database()`: 注入 Drizzle 数据库实例

### 常量 Token

- `DRIZZLE_DATABASE`: 可用于 `@Inject(DRIZZLE_DATABASE)` 注入数据库实例

### 工具函数

- `DatabaseUtils.safeExecute()`: 安全执行数据库操作
- `DatabaseUtils.batchExecute()`: 批量执行操作
- `DatabaseUtils.executeWithRetry()`: 带重试的执行
- `DatabaseUtils.tableExists()`: 检查表是否存在
- `DatabaseUtils.getTableStructure()`: 获取表结构
- `DatabaseUtils.getDatabaseVersion()`: 获取数据库版本
- `DatabaseUtils.getConnectionStats()`: 获取连接统计
- `DatabaseUtils.healthCheck()`: 健康检查


## 最佳实践
1. **健康检查**: 定期进行健康检查，监控连接状态
2. **依赖注入**: 充分利用 NestJS 的 DI 系统，避免手动创建服务实例

## 注意事项
1. 尽量保证 DataPaasModule 第一个加载注册，避免 autoContext 功能在某些初始场景失效
2. 应用层禁止安装 drizzle-orm 包，如果需要 drizzle-orm 的相关导出，可以直接从 @lark-apaas/nestjs-datapaas 导出，因为 drizzle-orm/postgres-js 已经被打了 git patch 以支持 autoContext 的功能，重新安装可能会引入非预期的 bug