befly 3.24.10 → 3.24.11
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/apis/admin/cacheRefresh.js +1 -1
- package/apis/menu/select.js +1 -1
- package/apis/role/select.js +1 -1
- package/index.js +0 -5
- package/lib/dbHelper.js +14 -14
- package/lib/dbParse.js +13 -13
- package/lib/dbUtil.js +4 -1
- package/lib/logger.js +8 -8
- package/lib/sqlBuilder.js +54 -54
- package/lib/validator.js +2 -2
- package/package.json +1 -1
- package/paths.js +9 -9
- package/plugins/cache.js +1 -1
- package/plugins/email.js +1 -1
- package/plugins/logger.js +1 -1
- package/plugins/mysql.js +1 -1
- package/plugins/redis.js +1 -1
package/apis/menu/select.js
CHANGED
package/apis/role/select.js
CHANGED
package/index.js
CHANGED
|
@@ -235,11 +235,6 @@ export class Befly {
|
|
|
235
235
|
Logger.info(`服务器监听地址: ${server.url}`);
|
|
236
236
|
Logger.info(`Mysql 数据库地址:${this.context.config.mysql.hostname}`);
|
|
237
237
|
Logger.info(`Redis 缓存地址:${this.context.config.redis.hostname}`);
|
|
238
|
-
console.log(`${this.context.config.appName} 启动成功!`);
|
|
239
|
-
console.log(`服务器启动耗时: ${finalStartupTime}`);
|
|
240
|
-
console.log(`服务器监听地址: ${server.url}`);
|
|
241
|
-
console.log(`Mysql 数据库地址:${this.context.config.mysql.hostname}`);
|
|
242
|
-
console.log(`Redis 缓存地址:${this.context.config.redis.hostname}`);
|
|
243
238
|
// 注意:作为库代码,这里不注册 SIGINT/SIGTERM 处理器,也不调用 process.exit。
|
|
244
239
|
// 宿主应用应自行处理信号并决定退出策略(包括是否调用 server.stop / Connect.disconnect / Logger.flush)。
|
|
245
240
|
return server;
|
package/lib/dbHelper.js
CHANGED
|
@@ -435,14 +435,14 @@ class DbHelper {
|
|
|
435
435
|
return normalizeBigIntValues(deserializedList);
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
-
|
|
438
|
+
prepareWriteInputData(data) {
|
|
439
439
|
return serializeArrayFields(keysToSnake(fieldClear(data, { excludeValues: [null, undefined] })));
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
-
|
|
442
|
+
prepareWriteUserData(data, allowState) {
|
|
443
443
|
const result = {};
|
|
444
444
|
|
|
445
|
-
for (const [key, value] of Object.entries(this.
|
|
445
|
+
for (const [key, value] of Object.entries(this.prepareWriteInputData(data))) {
|
|
446
446
|
if (key === "id") continue;
|
|
447
447
|
if (key === "created_at") continue;
|
|
448
448
|
if (key === "updated_at") continue;
|
|
@@ -454,8 +454,8 @@ class DbHelper {
|
|
|
454
454
|
return result;
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
|
|
458
|
-
const result = options.beflyMode === "manual" ? this.
|
|
457
|
+
buildInsertRow(options) {
|
|
458
|
+
const result = options.beflyMode === "manual" ? this.prepareWriteInputData(options.data) : this.prepareWriteUserData(options.data, false);
|
|
459
459
|
|
|
460
460
|
if (options.beflyMode === "auto") {
|
|
461
461
|
assertTimeIdValue(options.id);
|
|
@@ -471,8 +471,8 @@ class DbHelper {
|
|
|
471
471
|
return result;
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
|
|
475
|
-
const result = options.beflyMode === "manual" ? this.
|
|
474
|
+
buildUpdateRow(options) {
|
|
475
|
+
const result = options.beflyMode === "manual" ? this.prepareWriteInputData(options.data) : this.prepareWriteUserData(options.data, options.allowState);
|
|
476
476
|
if (options.beflyMode !== "manual") {
|
|
477
477
|
result.updated_at = options.now;
|
|
478
478
|
}
|
|
@@ -508,7 +508,7 @@ class DbHelper {
|
|
|
508
508
|
return {
|
|
509
509
|
ids: [],
|
|
510
510
|
processedList: dataList.map((data) =>
|
|
511
|
-
this.
|
|
511
|
+
this.buildInsertRow({
|
|
512
512
|
data: data,
|
|
513
513
|
now: now,
|
|
514
514
|
beflyMode: this.beflyMode
|
|
@@ -541,7 +541,7 @@ class DbHelper {
|
|
|
541
541
|
assertGeneratedBatchId(id, snakeTable, index);
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
return this.
|
|
544
|
+
return this.buildInsertRow({
|
|
545
545
|
data: data,
|
|
546
546
|
id: id,
|
|
547
547
|
now: now,
|
|
@@ -744,7 +744,7 @@ class DbHelper {
|
|
|
744
744
|
async insData(options) {
|
|
745
745
|
const parsed = this.createDbParse().parseInsert(options);
|
|
746
746
|
const { table, snakeTable, data } = parsed;
|
|
747
|
-
const inputData = this.
|
|
747
|
+
const inputData = this.prepareWriteInputData(data);
|
|
748
748
|
assertWriteDataHasFields(inputData, "插入数据必须至少有一个字段", snakeTable);
|
|
749
749
|
const now = Date.now();
|
|
750
750
|
const insertRows = await this.createInsertRows(table, snakeTable, [data], now);
|
|
@@ -857,7 +857,7 @@ class DbHelper {
|
|
|
857
857
|
const fieldSet = new Set();
|
|
858
858
|
|
|
859
859
|
for (const item of dataList) {
|
|
860
|
-
const userData = this.
|
|
860
|
+
const userData = this.prepareWriteUserData(item.data, true);
|
|
861
861
|
|
|
862
862
|
for (const key of Object.keys(userData)) {
|
|
863
863
|
fieldSet.add(key);
|
|
@@ -896,10 +896,10 @@ class DbHelper {
|
|
|
896
896
|
|
|
897
897
|
async updData(options) {
|
|
898
898
|
const parsed = this.createDbParse().parseUpdate(options);
|
|
899
|
-
const inputData = this.
|
|
899
|
+
const inputData = this.prepareWriteInputData(parsed.data);
|
|
900
900
|
assertWriteDataHasFields(inputData, "更新数据必须至少有一个字段", parsed.snakeTable);
|
|
901
901
|
|
|
902
|
-
const processed = this.
|
|
902
|
+
const processed = this.buildUpdateRow({
|
|
903
903
|
data: parsed.data,
|
|
904
904
|
now: Date.now(),
|
|
905
905
|
allowState: true,
|
|
@@ -922,7 +922,7 @@ class DbHelper {
|
|
|
922
922
|
let processed;
|
|
923
923
|
|
|
924
924
|
if (parsed.deleteMode === "manual") {
|
|
925
|
-
processed = this.
|
|
925
|
+
processed = this.prepareWriteInputData(parsed.data);
|
|
926
926
|
assertWriteDataHasFields(processed, "delData 在 beflyMode=manual 时 data 必须至少有一个字段", parsed.snakeTable);
|
|
927
927
|
} else {
|
|
928
928
|
const now = Date.now();
|
package/lib/dbParse.js
CHANGED
|
@@ -805,9 +805,9 @@ export class DbParse {
|
|
|
805
805
|
|
|
806
806
|
let prepared;
|
|
807
807
|
if (hasLeftJoin) {
|
|
808
|
-
prepared = await this.
|
|
808
|
+
prepared = await this.normalizeLeftJoinReadOptions(options, cleanWhere, classifiedFields);
|
|
809
809
|
} else {
|
|
810
|
-
prepared = await this.
|
|
810
|
+
prepared = await this.normalizeSingleTableReadOptions(options, cleanWhere, classifiedFields);
|
|
811
811
|
}
|
|
812
812
|
|
|
813
813
|
if (mode === "list") {
|
|
@@ -823,7 +823,7 @@ export class DbParse {
|
|
|
823
823
|
const hasLeftJoin = Array.isArray(options.leftJoin) && options.leftJoin.length > 0;
|
|
824
824
|
|
|
825
825
|
if (hasLeftJoin) {
|
|
826
|
-
return this.
|
|
826
|
+
return this.normalizeLeftJoinCountOptions(options, cleanWhere);
|
|
827
827
|
}
|
|
828
828
|
|
|
829
829
|
const snakeTable = snakeCase(Array.isArray(options.table) ? options.table[0] : options.table);
|
|
@@ -841,7 +841,7 @@ export class DbParse {
|
|
|
841
841
|
|
|
842
842
|
parseExists(options) {
|
|
843
843
|
validateNoLeftJoinReadOptions(options, "exists", "exists 不支持 leftJoin(请使用显式 query 或拆分查询)");
|
|
844
|
-
return this.
|
|
844
|
+
return this.prepareSingleTableWhere(options.table, options.where, true, false, "exists");
|
|
845
845
|
}
|
|
846
846
|
|
|
847
847
|
parseInsert(options) {
|
|
@@ -871,7 +871,7 @@ export class DbParse {
|
|
|
871
871
|
return {
|
|
872
872
|
table: options.table,
|
|
873
873
|
snakeTable: snakeCase(options.table),
|
|
874
|
-
where: this.
|
|
874
|
+
where: this.prepareSingleTableWhere(options.table, options.where, true, true, "updData").where,
|
|
875
875
|
data: options.data
|
|
876
876
|
};
|
|
877
877
|
}
|
|
@@ -884,7 +884,7 @@ export class DbParse {
|
|
|
884
884
|
const result = {
|
|
885
885
|
table: options.table,
|
|
886
886
|
snakeTable: snakeCase(options.table),
|
|
887
|
-
where: this.
|
|
887
|
+
where: this.prepareSingleTableWhere(options.table, options.where, !force, true, label, deleteMode).where,
|
|
888
888
|
deleteMode: deleteMode
|
|
889
889
|
};
|
|
890
890
|
|
|
@@ -923,7 +923,7 @@ export class DbParse {
|
|
|
923
923
|
|
|
924
924
|
parseIncrement(table, field, where, value, label = "increment") {
|
|
925
925
|
validateIncrementOptions(table, field, where, value, label);
|
|
926
|
-
const prepared = this.
|
|
926
|
+
const prepared = this.prepareSingleTableWhere(table, where, true, true, label);
|
|
927
927
|
return {
|
|
928
928
|
table: table,
|
|
929
929
|
snakeTable: prepared.snakeTable,
|
|
@@ -933,9 +933,9 @@ export class DbParse {
|
|
|
933
933
|
};
|
|
934
934
|
}
|
|
935
935
|
|
|
936
|
-
async
|
|
936
|
+
async normalizeLeftJoinReadOptions(options, cleanWhere, classifiedFields) {
|
|
937
937
|
const mainTableRef = options.table[0];
|
|
938
|
-
const processedFields = await this.
|
|
938
|
+
const processedFields = await this.joinFieldsToSnake(mainTableRef, classifiedFields);
|
|
939
939
|
const joinTableRefs = options.table.slice(1);
|
|
940
940
|
const normalizedTableRef = normalizeTableRef(mainTableRef);
|
|
941
941
|
const mainQualifier = getTableQualifier(mainTableRef);
|
|
@@ -953,7 +953,7 @@ export class DbParse {
|
|
|
953
953
|
};
|
|
954
954
|
}
|
|
955
955
|
|
|
956
|
-
|
|
956
|
+
normalizeLeftJoinCountOptions(options, cleanWhere) {
|
|
957
957
|
const mainTableRef = options.table[0];
|
|
958
958
|
const joinTableRefs = options.table.slice(1);
|
|
959
959
|
const normalizedTableRef = normalizeTableRef(mainTableRef);
|
|
@@ -972,7 +972,7 @@ export class DbParse {
|
|
|
972
972
|
};
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
-
async
|
|
975
|
+
async normalizeSingleTableReadOptions(options, cleanWhere, classifiedFields) {
|
|
976
976
|
const tableRef = Array.isArray(options.table) ? options.table[0] : options.table;
|
|
977
977
|
const snakeTable = snakeCase(tableRef);
|
|
978
978
|
const processedFields = await fieldsToSnake(tableRef, classifiedFields, this.getTableColumns);
|
|
@@ -989,7 +989,7 @@ export class DbParse {
|
|
|
989
989
|
};
|
|
990
990
|
}
|
|
991
991
|
|
|
992
|
-
|
|
992
|
+
prepareSingleTableWhere(table, where, useDefaultStateFilter, required, label, beflyMode = this.beflyMode) {
|
|
993
993
|
const snakeTable = snakeCase(table);
|
|
994
994
|
const normalizedWhere = whereKeysToSnake(clearDeep(where || {}));
|
|
995
995
|
if (required) {
|
|
@@ -1002,7 +1002,7 @@ export class DbParse {
|
|
|
1002
1002
|
};
|
|
1003
1003
|
}
|
|
1004
1004
|
|
|
1005
|
-
async
|
|
1005
|
+
async joinFieldsToSnake(mainTableRef, classifiedFields) {
|
|
1006
1006
|
if (classifiedFields.type !== "join") {
|
|
1007
1007
|
return [];
|
|
1008
1008
|
}
|
package/lib/dbUtil.js
CHANGED
|
@@ -508,7 +508,10 @@ export function processJoinOrderBy(orderBy) {
|
|
|
508
508
|
}
|
|
509
509
|
|
|
510
510
|
function replaceJoinOnSegment(segment) {
|
|
511
|
-
return segment.replace(/([a-zA-Z_][a-zA-Z0-9_]*)(\s*\.\s*)([a-zA-Z_][a-zA-Z0-9_]*)/g, (
|
|
511
|
+
return segment.replace(/([a-zA-Z_][a-zA-Z0-9_]*)(\s*\.\s*)([a-zA-Z_][a-zA-Z0-9_]*)/g, (...matchParts) => {
|
|
512
|
+
const left = matchParts[1];
|
|
513
|
+
const dot = matchParts[2];
|
|
514
|
+
const right = matchParts[3];
|
|
512
515
|
return `${snakeCase(left)}${dot}${snakeCase(right)}`;
|
|
513
516
|
});
|
|
514
517
|
}
|
package/lib/logger.js
CHANGED
|
@@ -531,7 +531,7 @@ function logWrite(level, input) {
|
|
|
531
531
|
* 日志实例(延迟初始化)
|
|
532
532
|
*/
|
|
533
533
|
export const Logger = {
|
|
534
|
-
info(msg, data) {
|
|
534
|
+
info: function (msg, data) {
|
|
535
535
|
if (isPlainObject(msg)) {
|
|
536
536
|
logWrite("info", msg);
|
|
537
537
|
return;
|
|
@@ -539,7 +539,7 @@ export const Logger = {
|
|
|
539
539
|
|
|
540
540
|
logWrite("info", { msg: msg, data: data });
|
|
541
541
|
},
|
|
542
|
-
warn(msg, data) {
|
|
542
|
+
warn: function (msg, data) {
|
|
543
543
|
if (isPlainObject(msg)) {
|
|
544
544
|
logWrite("warn", msg);
|
|
545
545
|
return;
|
|
@@ -547,7 +547,7 @@ export const Logger = {
|
|
|
547
547
|
|
|
548
548
|
logWrite("warn", { msg: msg, data: data });
|
|
549
549
|
},
|
|
550
|
-
error(msg, err, data) {
|
|
550
|
+
error: function (msg, err, data) {
|
|
551
551
|
if (isPlainObject(msg)) {
|
|
552
552
|
logWrite("error", msg);
|
|
553
553
|
return;
|
|
@@ -555,7 +555,7 @@ export const Logger = {
|
|
|
555
555
|
|
|
556
556
|
logWrite("error", { msg: msg, err: err, data: data });
|
|
557
557
|
},
|
|
558
|
-
debug(msg, data) {
|
|
558
|
+
debug: function (msg, data) {
|
|
559
559
|
if (isPlainObject(msg)) {
|
|
560
560
|
logWrite("debug", msg);
|
|
561
561
|
return;
|
|
@@ -563,16 +563,16 @@ export const Logger = {
|
|
|
563
563
|
|
|
564
564
|
logWrite("debug", { msg: msg, data: data });
|
|
565
565
|
},
|
|
566
|
-
async
|
|
566
|
+
flush: async function () {
|
|
567
567
|
await flush();
|
|
568
568
|
},
|
|
569
|
-
configure(cfg) {
|
|
569
|
+
configure: function (cfg) {
|
|
570
570
|
configure(cfg);
|
|
571
571
|
},
|
|
572
|
-
setMock(mock) {
|
|
572
|
+
setMock: function (mock) {
|
|
573
573
|
setMockLogger(mock);
|
|
574
574
|
},
|
|
575
|
-
async
|
|
575
|
+
shutdown: async function () {
|
|
576
576
|
await shutdown();
|
|
577
577
|
}
|
|
578
578
|
};
|
package/lib/sqlBuilder.js
CHANGED
|
@@ -10,12 +10,12 @@ import { escapeField, escapeTable, resolveQuoteIdent } from "./dbUtil.js";
|
|
|
10
10
|
* SQL 构建器类
|
|
11
11
|
*/
|
|
12
12
|
export class SqlBuilder {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
queryModel;
|
|
14
|
+
quoteIdentifier;
|
|
15
15
|
|
|
16
16
|
constructor(options = {}) {
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
17
|
+
this.quoteIdentifier = resolveQuoteIdent(options);
|
|
18
|
+
this.queryModel = {
|
|
19
19
|
select: [],
|
|
20
20
|
from: null,
|
|
21
21
|
where: { type: "group", join: "AND", items: [] },
|
|
@@ -30,7 +30,7 @@ export class SqlBuilder {
|
|
|
30
30
|
* 重置构建器状态
|
|
31
31
|
*/
|
|
32
32
|
reset() {
|
|
33
|
-
this.
|
|
33
|
+
this.queryModel = {
|
|
34
34
|
select: [],
|
|
35
35
|
from: null,
|
|
36
36
|
where: { type: "group", join: "AND", items: [] },
|
|
@@ -42,8 +42,8 @@ export class SqlBuilder {
|
|
|
42
42
|
return this;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
const escapedField = escapeField(node.field, this.
|
|
45
|
+
compileOperatorNode(node) {
|
|
46
|
+
const escapedField = escapeField(node.field, this.quoteIdentifier);
|
|
47
47
|
|
|
48
48
|
switch (node.operator) {
|
|
49
49
|
case "$not":
|
|
@@ -87,7 +87,7 @@ export class SqlBuilder {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
compileWhereNode(node) {
|
|
91
91
|
if (!node) {
|
|
92
92
|
return { sql: "", params: [] };
|
|
93
93
|
}
|
|
@@ -100,7 +100,7 @@ export class SqlBuilder {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
if (node.type === "op") {
|
|
103
|
-
return this.
|
|
103
|
+
return this.compileOperatorNode(node);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
if (node.type !== "group" || !node.items || node.items.length === 0) {
|
|
@@ -111,7 +111,7 @@ export class SqlBuilder {
|
|
|
111
111
|
const params = [];
|
|
112
112
|
|
|
113
113
|
for (const item of node.items) {
|
|
114
|
-
const built = this.
|
|
114
|
+
const built = this.compileWhereNode(item);
|
|
115
115
|
if (!built.sql) {
|
|
116
116
|
continue;
|
|
117
117
|
}
|
|
@@ -136,7 +136,7 @@ export class SqlBuilder {
|
|
|
136
136
|
* 获取 WHERE 条件(供 DbHelper 使用)
|
|
137
137
|
*/
|
|
138
138
|
getWhereConditions() {
|
|
139
|
-
const result = this.
|
|
139
|
+
const result = this.compileWhereNode(this.queryModel.where);
|
|
140
140
|
return { sql: result.sql, params: result.params };
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -146,12 +146,12 @@ export class SqlBuilder {
|
|
|
146
146
|
select(fields = "*") {
|
|
147
147
|
if (Array.isArray(fields)) {
|
|
148
148
|
for (const field of fields) {
|
|
149
|
-
this.
|
|
149
|
+
this.queryModel.select.push({ type: "field", value: field });
|
|
150
150
|
}
|
|
151
151
|
return this;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
this.
|
|
154
|
+
this.queryModel.select.push({ type: "field", value: fields });
|
|
155
155
|
return this;
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -159,7 +159,7 @@ export class SqlBuilder {
|
|
|
159
159
|
* SELECT 原始表达式(不做转义)
|
|
160
160
|
*/
|
|
161
161
|
selectRaw(expr) {
|
|
162
|
-
this.
|
|
162
|
+
this.queryModel.select.push({ type: "raw", value: expr });
|
|
163
163
|
return this;
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -167,7 +167,7 @@ export class SqlBuilder {
|
|
|
167
167
|
* FROM 表名
|
|
168
168
|
*/
|
|
169
169
|
from(table) {
|
|
170
|
-
this.
|
|
170
|
+
this.queryModel.from = { type: "table", value: table.trim() };
|
|
171
171
|
return this;
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -175,7 +175,7 @@ export class SqlBuilder {
|
|
|
175
175
|
* FROM 原始表达式(不做转义)
|
|
176
176
|
*/
|
|
177
177
|
fromRaw(tableExpr) {
|
|
178
|
-
this.
|
|
178
|
+
this.queryModel.from = { type: "raw", value: tableExpr.trim() };
|
|
179
179
|
return this;
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -183,19 +183,19 @@ export class SqlBuilder {
|
|
|
183
183
|
* WHERE 条件
|
|
184
184
|
*/
|
|
185
185
|
where(conditionOrField) {
|
|
186
|
-
if (this.
|
|
187
|
-
this.
|
|
186
|
+
if (this.queryModel.where.items.length === 0) {
|
|
187
|
+
this.queryModel.where = conditionOrField;
|
|
188
188
|
return this;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
if (conditionOrField.type === "group" && conditionOrField.join === "AND") {
|
|
192
192
|
for (const item of conditionOrField.items) {
|
|
193
|
-
this.
|
|
193
|
+
this.queryModel.where.items.push(item);
|
|
194
194
|
}
|
|
195
195
|
return this;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
this.
|
|
198
|
+
this.queryModel.where.items.push(conditionOrField);
|
|
199
199
|
return this;
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -208,7 +208,7 @@ export class SqlBuilder {
|
|
|
208
208
|
paramList = params;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
this.
|
|
211
|
+
this.queryModel.where.items.push({ type: "raw", sql: sql, params: paramList });
|
|
212
212
|
return this;
|
|
213
213
|
}
|
|
214
214
|
|
|
@@ -216,7 +216,7 @@ export class SqlBuilder {
|
|
|
216
216
|
* LEFT JOIN
|
|
217
217
|
*/
|
|
218
218
|
leftJoin(table, on) {
|
|
219
|
-
this.
|
|
219
|
+
this.queryModel.joins.push({ type: "left", table: table, on: on });
|
|
220
220
|
return this;
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -226,7 +226,7 @@ export class SqlBuilder {
|
|
|
226
226
|
*/
|
|
227
227
|
orderBy(fields) {
|
|
228
228
|
for (const item of fields) {
|
|
229
|
-
this.
|
|
229
|
+
this.queryModel.orderBy.push({ field: item.field, dir: item.dir });
|
|
230
230
|
}
|
|
231
231
|
return this;
|
|
232
232
|
}
|
|
@@ -235,8 +235,8 @@ export class SqlBuilder {
|
|
|
235
235
|
* LIMIT
|
|
236
236
|
*/
|
|
237
237
|
limit(count, offset) {
|
|
238
|
-
this.
|
|
239
|
-
this.
|
|
238
|
+
this.queryModel.limit = count;
|
|
239
|
+
this.queryModel.offset = offset;
|
|
240
240
|
return this;
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -244,7 +244,7 @@ export class SqlBuilder {
|
|
|
244
244
|
* OFFSET
|
|
245
245
|
*/
|
|
246
246
|
offset(count) {
|
|
247
|
-
this.
|
|
247
|
+
this.queryModel.offset = count;
|
|
248
248
|
return this;
|
|
249
249
|
}
|
|
250
250
|
|
|
@@ -253,29 +253,29 @@ export class SqlBuilder {
|
|
|
253
253
|
*/
|
|
254
254
|
toSelectSql() {
|
|
255
255
|
let selectSql = "*";
|
|
256
|
-
if (this.
|
|
257
|
-
selectSql = this.
|
|
256
|
+
if (this.queryModel.select.length > 0) {
|
|
257
|
+
selectSql = this.queryModel.select
|
|
258
258
|
.map((item) => {
|
|
259
259
|
if (item.type === "raw") {
|
|
260
260
|
return item.value;
|
|
261
261
|
}
|
|
262
|
-
return escapeField(item.value, this.
|
|
262
|
+
return escapeField(item.value, this.quoteIdentifier);
|
|
263
263
|
})
|
|
264
264
|
.join(", ");
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
const params = [];
|
|
268
|
-
let fromSql = this.
|
|
269
|
-
if (this.
|
|
270
|
-
fromSql = escapeTable(this.
|
|
268
|
+
let fromSql = this.queryModel.from.value;
|
|
269
|
+
if (this.queryModel.from.type !== "raw") {
|
|
270
|
+
fromSql = escapeTable(this.queryModel.from.value, this.quoteIdentifier);
|
|
271
271
|
}
|
|
272
272
|
let sql = `SELECT ${selectSql} FROM ${fromSql}`;
|
|
273
273
|
|
|
274
|
-
if (this.
|
|
275
|
-
sql += ` ${this.
|
|
274
|
+
if (this.queryModel.joins.length > 0) {
|
|
275
|
+
sql += ` ${this.queryModel.joins.map((join) => `${join.type.toUpperCase()} JOIN ${escapeTable(join.table, this.quoteIdentifier)} ON ${join.on}`).join(" ")}`;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
const whereResult = this.
|
|
278
|
+
const whereResult = this.compileWhereNode(this.queryModel.where);
|
|
279
279
|
if (whereResult.sql) {
|
|
280
280
|
sql += ` WHERE ${whereResult.sql}`;
|
|
281
281
|
for (const param of whereResult.params) {
|
|
@@ -283,14 +283,14 @@ export class SqlBuilder {
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
if (this.
|
|
287
|
-
sql += ` ORDER BY ${this.
|
|
286
|
+
if (this.queryModel.orderBy.length > 0) {
|
|
287
|
+
sql += ` ORDER BY ${this.queryModel.orderBy.map((item) => `${escapeField(item.field, this.quoteIdentifier)} ${item.dir}`).join(", ")}`;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
if (this.
|
|
291
|
-
sql += ` LIMIT ${this.
|
|
292
|
-
if (this.
|
|
293
|
-
sql += ` OFFSET ${this.
|
|
290
|
+
if (this.queryModel.limit !== null) {
|
|
291
|
+
sql += ` LIMIT ${this.queryModel.limit}`;
|
|
292
|
+
if (this.queryModel.offset !== null && this.queryModel.offset !== undefined) {
|
|
293
|
+
sql += ` OFFSET ${this.queryModel.offset}`;
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
|
|
@@ -301,7 +301,7 @@ export class SqlBuilder {
|
|
|
301
301
|
* 构建 INSERT 查询
|
|
302
302
|
*/
|
|
303
303
|
toInsertSql(table, data) {
|
|
304
|
-
const escapedTable = escapeTable(table, this.
|
|
304
|
+
const escapedTable = escapeTable(table, this.quoteIdentifier);
|
|
305
305
|
|
|
306
306
|
if (Array.isArray(data)) {
|
|
307
307
|
if (data.length === 0) {
|
|
@@ -310,7 +310,7 @@ export class SqlBuilder {
|
|
|
310
310
|
|
|
311
311
|
const firstRow = data[0] || {};
|
|
312
312
|
const fields = Object.keys(firstRow);
|
|
313
|
-
const escapedFields = fields.map((field) => escapeField(field, this.
|
|
313
|
+
const escapedFields = fields.map((field) => escapeField(field, this.quoteIdentifier));
|
|
314
314
|
const placeholders = fields.map(() => "?").join(", ");
|
|
315
315
|
const values = data.map(() => `(${placeholders})`).join(", ");
|
|
316
316
|
const params = [];
|
|
@@ -329,7 +329,7 @@ export class SqlBuilder {
|
|
|
329
329
|
|
|
330
330
|
const fields = Object.keys(data);
|
|
331
331
|
|
|
332
|
-
const escapedFields = fields.map((field) => escapeField(field, this.
|
|
332
|
+
const escapedFields = fields.map((field) => escapeField(field, this.quoteIdentifier));
|
|
333
333
|
const placeholders = fields.map(() => "?").join(", ");
|
|
334
334
|
const params = [];
|
|
335
335
|
for (const field of fields) {
|
|
@@ -353,13 +353,13 @@ export class SqlBuilder {
|
|
|
353
353
|
params.push(value);
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
const whereResult = this.
|
|
356
|
+
const whereResult = this.compileWhereNode(this.queryModel.where);
|
|
357
357
|
for (const param of whereResult.params) {
|
|
358
358
|
params.push(param);
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
return {
|
|
362
|
-
sql: `UPDATE ${escapeTable(table, this.
|
|
362
|
+
sql: `UPDATE ${escapeTable(table, this.quoteIdentifier)} SET ${fields.map((field) => `${escapeField(field, this.quoteIdentifier)} = ?`).join(", ")} WHERE ${whereResult.sql}`,
|
|
363
363
|
params: params
|
|
364
364
|
};
|
|
365
365
|
}
|
|
@@ -368,9 +368,9 @@ export class SqlBuilder {
|
|
|
368
368
|
* 构建 DELETE 查询
|
|
369
369
|
*/
|
|
370
370
|
toDeleteSql(table) {
|
|
371
|
-
const whereResult = this.
|
|
371
|
+
const whereResult = this.compileWhereNode(this.queryModel.where);
|
|
372
372
|
return {
|
|
373
|
-
sql: `DELETE FROM ${escapeTable(table, this.
|
|
373
|
+
sql: `DELETE FROM ${escapeTable(table, this.quoteIdentifier)} WHERE ${whereResult.sql}`,
|
|
374
374
|
params: whereResult.params
|
|
375
375
|
};
|
|
376
376
|
}
|
|
@@ -380,17 +380,17 @@ export class SqlBuilder {
|
|
|
380
380
|
*/
|
|
381
381
|
toCountSql() {
|
|
382
382
|
const params = [];
|
|
383
|
-
let fromSql = this.
|
|
384
|
-
if (this.
|
|
385
|
-
fromSql = escapeTable(this.
|
|
383
|
+
let fromSql = this.queryModel.from.value;
|
|
384
|
+
if (this.queryModel.from.type !== "raw") {
|
|
385
|
+
fromSql = escapeTable(this.queryModel.from.value, this.quoteIdentifier);
|
|
386
386
|
}
|
|
387
387
|
let sql = `SELECT COUNT(*) as total FROM ${fromSql}`;
|
|
388
388
|
|
|
389
|
-
if (this.
|
|
390
|
-
sql += ` ${this.
|
|
389
|
+
if (this.queryModel.joins.length > 0) {
|
|
390
|
+
sql += ` ${this.queryModel.joins.map((join) => `${join.type.toUpperCase()} JOIN ${escapeTable(join.table, this.quoteIdentifier)} ON ${join.on}`).join(" ")}`;
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
const whereResult = this.
|
|
393
|
+
const whereResult = this.compileWhereNode(this.queryModel.where);
|
|
394
394
|
if (whereResult.sql) {
|
|
395
395
|
sql += ` WHERE ${whereResult.sql}`;
|
|
396
396
|
for (const param of whereResult.params) {
|
package/lib/validator.js
CHANGED
|
@@ -50,10 +50,10 @@ export class Validator {
|
|
|
50
50
|
|
|
51
51
|
// 参数检查
|
|
52
52
|
if (!isPlainObject(data)) {
|
|
53
|
-
return this.buildResult({
|
|
53
|
+
return this.buildResult({ rootError: "数据必须是对象格式" });
|
|
54
54
|
}
|
|
55
55
|
if (!isPlainObject(rules)) {
|
|
56
|
-
return this.buildResult({
|
|
56
|
+
return this.buildResult({ rootError: "验证规则必须是对象格式" });
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// 检查必填字段
|
package/package.json
CHANGED
package/paths.js
CHANGED
|
@@ -15,8 +15,8 @@ import { fileURLToPath } from "node:url";
|
|
|
15
15
|
import { dirname, isAbsolute, join, normalize, resolve } from "pathe";
|
|
16
16
|
|
|
17
17
|
// 当前文件的路径信息
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
const moduleFilePath = fileURLToPath(import.meta.url);
|
|
19
|
+
const moduleDir = dirname(moduleFilePath);
|
|
20
20
|
|
|
21
21
|
// ==================== Core 框架路径 ====================
|
|
22
22
|
|
|
@@ -24,48 +24,48 @@ const __dirname = dirname(__filename);
|
|
|
24
24
|
* Core 框架根目录
|
|
25
25
|
* @description packages/core/
|
|
26
26
|
*/
|
|
27
|
-
export const coreDir =
|
|
27
|
+
export const coreDir = moduleDir;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Core 框架 dist 目录
|
|
31
31
|
* @description 源码态为 packages/core/dist;dist 运行态为 packages/core/dist
|
|
32
32
|
*/
|
|
33
|
-
export const coreDistDir = normalize(
|
|
33
|
+
export const coreDistDir = normalize(moduleDir).endsWith("/dist") ? moduleDir : join(moduleDir, "dist");
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Core 框架检查目录
|
|
37
37
|
* @description packages/core/checks/
|
|
38
38
|
* @usage 存放启动检查模块(返回 boolean 的 default 函数)
|
|
39
39
|
*/
|
|
40
|
-
export const coreCheckDir = join(
|
|
40
|
+
export const coreCheckDir = join(moduleDir, "checks");
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Core 框架插件目录
|
|
44
44
|
* @description packages/core/plugins/
|
|
45
45
|
* @usage 存放内置插件(mysql, logger, redis, tool 等)
|
|
46
46
|
*/
|
|
47
|
-
export const corePluginDir = join(
|
|
47
|
+
export const corePluginDir = join(moduleDir, "plugins");
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Core 框架钩子目录
|
|
51
51
|
* @description packages/core/hooks/
|
|
52
52
|
* @usage 存放内置钩子(auth, cors, parser 等)
|
|
53
53
|
*/
|
|
54
|
-
export const coreHookDir = join(
|
|
54
|
+
export const coreHookDir = join(moduleDir, "hooks");
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Core 框架 API 目录
|
|
58
58
|
* @description packages/core/apis/
|
|
59
59
|
* @usage 存放框架级别的 API 接口
|
|
60
60
|
*/
|
|
61
|
-
export const coreApiDir = join(
|
|
61
|
+
export const coreApiDir = join(moduleDir, "apis");
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Core 框架表定义目录
|
|
65
65
|
* @description packages/core/tables/
|
|
66
66
|
* @usage 存放框架核心表定义(JSON 格式)
|
|
67
67
|
*/
|
|
68
|
-
export const coreTableDir = join(
|
|
68
|
+
export const coreTableDir = join(moduleDir, "tables");
|
|
69
69
|
|
|
70
70
|
// ==================== 用户项目路径 ====================
|
|
71
71
|
|
package/plugins/cache.js
CHANGED
package/plugins/email.js
CHANGED
package/plugins/logger.js
CHANGED
package/plugins/mysql.js
CHANGED
package/plugins/redis.js
CHANGED