@qlover/create-app 0.7.14 → 0.7.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/README.en.md +131 -0
- package/dist/templates/next-app/README.md +115 -20
- package/dist/templates/next-app/docs/en/api.md +387 -0
- package/dist/templates/next-app/docs/en/component.md +544 -0
- package/dist/templates/next-app/docs/en/database.md +496 -0
- package/dist/templates/next-app/docs/en/development-guide.md +727 -0
- package/dist/templates/next-app/docs/en/env.md +563 -0
- package/dist/templates/next-app/docs/en/i18n.md +287 -0
- package/dist/templates/next-app/docs/en/index.md +166 -0
- package/dist/templates/next-app/docs/en/page.md +457 -0
- package/dist/templates/next-app/docs/en/project-structure.md +177 -0
- package/dist/templates/next-app/docs/en/router.md +427 -0
- package/dist/templates/next-app/docs/en/theme.md +532 -0
- package/dist/templates/next-app/docs/en/validator.md +478 -0
- package/dist/templates/next-app/docs/zh/api.md +387 -0
- package/dist/templates/next-app/docs/zh/component.md +544 -0
- package/dist/templates/next-app/docs/zh/database.md +496 -0
- package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
- package/dist/templates/next-app/docs/zh/env.md +563 -0
- package/dist/templates/next-app/docs/zh/i18n.md +287 -0
- package/dist/templates/next-app/docs/zh/index.md +166 -0
- package/dist/templates/next-app/docs/zh/page.md +457 -0
- package/dist/templates/next-app/docs/zh/project-structure.md +177 -0
- package/dist/templates/next-app/docs/zh/router.md +427 -0
- package/dist/templates/next-app/docs/zh/theme.md +532 -0
- package/dist/templates/next-app/docs/zh/validator.md +476 -0
- package/package.json +1 -1
- package/dist/templates/next-app/docs/env.md +0 -94
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
# 数据库开发指南
|
|
2
|
+
|
|
3
|
+
## 目录
|
|
4
|
+
|
|
5
|
+
1. [数据库架构概述](#数据库架构概述)
|
|
6
|
+
2. [Supabase 实现](#supabase-实现)
|
|
7
|
+
3. [数据库接口和抽象层](#数据库接口和抽象层)
|
|
8
|
+
4. [仓库模式实现](#仓库模式实现)
|
|
9
|
+
5. [MongoDB 实现示例](#mongodb-实现示例)
|
|
10
|
+
6. [最佳实践和示例](#最佳实践和示例)
|
|
11
|
+
|
|
12
|
+
## 数据库架构概述
|
|
13
|
+
|
|
14
|
+
### 1. 整体架构
|
|
15
|
+
|
|
16
|
+
项目采用分层的数据库架构设计:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
应用层 数据访问层
|
|
20
|
+
┌──────────────┐ ┌──────────────┐
|
|
21
|
+
│ 业务服务 │ │ 数据库接口 │
|
|
22
|
+
├──────────────┤ ├──────────────┤
|
|
23
|
+
│ 仓库接口 │ │ 数据库桥接器 │
|
|
24
|
+
├──────────────┤ ◄─────┤ │
|
|
25
|
+
│ 仓库实现 │ │ 具体实现 │
|
|
26
|
+
└──────────────┘ └──────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. 核心组件
|
|
30
|
+
|
|
31
|
+
- **数据库接口**:`DBBridgeInterface`
|
|
32
|
+
- **数据库实现**:`SupabaseBridge`, `MongoDBBridge` 等
|
|
33
|
+
- **仓库接口**:`UserRepositoryInterface` 等
|
|
34
|
+
- **仓库实现**:`UserRepository` 等
|
|
35
|
+
|
|
36
|
+
### 3. 数据模型
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// 用户模型示例
|
|
40
|
+
interface UserSchema {
|
|
41
|
+
id: number;
|
|
42
|
+
email: string;
|
|
43
|
+
password: string;
|
|
44
|
+
role: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
updated_at: string;
|
|
47
|
+
email_confirmed_at?: string;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Supabase 实现
|
|
52
|
+
|
|
53
|
+
### 1. 数据库桥接器
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
@injectable()
|
|
57
|
+
export class SupabaseBridge implements DBBridgeInterface {
|
|
58
|
+
protected supabase: SupabaseClient;
|
|
59
|
+
|
|
60
|
+
constructor(
|
|
61
|
+
@inject(I.AppConfig) appConfig: AppConfig,
|
|
62
|
+
@inject(I.Logger) protected logger: LoggerInterface
|
|
63
|
+
) {
|
|
64
|
+
// 初始化 Supabase 客户端
|
|
65
|
+
this.supabase = createClient(
|
|
66
|
+
appConfig.supabaseUrl,
|
|
67
|
+
appConfig.supabaseAnonKey
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 查询实现
|
|
72
|
+
async get(event: BridgeEvent): Promise<SupabaseBridgeResponse<unknown>> {
|
|
73
|
+
const { table, fields = '*', where } = event;
|
|
74
|
+
const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
|
|
75
|
+
const handler = this.supabase.from(table).select(selectFields);
|
|
76
|
+
|
|
77
|
+
this.handleWhere(handler, where ?? []);
|
|
78
|
+
|
|
79
|
+
return this.catch(await handler);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 分页查询实现
|
|
83
|
+
async pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>> {
|
|
84
|
+
const { table, fields = '*', where, page = 1, pageSize = 10 } = event;
|
|
85
|
+
const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
|
|
86
|
+
|
|
87
|
+
const handler = this.supabase
|
|
88
|
+
.from(table)
|
|
89
|
+
.select(selectFields, { count: 'exact' })
|
|
90
|
+
.range((page - 1) * pageSize, page * pageSize - 1);
|
|
91
|
+
|
|
92
|
+
this.handleWhere(handler, where ?? []);
|
|
93
|
+
|
|
94
|
+
return this.catch(await handler);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// WHERE 条件处理
|
|
98
|
+
protected handleWhere(
|
|
99
|
+
handler: PostgrestFilterBuilder<any, any, any>,
|
|
100
|
+
where: Where[]
|
|
101
|
+
): void {
|
|
102
|
+
where.forEach(([field, operation, value]) => {
|
|
103
|
+
const method = whereHandlerMaps[operation];
|
|
104
|
+
if (method) {
|
|
105
|
+
handler[method](field, value);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 2. 查询条件映射
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Supabase 操作符映射
|
|
116
|
+
const whereHandlerMaps = {
|
|
117
|
+
'=': 'eq', // 等于
|
|
118
|
+
'!=': 'neq', // 不等于
|
|
119
|
+
'>': 'gt', // 大于
|
|
120
|
+
'<': 'lt', // 小于
|
|
121
|
+
'>=': 'gte', // 大于等于
|
|
122
|
+
'<=': 'lte' // 小于等于
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 数据库接口和抽象层
|
|
127
|
+
|
|
128
|
+
### 1. 数据库桥接接口
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
export interface DBBridgeInterface {
|
|
132
|
+
// 基础 CRUD 操作
|
|
133
|
+
add(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
|
|
134
|
+
update(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
|
|
135
|
+
delete(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
|
|
136
|
+
get(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
|
|
137
|
+
|
|
138
|
+
// 分页查询
|
|
139
|
+
pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 查询事件定义
|
|
143
|
+
export interface BridgeEvent {
|
|
144
|
+
table: string;
|
|
145
|
+
fields?: string | string[];
|
|
146
|
+
where?: Where[];
|
|
147
|
+
data?: unknown;
|
|
148
|
+
page?: number;
|
|
149
|
+
pageSize?: number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 统一响应格式
|
|
153
|
+
export interface DBBridgeResponse<T> {
|
|
154
|
+
error?: unknown;
|
|
155
|
+
data: T;
|
|
156
|
+
pagination?: PaginationInfo;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 2. 查询条件类型
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// 操作符类型
|
|
164
|
+
export type WhereOperation = '=' | '!=' | '>' | '<' | '>=' | '<=';
|
|
165
|
+
|
|
166
|
+
// 查询条件类型
|
|
167
|
+
export type Where = [string, WhereOperation, string | number];
|
|
168
|
+
|
|
169
|
+
// 分页信息
|
|
170
|
+
export interface PaginationInfo {
|
|
171
|
+
total: number;
|
|
172
|
+
page: number;
|
|
173
|
+
pageSize: number;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 仓库模式实现
|
|
178
|
+
|
|
179
|
+
### 1. 用户仓库接口
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
export interface UserRepositoryInterface {
|
|
183
|
+
// 获取所有用户
|
|
184
|
+
getAll(): Promise<unknown>;
|
|
185
|
+
|
|
186
|
+
// 通过邮箱查询用户
|
|
187
|
+
getUserByEmail(email: string): Promise<UserSchema | null>;
|
|
188
|
+
|
|
189
|
+
// 添加用户
|
|
190
|
+
add(params: {
|
|
191
|
+
email: string;
|
|
192
|
+
password: string;
|
|
193
|
+
}): Promise<UserSchema[] | null>;
|
|
194
|
+
|
|
195
|
+
// 更新用户
|
|
196
|
+
updateById(
|
|
197
|
+
id: number,
|
|
198
|
+
params: Partial<Omit<UserSchema, 'id' | 'created_at'>>
|
|
199
|
+
): Promise<void>;
|
|
200
|
+
|
|
201
|
+
// 分页查询
|
|
202
|
+
pagination<UserSchema>(params: {
|
|
203
|
+
page: number;
|
|
204
|
+
pageSize: number;
|
|
205
|
+
}): Promise<PaginationInterface<UserSchema>>;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 2. 用户仓库实现
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
@injectable()
|
|
213
|
+
export class UserRepository implements UserRepositoryInterface {
|
|
214
|
+
readonly name = 'fe_users';
|
|
215
|
+
|
|
216
|
+
// 安全字段列表(排除敏感信息)
|
|
217
|
+
protected safeFields = [
|
|
218
|
+
'created_at',
|
|
219
|
+
'email',
|
|
220
|
+
'email_confirmed_at',
|
|
221
|
+
'id',
|
|
222
|
+
'role',
|
|
223
|
+
'updated_at'
|
|
224
|
+
];
|
|
225
|
+
|
|
226
|
+
constructor(
|
|
227
|
+
@inject(I.DBBridgeInterface) protected dbBridge: DBBridgeInterface
|
|
228
|
+
) {}
|
|
229
|
+
|
|
230
|
+
async getUserByEmail(email: string): Promise<UserSchema | null> {
|
|
231
|
+
const result = await this.dbBridge.get({
|
|
232
|
+
table: this.name,
|
|
233
|
+
where: [['email', '=', email]]
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return isEmpty(result.data) ? null : last(result.data as UserSchema[]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async pagination<UserSchema>(
|
|
240
|
+
params: PaginationParams
|
|
241
|
+
): Promise<PaginationResult> {
|
|
242
|
+
const result = await this.dbBridge.pagination({
|
|
243
|
+
table: this.name,
|
|
244
|
+
page: params.page,
|
|
245
|
+
pageSize: params.pageSize,
|
|
246
|
+
fields: this.safeFields // 只返回安全字段
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
list: result.data as UserSchema[],
|
|
251
|
+
total: result.count ?? 0,
|
|
252
|
+
page: params.page,
|
|
253
|
+
pageSize: params.pageSize
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## MongoDB 实现示例
|
|
260
|
+
|
|
261
|
+
### 1. MongoDB 桥接器
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
@injectable()
|
|
265
|
+
export class MongoDBBridge implements DBBridgeInterface {
|
|
266
|
+
protected client: MongoClient;
|
|
267
|
+
protected db: Db;
|
|
268
|
+
|
|
269
|
+
constructor(
|
|
270
|
+
@inject(I.AppConfig) appConfig: AppConfig,
|
|
271
|
+
@inject(I.Logger) protected logger: LoggerInterface
|
|
272
|
+
) {
|
|
273
|
+
this.client = new MongoClient(appConfig.mongodbUrl);
|
|
274
|
+
this.db = this.client.db(appConfig.mongodbDatabase);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async get(event: BridgeEvent): Promise<DBBridgeResponse<unknown>> {
|
|
278
|
+
const { table, where } = event;
|
|
279
|
+
const collection = this.db.collection(table);
|
|
280
|
+
|
|
281
|
+
const query = this.buildQuery(where ?? []);
|
|
282
|
+
const data = await collection.find(query).toArray();
|
|
283
|
+
|
|
284
|
+
return { data };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>> {
|
|
288
|
+
const { table, where, page = 1, pageSize = 10 } = event;
|
|
289
|
+
const collection = this.db.collection(table);
|
|
290
|
+
|
|
291
|
+
const query = this.buildQuery(where ?? []);
|
|
292
|
+
const total = await collection.countDocuments(query);
|
|
293
|
+
const data = await collection
|
|
294
|
+
.find(query)
|
|
295
|
+
.skip((page - 1) * pageSize)
|
|
296
|
+
.limit(pageSize)
|
|
297
|
+
.toArray();
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
data,
|
|
301
|
+
pagination: { total, page, pageSize }
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
protected buildQuery(where: Where[]): Document {
|
|
306
|
+
return where.reduce((query, [field, operation, value]) => {
|
|
307
|
+
switch (operation) {
|
|
308
|
+
case '=':
|
|
309
|
+
return { ...query, [field]: value };
|
|
310
|
+
case '!=':
|
|
311
|
+
return { ...query, [field]: { $ne: value } };
|
|
312
|
+
case '>':
|
|
313
|
+
return { ...query, [field]: { $gt: value } };
|
|
314
|
+
case '<':
|
|
315
|
+
return { ...query, [field]: { $lt: value } };
|
|
316
|
+
case '>=':
|
|
317
|
+
return { ...query, [field]: { $gte: value } };
|
|
318
|
+
case '<=':
|
|
319
|
+
return { ...query, [field]: { $lte: value } };
|
|
320
|
+
default:
|
|
321
|
+
return query;
|
|
322
|
+
}
|
|
323
|
+
}, {});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 2. MongoDB 配置
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// 在 AppConfig 中添加 MongoDB 配置
|
|
332
|
+
export class AppConfig implements EnvConfigInterface {
|
|
333
|
+
readonly mongodbUrl: string = process.env.MONGODB_URL!;
|
|
334
|
+
readonly mongodbDatabase: string = process.env.MONGODB_DATABASE!;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 注册 MongoDB 桥接器
|
|
338
|
+
export class ServerIOCRegister {
|
|
339
|
+
protected registerImplement(ioc: IOCContainerInterface): void {
|
|
340
|
+
// 使用 MongoDB 实现
|
|
341
|
+
ioc.bind(I.DBBridgeInterface, ioc.get(MongoDBBridge));
|
|
342
|
+
// 或使用 Supabase 实现
|
|
343
|
+
// ioc.bind(I.DBBridgeInterface, ioc.get(SupabaseBridge));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## 最佳实践和示例
|
|
349
|
+
|
|
350
|
+
### 1. 仓库模式使用
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
@injectable()
|
|
354
|
+
export class UserService {
|
|
355
|
+
constructor(
|
|
356
|
+
@inject(I.UserRepository)
|
|
357
|
+
private userRepository: UserRepositoryInterface
|
|
358
|
+
) {}
|
|
359
|
+
|
|
360
|
+
async getUserProfile(email: string): Promise<UserProfile | null> {
|
|
361
|
+
const user = await this.userRepository.getUserByEmail(email);
|
|
362
|
+
if (!user) return null;
|
|
363
|
+
|
|
364
|
+
// 转换为业务模型
|
|
365
|
+
return this.mapToUserProfile(user);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async listUsers(
|
|
369
|
+
params: PaginationParams
|
|
370
|
+
): Promise<PaginationResult<UserProfile>> {
|
|
371
|
+
const result = await this.userRepository.pagination(params);
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
...result,
|
|
375
|
+
list: result.list.map(this.mapToUserProfile)
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### 2. 事务处理
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
@injectable()
|
|
385
|
+
export class TransactionManager {
|
|
386
|
+
async withTransaction<T>(
|
|
387
|
+
callback: (transaction: Transaction) => Promise<T>
|
|
388
|
+
): Promise<T> {
|
|
389
|
+
const transaction = await this.dbBridge.startTransaction();
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const result = await callback(transaction);
|
|
393
|
+
await transaction.commit();
|
|
394
|
+
return result;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
await transaction.rollback();
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// 使用事务
|
|
403
|
+
async createUserWithProfile(data: UserData): Promise<User> {
|
|
404
|
+
return this.transactionManager.withTransaction(async (transaction) => {
|
|
405
|
+
const user = await this.userRepository.add(data, transaction);
|
|
406
|
+
await this.profileRepository.add(data.profile, transaction);
|
|
407
|
+
return user;
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### 3. 查询优化
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
@injectable()
|
|
416
|
+
export class OptimizedUserRepository extends UserRepository {
|
|
417
|
+
// 使用字段选择优化查询
|
|
418
|
+
async getUserProfile(id: number): Promise<UserProfile> {
|
|
419
|
+
const result = await this.dbBridge.get({
|
|
420
|
+
table: this.name,
|
|
421
|
+
fields: this.safeFields, // 只选择需要的字段
|
|
422
|
+
where: [['id', '=', id]]
|
|
423
|
+
});
|
|
424
|
+
return this.mapToProfile(result.data);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// 使用索引优化查询
|
|
428
|
+
async searchUsers(query: string): Promise<User[]> {
|
|
429
|
+
const result = await this.dbBridge.get({
|
|
430
|
+
table: this.name,
|
|
431
|
+
where: [
|
|
432
|
+
['email', '=', query], // 假设 email 字段有索引
|
|
433
|
+
['role', '=', 'user']
|
|
434
|
+
]
|
|
435
|
+
});
|
|
436
|
+
return result.data as User[];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### 4. 缓存策略
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
@injectable()
|
|
445
|
+
export class CachedUserRepository extends UserRepository {
|
|
446
|
+
constructor(
|
|
447
|
+
@inject(I.DBBridgeInterface) dbBridge: DBBridgeInterface,
|
|
448
|
+
@inject(I.CacheManager) private cache: CacheManager
|
|
449
|
+
) {
|
|
450
|
+
super(dbBridge);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async getUserByEmail(email: string): Promise<UserSchema | null> {
|
|
454
|
+
// 先查缓存
|
|
455
|
+
const cached = await this.cache.get(`user:${email}`);
|
|
456
|
+
if (cached) return cached;
|
|
457
|
+
|
|
458
|
+
// 缓存未命中,查数据库
|
|
459
|
+
const user = await super.getUserByEmail(email);
|
|
460
|
+
if (user) {
|
|
461
|
+
await this.cache.set(`user:${email}`, user, '1h');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return user;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## 总结
|
|
470
|
+
|
|
471
|
+
项目的数据库设计遵循以下原则:
|
|
472
|
+
|
|
473
|
+
1. **抽象分层**:
|
|
474
|
+
- 清晰的接口定义
|
|
475
|
+
- 数据库实现可替换
|
|
476
|
+
- 仓库模式封装业务逻辑
|
|
477
|
+
|
|
478
|
+
2. **类型安全**:
|
|
479
|
+
- 完整的 TypeScript 类型定义
|
|
480
|
+
- 查询条件类型检查
|
|
481
|
+
- 响应数据类型验证
|
|
482
|
+
|
|
483
|
+
3. **安全性**:
|
|
484
|
+
- 字段级别的访问控制
|
|
485
|
+
- 参数化查询防注入
|
|
486
|
+
- 敏感数据过滤
|
|
487
|
+
|
|
488
|
+
4. **可扩展性**:
|
|
489
|
+
- 支持多种数据库实现
|
|
490
|
+
- 插件化的功能扩展
|
|
491
|
+
- 统一的查询接口
|
|
492
|
+
|
|
493
|
+
5. **性能优化**:
|
|
494
|
+
- 字段选择优化
|
|
495
|
+
- 查询条件优化
|
|
496
|
+
- 缓存策略支持
|