befly 3.17.0 → 3.17.2
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/README.md +6 -0
- package/apis/admin/cacheRefresh.js +122 -0
- package/apis/admin/del.js +34 -0
- package/apis/admin/detail.js +23 -0
- package/apis/admin/ins.js +69 -0
- package/apis/admin/list.js +28 -0
- package/apis/admin/upd.js +95 -0
- package/apis/api/all.js +24 -0
- package/apis/api/list.js +31 -0
- package/apis/auth/login.js +123 -0
- package/apis/auth/sendSmsCode.js +24 -0
- package/apis/dashboard/configStatus.js +39 -0
- package/apis/dashboard/environmentInfo.js +43 -0
- package/apis/dashboard/performanceMetrics.js +20 -0
- package/apis/dashboard/permissionStats.js +27 -0
- package/apis/dashboard/serviceStatus.js +75 -0
- package/apis/dashboard/systemInfo.js +19 -0
- package/apis/dashboard/systemOverview.js +30 -0
- package/apis/dashboard/systemResources.js +106 -0
- package/apis/dict/all.js +23 -0
- package/apis/dict/del.js +16 -0
- package/apis/dict/detail.js +27 -0
- package/apis/dict/ins.js +51 -0
- package/apis/dict/items.js +30 -0
- package/apis/dict/list.js +36 -0
- package/apis/dict/upd.js +74 -0
- package/apis/dictType/all.js +16 -0
- package/apis/dictType/del.js +38 -0
- package/apis/dictType/detail.js +20 -0
- package/apis/dictType/ins.js +37 -0
- package/apis/dictType/list.js +26 -0
- package/apis/dictType/upd.js +51 -0
- package/apis/email/config.js +25 -0
- package/apis/email/logList.js +23 -0
- package/apis/email/send.js +66 -0
- package/apis/email/verify.js +21 -0
- package/apis/loginLog/list.js +23 -0
- package/apis/menu/all.js +41 -0
- package/apis/menu/list.js +25 -0
- package/apis/operateLog/list.js +23 -0
- package/apis/role/all.js +21 -0
- package/apis/role/apiSave.js +43 -0
- package/apis/role/apis.js +22 -0
- package/apis/role/del.js +49 -0
- package/apis/role/detail.js +32 -0
- package/apis/role/ins.js +46 -0
- package/apis/role/list.js +27 -0
- package/apis/role/menuSave.js +42 -0
- package/apis/role/menus.js +22 -0
- package/apis/role/save.js +40 -0
- package/apis/role/upd.js +50 -0
- package/apis/sysConfig/all.js +16 -0
- package/apis/sysConfig/del.js +36 -0
- package/apis/sysConfig/get.js +49 -0
- package/apis/sysConfig/ins.js +50 -0
- package/apis/sysConfig/list.js +24 -0
- package/apis/sysConfig/upd.js +62 -0
- package/checks/api.js +55 -0
- package/checks/config.js +107 -0
- package/checks/hook.js +38 -0
- package/checks/menu.js +58 -0
- package/checks/plugin.js +38 -0
- package/checks/table.js +78 -0
- package/configs/beflyConfig.json +61 -0
- package/configs/beflyMenus.json +85 -0
- package/configs/constConfig.js +34 -0
- package/configs/regexpAlias.json +55 -0
- package/hooks/auth.js +34 -0
- package/hooks/cors.js +39 -0
- package/hooks/parser.js +90 -0
- package/hooks/permission.js +71 -0
- package/hooks/validator.js +43 -0
- package/index.js +326 -0
- package/lib/cacheHelper.js +483 -0
- package/lib/cacheKeys.js +42 -0
- package/lib/connect.js +120 -0
- package/lib/dbHelper/builders.js +698 -0
- package/lib/dbHelper/context.js +131 -0
- package/lib/dbHelper/dataOps.js +505 -0
- package/lib/dbHelper/execute.js +65 -0
- package/lib/dbHelper/index.js +27 -0
- package/lib/dbHelper/transaction.js +43 -0
- package/lib/dbHelper/util.js +58 -0
- package/lib/dbHelper/validate.js +549 -0
- package/lib/emailHelper.js +110 -0
- package/lib/logger.js +604 -0
- package/lib/redisHelper.js +684 -0
- package/lib/sqlBuilder/batch.js +113 -0
- package/lib/sqlBuilder/check.js +150 -0
- package/lib/sqlBuilder/compiler.js +347 -0
- package/lib/sqlBuilder/errors.js +60 -0
- package/lib/sqlBuilder/index.js +218 -0
- package/lib/sqlBuilder/parser.js +296 -0
- package/lib/sqlBuilder/util.js +260 -0
- package/lib/validator.js +303 -0
- package/package.json +19 -12
- package/paths.js +112 -0
- package/plugins/cache.js +16 -0
- package/plugins/config.js +11 -0
- package/plugins/email.js +27 -0
- package/plugins/logger.js +20 -0
- package/plugins/mysql.js +36 -0
- package/plugins/redis.js +34 -0
- package/plugins/tool.js +155 -0
- package/router/api.js +140 -0
- package/router/static.js +71 -0
- package/sql/admin.sql +18 -0
- package/sql/api.sql +12 -0
- package/sql/dict.sql +13 -0
- package/sql/dictType.sql +12 -0
- package/sql/emailLog.sql +20 -0
- package/sql/loginLog.sql +25 -0
- package/sql/menu.sql +12 -0
- package/sql/operateLog.sql +22 -0
- package/sql/role.sql +14 -0
- package/sql/sysConfig.sql +16 -0
- package/sync/api.js +93 -0
- package/sync/cache.js +13 -0
- package/sync/dev.js +171 -0
- package/sync/menu.js +99 -0
- package/tables/admin.json +56 -0
- package/tables/api.json +26 -0
- package/tables/dict.json +30 -0
- package/tables/dictType.json +24 -0
- package/tables/emailLog.json +61 -0
- package/tables/loginLog.json +86 -0
- package/tables/menu.json +24 -0
- package/tables/operateLog.json +68 -0
- package/tables/role.json +32 -0
- package/tables/sysConfig.json +43 -0
- package/utils/calcPerfTime.js +13 -0
- package/utils/cors.js +17 -0
- package/utils/deepMerge.js +78 -0
- package/utils/fieldClear.js +65 -0
- package/utils/formatYmdHms.js +23 -0
- package/utils/formatZodIssues.js +109 -0
- package/utils/getClientIp.js +47 -0
- package/utils/importDefault.js +51 -0
- package/utils/is.js +462 -0
- package/utils/loggerUtils.js +185 -0
- package/utils/processInfo.js +39 -0
- package/utils/regexpUtil.js +52 -0
- package/utils/response.js +114 -0
- package/utils/scanFiles.js +124 -0
- package/utils/scanSources.js +68 -0
- package/utils/sortModules.js +75 -0
- package/utils/toSessionTtlSeconds.js +14 -0
- package/utils/util.js +374 -0
- package/befly.js +0 -16413
- package/befly.min.js +0 -72
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL 构造器 - JavaScript 版本
|
|
3
|
+
* 提供链式 API 构建 SQL 查询
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { resolveQuoteIdent, normalizeLimitValue, normalizeOffsetValue } from "./util.js";
|
|
7
|
+
import { appendGroupByItems, appendHavingItems, appendJoinItem, appendOrderByItems, appendSelectItems, appendSelectRaw, appendWhereInput, appendWhereRaw, createWhereRoot, setFromValue } from "./parser.js";
|
|
8
|
+
import { compileCount, compileDelete, compileInsert, compileSelect, compileUpdate, compileWhere } from "./compiler.js";
|
|
9
|
+
import { toDeleteInSql, toUpdateCaseByIdSql } from "./batch.js";
|
|
10
|
+
|
|
11
|
+
function createModel() {
|
|
12
|
+
return {
|
|
13
|
+
select: [],
|
|
14
|
+
from: null,
|
|
15
|
+
where: createWhereRoot(),
|
|
16
|
+
joins: [],
|
|
17
|
+
orderBy: [],
|
|
18
|
+
groupBy: [],
|
|
19
|
+
having: [],
|
|
20
|
+
limit: null,
|
|
21
|
+
offset: null
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* SQL 构建器类
|
|
27
|
+
*/
|
|
28
|
+
export class SqlBuilder {
|
|
29
|
+
_model;
|
|
30
|
+
_quoteIdent;
|
|
31
|
+
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this._quoteIdent = resolveQuoteIdent(options);
|
|
34
|
+
this._model = createModel();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 重置构建器状态
|
|
39
|
+
*/
|
|
40
|
+
reset() {
|
|
41
|
+
this._model = createModel();
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 获取 WHERE 条件(供 DbHelper 使用)
|
|
47
|
+
*/
|
|
48
|
+
getWhereConditions() {
|
|
49
|
+
const result = compileWhere(this._model.where, this._quoteIdent);
|
|
50
|
+
return { sql: result.sql, params: result.params };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* SELECT 字段
|
|
55
|
+
*/
|
|
56
|
+
select(fields = "*") {
|
|
57
|
+
appendSelectItems(this._model.select, fields);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* SELECT 原始表达式(不做转义)
|
|
63
|
+
*/
|
|
64
|
+
selectRaw(expr) {
|
|
65
|
+
appendSelectRaw(this._model.select, expr);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* FROM 表名
|
|
71
|
+
*/
|
|
72
|
+
from(table) {
|
|
73
|
+
setFromValue(this._model, table, false);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* FROM 原始表达式(不做转义)
|
|
79
|
+
*/
|
|
80
|
+
fromRaw(tableExpr) {
|
|
81
|
+
setFromValue(this._model, tableExpr, true);
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* WHERE 条件
|
|
87
|
+
*/
|
|
88
|
+
where(conditionOrField, value) {
|
|
89
|
+
appendWhereInput(this._model.where, conditionOrField, value);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* WHERE 原始片段(不做转义),可附带参数。
|
|
95
|
+
*/
|
|
96
|
+
whereRaw(sql, params) {
|
|
97
|
+
appendWhereRaw(this._model.where, sql, params);
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* LEFT JOIN
|
|
103
|
+
*/
|
|
104
|
+
leftJoin(table, on) {
|
|
105
|
+
appendJoinItem(this._model.joins, "left", table, on);
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* RIGHT JOIN
|
|
111
|
+
*/
|
|
112
|
+
rightJoin(table, on) {
|
|
113
|
+
appendJoinItem(this._model.joins, "right", table, on);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* INNER JOIN
|
|
119
|
+
*/
|
|
120
|
+
innerJoin(table, on) {
|
|
121
|
+
appendJoinItem(this._model.joins, "inner", table, on);
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* ORDER BY
|
|
127
|
+
* @param fields - 格式为 ["field#ASC", "field2#DESC"]
|
|
128
|
+
*/
|
|
129
|
+
orderBy(fields) {
|
|
130
|
+
appendOrderByItems(this._model.orderBy, fields);
|
|
131
|
+
return this;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* GROUP BY
|
|
136
|
+
*/
|
|
137
|
+
groupBy(field) {
|
|
138
|
+
appendGroupByItems(this._model.groupBy, field);
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* HAVING
|
|
144
|
+
*/
|
|
145
|
+
having(condition) {
|
|
146
|
+
appendHavingItems(this._model.having, condition);
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* LIMIT
|
|
152
|
+
*/
|
|
153
|
+
limit(count, offset) {
|
|
154
|
+
const result = normalizeLimitValue(count, offset);
|
|
155
|
+
this._model.limit = result.limitValue;
|
|
156
|
+
this._model.offset = result.offsetValue;
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* OFFSET
|
|
162
|
+
*/
|
|
163
|
+
offset(count) {
|
|
164
|
+
const offsetValue = normalizeOffsetValue(count);
|
|
165
|
+
this._model.offset = offsetValue;
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 构建 SELECT 查询
|
|
171
|
+
*/
|
|
172
|
+
toSelectSql() {
|
|
173
|
+
return compileSelect(this._model, this._quoteIdent);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 构建 INSERT 查询
|
|
178
|
+
*/
|
|
179
|
+
toInsertSql(table, data) {
|
|
180
|
+
return compileInsert(table, data, this._quoteIdent);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 构建 UPDATE 查询
|
|
185
|
+
*/
|
|
186
|
+
toUpdateSql(table, data) {
|
|
187
|
+
return compileUpdate(this._model, table, data, this._quoteIdent);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 构建 DELETE 查询
|
|
192
|
+
*/
|
|
193
|
+
toDeleteSql(table) {
|
|
194
|
+
return compileDelete(this._model, table, this._quoteIdent);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 构建 COUNT 查询
|
|
199
|
+
*/
|
|
200
|
+
toCountSql() {
|
|
201
|
+
return compileCount(this._model, this._quoteIdent);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static toDeleteInSql(options) {
|
|
205
|
+
return toDeleteInSql(options);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static toUpdateCaseByIdSql(options) {
|
|
209
|
+
return toUpdateCaseByIdSql(options);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 创建新的 SQL 构建器实例
|
|
215
|
+
*/
|
|
216
|
+
export function createQueryBuilder() {
|
|
217
|
+
return new SqlBuilder();
|
|
218
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { SqlErrors } from "./errors.js";
|
|
2
|
+
import { validateParam } from "./util.js";
|
|
3
|
+
import { isNonEmptyString, isString } from "../../utils/is.js";
|
|
4
|
+
|
|
5
|
+
export function createWhereRoot() {
|
|
6
|
+
return { type: "group", join: "AND", items: [] };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function appendSelectItems(list, fields) {
|
|
10
|
+
if (Array.isArray(fields)) {
|
|
11
|
+
for (const field of fields) {
|
|
12
|
+
list.push({ type: "field", value: field });
|
|
13
|
+
}
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (isString(fields)) {
|
|
18
|
+
list.push({ type: "field", value: fields });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
throw new Error(SqlErrors.SELECT_FIELDS_INVALID, {
|
|
23
|
+
cause: null,
|
|
24
|
+
code: "validation"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function appendSelectRaw(list, expr) {
|
|
29
|
+
if (!isNonEmptyString(expr)) {
|
|
30
|
+
throw new Error(SqlErrors.SELECT_RAW_NEED_NON_EMPTY(expr), {
|
|
31
|
+
cause: null,
|
|
32
|
+
code: "validation"
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
list.push({ type: "raw", value: expr });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function setFromValue(state, table, isRaw) {
|
|
39
|
+
if (!isNonEmptyString(table)) {
|
|
40
|
+
const err = isRaw ? SqlErrors.FROM_RAW_NEED_NON_EMPTY(table) : SqlErrors.FROM_NEED_NON_EMPTY(table);
|
|
41
|
+
throw new Error(err, {
|
|
42
|
+
cause: null,
|
|
43
|
+
code: "validation"
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
state.from = { type: isRaw ? "raw" : "table", value: table.trim() };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function appendJoinItem(list, joinType, table, on) {
|
|
51
|
+
if (!isString(table) || !isString(on)) {
|
|
52
|
+
throw new Error(SqlErrors.JOIN_NEED_STRING(table, on), {
|
|
53
|
+
cause: null,
|
|
54
|
+
code: "validation"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
list.push({ type: joinType, table: table, on: on });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function appendOrderByItems(list, fields) {
|
|
62
|
+
if (!Array.isArray(fields)) {
|
|
63
|
+
throw new Error(SqlErrors.ORDER_BY_NEED_ARRAY, {
|
|
64
|
+
cause: null,
|
|
65
|
+
code: "validation"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const item of fields) {
|
|
70
|
+
if (!isString(item) || !item.includes("#")) {
|
|
71
|
+
throw new Error(SqlErrors.ORDER_BY_ITEM_NEED_HASH(item), {
|
|
72
|
+
cause: null,
|
|
73
|
+
code: "validation"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const parts = item.split("#");
|
|
78
|
+
if (parts.length !== 2) {
|
|
79
|
+
throw new Error(SqlErrors.ORDER_BY_ITEM_NEED_HASH(item), {
|
|
80
|
+
cause: null,
|
|
81
|
+
code: "validation"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const fieldName = parts[0];
|
|
86
|
+
const direction = parts[1];
|
|
87
|
+
const cleanField = fieldName.trim();
|
|
88
|
+
const cleanDir = direction.trim().toUpperCase();
|
|
89
|
+
|
|
90
|
+
if (!cleanField) {
|
|
91
|
+
throw new Error(SqlErrors.ORDER_BY_FIELD_EMPTY(item), {
|
|
92
|
+
cause: null,
|
|
93
|
+
code: "validation"
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!["ASC", "DESC"].includes(cleanDir)) {
|
|
98
|
+
throw new Error(SqlErrors.ORDER_BY_DIR_INVALID(cleanDir), {
|
|
99
|
+
cause: null,
|
|
100
|
+
code: "validation"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
list.push({ field: cleanField, dir: cleanDir });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function appendGroupByItems(list, field) {
|
|
109
|
+
if (Array.isArray(field)) {
|
|
110
|
+
for (const item of field) {
|
|
111
|
+
if (isString(item)) {
|
|
112
|
+
list.push(item);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (isString(field)) {
|
|
119
|
+
list.push(field);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function appendHavingItems(list, condition) {
|
|
124
|
+
if (isString(condition)) {
|
|
125
|
+
list.push(condition);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function appendWhereInput(root, conditionOrField, value) {
|
|
130
|
+
if (conditionOrField && typeof conditionOrField === "object" && !Array.isArray(conditionOrField)) {
|
|
131
|
+
const node = parseWhereObject(conditionOrField);
|
|
132
|
+
if (node && node.items.length > 0) {
|
|
133
|
+
root.items.push(node);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isString(conditionOrField)) {
|
|
139
|
+
if (value === undefined) {
|
|
140
|
+
throw new Error(SqlErrors.WHERE_VALUE_REQUIRED, {
|
|
141
|
+
cause: null,
|
|
142
|
+
code: "validation"
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const node = buildOperatorNode(conditionOrField, "=", value);
|
|
146
|
+
if (node) {
|
|
147
|
+
root.items.push(node);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function appendWhereRaw(root, sql, params) {
|
|
153
|
+
if (!isNonEmptyString(sql)) {
|
|
154
|
+
throw new Error(SqlErrors.WHERE_RAW_NEED_NON_EMPTY(sql), {
|
|
155
|
+
cause: null,
|
|
156
|
+
code: "validation"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const paramList = Array.isArray(params) ? params : [];
|
|
161
|
+
for (const param of paramList) {
|
|
162
|
+
validateParam(param);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
root.items.push({ type: "raw", sql: sql, params: paramList });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function parseWhereObject(whereObj) {
|
|
169
|
+
if (!whereObj || typeof whereObj !== "object") {
|
|
170
|
+
return { type: "group", join: "AND", items: [] };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const group = { type: "group", join: "AND", items: [] };
|
|
174
|
+
|
|
175
|
+
for (const [key, value] of Object.entries(whereObj)) {
|
|
176
|
+
if (value === undefined) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (key === "$and") {
|
|
181
|
+
if (Array.isArray(value)) {
|
|
182
|
+
for (const condition of value) {
|
|
183
|
+
if (condition && typeof condition === "object" && !Array.isArray(condition)) {
|
|
184
|
+
const sub = parseWhereObject(condition);
|
|
185
|
+
if (sub.items.length > 0) {
|
|
186
|
+
if (sub.join === "AND") {
|
|
187
|
+
for (const item of sub.items) {
|
|
188
|
+
group.items.push(item);
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
group.items.push(sub);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (key === "$or") {
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
const orGroup = { type: "group", join: "OR", items: [] };
|
|
203
|
+
for (const condition of value) {
|
|
204
|
+
if (!condition || typeof condition !== "object" || Array.isArray(condition)) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const sub = parseWhereObject(condition);
|
|
208
|
+
if (sub.items.length > 0) {
|
|
209
|
+
orGroup.items.push(sub);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (orGroup.items.length > 0) {
|
|
213
|
+
group.items.push(orGroup);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (key.includes("$")) {
|
|
220
|
+
const lastDollarIndex = key.lastIndexOf("$");
|
|
221
|
+
const fieldName = key.substring(0, lastDollarIndex);
|
|
222
|
+
const operator = "$" + key.substring(lastDollarIndex + 1);
|
|
223
|
+
const node = buildOperatorNode(fieldName, operator, value);
|
|
224
|
+
if (node) {
|
|
225
|
+
group.items.push(node);
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
231
|
+
for (const [op, val] of Object.entries(value)) {
|
|
232
|
+
const node = buildOperatorNode(key, op, val);
|
|
233
|
+
if (node) {
|
|
234
|
+
group.items.push(node);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const node = buildOperatorNode(key, "=", value);
|
|
241
|
+
if (node) {
|
|
242
|
+
group.items.push(node);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return group;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function buildOperatorNode(fieldName, operator, value) {
|
|
250
|
+
switch (operator) {
|
|
251
|
+
case "$in":
|
|
252
|
+
if (!Array.isArray(value)) {
|
|
253
|
+
throw new Error(SqlErrors.IN_NEED_ARRAY(operator), {
|
|
254
|
+
cause: null,
|
|
255
|
+
code: "validation"
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (value.length === 0) {
|
|
259
|
+
throw new Error(SqlErrors.IN_NEED_NON_EMPTY, {
|
|
260
|
+
cause: null,
|
|
261
|
+
code: "validation"
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return { type: "op", field: fieldName, operator: operator, value: value };
|
|
265
|
+
case "$nin":
|
|
266
|
+
case "$notIn":
|
|
267
|
+
if (!Array.isArray(value)) {
|
|
268
|
+
throw new Error(SqlErrors.NIN_NEED_ARRAY(operator), {
|
|
269
|
+
cause: null,
|
|
270
|
+
code: "validation"
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (value.length === 0) {
|
|
274
|
+
throw new Error(SqlErrors.NIN_NEED_NON_EMPTY, {
|
|
275
|
+
cause: null,
|
|
276
|
+
code: "validation"
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
return { type: "op", field: fieldName, operator: operator, value: value };
|
|
280
|
+
case "$between":
|
|
281
|
+
case "$notBetween":
|
|
282
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
283
|
+
return { type: "op", field: fieldName, operator: operator, value: value };
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
case "$null":
|
|
287
|
+
case "$notNull":
|
|
288
|
+
if (value === true) {
|
|
289
|
+
return { type: "op", field: fieldName, operator: operator, value: value };
|
|
290
|
+
}
|
|
291
|
+
return null;
|
|
292
|
+
default:
|
|
293
|
+
validateParam(value);
|
|
294
|
+
return { type: "op", field: fieldName, operator: operator, value: value };
|
|
295
|
+
}
|
|
296
|
+
}
|