befly 3.20.10 → 3.21.0

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.
@@ -1,200 +0,0 @@
1
- /**
2
- * SQL 构造器 - JavaScript 版本
3
- * 提供链式 API 构建 SQL 查询
4
- */
5
-
6
- import { resolveQuoteIdent, normalizeLimitValue, normalizeOffsetValue } from "./util.js";
7
- import { 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
- limit: null,
19
- offset: null
20
- };
21
- }
22
-
23
- /**
24
- * SQL 构建器类
25
- */
26
- export class SqlBuilder {
27
- _model;
28
- _quoteIdent;
29
-
30
- constructor(options) {
31
- this._quoteIdent = resolveQuoteIdent(options);
32
- this._model = createModel();
33
- }
34
-
35
- /**
36
- * 重置构建器状态
37
- */
38
- reset() {
39
- this._model = createModel();
40
- return this;
41
- }
42
-
43
- /**
44
- * 获取 WHERE 条件(供 DbHelper 使用)
45
- */
46
- getWhereConditions() {
47
- const result = compileWhere(this._model.where, this._quoteIdent);
48
- return { sql: result.sql, params: result.params };
49
- }
50
-
51
- /**
52
- * SELECT 字段
53
- */
54
- select(fields = "*") {
55
- appendSelectItems(this._model.select, fields);
56
- return this;
57
- }
58
-
59
- /**
60
- * SELECT 原始表达式(不做转义)
61
- */
62
- selectRaw(expr) {
63
- appendSelectRaw(this._model.select, expr);
64
- return this;
65
- }
66
-
67
- /**
68
- * FROM 表名
69
- */
70
- from(table) {
71
- setFromValue(this._model, table, false);
72
- return this;
73
- }
74
-
75
- /**
76
- * FROM 原始表达式(不做转义)
77
- */
78
- fromRaw(tableExpr) {
79
- setFromValue(this._model, tableExpr, true);
80
- return this;
81
- }
82
-
83
- /**
84
- * WHERE 条件
85
- */
86
- where(conditionOrField, value) {
87
- appendWhereInput(this._model.where, conditionOrField, value);
88
- return this;
89
- }
90
-
91
- /**
92
- * WHERE 原始片段(不做转义),可附带参数。
93
- */
94
- whereRaw(sql, params) {
95
- appendWhereRaw(this._model.where, sql, params);
96
- return this;
97
- }
98
-
99
- /**
100
- * LEFT JOIN
101
- */
102
- leftJoin(table, on) {
103
- appendJoinItem(this._model.joins, "left", table, on);
104
- return this;
105
- }
106
-
107
- /**
108
- * RIGHT JOIN
109
- */
110
- rightJoin(table, on) {
111
- appendJoinItem(this._model.joins, "right", table, on);
112
- return this;
113
- }
114
-
115
- /**
116
- * INNER JOIN
117
- */
118
- innerJoin(table, on) {
119
- appendJoinItem(this._model.joins, "inner", table, on);
120
- return this;
121
- }
122
-
123
- /**
124
- * ORDER BY
125
- * @param fields - 格式为 ["field#ASC", "field2#DESC"]
126
- */
127
- orderBy(fields) {
128
- appendOrderByItems(this._model.orderBy, fields);
129
- return this;
130
- }
131
-
132
- /**
133
- * LIMIT
134
- */
135
- limit(count, offset) {
136
- const result = normalizeLimitValue(count, offset);
137
- this._model.limit = result.limitValue;
138
- this._model.offset = result.offsetValue;
139
- return this;
140
- }
141
-
142
- /**
143
- * OFFSET
144
- */
145
- offset(count) {
146
- const offsetValue = normalizeOffsetValue(count);
147
- this._model.offset = offsetValue;
148
- return this;
149
- }
150
-
151
- /**
152
- * 构建 SELECT 查询
153
- */
154
- toSelectSql() {
155
- return compileSelect(this._model, this._quoteIdent);
156
- }
157
-
158
- /**
159
- * 构建 INSERT 查询
160
- */
161
- toInsertSql(table, data) {
162
- return compileInsert(table, data, this._quoteIdent);
163
- }
164
-
165
- /**
166
- * 构建 UPDATE 查询
167
- */
168
- toUpdateSql(table, data) {
169
- return compileUpdate(this._model, table, data, this._quoteIdent);
170
- }
171
-
172
- /**
173
- * 构建 DELETE 查询
174
- */
175
- toDeleteSql(table) {
176
- return compileDelete(this._model, table, this._quoteIdent);
177
- }
178
-
179
- /**
180
- * 构建 COUNT 查询
181
- */
182
- toCountSql() {
183
- return compileCount(this._model, this._quoteIdent);
184
- }
185
-
186
- static toDeleteInSql(options) {
187
- return toDeleteInSql(options);
188
- }
189
-
190
- static toUpdateCaseByIdSql(options) {
191
- return toUpdateCaseByIdSql(options);
192
- }
193
- }
194
-
195
- /**
196
- * 创建新的 SQL 构建器实例
197
- */
198
- export function createQueryBuilder() {
199
- return new SqlBuilder();
200
- }
@@ -1,305 +0,0 @@
1
- import { validateParam } from "./util.js";
2
- import { isNonEmptyString, isString } from "../../utils/is.js";
3
-
4
- export function createWhereRoot() {
5
- return { type: "group", join: "AND", items: [] };
6
- }
7
-
8
- export function appendSelectItems(list, fields) {
9
- if (Array.isArray(fields)) {
10
- for (const field of fields) {
11
- list.push({ type: "field", value: field });
12
- }
13
- return;
14
- }
15
-
16
- if (isString(fields)) {
17
- list.push({ type: "field", value: fields });
18
- return;
19
- }
20
-
21
- throw new Error("SELECT 字段必须是字符串或数组", {
22
- cause: null,
23
- code: "validation"
24
- });
25
- }
26
-
27
- export function appendSelectRaw(list, expr) {
28
- if (!isNonEmptyString(expr)) {
29
- throw new Error(`selectRaw 需要非空字符串 (expr: ${String(expr)})`, {
30
- cause: null,
31
- code: "validation"
32
- });
33
- }
34
- list.push({ type: "raw", value: expr });
35
- }
36
-
37
- export function setFromValue(state, table, isRaw) {
38
- if (!isNonEmptyString(table)) {
39
- const err = isRaw ? `fromRaw 需要非空字符串 (tableExpr: ${String(table)})` : `FROM 表名必须是非空字符串 (table: ${String(table)})`;
40
- throw new Error(err, {
41
- cause: null,
42
- code: "validation"
43
- });
44
- }
45
-
46
- state.from = { type: isRaw ? "raw" : "table", value: table.trim() };
47
- }
48
-
49
- export function appendJoinItem(list, joinType, table, on) {
50
- if (!isString(table) || !isString(on)) {
51
- throw new Error(`JOIN 表名和条件必须是字符串 (table: ${String(table)}, on: ${String(on)})`, {
52
- cause: null,
53
- code: "validation"
54
- });
55
- }
56
-
57
- list.push({ type: joinType, table: table, on: on });
58
- }
59
-
60
- export function appendOrderByItems(list, fields) {
61
- if (!Array.isArray(fields)) {
62
- throw new Error('orderBy 必须是字符串数组,格式为 "字段#方向"', {
63
- cause: null,
64
- code: "validation"
65
- });
66
- }
67
-
68
- for (const item of fields) {
69
- if (!isString(item) || !item.includes("#")) {
70
- throw new Error(`orderBy 字段必须是 "字段#方向" 格式的字符串(例如:"name#ASC", "id#DESC") (item: ${String(item)})`, {
71
- cause: null,
72
- code: "validation"
73
- });
74
- }
75
-
76
- const parts = item.split("#");
77
- if (parts.length !== 2) {
78
- throw new Error(`orderBy 字段必须是 "字段#方向" 格式的字符串(例如:"name#ASC", "id#DESC") (item: ${String(item)})`, {
79
- cause: null,
80
- code: "validation"
81
- });
82
- }
83
-
84
- const fieldName = parts[0];
85
- const direction = parts[1];
86
- const cleanField = fieldName.trim();
87
- const cleanDir = direction.trim().toUpperCase();
88
-
89
- if (!cleanField) {
90
- throw new Error(`orderBy 中字段名不能为空 (item: ${item})`, {
91
- cause: null,
92
- code: "validation"
93
- });
94
- }
95
-
96
- if (!["ASC", "DESC"].includes(cleanDir)) {
97
- throw new Error(`ORDER BY 方向必须是 ASC 或 DESC (direction: ${cleanDir})`, {
98
- cause: null,
99
- code: "validation"
100
- });
101
- }
102
-
103
- list.push({ field: cleanField, dir: cleanDir });
104
- }
105
- }
106
-
107
- export function appendWhereInput(root, conditionOrField, value) {
108
- if (conditionOrField && typeof conditionOrField === "object" && !Array.isArray(conditionOrField)) {
109
- appendWhereObject(root, conditionOrField);
110
- return;
111
- }
112
-
113
- if (isString(conditionOrField)) {
114
- if (value === undefined) {
115
- throw new Error("where(field, value) 不允许省略 value。若需传入原始 WHERE,请使用 whereRaw", {
116
- cause: null,
117
- code: "validation"
118
- });
119
- }
120
- appendWhereNode(root, buildOperatorNode(conditionOrField, "=", value));
121
- }
122
- }
123
-
124
- export function appendWhereRaw(root, sql, params) {
125
- if (!isNonEmptyString(sql)) {
126
- throw new Error(`whereRaw 需要非空字符串 (sql: ${String(sql)})`, {
127
- cause: null,
128
- code: "validation"
129
- });
130
- }
131
-
132
- const paramList = Array.isArray(params) ? params : [];
133
- for (const param of paramList) {
134
- validateParam(param);
135
- }
136
-
137
- root.items.push({ type: "raw", sql: sql, params: paramList });
138
- }
139
-
140
- function appendWhereNode(root, node) {
141
- if (node) {
142
- root.items.push(node);
143
- }
144
- }
145
-
146
- function appendWhereObject(root, whereObj) {
147
- const node = parseWhereObject(whereObj);
148
- if (node.items.length > 0) {
149
- root.items.push(node);
150
- }
151
- }
152
-
153
- function parseWhereObject(whereObj) {
154
- if (!whereObj || typeof whereObj !== "object") {
155
- return { type: "group", join: "AND", items: [] };
156
- }
157
-
158
- const group = { type: "group", join: "AND", items: [] };
159
-
160
- for (const [key, value] of Object.entries(whereObj)) {
161
- if (value === undefined) {
162
- continue;
163
- }
164
-
165
- if (key === "$and") {
166
- appendAndConditions(group, value);
167
- continue;
168
- }
169
-
170
- if (key === "$or") {
171
- appendOrConditions(group, value);
172
- continue;
173
- }
174
-
175
- appendFieldCondition(group, key, value);
176
- }
177
-
178
- return group;
179
- }
180
-
181
- function appendAndConditions(group, value) {
182
- if (!Array.isArray(value)) {
183
- return;
184
- }
185
-
186
- for (const condition of value) {
187
- if (!condition || typeof condition !== "object" || Array.isArray(condition)) {
188
- continue;
189
- }
190
-
191
- const sub = parseWhereObject(condition);
192
- if (sub.items.length === 0) {
193
- continue;
194
- }
195
-
196
- if (sub.join === "AND") {
197
- for (const item of sub.items) {
198
- group.items.push(item);
199
- }
200
- continue;
201
- }
202
-
203
- group.items.push(sub);
204
- }
205
- }
206
-
207
- function appendOrConditions(group, value) {
208
- if (!Array.isArray(value)) {
209
- return;
210
- }
211
-
212
- const orGroup = { type: "group", join: "OR", items: [] };
213
- for (const condition of value) {
214
- if (!condition || typeof condition !== "object" || Array.isArray(condition)) {
215
- continue;
216
- }
217
-
218
- const sub = parseWhereObject(condition);
219
- if (sub.items.length > 0) {
220
- orGroup.items.push(sub);
221
- }
222
- }
223
-
224
- if (orGroup.items.length > 0) {
225
- group.items.push(orGroup);
226
- }
227
- }
228
-
229
- function appendFieldCondition(group, key, value) {
230
- if (key.includes("$")) {
231
- const lastDollarIndex = key.lastIndexOf("$");
232
- appendWhereNode(group, buildOperatorNode(key.substring(0, lastDollarIndex), `$${key.substring(lastDollarIndex + 1)}`, value));
233
- return;
234
- }
235
-
236
- if (value && typeof value === "object" && !Array.isArray(value)) {
237
- for (const [operator, operatorValue] of Object.entries(value)) {
238
- appendWhereNode(group, buildOperatorNode(key, operator, operatorValue));
239
- }
240
- return;
241
- }
242
-
243
- appendWhereNode(group, buildOperatorNode(key, "=", value));
244
- }
245
-
246
- function buildArrayOperatorNode(fieldName, operator, value, errorFactory, emptyMessage) {
247
- if (!Array.isArray(value)) {
248
- throw new Error(errorFactory(operator), {
249
- cause: null,
250
- code: "validation"
251
- });
252
- }
253
- if (value.length === 0) {
254
- throw new Error(emptyMessage, {
255
- cause: null,
256
- code: "validation"
257
- });
258
- }
259
-
260
- return { type: "op", field: fieldName, operator: operator, value: value };
261
- }
262
-
263
- function buildRangeOrNullOperatorNode(fieldName, operator, value) {
264
- if (operator === "$between" || operator === "$notBetween") {
265
- if (Array.isArray(value) && value.length === 2) {
266
- return { type: "op", field: fieldName, operator: operator, value: value };
267
- }
268
- return null;
269
- }
270
-
271
- if (value === true) {
272
- return { type: "op", field: fieldName, operator: operator, value: value };
273
- }
274
-
275
- return null;
276
- }
277
-
278
- function buildOperatorNode(fieldName, operator, value) {
279
- switch (operator) {
280
- case "$in":
281
- return buildArrayOperatorNode(fieldName, operator, value, (currentOperator) => `$in 操作符的值必须是数组 (operator: ${currentOperator})`, "$in 操作符的数组不能为空。提示:空数组会导致查询永远不匹配任何记录,这通常不是预期行为。请检查查询条件或移除该字段。");
282
- case "$nin":
283
- case "$notIn":
284
- return buildArrayOperatorNode(fieldName, operator, value, (currentOperator) => `$nin/$notIn 操作符的值必须是数组 (operator: ${currentOperator})`, "$nin/$notIn 操作符的数组不能为空。提示:空数组会导致查询匹配所有记录,这通常不是预期行为。请检查查询条件或移除该字段。");
285
- case "$between":
286
- case "$notBetween":
287
- case "$null":
288
- case "$notNull":
289
- return buildRangeOrNullOperatorNode(fieldName, operator, value);
290
- case "$like":
291
- case "like":
292
- case "$leftLike":
293
- case "leftLike":
294
- case "$rightLike":
295
- case "rightLike":
296
- if (isString(value) && value.trim() === "") {
297
- return null;
298
- }
299
- validateParam(value);
300
- return { type: "op", field: fieldName, operator: operator, value: value };
301
- default:
302
- validateParam(value);
303
- return { type: "op", field: fieldName, operator: operator, value: value };
304
- }
305
- }