befly 2.0.7 → 2.0.10
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/package.json +2 -2
- package/plugins/db.js +166 -85
- package/utils/curd.js +104 -113
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "Buma - 为 Bun 专属打造的 API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"README.md",
|
|
52
52
|
"vitest.config.js"
|
|
53
53
|
],
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "e87ddebec60d7dcde96510b2177ec23719972f54"
|
|
55
55
|
}
|
package/plugins/db.js
CHANGED
|
@@ -101,75 +101,36 @@ export default {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
//
|
|
105
|
-
async
|
|
104
|
+
// 私有方法:执行 SQL(支持传入连接对象)
|
|
105
|
+
async #executeWithConn(sql, params = [], conn = null) {
|
|
106
106
|
if (!sql || typeof sql !== 'string') {
|
|
107
107
|
throw new Error('SQL 语句是必需的');
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
let conn;
|
|
110
|
+
let providedConn = conn;
|
|
111
|
+
let shouldRelease = false;
|
|
112
|
+
|
|
111
113
|
try {
|
|
112
|
-
|
|
114
|
+
// 如果没有提供连接,从池中获取
|
|
115
|
+
if (!providedConn) {
|
|
116
|
+
providedConn = await this.#pool.getConnection();
|
|
117
|
+
shouldRelease = true;
|
|
118
|
+
}
|
|
113
119
|
|
|
114
120
|
if (Env.MYSQL_DEBUG === 1) {
|
|
115
121
|
Logger.debug('执行SQL:', { sql, params });
|
|
116
122
|
}
|
|
117
123
|
|
|
118
|
-
const result = await
|
|
124
|
+
const result = await providedConn.query(sql, params);
|
|
119
125
|
return result;
|
|
120
126
|
} catch (error) {
|
|
121
127
|
Logger.error('SQL 执行失败:', { sql, params, error: error.message });
|
|
122
128
|
throw error;
|
|
123
129
|
} finally {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
conn.release();
|
|
127
|
-
} catch (releaseError) {
|
|
128
|
-
Logger.warn('连接释放警告:', releaseError.message);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// 事务处理
|
|
135
|
-
async transaction(callback) {
|
|
136
|
-
if (typeof callback !== 'function') {
|
|
137
|
-
throw new Error('事务回调函数是必需的');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let conn;
|
|
141
|
-
try {
|
|
142
|
-
conn = await this.#pool.getConnection();
|
|
143
|
-
await conn.beginTransaction();
|
|
144
|
-
|
|
145
|
-
// 为回调函数提供连接对象
|
|
146
|
-
const txMethods = {
|
|
147
|
-
query: async (sql, params = []) => {
|
|
148
|
-
return await conn.query(sql, params);
|
|
149
|
-
},
|
|
150
|
-
execute: async (sql, params = []) => {
|
|
151
|
-
return await conn.query(sql, params);
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
const result = await callback(txMethods);
|
|
156
|
-
|
|
157
|
-
await conn.commit();
|
|
158
|
-
return result;
|
|
159
|
-
} catch (error) {
|
|
160
|
-
if (conn) {
|
|
161
|
-
try {
|
|
162
|
-
await conn.rollback();
|
|
163
|
-
Logger.info('事务已回滚');
|
|
164
|
-
} catch (rollbackError) {
|
|
165
|
-
Logger.error('事务回滚失败:', rollbackError);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
throw error;
|
|
169
|
-
} finally {
|
|
170
|
-
if (conn) {
|
|
130
|
+
// 只有当连接是我们获取的时候才释放
|
|
131
|
+
if (shouldRelease && providedConn) {
|
|
171
132
|
try {
|
|
172
|
-
|
|
133
|
+
providedConn.release();
|
|
173
134
|
} catch (releaseError) {
|
|
174
135
|
Logger.warn('连接释放警告:', releaseError.message);
|
|
175
136
|
}
|
|
@@ -177,18 +138,13 @@ export default {
|
|
|
177
138
|
}
|
|
178
139
|
}
|
|
179
140
|
|
|
180
|
-
//
|
|
181
|
-
async
|
|
141
|
+
// 私有方法:获取单条记录详情(支持传入连接对象)
|
|
142
|
+
async #getDetailWithConn(table, options = {}, conn = null) {
|
|
182
143
|
if (!table || typeof table !== 'string') {
|
|
183
144
|
throw new Error('表名是必需的');
|
|
184
145
|
}
|
|
185
146
|
|
|
186
|
-
const {
|
|
187
|
-
//
|
|
188
|
-
where = {},
|
|
189
|
-
fields = '*',
|
|
190
|
-
leftJoins = []
|
|
191
|
-
} = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
147
|
+
const { where = {}, fields = '*', leftJoins = [] } = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
192
148
|
|
|
193
149
|
try {
|
|
194
150
|
const builder = createQueryBuilder().select(fields).from(table).where(where).limit(1);
|
|
@@ -206,7 +162,7 @@ export default {
|
|
|
206
162
|
});
|
|
207
163
|
|
|
208
164
|
const { sql, params } = builder.toSelectSql();
|
|
209
|
-
const result = await this
|
|
165
|
+
const result = await this.#executeWithConn(sql, params, conn);
|
|
210
166
|
return result[0] || null;
|
|
211
167
|
} catch (error) {
|
|
212
168
|
Logger.error('getDetail 执行失败:', error);
|
|
@@ -214,8 +170,8 @@ export default {
|
|
|
214
170
|
}
|
|
215
171
|
}
|
|
216
172
|
|
|
217
|
-
//
|
|
218
|
-
async
|
|
173
|
+
// 私有方法:获取列表(支持传入连接对象)
|
|
174
|
+
async #getListWithConn(table, options = {}, conn = null) {
|
|
219
175
|
if (!table || typeof table !== 'string') {
|
|
220
176
|
throw new Error('表名是必需的');
|
|
221
177
|
}
|
|
@@ -260,7 +216,7 @@ export default {
|
|
|
260
216
|
}
|
|
261
217
|
|
|
262
218
|
const { sql, params } = builder.toSelectSql();
|
|
263
|
-
const
|
|
219
|
+
const rows = await this.#executeWithConn(sql, params, conn);
|
|
264
220
|
|
|
265
221
|
// 获取总数(如果需要分页)
|
|
266
222
|
let total = 0;
|
|
@@ -280,12 +236,12 @@ export default {
|
|
|
280
236
|
});
|
|
281
237
|
|
|
282
238
|
const { sql: countSql, params: countParams } = countBuilder.toCountSql();
|
|
283
|
-
const countResult = await this
|
|
239
|
+
const countResult = await this.#executeWithConn(countSql, countParams, conn);
|
|
284
240
|
total = countResult[0]?.total || 0;
|
|
285
241
|
}
|
|
286
242
|
|
|
287
243
|
return {
|
|
288
|
-
|
|
244
|
+
rows: Array.isArray(rows) ? rows : [],
|
|
289
245
|
total,
|
|
290
246
|
page: numPage,
|
|
291
247
|
pageSize: numPageSize
|
|
@@ -296,8 +252,8 @@ export default {
|
|
|
296
252
|
}
|
|
297
253
|
}
|
|
298
254
|
|
|
299
|
-
//
|
|
300
|
-
async
|
|
255
|
+
// 私有方法:获取所有记录(支持传入连接对象)
|
|
256
|
+
async #getAllWithConn(table, options = {}, conn = null) {
|
|
301
257
|
if (!table || typeof table !== 'string') {
|
|
302
258
|
throw new Error('表名是必需的');
|
|
303
259
|
}
|
|
@@ -324,7 +280,7 @@ export default {
|
|
|
324
280
|
}
|
|
325
281
|
|
|
326
282
|
const { sql, params } = builder.toSelectSql();
|
|
327
|
-
const result = await this
|
|
283
|
+
const result = await this.#executeWithConn(sql, params, conn);
|
|
328
284
|
return Array.isArray(result) ? result : [];
|
|
329
285
|
} catch (error) {
|
|
330
286
|
Logger.error('getAll 执行失败:', error);
|
|
@@ -332,8 +288,8 @@ export default {
|
|
|
332
288
|
}
|
|
333
289
|
}
|
|
334
290
|
|
|
335
|
-
//
|
|
336
|
-
async
|
|
291
|
+
// 私有方法:插入数据(支持传入连接对象)
|
|
292
|
+
async #insDataWithConn(table, data, conn = null) {
|
|
337
293
|
if (!table || typeof table !== 'string') {
|
|
338
294
|
throw new Error('表名是必需的');
|
|
339
295
|
}
|
|
@@ -346,15 +302,15 @@ export default {
|
|
|
346
302
|
const processedData = await this.#processDataForInsert(data);
|
|
347
303
|
const builder = createQueryBuilder();
|
|
348
304
|
const { sql, params } = builder.toInsertSql(table, processedData);
|
|
349
|
-
return await this
|
|
305
|
+
return await this.#executeWithConn(sql, params, conn);
|
|
350
306
|
} catch (error) {
|
|
351
307
|
Logger.error('insData 执行失败:', error);
|
|
352
308
|
throw error;
|
|
353
309
|
}
|
|
354
310
|
}
|
|
355
311
|
|
|
356
|
-
//
|
|
357
|
-
async
|
|
312
|
+
// 私有方法:更新数据(支持传入连接对象)
|
|
313
|
+
async #upDataWithConn(table, data, where, conn = null) {
|
|
358
314
|
if (!table || typeof table !== 'string') {
|
|
359
315
|
throw new Error('表名是必需的');
|
|
360
316
|
}
|
|
@@ -379,15 +335,15 @@ export default {
|
|
|
379
335
|
|
|
380
336
|
const builder = createQueryBuilder().where(where);
|
|
381
337
|
const { sql, params } = builder.toUpdateSql(table, updateData);
|
|
382
|
-
return await this
|
|
338
|
+
return await this.#executeWithConn(sql, params, conn);
|
|
383
339
|
} catch (error) {
|
|
384
340
|
Logger.error('upData 执行失败:', error);
|
|
385
341
|
throw error;
|
|
386
342
|
}
|
|
387
343
|
}
|
|
388
344
|
|
|
389
|
-
//
|
|
390
|
-
async
|
|
345
|
+
// 私有方法:删除数据(支持传入连接对象)
|
|
346
|
+
async #delDataWithConn(table, where, conn = null) {
|
|
391
347
|
if (!table || typeof table !== 'string') {
|
|
392
348
|
throw new Error('表名是必需的');
|
|
393
349
|
}
|
|
@@ -399,15 +355,15 @@ export default {
|
|
|
399
355
|
try {
|
|
400
356
|
const builder = createQueryBuilder().where(where);
|
|
401
357
|
const { sql, params } = builder.toDeleteSql(table);
|
|
402
|
-
return await this
|
|
358
|
+
return await this.#executeWithConn(sql, params, conn);
|
|
403
359
|
} catch (error) {
|
|
404
360
|
Logger.error('delData 执行失败:', error);
|
|
405
361
|
throw error;
|
|
406
362
|
}
|
|
407
363
|
}
|
|
408
364
|
|
|
409
|
-
//
|
|
410
|
-
async
|
|
365
|
+
// 私有方法:批量插入(支持传入连接对象)
|
|
366
|
+
async #insBatchWithConn(table, dataArray, conn = null) {
|
|
411
367
|
if (!table || typeof table !== 'string') {
|
|
412
368
|
throw new Error('表名是必需的');
|
|
413
369
|
}
|
|
@@ -420,15 +376,15 @@ export default {
|
|
|
420
376
|
const processedDataArray = await this.#processDataForInsert(dataArray);
|
|
421
377
|
const builder = createQueryBuilder();
|
|
422
378
|
const { sql, params } = builder.toInsertSql(table, processedDataArray);
|
|
423
|
-
return await this
|
|
379
|
+
return await this.#executeWithConn(sql, params, conn);
|
|
424
380
|
} catch (error) {
|
|
425
381
|
Logger.error('insBatch 执行失败:', error);
|
|
426
382
|
throw error;
|
|
427
383
|
}
|
|
428
384
|
}
|
|
429
385
|
|
|
430
|
-
//
|
|
431
|
-
async
|
|
386
|
+
// 私有方法:获取记录总数(支持传入连接对象)
|
|
387
|
+
async #getCountWithConn(table, options = {}, conn = null) {
|
|
432
388
|
if (!table || typeof table !== 'string') {
|
|
433
389
|
throw new Error('表名是必需的');
|
|
434
390
|
}
|
|
@@ -451,7 +407,7 @@ export default {
|
|
|
451
407
|
});
|
|
452
408
|
|
|
453
409
|
const { sql, params } = builder.toCountSql();
|
|
454
|
-
const result = await this
|
|
410
|
+
const result = await this.#executeWithConn(sql, params, conn);
|
|
455
411
|
return result[0]?.total || 0;
|
|
456
412
|
} catch (error) {
|
|
457
413
|
Logger.error('getCount 执行失败:', error);
|
|
@@ -459,6 +415,131 @@ export default {
|
|
|
459
415
|
}
|
|
460
416
|
}
|
|
461
417
|
|
|
418
|
+
// 执行原始 SQL - 核心方法
|
|
419
|
+
async execute(sql, params = []) {
|
|
420
|
+
return await this.#executeWithConn(sql, params);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// 获取单条记录详情
|
|
424
|
+
async getDetail(table, options = {}) {
|
|
425
|
+
return await this.#getDetailWithConn(table, options);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 获取列表(支持分页)
|
|
429
|
+
async getList(table, options = {}) {
|
|
430
|
+
return await this.#getListWithConn(table, options);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// 获取所有记录
|
|
434
|
+
async getAll(table, options = {}) {
|
|
435
|
+
return await this.#getAllWithConn(table, options);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// 插入数据 - 增强版,自动添加 ID 和时间戳
|
|
439
|
+
async insData(table, data) {
|
|
440
|
+
return await this.#insDataWithConn(table, data);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 更新数据 - 增强版,自动添加 updated_at,过滤敏感字段
|
|
444
|
+
async upData(table, data, where) {
|
|
445
|
+
return await this.#upDataWithConn(table, data, where);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// 删除数据
|
|
449
|
+
async delData(table, where) {
|
|
450
|
+
return await this.#delDataWithConn(table, where);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// 批量插入 - 增强版,自动添加 ID 和时间戳
|
|
454
|
+
async insBatch(table, dataArray) {
|
|
455
|
+
return await this.#insBatchWithConn(table, dataArray);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 获取记录总数
|
|
459
|
+
async getCount(table, options = {}) {
|
|
460
|
+
return await this.#getCountWithConn(table, options);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// 事务处理
|
|
464
|
+
async trans(callback) {
|
|
465
|
+
if (typeof callback !== 'function') {
|
|
466
|
+
throw new Error('事务回调函数是必需的');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
let conn;
|
|
470
|
+
try {
|
|
471
|
+
conn = await this.#pool.getConnection();
|
|
472
|
+
await conn.beginTransaction();
|
|
473
|
+
|
|
474
|
+
// 为回调函数提供连接对象和高级方法
|
|
475
|
+
const txMethods = {
|
|
476
|
+
// 原始SQL执行方法
|
|
477
|
+
query: async (sql, params = []) => {
|
|
478
|
+
return await conn.query(sql, params);
|
|
479
|
+
},
|
|
480
|
+
execute: async (sql, params = []) => {
|
|
481
|
+
return await conn.query(sql, params);
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
// 高级数据操作方法 - 直接调用私有方法,传入事务连接
|
|
485
|
+
getDetail: async (table, options = {}) => {
|
|
486
|
+
return await this.#getDetailWithConn(table, options, conn);
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
getList: async (table, options = {}) => {
|
|
490
|
+
return await this.#getListWithConn(table, options, conn);
|
|
491
|
+
},
|
|
492
|
+
|
|
493
|
+
getAll: async (table, options = {}) => {
|
|
494
|
+
return await this.#getAllWithConn(table, options, conn);
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
insData: async (table, data) => {
|
|
498
|
+
return await this.#insDataWithConn(table, data, conn);
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
upData: async (table, data, where) => {
|
|
502
|
+
return await this.#upDataWithConn(table, data, where, conn);
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
delData: async (table, where) => {
|
|
506
|
+
return await this.#delDataWithConn(table, where, conn);
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
getCount: async (table, options = {}) => {
|
|
510
|
+
return await this.#getCountWithConn(table, options, conn);
|
|
511
|
+
},
|
|
512
|
+
|
|
513
|
+
insBatch: async (table, dataArray) => {
|
|
514
|
+
return await this.#insBatchWithConn(table, dataArray, conn);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const result = await callback(txMethods);
|
|
519
|
+
|
|
520
|
+
await conn.commit();
|
|
521
|
+
return result;
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (conn) {
|
|
524
|
+
try {
|
|
525
|
+
await conn.rollback();
|
|
526
|
+
Logger.info('事务已回滚');
|
|
527
|
+
} catch (rollbackError) {
|
|
528
|
+
Logger.error('事务回滚失败:', rollbackError);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
throw error;
|
|
532
|
+
} finally {
|
|
533
|
+
if (conn) {
|
|
534
|
+
try {
|
|
535
|
+
conn.release();
|
|
536
|
+
} catch (releaseError) {
|
|
537
|
+
Logger.warn('连接释放警告:', releaseError.message);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
462
543
|
// 获取连接池状态
|
|
463
544
|
getPoolStatus() {
|
|
464
545
|
return {
|
package/utils/curd.js
CHANGED
|
@@ -58,6 +58,7 @@ export class SqlBuilder {
|
|
|
58
58
|
if (value === undefined) {
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
+
|
|
61
62
|
if (key === '$and') {
|
|
62
63
|
if (Array.isArray(value)) {
|
|
63
64
|
value.forEach((condition) => this._processWhereConditions(condition));
|
|
@@ -81,83 +82,85 @@ export class SqlBuilder {
|
|
|
81
82
|
this._params.push(...tempParams);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
} else if (
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
85
|
+
} else if (key.includes('$')) {
|
|
86
|
+
// 一级属性格式:age$gt, role$in 等
|
|
87
|
+
const lastDollarIndex = key.lastIndexOf('$');
|
|
88
|
+
const fieldName = key.substring(0, lastDollarIndex);
|
|
89
|
+
const operator = '$' + key.substring(lastDollarIndex + 1);
|
|
90
|
+
|
|
91
|
+
this._validateParam(value);
|
|
92
|
+
|
|
93
|
+
switch (operator) {
|
|
94
|
+
case '$ne':
|
|
95
|
+
case '$not':
|
|
96
|
+
this._where.push(`${fieldName} != ?`);
|
|
97
|
+
this._params.push(value);
|
|
98
|
+
break;
|
|
99
|
+
case '$in':
|
|
100
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
101
|
+
const placeholders = value.map(() => '?').join(',');
|
|
102
|
+
this._where.push(`${fieldName} IN (${placeholders})`);
|
|
103
|
+
this._params.push(...value);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case '$nin':
|
|
107
|
+
case '$notIn':
|
|
108
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
109
|
+
const placeholders = value.map(() => '?').join(',');
|
|
110
|
+
this._where.push(`${fieldName} NOT IN (${placeholders})`);
|
|
111
|
+
this._params.push(...value);
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
case '$like':
|
|
115
|
+
this._where.push(`${fieldName} LIKE ?`);
|
|
116
|
+
this._params.push(value);
|
|
117
|
+
break;
|
|
118
|
+
case '$notLike':
|
|
119
|
+
this._where.push(`${fieldName} NOT LIKE ?`);
|
|
120
|
+
this._params.push(value);
|
|
121
|
+
break;
|
|
122
|
+
case '$gt':
|
|
123
|
+
this._where.push(`${fieldName} > ?`);
|
|
124
|
+
this._params.push(value);
|
|
125
|
+
break;
|
|
126
|
+
case '$gte':
|
|
127
|
+
this._where.push(`${fieldName} >= ?`);
|
|
128
|
+
this._params.push(value);
|
|
129
|
+
break;
|
|
130
|
+
case '$lt':
|
|
131
|
+
this._where.push(`${fieldName} < ?`);
|
|
132
|
+
this._params.push(value);
|
|
133
|
+
break;
|
|
134
|
+
case '$lte':
|
|
135
|
+
this._where.push(`${fieldName} <= ?`);
|
|
136
|
+
this._params.push(value);
|
|
137
|
+
break;
|
|
138
|
+
case '$between':
|
|
139
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
140
|
+
this._where.push(`${fieldName} BETWEEN ? AND ?`);
|
|
141
|
+
this._params.push(value[0], value[1]);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
case '$notBetween':
|
|
145
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
146
|
+
this._where.push(`${fieldName} NOT BETWEEN ? AND ?`);
|
|
147
|
+
this._params.push(value[0], value[1]);
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case '$null':
|
|
151
|
+
if (value === true) {
|
|
152
|
+
this._where.push(`${fieldName} IS NULL`);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
case '$notNull':
|
|
156
|
+
if (value === true) {
|
|
157
|
+
this._where.push(`${fieldName} IS NOT NULL`);
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
this._where.push(`${fieldName} = ?`);
|
|
162
|
+
this._params.push(value);
|
|
163
|
+
}
|
|
161
164
|
} else {
|
|
162
165
|
// 简单的等于条件
|
|
163
166
|
this._validateParam(value);
|
|
@@ -189,43 +192,31 @@ export class SqlBuilder {
|
|
|
189
192
|
return this;
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
orderBy(
|
|
193
|
-
if (Array.isArray(
|
|
194
|
-
|
|
195
|
-
if (typeof item === 'string' && item.includes('#')) {
|
|
196
|
-
const [fieldName, dir] = item.split('#');
|
|
197
|
-
const cleanDir = (dir || 'ASC').trim().toUpperCase();
|
|
198
|
-
if (!['ASC', 'DESC'].includes(cleanDir)) {
|
|
199
|
-
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
200
|
-
}
|
|
201
|
-
this._orderBy.push(`${fieldName.trim()} ${cleanDir}`);
|
|
202
|
-
} else if (Array.isArray(item) && item.length >= 1) {
|
|
203
|
-
const [fieldName, dir] = item;
|
|
204
|
-
const cleanDir = (dir || 'ASC').toUpperCase();
|
|
205
|
-
if (!['ASC', 'DESC'].includes(cleanDir)) {
|
|
206
|
-
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
207
|
-
}
|
|
208
|
-
this._orderBy.push(`${fieldName} ${cleanDir}`);
|
|
209
|
-
} else if (typeof item === 'string') {
|
|
210
|
-
this._orderBy.push(`${item} ASC`);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
} else if (typeof field === 'string') {
|
|
214
|
-
if (field.includes('#')) {
|
|
215
|
-
const [fieldName, dir] = field.split('#');
|
|
216
|
-
const cleanDir = (dir || 'ASC').trim().toUpperCase();
|
|
217
|
-
if (!['ASC', 'DESC'].includes(cleanDir)) {
|
|
218
|
-
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
219
|
-
}
|
|
220
|
-
this._orderBy.push(`${fieldName.trim()} ${cleanDir}`);
|
|
221
|
-
} else {
|
|
222
|
-
const cleanDir = direction.toUpperCase();
|
|
223
|
-
if (!['ASC', 'DESC'].includes(cleanDir)) {
|
|
224
|
-
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
225
|
-
}
|
|
226
|
-
this._orderBy.push(`${field} ${cleanDir}`);
|
|
227
|
-
}
|
|
195
|
+
orderBy(fields) {
|
|
196
|
+
if (!Array.isArray(fields)) {
|
|
197
|
+
throw new Error('orderBy must be an array of strings in "field#direction" format');
|
|
228
198
|
}
|
|
199
|
+
|
|
200
|
+
fields.forEach((item) => {
|
|
201
|
+
if (typeof item !== 'string' || !item.includes('#')) {
|
|
202
|
+
throw new Error('orderBy field must be a string in "field#direction" format (e.g., "name#ASC", "id#DESC")');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const [fieldName, direction] = item.split('#');
|
|
206
|
+
const cleanField = fieldName.trim();
|
|
207
|
+
const cleanDir = direction.trim().toUpperCase();
|
|
208
|
+
|
|
209
|
+
if (!cleanField) {
|
|
210
|
+
throw new Error('Field name cannot be empty in orderBy');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!['ASC', 'DESC'].includes(cleanDir)) {
|
|
214
|
+
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this._orderBy.push(`${cleanField} ${cleanDir}`);
|
|
218
|
+
});
|
|
219
|
+
|
|
229
220
|
return this;
|
|
230
221
|
}
|
|
231
222
|
|