@fastcar/cli 0.1.2 → 0.1.4

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.
@@ -5,7 +5,7 @@ description: FastCar 数据库与缓存开发指南。Use when working with Fast
5
5
 
6
6
  # FastCar Database
7
7
 
8
- FastCar 数据库模块提供基于装饰器的 ORM 支持,涵盖 MySQL、PostgreSQL、MongoDB 和 Redis,并支持通过 `mysql-tool` 逆向生成 Model 和 Mapper
8
+ FastCar 数据库模块提供基于装饰器的 ORM 支持,涵盖 MySQL、PostgreSQL、MongoDB 和 Redis。
9
9
 
10
10
  ## 模块速查
11
11
 
@@ -26,10 +26,17 @@ export default new APP();
26
26
  #### 定义实体模型
27
27
 
28
28
  ```typescript
29
- import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
30
-
31
- @Table("users")
32
- class User {
29
+ import {
30
+ Table,
31
+ Field,
32
+ DBType,
33
+ PrimaryKey,
34
+ NotNull,
35
+ Size,
36
+ } from "@fastcar/core/annotation";
37
+
38
+ @Table("entities")
39
+ class Entity {
33
40
  @Field("id")
34
41
  @DBType("int")
35
42
  @PrimaryKey
@@ -41,27 +48,16 @@ class User {
41
48
  @Size({ maxSize: 50 })
42
49
  name!: string;
43
50
 
44
- @Field("profile")
51
+ @Field("data")
45
52
  @DBType("json")
46
- profile!: any;
53
+ data!: any;
47
54
 
48
55
  @Field("created_at")
49
56
  @DBType("datetime")
50
57
  createdAt!: Date;
51
58
 
52
- constructor(args?: Partial<User>) {
53
- if (args) {
54
- Object.assign(this, args);
55
- }
56
- }
57
-
58
- toObject() {
59
- return {
60
- id: this.id,
61
- name: this.name,
62
- profile: this.profile,
63
- createdAt: this.createdAt,
64
- };
59
+ constructor(args?: Partial<Entity>) {
60
+ if (args) Object.assign(this, args);
65
61
  }
66
62
  }
67
63
  ```
@@ -71,300 +67,269 @@ class User {
71
67
  ```typescript
72
68
  import { Entity, Repository } from "@fastcar/core/annotation";
73
69
  import { MysqlMapper } from "@fastcar/mysql";
74
- import User from "./User";
70
+ import Entity from "./Entity";
75
71
 
76
- @Entity(User)
72
+ @Entity(Entity)
77
73
  @Repository
78
- class UserMapper extends MysqlMapper<User> {}
79
-
80
- export default UserMapper;
74
+ class EntityMapper extends MysqlMapper<Entity> {}
75
+ export default EntityMapper;
81
76
  ```
82
77
 
83
- #### MysqlMapper 完整 API 参考
78
+ #### MysqlMapper 核心 API
84
79
 
85
80
  ```typescript
86
81
  import { Service, Autowired } from "@fastcar/core/annotation";
87
82
  import { OrderEnum, OperatorEnum } from "@fastcar/core/db";
88
- import UserMapper from "./UserMapper";
89
- import User from "./User";
83
+ import EntityMapper from "./EntityMapper";
84
+ import Entity from "./Entity";
90
85
 
91
86
  @Service
92
- class UserService {
87
+ class EntityService {
93
88
  @Autowired
94
- private userMapper!: UserMapper;
89
+ private mapper!: EntityMapper;
95
90
 
96
- // ==================== 查询方法 ====================
91
+ // ===== 查询方法 =====
97
92
 
98
- // 1. select(conditions) - 查询列表
99
- // 返回: T[] - 实体对象数组
100
- async getAllUsers() {
101
- return this.userMapper.select({});
93
+ // 查询列表
94
+ async list() {
95
+ return this.mapper.select({});
102
96
  }
103
97
 
104
- // 2. selectOne(conditions) - 查询单个
105
- // 返回: T | null
106
- async getUserById(id: number) {
107
- return this.userMapper.selectOne({
108
- where: { id }
109
- });
98
+ // 查询单个
99
+ async getOne(id: number) {
100
+ return this.mapper.selectOne({ where: { id } });
110
101
  }
111
102
 
112
- // 3. selectByPrimaryKey(row) - 根据主键查询
113
- // 参数: 包含主键字段的对象
114
- // 返回: T | null
115
- async getUserByPK(id: number) {
116
- return this.userMapper.selectByPrimaryKey({ id } as User);
103
+ // 根据主键查询
104
+ async getByPK(id: number) {
105
+ return this.mapper.selectByPrimaryKey({ id } as Entity);
117
106
  }
118
107
 
119
- // 4. count(where) - 统计记录数
120
- // 返回: number
121
- async countUsers() {
122
- return this.userMapper.count({ status: 1 });
108
+ // 统计记录数
109
+ async count() {
110
+ return this.mapper.count({ status: 1 });
123
111
  }
124
112
 
125
- // 5. exist(where) - 判断是否存在
126
- // 返回: boolean
127
- async checkUserExists(name: string) {
128
- return this.userMapper.exist({ name });
113
+ // 判断是否存在
114
+ async exists(name: string) {
115
+ return this.mapper.exist({ name });
129
116
  }
130
117
 
131
- // ==================== 条件查询详解 ====================
118
+ // ===== 条件查询 =====
132
119
 
133
120
  // 简单等于条件
134
121
  async queryByStatus(status: number) {
135
- return this.userMapper.select({
136
- where: { status }
137
- });
122
+ return this.mapper.select({ where: { status } });
138
123
  }
139
124
 
140
125
  // 多条件 AND
141
126
  async queryByConditions(name: string, status: number) {
142
- return this.userMapper.select({
143
- where: {
144
- name,
145
- status,
146
- delStatus: false
147
- }
127
+ return this.mapper.select({
128
+ where: { name, status, delStatus: false },
148
129
  });
149
130
  }
150
131
 
151
132
  // 比较运算符
152
- async queryByAgeRange(minAge: number, maxAge: number) {
153
- return this.userMapper.select({
154
- where: {
155
- age: { $gte: minAge, $lte: maxAge }
156
- }
133
+ async queryByRange(min: number, max: number) {
134
+ return this.mapper.select({
135
+ where: { value: { [OperatorEnum.gte]: min, [OperatorEnum.lte]: max } },
157
136
  });
158
137
  }
159
138
 
160
- // 支持的运算符:
161
- // $eq - 等于 (默认)
162
- // $gt / $gte - 大于 / 大于等于
163
- // $lt / $lte - 小于 / 小于等于
164
- // $ne - 不等于
165
- // $in - IN 查询 (数组)
166
- // $nin - NOT IN 查询
167
- // $isNull - IS NULL
168
- // $isNotNull - IS NOT NULL
169
-
170
139
  // IN 查询
171
140
  async queryByIds(ids: number[]) {
172
- return this.userMapper.select({
173
- where: { id: { $in: ids } }
141
+ return this.mapper.select({
142
+ where: { id: { [OperatorEnum.in]: ids } },
174
143
  });
175
144
  }
176
145
 
177
146
  // IS NULL 查询
178
- async queryDeletedUsers() {
179
- return this.userMapper.select({
180
- where: { deletedAt: { $isNull: true } }
147
+ async queryDeleted() {
148
+ return this.mapper.select({
149
+ where: { deletedAt: { [OperatorEnum.isNUll]: true } },
181
150
  });
182
151
  }
183
152
 
184
- // ==================== 排序和分页 ====================
153
+ // ===== AND 条件查询 =====
185
154
 
186
- // 排序 - 必须使用 OrderEnum
187
- async getUsersOrdered() {
188
- return this.userMapper.select({
189
- where: { status: 1 },
190
- orders: { createdAt: OrderEnum.desc } // 正确: 使用 OrderEnum.desc
191
- // 错误: orders: { createdAt: "DESC" }
155
+ // 方式1:默认多字段自动 AND
156
+ async queryByMultipleConditions(name: string, status: number) {
157
+ return this.mapper.select({
158
+ where: { name, status, delStatus: false },
159
+ // 生成 SQL: WHERE name = ? AND status = ? AND del_status = ?
192
160
  });
193
161
  }
194
162
 
195
- // OrderEnum 定义:
196
- // OrderEnum.asc = "ASC"
197
- // OrderEnum.desc = "DESC"
198
-
199
- // 多字段排序
200
- async getUsersMultiOrder() {
201
- return this.userMapper.select({
202
- orders: {
203
- status: OrderEnum.asc,
204
- createdAt: OrderEnum.desc
205
- }
163
+ // 方式2:同一字段多条件 AND
164
+ async queryByAgeRange(min: number, max: number) {
165
+ return this.mapper.select({
166
+ where: {
167
+ age: { [OperatorEnum.gte]: min, [OperatorEnum.lte]: max },
168
+ // 生成 SQL: WHERE age >= ? AND age <= ?
169
+ },
206
170
  });
207
171
  }
208
172
 
209
- // 分页
210
- async getUsersPaged(page: number, pageSize: number) {
211
- return this.userMapper.select({
212
- orders: { id: OrderEnum.desc },
213
- offest: (page - 1) * pageSize,
214
- limit: pageSize
173
+ // ===== OR 条件查询 =====
174
+
175
+ // 方式1:对象形式(推荐)- 不同字段 OR
176
+ async queryByNameOrEmail(keyword: string) {
177
+ return this.mapper.select({
178
+ where: {
179
+ [JoinEnum.or]: {
180
+ name: keyword,
181
+ email: keyword,
182
+ },
183
+ // 生成 SQL: WHERE name = ? OR email = ?
184
+ },
215
185
  });
216
186
  }
217
187
 
218
- // 只取前N条
219
- async getTopUsers(limit: number) {
220
- return this.userMapper.select({
221
- orders: { score: OrderEnum.desc },
222
- limit
188
+ // 方式2:数组形式 - 复杂条件 OR
189
+ async queryComplexOr() {
190
+ return this.mapper.select({
191
+ where: {
192
+ [JoinEnum.or]: [
193
+ { status: 1, type: "A" },
194
+ { status: 2, type: "B" },
195
+ ],
196
+ // 生成 SQL: WHERE (status = 1 AND type = 'A') OR (status = 2 AND type = 'B')
197
+ },
223
198
  });
224
199
  }
225
200
 
226
- // ==================== 插入方法 ====================
201
+ // ===== AND 与 OR 组合 =====
227
202
 
228
- // 1. saveOne(row) - 插入单条
229
- // 返回: number - 插入的主键ID
230
- async createUser(name: string) {
231
- const user = new User({ name, createdAt: new Date() });
232
- const insertId = await this.userMapper.saveOne(user);
233
- return insertId;
203
+ async queryComplex(department: string, status: number, keyword: string) {
204
+ return this.mapper.select({
205
+ where: {
206
+ department,
207
+ [JoinEnum.or]: {
208
+ name: { [OperatorEnum.like]: `%${keyword}%` },
209
+ email: { [OperatorEnum.like]: `%${keyword}%` },
210
+ },
211
+ status,
212
+ // 生成 SQL: WHERE department = ? AND (name LIKE ? OR email LIKE ?) AND status = ?
213
+ },
214
+ });
234
215
  }
235
216
 
236
- // 2. saveList(rows) - 批量插入
237
- // 返回: boolean
238
- async createUsers(users: User[]) {
239
- return this.userMapper.saveList(users);
217
+ // ===== 排序和分页 =====
218
+
219
+ async getOrdered() {
220
+ return this.mapper.select({
221
+ where: { status: 1 },
222
+ orders: { createdAt: OrderEnum.desc },
223
+ });
240
224
  }
241
225
 
242
- // 3. saveORUpdate(rows) - 插入或更新 (UPSERT)
243
- // 主键冲突时更新,否则插入
244
- // 返回: number - 主键ID
245
- async saveOrUpdateUser(user: User) {
246
- return this.userMapper.saveORUpdate(user);
226
+ async getPaged(page: number, pageSize: number) {
227
+ return this.mapper.select({
228
+ orders: { id: OrderEnum.desc },
229
+ offset: (page - 1) * pageSize,
230
+ limit: pageSize,
231
+ });
247
232
  }
248
233
 
249
- // ==================== 更新方法 ====================
234
+ // ===== 插入方法 =====
250
235
 
251
- // 1. update({ row, where, limit }) - 条件更新
252
- // 返回: boolean
253
- async updateUserName(id: number, name: string) {
254
- return this.userMapper.update({
255
- where: { id },
256
- row: { name, updatedAt: new Date() }
257
- });
236
+ // 插入单条
237
+ async create(name: string) {
238
+ const entity = new Entity({ name, createdAt: new Date() });
239
+ return this.mapper.saveOne(entity);
258
240
  }
259
241
 
260
- // 2. updateOne({ row, where }) - 更新单条
261
- // 自动限制 limit: 1
262
- async updateOneUser(where: any, row: any) {
263
- return this.userMapper.updateOne({ where, row });
242
+ // 批量插入
243
+ async createBatch(list: Entity[]) {
244
+ return this.mapper.saveList(list);
264
245
  }
265
246
 
266
- // 3. updateByPrimaryKey(row) - 根据主键更新
267
- // 根据实体对象的主键字段更新
268
- // 返回: boolean
269
- async updateById(user: User) {
270
- return this.userMapper.updateByPrimaryKey(user);
247
+ // 插入或更新
248
+ async saveOrUpdate(entity: Entity) {
249
+ return this.mapper.saveORUpdate(entity);
271
250
  }
272
251
 
273
- // 更新示例:软删除
274
- async softDeleteUser(id: number) {
275
- return this.userMapper.update({
252
+ // ===== 更新方法 =====
253
+
254
+ // 条件更新
255
+ async updateName(id: number, name: string) {
256
+ return this.mapper.update({
276
257
  where: { id },
277
- row: { delStatus: true, deletedAt: new Date() }
258
+ row: { name, updatedAt: new Date() },
278
259
  });
279
260
  }
280
261
 
281
- // ==================== 删除方法 ====================
282
-
283
- // 1. delete({ where, limit }) - 条件删除
284
- // 返回: boolean
285
- async deleteUser(id: number) {
286
- return this.userMapper.delete({
287
- where: { id }
288
- });
262
+ // 更新单条
263
+ async updateOne(where: any, row: any) {
264
+ return this.mapper.updateOne({ where, row });
289
265
  }
290
266
 
291
- // 2. deleteOne(where) - 删除单条
292
- async deleteOneUser(where: any) {
293
- return this.userMapper.deleteOne(where);
267
+ // 根据主键更新
268
+ async updateById(entity: Entity) {
269
+ return this.mapper.updateByPrimaryKey(entity);
294
270
  }
295
271
 
296
- // 3. deleteByPrimaryKey(row) - 根据主键删除
297
- async deleteById(id: number) {
298
- return this.userMapper.deleteByPrimaryKey({ id } as User);
272
+ // 软删除
273
+ async softDelete(id: number) {
274
+ return this.mapper.update({
275
+ where: { id },
276
+ row: { delStatus: true, deletedAt: new Date() },
277
+ });
299
278
  }
300
279
 
301
- // ==================== 高级查询 ====================
280
+ // ===== 删除方法 =====
302
281
 
303
- // 自定义 SQL 查询
304
- // query(sql, args) - 执行查询 SQL
305
- async customQuery() {
306
- return this.userMapper.query(
307
- "SELECT * FROM users WHERE status = ? AND created_at > ?",
308
- [1, "2024-01-01"]
309
- );
282
+ async deleteById(id: number) {
283
+ return this.mapper.delete({ where: { id } });
310
284
  }
311
285
 
312
- // execute(sql, args) - 执行任意 SQL
313
- async customExecute() {
314
- return this.userMapper.execute(
315
- "UPDATE users SET login_count = login_count + 1 WHERE id = ?",
316
- [1]
317
- );
286
+ async deleteOne(where: any) {
287
+ return this.mapper.deleteOne(where);
318
288
  }
319
289
 
320
- // 左连接查询 - 使用 selectByCustom
321
- async leftJoinQuery() {
322
- return this.userMapper.selectByCustom({
290
+ // ===== 高级查询 =====
291
+
292
+ // selectByCustom 支持 JOIN、分组、聚合
293
+ async advancedQuery() {
294
+ // 指定字段 + 泛型类型
295
+ const results = await this.mapper.selectByCustom<{
296
+ id: number;
297
+ name: string;
298
+ relatedName: string;
299
+ }>({
300
+ tableAlias: "t",
301
+ fields: ["t.id", "t.name", "r.name as relatedName"],
323
302
  join: [
324
303
  {
325
304
  type: "LEFT",
326
- table: "orders o",
327
- on: "o.user_id = t.id",
305
+ table: "related_table r",
306
+ on: "r.entity_id = t.id",
328
307
  },
329
308
  ],
330
- tableAlias: "t",
331
- where: { "t.status": 1 }
332
- });
333
- }
334
-
335
- // 强制索引
336
- async forceIndexQuery() {
337
- return this.userMapper.select({
338
- forceIndex: ["idx_name"],
339
- where: { status: 1 }
309
+ where: { "t.status": 1 },
310
+ camelcaseStyle: true,
340
311
  });
341
- }
342
312
 
343
- // 指定查询字段
344
- async selectFields() {
345
- return this.userMapper.select({
346
- fields: ["id", "name", "email"],
347
- where: { status: 1 }
313
+ // 聚合查询
314
+ const stats = await this.mapper.selectByCustom({
315
+ fields: [
316
+ "status",
317
+ "COUNT(*) as totalCount",
318
+ "MAX(created_at) as lastCreated",
319
+ ],
320
+ groups: ["status"],
321
+ orders: { totalCount: OrderEnum.desc },
348
322
  });
349
- }
350
323
 
351
- // 分组查询
352
- async groupByStatus() {
353
- return this.userMapper.selectByCustom({
354
- fields: ["status", "COUNT(*) as count"],
355
- groups: ["status"]
356
- });
324
+ return { results, stats };
357
325
  }
358
326
 
359
- // 使用数据库函数
360
- async useDbFunction() {
361
- return this.userMapper.selectByCustom({
362
- fields: [
363
- 'id',
364
- 'name',
365
- 'DATE_FORMAT(created_at, "%Y-%m-%d") as createdDate'
366
- ]
367
- });
327
+ // 自定义 SQL
328
+ async customQuery() {
329
+ return this.mapper.query(
330
+ "SELECT * FROM entities WHERE status = ? AND created_at > ?",
331
+ [1, "2024-01-01"],
332
+ );
368
333
  }
369
334
  }
370
335
  ```
@@ -372,45 +337,43 @@ class UserService {
372
337
  #### 常用查询条件速查表
373
338
 
374
339
  ```typescript
340
+ import { OperatorEnum, OrderEnum } from "@fastcar/core/db";
341
+
375
342
  // 等于 (默认)
376
343
  { where: { status: 1 } }
377
344
 
378
345
  // 不等于
379
- { where: { status: { $ne: 1 } } }
380
-
381
- // 大于 / 大于等于
382
- { where: { age: { $gt: 18 } } }
383
- { where: { age: { $gte: 18 } } }
346
+ { where: { status: { [OperatorEnum.neq]: 1 } } }
384
347
 
385
- // 小于 / 小于等于
386
- { where: { age: { $lt: 60 } } }
387
- { where: { age: { $lte: 60 } } }
348
+ // 大于 / 大于等于 / 小于 / 小于等于
349
+ { where: { age: { [OperatorEnum.gt]: 18 } } }
350
+ { where: { age: { [OperatorEnum.gte]: 18, [OperatorEnum.lte]: 60 } } }
388
351
 
389
- // 范围查询
390
- { where: { age: { $gte: 18, $lte: 60 } } }
352
+ // IN / NOT IN
353
+ { where: { id: { [OperatorEnum.in]: [1, 2, 3] } } }
354
+ { where: { id: { [OperatorEnum.notin]: [1, 2, 3] } } }
391
355
 
392
- // IN 查询
393
- { where: { id: { $in: [1, 2, 3] } } }
356
+ // IS NULL / IS NOT NULL
357
+ { where: { deletedAt: { [OperatorEnum.isNUll]: true } } }
358
+ { where: { deletedAt: { [OperatorEnum.isNotNull]: true } } }
394
359
 
395
- // NOT IN 查询
396
- { where: { id: { $nin: [1, 2, 3] } } }
360
+ // AND(默认,多字段自动 AND)
361
+ { where: { name: "A", status: 1 } }
397
362
 
398
- // IS NULL
399
- { where: { deletedAt: { $isNull: true } } }
363
+ // OR(对象形式 - 推荐,不同字段)
364
+ { where: { [JoinEnum.or]: { name: "A", email: "A" } } }
400
365
 
401
- // IS NOT NULL
402
- { where: { deletedAt: { $isNotNull: true } } }
366
+ // OR(数组形式,复杂条件)
367
+ { where: { [JoinEnum.or]: [{ status: 1 }, { status: 2 }] } }
403
368
 
404
- // 多条件 AND (默认)
405
- { where: { status: 1, delStatus: false } }
369
+ // AND + OR 组合
370
+ { where: { status: 1, [JoinEnum.or]: { type: 1, category: 2 } } }
406
371
 
407
- // 排序 (必须使用 OrderEnum)
408
- import { OrderEnum } from "@fastcar/core/db";
372
+ // 排序
409
373
  { orders: { createdAt: OrderEnum.desc } }
410
- { orders: { createdAt: OrderEnum.asc } }
411
374
 
412
375
  // 分页
413
- { offest: 0, limit: 10 }
376
+ { offset: 0, limit: 10 }
414
377
  ```
415
378
 
416
379
  #### 事务处理
@@ -420,35 +383,33 @@ import { SqlSession } from "@fastcar/core/annotation";
420
383
  import { MysqlDataSourceManager } from "@fastcar/mysql";
421
384
 
422
385
  @Service
423
- class OrderService {
386
+ class BizService {
424
387
  @Autowired
425
388
  private dsm!: MysqlDataSourceManager;
426
389
 
427
390
  @Autowired
428
- private orderMapper!: OrderMapper;
391
+ private mapperA!: MapperA;
429
392
 
430
393
  @Autowired
431
- private inventoryMapper!: InventoryMapper;
394
+ private mapperB!: MapperB;
432
395
 
433
- async createOrderWithTransaction(order: Order, inventoryUpdate: any) {
396
+ async transactionExample(dataA: any, dataB: any) {
434
397
  const sessionId = await this.dsm.beginTransaction();
435
-
398
+
436
399
  try {
437
- // 插入订单
438
- await this.orderMapper.saveOne(order, undefined, sessionId);
439
-
440
- // 更新库存
441
- await this.inventoryMapper.update({
442
- where: { id: inventoryUpdate.id },
443
- row: { quantity: inventoryUpdate.quantity }
444
- }, undefined, sessionId);
445
-
446
- // 提交事务
400
+ await this.mapperA.saveOne(dataA, undefined, sessionId);
401
+ await this.mapperB.update(
402
+ {
403
+ where: { id: dataB.id },
404
+ row: { status: dataB.status },
405
+ },
406
+ undefined,
407
+ sessionId,
408
+ );
409
+
447
410
  await this.dsm.commit(sessionId);
448
-
449
411
  return true;
450
412
  } catch (error) {
451
- // 回滚事务
452
413
  await this.dsm.rollback(sessionId);
453
414
  throw error;
454
415
  }
@@ -458,81 +419,45 @@ class OrderService {
458
419
 
459
420
  ### PostgreSQL (@fastcar/pgsql)
460
421
 
461
- #### 开启 PostgreSQL
462
-
463
422
  ```typescript
464
- import { Application } from "@fastcar/core/annotation";
465
423
  import { EnablePgsql } from "@fastcar/pgsql/annotation";
424
+ import { PgsqlMapper } from "@fastcar/pgsql";
466
425
 
467
426
  @Application
468
427
  @EnablePgsql
469
428
  class APP {}
470
- export default new APP();
471
- ```
472
-
473
- #### 定义 Mapper
474
-
475
- ```typescript
476
- import { Entity, Repository } from "@fastcar/core/annotation";
477
- import { PgsqlMapper } from "@fastcar/pgsql";
478
- import User from "./User";
479
429
 
480
- @Entity(User)
430
+ @Entity(Entity)
481
431
  @Repository
482
- class UserMapper extends PgsqlMapper<User> {}
483
-
484
- export default UserMapper;
432
+ class EntityMapper extends PgsqlMapper<Entity> {}
485
433
  ```
486
434
 
487
- 用法与 `MysqlMapper` 基本一致,支持相同的查询条件和 CRUD 操作。
435
+ 用法与 `MysqlMapper` 基本一致。
488
436
 
489
437
  ### MongoDB (@fastcar/mongo)
490
438
 
491
- #### 开启 MongoDB
492
-
493
439
  ```typescript
494
- import { Application } from "@fastcar/core/annotation";
495
440
  import { EnableMongo } from "@fastcar/mongo/annotation";
441
+ import { MongoMapper } from "@fastcar/mongo";
496
442
 
497
443
  @Application
498
444
  @EnableMongo
499
445
  class APP {}
500
- export default new APP();
501
- ```
502
-
503
- #### 定义 Mapper
504
446
 
505
- ```typescript
506
- import { Entity, Repository } from "@fastcar/core/annotation";
507
- import { MongoMapper } from "@fastcar/mongo";
508
- import User from "./User";
509
-
510
- @Entity(User)
447
+ @Entity(Entity)
511
448
  @Repository
512
- class UserMapper extends MongoMapper<User> {}
513
-
514
- export default UserMapper;
449
+ class EntityMapper extends MongoMapper<Entity> {}
515
450
  ```
516
451
 
517
452
  ### Redis (@fastcar/redis)
518
453
 
519
- #### 开启 Redis
520
-
521
454
  ```typescript
522
- import { Application } from "@fastcar/core/annotation";
523
455
  import { EnableRedis } from "@fastcar/redis/annotation";
456
+ import { RedisClient } from "@fastcar/redis/annotation";
524
457
 
525
458
  @Application
526
459
  @EnableRedis
527
460
  class APP {}
528
- export default new APP();
529
- ```
530
-
531
- #### 使用 RedisClient
532
-
533
- ```typescript
534
- import { Service, Autowired } from "@fastcar/core/annotation";
535
- import { RedisClient } from "@fastcar/redis/annotation";
536
461
 
537
462
  @Service
538
463
  class CacheService {
@@ -551,10 +476,6 @@ class CacheService {
551
476
  await this.redis.del(key);
552
477
  }
553
478
 
554
- async expire(key: string, seconds: number) {
555
- await this.redis.expire(key, seconds);
556
- }
557
-
558
479
  // Hash 操作
559
480
  async hset(key: string, field: string, value: string) {
560
481
  await this.redis.hset(key, field, value);
@@ -577,17 +498,19 @@ class CacheService {
577
498
 
578
499
  ## 数据库逆向生成 (@fastcar/mysql-tool)
579
500
 
580
- ### 生成配置文件
581
-
582
501
  ```bash
502
+ # 生成配置文件
583
503
  fastcar-cli reverse:init
504
+
505
+ # 执行逆向生成
506
+ fastcar-cli reverse
584
507
  ```
585
508
 
586
- ### 配置文件示例
509
+ 配置文件示例:
587
510
 
588
511
  ```json
589
512
  {
590
- "tables": ["users", "orders"],
513
+ "tables": ["table1", "table2"],
591
514
  "modelDir": "D:/project/src/model",
592
515
  "mapperDir": "D:/project/src/mapper",
593
516
  "dbConfig": {
@@ -596,25 +519,10 @@ fastcar-cli reverse:init
596
519
  "user": "root",
597
520
  "password": "password",
598
521
  "database": "test_db"
599
- },
600
- "style": {
601
- "tabWidth": 4,
602
- "printWidth": 200,
603
- "trailingComma": "es5",
604
- "useTabs": true,
605
- "parser": "typescript",
606
- "endOfLine": "crlf"
607
- },
608
- "ignoreCamelcase": false
522
+ }
609
523
  }
610
524
  ```
611
525
 
612
- ### 执行逆向生成
613
-
614
- ```bash
615
- fastcar-cli reverse
616
- ```
617
-
618
526
  ## application.yml 数据库配置
619
527
 
620
528
  ```yaml
@@ -627,10 +535,7 @@ mysql:
627
535
  database: mydb
628
536
  username: root
629
537
  password: password
630
- # 连接池配置
631
538
  connectionLimit: 10
632
- # 是否使用预处理语句
633
- useServerPrepStmts: true
634
539
 
635
540
  pgsql:
636
541
  host: localhost
@@ -653,13 +558,13 @@ redis:
653
558
 
654
559
  ## 完整模块列表
655
560
 
656
- | 模块 | 安装命令 | 用途 |
657
- |------|----------|------|
658
- | @fastcar/mysql | `npm i @fastcar/mysql` | MySQL ORM |
659
- | @fastcar/pgsql | `npm i @fastcar/pgsql` | PostgreSQL ORM |
660
- | @fastcar/mongo | `npm i @fastcar/mongo` | MongoDB |
661
- | @fastcar/redis | `npm i @fastcar/redis` | Redis 缓存 |
662
- | @fastcar/mysql-tool | `npm i @fastcar/mysql-tool` | 逆向生成工具 |
561
+ | 模块 | 安装命令 | 用途 |
562
+ | ------------------- | --------------------------- | -------------- |
563
+ | @fastcar/mysql | `npm i @fastcar/mysql` | MySQL ORM |
564
+ | @fastcar/pgsql | `npm i @fastcar/pgsql` | PostgreSQL ORM |
565
+ | @fastcar/mongo | `npm i @fastcar/mongo` | MongoDB |
566
+ | @fastcar/redis | `npm i @fastcar/redis` | Redis 缓存 |
567
+ | @fastcar/mysql-tool | `npm i @fastcar/mysql-tool` | 逆向生成工具 |
663
568
 
664
569
  ## 快速开始
665
570
 
@@ -679,6 +584,200 @@ npm run debug
679
584
 
680
585
  1. **排序必须使用 OrderEnum**:`orders: { createdAt: OrderEnum.desc }`,不能使用字符串 `"DESC"`
681
586
  2. **主键查询**:`selectByPrimaryKey` 和 `updateByPrimaryKey` 需要传入包含主键字段的对象
682
- 3. **时间范围查询**:使用 `$gte` 和 `$lte` 运算符
683
- 4. **批量插入**:`saveList` 会自动分批处理(每批1000条)
684
- 5. **软删除**:建议使用 `update` 方法更新 `delStatus` 字段,而不是物理删除
587
+ 3. **批量插入**:`saveList` 会自动分批处理(每批1000条)
588
+ 4. **软删除**:建议使用 `update` 方法更新 `delStatus` 字段,而不是物理删除
589
+
590
+ ## 数据库查询最佳实践
591
+
592
+ ### ⚠️ 分页查询 - 必须使用数据库层分页
593
+
594
+ **核心原则**:分页必须在数据库层完成,严禁全表查询后在内存中切片。
595
+
596
+ ```typescript
597
+ // ✅ 正确:使用 SQL LIMIT/OFFSET 分页(数据库层完成分页)
598
+ const list = await this.mapper.select({
599
+ where: { status: 1 },
600
+ orders: { id: OrderEnum.desc },
601
+ offset: (page - 1) * pageSize,
602
+ limit: pageSize, // 只取需要的记录
603
+ });
604
+
605
+ // ✅ 正确:使用游标/滚动分页(适合大数据量)
606
+ const list = await this.mapper.select({
607
+ where: {
608
+ id: { [OperatorEnum.lt]: lastId } // 基于上一页最后ID
609
+ },
610
+ orders: { id: OrderEnum.desc },
611
+ limit: pageSize,
612
+ });
613
+
614
+ // ❌ 错误:全表查询后在内存中切片(数据量大时会导致 OOM)
615
+ const allData = await this.mapper.select({ where: { status: 1 } }); // 可能百万级数据
616
+ const pageData = allData.slice((page - 1) * pageSize, page * pageSize); // 内存中切片
617
+ ```
618
+
619
+ **为什么重要**:
620
+ - 全表查询会将所有数据加载到 Node.js 内存,数据量大时会导致内存溢出(OOM)
621
+ - 网络传输大量无用数据,严重影响性能
622
+ - 数据库层分页只返回需要的记录,内存占用固定
623
+
624
+ ---
625
+
626
+ ### ⚠️ 分组聚合 - 必须使用数据库层 GROUP BY
627
+
628
+ **核心原则**:分组统计必须在数据库层完成,严禁全表查询后在 JS 中分组。
629
+
630
+ ```typescript
631
+ // ✅ 正确:使用 SQL GROUP BY 分组(数据库层聚合)
632
+ const stats = await this.mapper.selectByCustom({
633
+ fields: [
634
+ "status",
635
+ "COUNT(*) as count",
636
+ "SUM(amount) as totalAmount",
637
+ "MAX(created_at) as latestTime",
638
+ ],
639
+ groups: ["status"], // 数据库层分组
640
+ orders: { count: OrderEnum.desc },
641
+ });
642
+
643
+ // ✅ 正确:使用 JOIN + GROUP BY 关联聚合
644
+ const userOrderStats = await this.mapper.selectByCustom({
645
+ fields: [
646
+ "u.id",
647
+ "u.name",
648
+ "COUNT(o.id) as orderCount",
649
+ "SUM(o.amount) as totalAmount",
650
+ ],
651
+ join: [{
652
+ type: "LEFT",
653
+ table: "orders o",
654
+ on: "o.user_id = u.id",
655
+ }],
656
+ groups: ["u.id", "u.name"], // 数据库层分组聚合
657
+ });
658
+
659
+ // ❌ 错误:全表查询后在 JS 中分组(数据量大时会导致 OOM)
660
+ const allRecords = await this.mapper.select({}); // 加载所有数据
661
+ const grouped = allRecords.reduce((acc, item) => {
662
+ if (!acc[item.status]) acc[item.status] = { count: 0, total: 0 };
663
+ acc[item.status].count++;
664
+ acc[item.status].total += item.amount;
665
+ return acc;
666
+ }, {}); // 内存中分组,大数据量时性能极差
667
+ ```
668
+
669
+ **为什么重要**:
670
+ - 数据库专为聚合计算优化,性能远高于 JS 遍历
671
+ - 减少网络传输(只返回聚合结果,而非原始数据)
672
+ - 避免 JS 单线程处理大量数据的性能瓶颈
673
+ - 防止内存溢出风险
674
+
675
+ ---
676
+
677
+ ## 编码规范
678
+
679
+ ### 1. 实体对象创建规范
680
+
681
+ ```typescript
682
+ // ✅ 正确:使用 key-value 形式创建对象
683
+ const entity = new Entity({
684
+ name: "示例",
685
+ status: 1,
686
+ createTime: new Date(),
687
+ });
688
+
689
+ // ❌ 错误:逐行赋值创建对象
690
+ const entity = new Entity();
691
+ entity.name = "示例";
692
+ entity.status = 1;
693
+ ```
694
+
695
+ ### 2. 分页查询规范
696
+
697
+ ```typescript
698
+ // ✅ 正确:使用 SQL limit/offset 分页
699
+ const total = await this.mapper.count(where);
700
+ const list = await this.mapper.select({
701
+ where: where,
702
+ orders: { createTime: OrderEnum.desc },
703
+ offset: (page - 1) * pageSize,
704
+ limit: pageSize,
705
+ });
706
+
707
+ // ❌ 错误:先全表查询再用 JS slice 分页
708
+ const list = await this.mapper.select({ where });
709
+ const pageData = list.slice((page - 1) * pageSize, page * pageSize);
710
+ ```
711
+
712
+ ### 3. 查询条件规范
713
+
714
+ ```typescript
715
+ import { OperatorEnum } from "@fastcar/core/db";
716
+
717
+ // ✅ 正确:使用 OperatorEnum
718
+ const list = await this.mapper.select({
719
+ where: {
720
+ age: { [OperatorEnum.gte]: 18, [OperatorEnum.lte]: 60 },
721
+ status: { [OperatorEnum.in]: [1, 2, 3] },
722
+ },
723
+ });
724
+ ```
725
+
726
+ ### 4. 接口返回规范
727
+
728
+ ```typescript
729
+ // ✅ 正确:返回空数据
730
+ if (records.length === 0) {
731
+ return Result.ok({ list: [], total: 0 });
732
+ }
733
+
734
+ // ❌ 错误:返回模拟数据
735
+ if (records.length === 0) {
736
+ return Result.ok({ list: [{ name: "模拟数据1" }] });
737
+ }
738
+ ```
739
+
740
+ ### 5. 更新操作规范
741
+
742
+ ```typescript
743
+ // ✅ 正确:更新少于3个字段时使用 update/updateOne
744
+ await this.mapper.updateOne({
745
+ where: { id },
746
+ row: { lastLoginTime: new Date() },
747
+ });
748
+
749
+ // ❌ 错误:为了更新1-2个字段而查询整个实体对象
750
+ const entity = await this.mapper.selectByPrimaryKey({ id });
751
+ entity.lastLoginTime = new Date();
752
+ await this.mapper.updateByPrimaryKey(entity);
753
+ ```
754
+
755
+ ### 6. 复杂查询优化
756
+
757
+ ```typescript
758
+ // ✅ 正确:使用 selectByCustom + JOIN 一条 SQL 完成
759
+ interface QueryResult {
760
+ id: number;
761
+ name: string;
762
+ relatedName: string;
763
+ }
764
+
765
+ const results = await this.mapper.selectByCustom<QueryResult>({
766
+ tableAlias: "t",
767
+ fields: ["t.id", "t.name", "r.name as relatedName"],
768
+ join: [{
769
+ type: "INNER",
770
+ table: "related_table r",
771
+ on: "r.entity_id = t.id",
772
+ }],
773
+ where: { "t.status": 1 },
774
+ camelcaseStyle: true,
775
+ });
776
+
777
+ // ❌ 错误:多次查询 + 内存组装(N+1 问题)
778
+ const list = await this.mapper.select({});
779
+ for (const item of list) {
780
+ const related = await this.relatedMapper.selectOne({ ... });
781
+ // 内存组装...
782
+ }
783
+ ```