befly 3.9.6 → 3.9.7

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.
@@ -0,0 +1,1012 @@
1
+ # Befly 数据库操作指南
2
+
3
+ > 本文档详细介绍 Befly 框架的数据库操作 API,包括 CRUD 操作、事务、条件查询等。
4
+
5
+ ## 目录
6
+
7
+ - [Befly 数据库操作指南](#befly-数据库操作指南)
8
+ - [目录](#目录)
9
+ - [核心概念](#核心概念)
10
+ - [DbHelper](#dbhelper)
11
+ - [自动转换](#自动转换)
12
+ - [字段命名规范](#字段命名规范)
13
+ - [查询方法](#查询方法)
14
+ - [getOne - 查询单条](#getone---查询单条)
15
+ - [getList - 分页查询](#getlist---分页查询)
16
+ - [getAll - 查询全部](#getall---查询全部)
17
+ - [getCount - 查询数量](#getcount---查询数量)
18
+ - [exists - 检查存在](#exists---检查存在)
19
+ - [getFieldValue - 查询单字段](#getfieldvalue---查询单字段)
20
+ - [写入方法](#写入方法)
21
+ - [insData - 插入数据](#insdata---插入数据)
22
+ - [insBatch - 批量插入](#insbatch---批量插入)
23
+ - [updData - 更新数据](#upddata---更新数据)
24
+ - [delData - 软删除](#deldata---软删除)
25
+ - [delForce - 硬删除](#delforce---硬删除)
26
+ - [disableData - 禁用](#disabledata---禁用)
27
+ - [enableData - 启用](#enabledata---启用)
28
+ - [数值操作](#数值操作)
29
+ - [increment - 自增](#increment---自增)
30
+ - [decrement - 自减](#decrement---自减)
31
+ - [事务操作](#事务操作)
32
+ - [多表联查](#多表联查)
33
+ - [简洁写法(推荐)](#简洁写法推荐)
34
+ - [JoinOption 参数说明](#joinoption-参数说明)
35
+ - [联查注意事项](#联查注意事项)
36
+ - [完整示例:订单列表 API](#完整示例订单列表-api)
37
+ - [使用 query 原始 SQL](#使用-query-原始-sql)
38
+ - [Where 条件语法](#where-条件语法)
39
+ - [基础条件](#基础条件)
40
+ - [比较操作符](#比较操作符)
41
+ - [逻辑操作符](#逻辑操作符)
42
+ - [范围操作符](#范围操作符)
43
+ - [空值操作符](#空值操作符)
44
+ - [模糊匹配](#模糊匹配)
45
+ - [字段选择语法](#字段选择语法)
46
+ - [查询所有字段](#查询所有字段)
47
+ - [指定字段](#指定字段)
48
+ - [排除字段](#排除字段)
49
+ - [排序语法](#排序语法)
50
+ - [系统字段说明](#系统字段说明)
51
+ - [State 状态值](#state-状态值)
52
+ - [默认 State 过滤](#默认-state-过滤)
53
+ - [完整示例](#完整示例)
54
+ - [用户管理 API](#用户管理-api)
55
+ - [订单创建(事务)](#订单创建事务)
56
+ - [复杂查询](#复杂查询)
57
+
58
+ ---
59
+
60
+ ## 核心概念
61
+
62
+ ### DbHelper
63
+
64
+ `DbHelper` 是 Befly 的数据库操作核心类,提供了完整的 CRUD 封装。通过 `befly.db` 访问。
65
+
66
+ ```typescript
67
+ // 在 API handler 中使用
68
+ handler: async (befly, ctx) => {
69
+ const user = await befly.db.getOne({
70
+ table: 'user',
71
+ where: { id: 1 }
72
+ });
73
+ };
74
+ ```
75
+
76
+ ### 自动转换
77
+
78
+ - **表名**:小驼峰 `userProfile` 自动转换为下划线 `user_profile`
79
+ - **字段名**:写入时小驼峰转下划线,查询时下划线转小驼峰
80
+ - **BIGINT 字段**:`id`、`*Id`、`*_id`、`*At`、`*_at` 自动转为 number
81
+
82
+ ---
83
+
84
+ ## 字段命名规范
85
+
86
+ | 位置 | 格式 | 示例 |
87
+ | --------------------- | ------ | ----------------------- |
88
+ | 代码中(参数/返回值) | 小驼峰 | `userId`, `createdAt` |
89
+ | 数据库中 | 下划线 | `user_id`, `created_at` |
90
+
91
+ ```typescript
92
+ // 写入时使用小驼峰
93
+ await befly.db.insData({
94
+ table: 'user',
95
+ data: {
96
+ userName: 'John', // → user_name
97
+ createdBy: 1 // → created_by
98
+ }
99
+ });
100
+
101
+ // 查询返回小驼峰
102
+ const user = await befly.db.getOne({
103
+ table: 'user',
104
+ where: { userId: 1 } // → WHERE user_id = 1
105
+ });
106
+ // 返回: { userId: 1, userName: 'John', createdBy: 1 }
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 查询方法
112
+
113
+ ### getOne - 查询单条
114
+
115
+ 查询满足条件的第一条记录。
116
+
117
+ ```typescript
118
+ interface QueryOptions {
119
+ table: string; // 表名
120
+ fields?: string[]; // 字段列表(可选)
121
+ where?: WhereConditions; // 查询条件(可选)
122
+ }
123
+ ```
124
+
125
+ **示例:**
126
+
127
+ ```typescript
128
+ // 基础查询
129
+ const user = await befly.db.getOne({
130
+ table: 'user',
131
+ where: { id: 1 }
132
+ });
133
+
134
+ // 指定字段
135
+ const user = await befly.db.getOne({
136
+ table: 'user',
137
+ fields: ['id', 'username', 'email'],
138
+ where: { id: 1 }
139
+ });
140
+
141
+ // 排除字段(使用 ! 前缀)
142
+ const user = await befly.db.getOne({
143
+ table: 'user',
144
+ fields: ['!password', '!token'],
145
+ where: { id: 1 }
146
+ });
147
+ ```
148
+
149
+ ### getList - 分页查询
150
+
151
+ 分页查询,返回列表和分页信息。
152
+
153
+ ```typescript
154
+ interface QueryOptions {
155
+ table: string;
156
+ fields?: string[];
157
+ where?: WhereConditions;
158
+ orderBy?: string[]; // 排序,格式: ["field#ASC", "field#DESC"]
159
+ page?: number; // 页码,默认 1
160
+ limit?: number; // 每页数量,默认 10
161
+ }
162
+
163
+ interface ListResult<T> {
164
+ list: T[]; // 数据列表
165
+ total: number; // 总记录数
166
+ page: number; // 当前页码
167
+ limit: number; // 每页数量
168
+ pages: number; // 总页数
169
+ }
170
+ ```
171
+
172
+ **示例:**
173
+
174
+ ```typescript
175
+ // 基础分页
176
+ const result = await befly.db.getList({
177
+ table: 'user',
178
+ page: 1,
179
+ limit: 10
180
+ });
181
+ // 返回: { list: [...], total: 100, page: 1, limit: 10, pages: 10 }
182
+
183
+ // 带条件和排序
184
+ const result = await befly.db.getList({
185
+ table: 'user',
186
+ fields: ['id', 'username', 'createdAt'],
187
+ where: { state: 1 },
188
+ orderBy: ['createdAt#DESC', 'id#ASC'],
189
+ page: 2,
190
+ limit: 20
191
+ });
192
+ ```
193
+
194
+ ### getAll - 查询全部
195
+
196
+ 查询所有满足条件的记录(有上限保护,最多 10000 条)。
197
+
198
+ ```typescript
199
+ // 查询所有
200
+ const users = await befly.db.getAll({
201
+ table: 'user'
202
+ });
203
+
204
+ // 带条件
205
+ const activeUsers = await befly.db.getAll({
206
+ table: 'user',
207
+ fields: ['id', 'username'],
208
+ where: { state: 1 },
209
+ orderBy: ['sort#ASC']
210
+ });
211
+ ```
212
+
213
+ > ⚠️ **警告**:此方法可能返回大量数据,建议使用 `getList` 分页查询。超过 1000 条会输出警告日志。
214
+
215
+ ### getCount - 查询数量
216
+
217
+ 仅查询满足条件的记录数量。
218
+
219
+ ```typescript
220
+ // 查询总数
221
+ const count = await befly.db.getCount({
222
+ table: 'user'
223
+ });
224
+
225
+ // 条件计数
226
+ const activeCount = await befly.db.getCount({
227
+ table: 'user',
228
+ where: { state: 1 }
229
+ });
230
+ ```
231
+
232
+ ### exists - 检查存在
233
+
234
+ 检查是否存在满足条件的记录(性能优化版)。
235
+
236
+ ```typescript
237
+ const hasAdmin = await befly.db.exists({
238
+ table: 'user',
239
+ where: { roleCode: 'admin' }
240
+ });
241
+
242
+ if (hasAdmin) {
243
+ // 存在管理员
244
+ }
245
+ ```
246
+
247
+ ### getFieldValue - 查询单字段
248
+
249
+ 查询单条记录的单个字段值。
250
+
251
+ ```typescript
252
+ // 查询用户名
253
+ const username = await befly.db.getFieldValue({
254
+ table: 'user',
255
+ field: 'username',
256
+ where: { id: 1 }
257
+ });
258
+
259
+ // 查询余额
260
+ const balance = await befly.db.getFieldValue<number>({
261
+ table: 'account',
262
+ field: 'balance',
263
+ where: { userId: 1 }
264
+ });
265
+ ```
266
+
267
+ ---
268
+
269
+ ## 写入方法
270
+
271
+ ### insData - 插入数据
272
+
273
+ 插入单条数据,自动生成系统字段。
274
+
275
+ ```typescript
276
+ interface InsertOptions {
277
+ table: string;
278
+ data: Record<string, any>;
279
+ }
280
+ ```
281
+
282
+ **自动生成的字段:**
283
+
284
+ | 字段 | 说明 |
285
+ | ------------ | ----------------- |
286
+ | `id` | 基于时间的唯一 ID |
287
+ | `created_at` | 创建时间戳 |
288
+ | `updated_at` | 更新时间戳 |
289
+ | `state` | 状态,默认 1 |
290
+
291
+ **示例:**
292
+
293
+ ```typescript
294
+ // 插入用户
295
+ const userId = await befly.db.insData({
296
+ table: 'user',
297
+ data: {
298
+ username: 'john',
299
+ email: 'john@example.com',
300
+ password: hashedPassword,
301
+ roleId: 1
302
+ }
303
+ });
304
+ // 返回新记录的 ID
305
+
306
+ // 系统字段不可覆盖
307
+ await befly.db.insData({
308
+ table: 'user',
309
+ data: {
310
+ id: 999, // ❌ 会被忽略,自动生成
311
+ createdAt: 0, // ❌ 会被忽略,自动生成
312
+ state: 2, // ❌ 会被忽略,强制设为 1
313
+ username: 'john' // ✅ 正常写入
314
+ }
315
+ });
316
+ ```
317
+
318
+ ### insBatch - 批量插入
319
+
320
+ 批量插入多条数据(最多 1000 条)。
321
+
322
+ ```typescript
323
+ // 批量插入
324
+ const ids = await befly.db.insBatch('user', [
325
+ { username: 'user1', email: 'user1@example.com' },
326
+ { username: 'user2', email: 'user2@example.com' },
327
+ { username: 'user3', email: 'user3@example.com' }
328
+ ]);
329
+ // 返回: [id1, id2, id3]
330
+ ```
331
+
332
+ ### updData - 更新数据
333
+
334
+ 更新满足条件的记录。
335
+
336
+ ```typescript
337
+ interface UpdateOptions {
338
+ table: string;
339
+ data: Record<string, any>;
340
+ where: WhereConditions;
341
+ }
342
+ ```
343
+
344
+ **示例:**
345
+
346
+ ```typescript
347
+ // 更新用户
348
+ const affected = await befly.db.updData({
349
+ table: 'user',
350
+ data: {
351
+ nickname: '新昵称',
352
+ email: 'new@example.com'
353
+ },
354
+ where: { id: 1 }
355
+ });
356
+ // 返回受影响的行数
357
+
358
+ // 批量更新
359
+ await befly.db.updData({
360
+ table: 'user',
361
+ data: { state: 2 },
362
+ where: { roleId: 5 }
363
+ });
364
+ ```
365
+
366
+ **注意事项:**
367
+
368
+ - `updated_at` 自动更新为当前时间
369
+ - `id`、`created_at`、`deleted_at` 不可修改
370
+ - `state` 允许修改(用于禁用/启用)
371
+
372
+ ### delData - 软删除
373
+
374
+ 软删除记录(设置 `state=0` 和 `deleted_at`)。
375
+
376
+ ```typescript
377
+ // 软删除
378
+ const affected = await befly.db.delData({
379
+ table: 'user',
380
+ where: { id: 1 }
381
+ });
382
+ ```
383
+
384
+ ### delForce - 硬删除
385
+
386
+ 物理删除记录(不可恢复)。
387
+
388
+ ```typescript
389
+ // 硬删除
390
+ const affected = await befly.db.delForce({
391
+ table: 'temp_data',
392
+ where: { expiredAt$lt: Date.now() }
393
+ });
394
+ ```
395
+
396
+ > ⚠️ **警告**:硬删除不可恢复,请谨慎使用。
397
+
398
+ ### disableData - 禁用
399
+
400
+ 禁用记录(设置 `state=2`)。
401
+
402
+ ```typescript
403
+ // 禁用用户
404
+ await befly.db.disableData({
405
+ table: 'user',
406
+ where: { id: 1 }
407
+ });
408
+ ```
409
+
410
+ ### enableData - 启用
411
+
412
+ 启用记录(设置 `state=1`)。
413
+
414
+ ```typescript
415
+ // 启用用户
416
+ await befly.db.enableData({
417
+ table: 'user',
418
+ where: { id: 1 }
419
+ });
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 数值操作
425
+
426
+ ### increment - 自增
427
+
428
+ 对数值字段进行自增操作。
429
+
430
+ ```typescript
431
+ // 阅读数 +1
432
+ await befly.db.increment('article', 'viewCount', { id: 1 });
433
+
434
+ // 阅读数 +10
435
+ await befly.db.increment('article', 'viewCount', { id: 1 }, 10);
436
+ ```
437
+
438
+ ### decrement - 自减
439
+
440
+ 对数值字段进行自减操作。
441
+
442
+ ```typescript
443
+ // 库存 -1
444
+ await befly.db.decrement('product', 'stock', { id: 1 });
445
+
446
+ // 余额 -100
447
+ await befly.db.decrement('account', 'balance', { userId: 1 }, 100);
448
+ ```
449
+
450
+ ---
451
+
452
+ ## 事务操作
453
+
454
+ 使用 `trans` 方法执行事务,自动处理 commit/rollback。
455
+
456
+ ```typescript
457
+ // 转账示例
458
+ const result = await befly.db.trans(async (tx) => {
459
+ // 扣除转出方余额
460
+ await tx.decrement('account', 'balance', { userId: 1 }, 100);
461
+
462
+ // 增加转入方余额
463
+ await tx.increment('account', 'balance', { userId: 2 }, 100);
464
+
465
+ // 记录转账日志
466
+ await tx.insData({
467
+ table: 'transfer_log',
468
+ data: {
469
+ fromUserId: 1,
470
+ toUserId: 2,
471
+ amount: 100
472
+ }
473
+ });
474
+
475
+ return { success: true };
476
+ });
477
+
478
+ // 事务中抛出异常会自动回滚
479
+ await befly.db.trans(async (tx) => {
480
+ await tx.updData({ table: 'user', data: { balance: 0 }, where: { id: 1 } });
481
+
482
+ throw new Error('业务校验失败'); // 自动回滚
483
+ });
484
+ ```
485
+
486
+ ---
487
+
488
+ ## 多表联查
489
+
490
+ DbHelper 的查询方法(getOne、getList、getAll、getCount)支持通过 `joins` 参数进行多表联查。
491
+
492
+ ### 简洁写法(推荐)
493
+
494
+ 直接在查询方法中使用 `joins` 参数,无需手动构建 SQL。
495
+
496
+ ```typescript
497
+ // 单条联查
498
+ const order = await befly.db.getOne({
499
+ table: 'order',
500
+ joins: [{ table: 'user', on: 'order.user_id = user.id' }],
501
+ fields: ['order.id', 'order.totalAmount', 'order.status', 'user.username', 'user.nickname'],
502
+ where: { 'order.id': orderId }
503
+ });
504
+ // 返回: { id: 1, totalAmount: 100, status: 'paid', username: 'john', nickname: '张三' }
505
+
506
+ // 分页联查
507
+ const result = await befly.db.getList({
508
+ table: 'order',
509
+ joins: [
510
+ { table: 'user', on: 'order.userId = user.id' },
511
+ { table: 'product', on: 'order.productId = product.id' }
512
+ ],
513
+ fields: ['order.id', 'order.totalAmount', 'user.username', 'product.name AS productName'],
514
+ where: { 'order.status': 'paid' },
515
+ orderBy: ['order.createdAt#DESC'],
516
+ page: 1,
517
+ limit: 10
518
+ });
519
+ // 返回: { list: [...], total: 100, page: 1, limit: 10, pages: 10 }
520
+
521
+ // 联查计数
522
+ const count = await befly.db.getCount({
523
+ table: 'order',
524
+ joins: [{ table: 'user', on: 'order.userId = user.id' }],
525
+ where: { 'order.state': 1, 'user.state': 1 }
526
+ });
527
+
528
+ // 联查全部
529
+ const allOrders = await befly.db.getAll({
530
+ table: 'order',
531
+ joins: [{ table: 'user', on: 'order.userId = user.id' }],
532
+ fields: ['order.id', 'user.username'],
533
+ where: { 'order.state': 1 },
534
+ orderBy: ['order.id#DESC']
535
+ });
536
+ ```
537
+
538
+ ### JoinOption 参数说明
539
+
540
+ ```typescript
541
+ interface JoinOption {
542
+ /** JOIN 类型:'left' | 'right' | 'inner',默认 'left' */
543
+ type?: 'left' | 'right' | 'inner';
544
+ /** 表名(不支持别名) */
545
+ table: string;
546
+ /** JOIN 条件(如 'order.user_id = user.id') */
547
+ on: string;
548
+ }
549
+ ```
550
+
551
+ **示例:**
552
+
553
+ ```typescript
554
+ joins: [
555
+ { table: 'user', on: 'order.userId = user.id' }, // LEFT JOIN(默认)
556
+ { type: 'left', table: 'product', on: 'order.productId = product.id' }, // LEFT JOIN
557
+ { type: 'inner', table: 'category', on: 'product.categoryId = category.id' }, // INNER JOIN
558
+ { type: 'right', table: 'warehouse', on: 'product.warehouseId = warehouse.id' } // RIGHT JOIN
559
+ ];
560
+ ```
561
+
562
+ ### 联查注意事项
563
+
564
+ 1. **使用完整表名**:字段需要带完整表名(如 `order.id`, `user.username`)
565
+ 2. **字段自动转换**:`order.userId` 会自动转换为 `order.user_id`
566
+ 3. **结果自动转换**:返回结果的字段名会自动转为小驼峰
567
+ 4. **State 过滤**:默认只添加主表的 `state > 0`,联表需在 where 中显式指定
568
+
569
+ ### 完整示例:订单列表 API
570
+
571
+ ```typescript
572
+ export default {
573
+ name: '订单列表',
574
+ fields: {
575
+ keyword: { name: '关键词', type: 'string', max: 50 },
576
+ status: { name: '状态', type: 'string' },
577
+ page: Fields.page,
578
+ limit: Fields.limit
579
+ },
580
+ handler: async (befly, ctx) => {
581
+ const where: any = {
582
+ 'order.state': 1,
583
+ 'user.state': 1
584
+ };
585
+
586
+ // 关键词搜索
587
+ if (ctx.body.keyword) {
588
+ where.$or = [{ 'user.username$like': `%${ctx.body.keyword}%` }, { 'user.nickname$like': `%${ctx.body.keyword}%` }, { 'product.name$like': `%${ctx.body.keyword}%` }];
589
+ }
590
+
591
+ // 状态过滤
592
+ if (ctx.body.status) {
593
+ where['order.status'] = ctx.body.status;
594
+ }
595
+
596
+ const result = await befly.db.getList({
597
+ table: 'order',
598
+ joins: [
599
+ { table: 'user', on: 'order.userId = user.id' },
600
+ { table: 'product', on: 'order.productId = product.id' }
601
+ ],
602
+ fields: ['order.id', 'order.quantity', 'order.totalAmount', 'order.status', 'order.createdAt', 'user.username', 'user.nickname', 'product.name AS productName', 'product.price AS productPrice'],
603
+ where: where,
604
+ orderBy: ['order.createdAt#DESC'],
605
+ page: ctx.body.page,
606
+ limit: ctx.body.limit
607
+ });
608
+
609
+ return befly.tool.Yes('查询成功', result);
610
+ }
611
+ };
612
+ ```
613
+
614
+ ---
615
+
616
+ ### 使用 query 原始 SQL
617
+
618
+ 对于更复杂的场景(如 GROUP BY、子查询等),可以使用 `befly.db.query()` 执行原始 SQL。
619
+
620
+ ```typescript
621
+ // 带统计的联查:用户及其订单数量
622
+ const usersWithOrderCount = await befly.db.query(
623
+ `SELECT
624
+ u.id, u.username, u.nickname,
625
+ COUNT(o.id) AS orderCount,
626
+ COALESCE(SUM(o.total_amount), 0) AS totalSpent
627
+ FROM user u
628
+ LEFT JOIN \`order\` o ON u.id = o.user_id AND o.state > 0
629
+ WHERE u.state > 0
630
+ GROUP BY u.id
631
+ ORDER BY totalSpent DESC
632
+ LIMIT ?`,
633
+ [20]
634
+ );
635
+
636
+ // 需要手动转换字段名
637
+ import { arrayKeysToCamel } from 'befly-shared/arrayKeysToCamel';
638
+ const list = arrayKeysToCamel(usersWithOrderCount);
639
+ ```
640
+
641
+ ---
642
+
643
+ ## Where 条件语法
644
+
645
+ ### 基础条件
646
+
647
+ ```typescript
648
+ // 等于
649
+ where: { id: 1 }
650
+ // → WHERE id = 1
651
+
652
+ // 多条件(AND)
653
+ where: { state: 1, roleId: 2 }
654
+ // → WHERE state = 1 AND role_id = 2
655
+ ```
656
+
657
+ ### 比较操作符
658
+
659
+ | 操作符 | 说明 | SQL |
660
+ | -------------- | -------- | ---- |
661
+ | `$ne` / `$not` | 不等于 | `!=` |
662
+ | `$gt` | 大于 | `>` |
663
+ | `$gte` | 大于等于 | `>=` |
664
+ | `$lt` | 小于 | `<` |
665
+ | `$lte` | 小于等于 | `<=` |
666
+
667
+ **两种写法:**
668
+
669
+ ```typescript
670
+ // 写法1:一级属性格式(推荐)
671
+ where: {
672
+ age$gt: 18,
673
+ age$lte: 60
674
+ }
675
+ // → WHERE age > 18 AND age <= 60
676
+
677
+ // 写法2:嵌套对象格式
678
+ where: {
679
+ age: { $gt: 18, $lte: 60 }
680
+ }
681
+ // → WHERE age > 18 AND age <= 60
682
+ ```
683
+
684
+ ### 逻辑操作符
685
+
686
+ **$or - 或条件**
687
+
688
+ ```typescript
689
+ // 用户名或邮箱匹配
690
+ where: {
691
+ $or: [{ username: 'admin' }, { email: 'admin@example.com' }];
692
+ }
693
+ // → WHERE (username = 'admin' OR email = 'admin@example.com')
694
+ ```
695
+
696
+ **$and - 与条件**
697
+
698
+ ```typescript
699
+ // 显式 AND(通常不需要,多条件默认就是 AND)
700
+ where: {
701
+ $and: [{ state: 1 }, { roleId: 2 }];
702
+ }
703
+ // → WHERE state = 1 AND role_id = 2
704
+ ```
705
+
706
+ **组合使用**
707
+
708
+ ```typescript
709
+ // 复杂条件
710
+ where: {
711
+ state: 1,
712
+ $or: [
713
+ { roleCode: 'admin' },
714
+ { roleCode: 'super' }
715
+ ]
716
+ }
717
+ // → WHERE state = 1 AND (role_code = 'admin' OR role_code = 'super')
718
+ ```
719
+
720
+ ### 范围操作符
721
+
722
+ **$in - 在列表中**
723
+
724
+ ```typescript
725
+ where: {
726
+ roleId$in: [1, 2, 3];
727
+ }
728
+ // → WHERE role_id IN (1, 2, 3)
729
+
730
+ where: {
731
+ status$in: ['pending', 'processing'];
732
+ }
733
+ // → WHERE status IN ('pending', 'processing')
734
+ ```
735
+
736
+ **$nin / $notIn - 不在列表中**
737
+
738
+ ```typescript
739
+ where: {
740
+ state$nin: [0, 2];
741
+ }
742
+ // → WHERE state NOT IN (0, 2)
743
+ ```
744
+
745
+ **$between - 区间**
746
+
747
+ ```typescript
748
+ where: {
749
+ age$between: [18, 60];
750
+ }
751
+ // → WHERE age BETWEEN 18 AND 60
752
+
753
+ where: {
754
+ createdAt$between: [startTime, endTime];
755
+ }
756
+ // → WHERE created_at BETWEEN {startTime} AND {endTime}
757
+ ```
758
+
759
+ **$notBetween - 不在区间**
760
+
761
+ ```typescript
762
+ where: {
763
+ price$notBetween: [100, 500];
764
+ }
765
+ // → WHERE price NOT BETWEEN 100 AND 500
766
+ ```
767
+
768
+ ### 空值操作符
769
+
770
+ **$null - 为空**
771
+
772
+ ```typescript
773
+ where: {
774
+ deletedAt$null: true;
775
+ }
776
+ // → WHERE deleted_at IS NULL
777
+ ```
778
+
779
+ **$notNull - 不为空**
780
+
781
+ ```typescript
782
+ where: {
783
+ email$notNull: true;
784
+ }
785
+ // → WHERE email IS NOT NULL
786
+ ```
787
+
788
+ ### 模糊匹配
789
+
790
+ **$like - 模糊匹配**
791
+
792
+ ```typescript
793
+ // 包含
794
+ where: {
795
+ username$like: '%admin%';
796
+ }
797
+ // → WHERE username LIKE '%admin%'
798
+
799
+ // 以...开头
800
+ where: {
801
+ email$like: 'test%';
802
+ }
803
+ // → WHERE email LIKE 'test%'
804
+
805
+ // 以...结尾
806
+ where: {
807
+ phone$like: '%1234';
808
+ }
809
+ // → WHERE phone LIKE '%1234'
810
+ ```
811
+
812
+ **$notLike - 不匹配**
813
+
814
+ ```typescript
815
+ where: {
816
+ username$notLike: '%test%';
817
+ }
818
+ // → WHERE username NOT LIKE '%test%'
819
+ ```
820
+
821
+ ---
822
+
823
+ ## 字段选择语法
824
+
825
+ ### 查询所有字段
826
+
827
+ ```typescript
828
+ // 以下三种方式等效
829
+ fields: [];
830
+ fields: undefined;
831
+ // 不传 fields 参数
832
+ ```
833
+
834
+ ### 指定字段
835
+
836
+ ```typescript
837
+ fields: ['id', 'username', 'email'];
838
+ // → SELECT id, username, email
839
+ ```
840
+
841
+ ### 排除字段
842
+
843
+ 使用 `!` 前缀排除字段(查询除指定字段外的所有字段)。
844
+
845
+ ```typescript
846
+ fields: ['!password', '!token', '!salt'];
847
+ // → SELECT id, username, email, created_at, ... (除了 password, token, salt)
848
+ ```
849
+
850
+ > ⚠️ **注意**:不能混用指定字段和排除字段。
851
+
852
+ ---
853
+
854
+ ## 排序语法
855
+
856
+ 使用 `字段#方向` 格式,方向为 `ASC`(升序)或 `DESC`(降序)。
857
+
858
+ ```typescript
859
+ // 单字段排序
860
+ orderBy: ['createdAt#DESC'];
861
+ // → ORDER BY created_at DESC
862
+
863
+ // 多字段排序
864
+ orderBy: ['sort#ASC', 'id#DESC'];
865
+ // → ORDER BY sort ASC, id DESC
866
+ ```
867
+
868
+ ---
869
+
870
+ ## 系统字段说明
871
+
872
+ 每条记录自动包含以下系统字段:
873
+
874
+ | 字段 | 类型 | 说明 | 插入时 | 更新时 |
875
+ | ------------ | ------- | ------------------ | ---------- | ------------ |
876
+ | `id` | BIGINT | 主键,基于时间生成 | 自动生成 | 不可修改 |
877
+ | `created_at` | BIGINT | 创建时间戳 | 自动生成 | 不可修改 |
878
+ | `updated_at` | BIGINT | 更新时间戳 | 自动生成 | 自动更新 |
879
+ | `deleted_at` | BIGINT | 删除时间戳 | 不生成 | 软删除时设置 |
880
+ | `state` | TINYINT | 状态 | 强制设为 1 | 可修改 |
881
+
882
+ ### State 状态值
883
+
884
+ | 值 | 含义 | 说明 |
885
+ | --- | ------ | -------------- |
886
+ | 0 | 已删除 | 软删除后的状态 |
887
+ | 1 | 正常 | 默认状态 |
888
+ | 2 | 禁用 | 禁用状态 |
889
+
890
+ ### 默认 State 过滤
891
+
892
+ 所有查询方法默认添加 `state > 0` 条件,自动过滤已删除的数据。
893
+
894
+ ```typescript
895
+ // 实际执行
896
+ getOne({ table: 'user', where: { id: 1 } });
897
+ // → WHERE id = 1 AND state > 0
898
+
899
+ // 如需查询所有状态,显式指定 state 条件
900
+ getOne({ table: 'user', where: { id: 1, state$gte: 0 } });
901
+ // → WHERE id = 1 AND state >= 0
902
+ ```
903
+
904
+ ---
905
+
906
+ ## 完整示例
907
+
908
+ ### 用户管理 API
909
+
910
+ ```typescript
911
+ // 用户列表
912
+ export default {
913
+ name: '用户列表',
914
+ fields: {
915
+ keyword: { name: '关键词', type: 'string', max: 50 },
916
+ roleId: { name: '角色ID', type: 'number' },
917
+ page: Fields.page,
918
+ limit: Fields.limit
919
+ },
920
+ handler: async (befly, ctx) => {
921
+ const where: any = {};
922
+
923
+ // 关键词搜索
924
+ if (ctx.body.keyword) {
925
+ where.$or = [{ username$like: `%${ctx.body.keyword}%` }, { nickname$like: `%${ctx.body.keyword}%` }, { email$like: `%${ctx.body.keyword}%` }];
926
+ }
927
+
928
+ // 角色过滤
929
+ if (ctx.body.roleId) {
930
+ where.roleId = ctx.body.roleId;
931
+ }
932
+
933
+ const result = await befly.db.getList({
934
+ table: 'user',
935
+ fields: ['!password', '!token'],
936
+ where: where,
937
+ orderBy: ['createdAt#DESC'],
938
+ page: ctx.body.page,
939
+ limit: ctx.body.limit
940
+ });
941
+
942
+ return befly.tool.Yes('查询成功', result);
943
+ }
944
+ };
945
+ ```
946
+
947
+ ### 订单创建(事务)
948
+
949
+ ```typescript
950
+ export default {
951
+ name: '创建订单',
952
+ fields: {
953
+ productId: { name: '商品ID', type: 'number' },
954
+ quantity: { name: '数量', type: 'number', min: 1 }
955
+ },
956
+ required: ['productId', 'quantity'],
957
+ handler: async (befly, ctx) => {
958
+ const result = await befly.db.trans(async (tx) => {
959
+ // 1. 查询商品
960
+ const product = await tx.getOne({
961
+ table: 'product',
962
+ where: { id: ctx.body.productId }
963
+ });
964
+
965
+ if (!product) {
966
+ throw new Error('商品不存在');
967
+ }
968
+
969
+ if (product.stock < ctx.body.quantity) {
970
+ throw new Error('库存不足');
971
+ }
972
+
973
+ // 2. 扣减库存
974
+ await tx.decrement('product', 'stock', { id: ctx.body.productId }, ctx.body.quantity);
975
+
976
+ // 3. 创建订单
977
+ const orderId = await tx.insData({
978
+ table: 'order',
979
+ data: {
980
+ userId: ctx.user.id,
981
+ productId: ctx.body.productId,
982
+ quantity: ctx.body.quantity,
983
+ totalAmount: product.price * ctx.body.quantity,
984
+ status: 'pending'
985
+ }
986
+ });
987
+
988
+ return { orderId: orderId };
989
+ });
990
+
991
+ return befly.tool.Yes('订单创建成功', result);
992
+ }
993
+ };
994
+ ```
995
+
996
+ ### 复杂查询
997
+
998
+ ```typescript
999
+ // 查询最近7天内,状态为正常或待审核的文章
1000
+ const articles = await befly.db.getList({
1001
+ table: 'article',
1002
+ fields: ['id', 'title', 'authorId', 'viewCount', 'createdAt'],
1003
+ where: {
1004
+ createdAt$gte: Date.now() - 7 * 24 * 60 * 60 * 1000,
1005
+ $or: [{ status: 'published' }, { status: 'pending' }],
1006
+ categoryId$in: [1, 2, 3]
1007
+ },
1008
+ orderBy: ['viewCount#DESC', 'createdAt#DESC'],
1009
+ page: 1,
1010
+ limit: 20
1011
+ });
1012
+ ```