befly 2.0.10 → 2.0.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/package.json +2 -2
- package/plugins/db.js +70 -12
- package/utils/curd.js +111 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
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": "b4be4ddfba91544b051e0c0f379c14de46cbdac9"
|
|
55
55
|
}
|
package/plugins/db.js
CHANGED
|
@@ -78,7 +78,7 @@ export default {
|
|
|
78
78
|
return createQueryBuilder();
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// 私有方法:通用数据处理函数 - 自动添加ID
|
|
81
|
+
// 私有方法:通用数据处理函数 - 自动添加ID、时间戳和状态
|
|
82
82
|
async #processDataForInsert(data) {
|
|
83
83
|
const now = Date.now();
|
|
84
84
|
|
|
@@ -87,6 +87,7 @@ export default {
|
|
|
87
87
|
data.map(async (item) => ({
|
|
88
88
|
...item,
|
|
89
89
|
id: await befly.redis.genTimeID(),
|
|
90
|
+
state: item.state !== undefined ? item.state : 0,
|
|
90
91
|
created_at: now,
|
|
91
92
|
updated_at: now
|
|
92
93
|
}))
|
|
@@ -95,12 +96,26 @@ export default {
|
|
|
95
96
|
return {
|
|
96
97
|
...data,
|
|
97
98
|
id: await befly.redis.genTimeID(),
|
|
99
|
+
state: data.state !== undefined ? data.state : 0,
|
|
98
100
|
created_at: now,
|
|
99
101
|
updated_at: now
|
|
100
102
|
};
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
|
|
106
|
+
// 私有方法:添加默认的state过滤条件
|
|
107
|
+
#addDefaultStateFilter(where = {}) {
|
|
108
|
+
// 检查是否已有state相关条件
|
|
109
|
+
const hasStateCondition = Object.keys(where).some((key) => key === 'state' || key.startsWith('state$'));
|
|
110
|
+
|
|
111
|
+
// 如果没有state条件,添加默认过滤
|
|
112
|
+
if (!hasStateCondition) {
|
|
113
|
+
return { ...where, state$ne: 2 };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return where;
|
|
117
|
+
}
|
|
118
|
+
|
|
104
119
|
// 私有方法:执行 SQL(支持传入连接对象)
|
|
105
120
|
async #executeWithConn(sql, params = [], conn = null) {
|
|
106
121
|
if (!sql || typeof sql !== 'string') {
|
|
@@ -147,7 +162,9 @@ export default {
|
|
|
147
162
|
const { where = {}, fields = '*', leftJoins = [] } = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
148
163
|
|
|
149
164
|
try {
|
|
150
|
-
|
|
165
|
+
// 添加默认的state过滤条件
|
|
166
|
+
const filteredWhere = this.#addDefaultStateFilter(where);
|
|
167
|
+
const builder = createQueryBuilder().select(fields).from(table).where(filteredWhere).limit(1);
|
|
151
168
|
|
|
152
169
|
// 添加 LEFT JOIN
|
|
153
170
|
leftJoins.forEach((join) => {
|
|
@@ -179,7 +196,9 @@ export default {
|
|
|
179
196
|
const { where = {}, fields = '*', leftJoins = [], orderBy = [], groupBy = [], having = [], page = 1, pageSize = 10 } = options;
|
|
180
197
|
|
|
181
198
|
try {
|
|
182
|
-
|
|
199
|
+
// 添加默认的state过滤条件
|
|
200
|
+
const filteredWhere = this.#addDefaultStateFilter(where);
|
|
201
|
+
const builder = createQueryBuilder().select(fields).from(table).where(filteredWhere);
|
|
183
202
|
|
|
184
203
|
// 添加 LEFT JOIN
|
|
185
204
|
leftJoins.forEach((join) => {
|
|
@@ -221,7 +240,7 @@ export default {
|
|
|
221
240
|
// 获取总数(如果需要分页)
|
|
222
241
|
let total = 0;
|
|
223
242
|
if (numPage > 0 && numPageSize > 0) {
|
|
224
|
-
const countBuilder = createQueryBuilder().from(table).where(
|
|
243
|
+
const countBuilder = createQueryBuilder().from(table).where(filteredWhere);
|
|
225
244
|
|
|
226
245
|
// 计算总数时也要包含 JOIN
|
|
227
246
|
leftJoins.forEach((join) => {
|
|
@@ -261,7 +280,9 @@ export default {
|
|
|
261
280
|
const { where = {}, fields = '*', leftJoins = [], orderBy = [] } = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
262
281
|
|
|
263
282
|
try {
|
|
264
|
-
|
|
283
|
+
// 添加默认的state过滤条件
|
|
284
|
+
const filteredWhere = this.#addDefaultStateFilter(where);
|
|
285
|
+
const builder = createQueryBuilder().select(fields).from(table).where(filteredWhere);
|
|
265
286
|
|
|
266
287
|
// 添加 LEFT JOIN
|
|
267
288
|
leftJoins.forEach((join) => {
|
|
@@ -310,7 +331,7 @@ export default {
|
|
|
310
331
|
}
|
|
311
332
|
|
|
312
333
|
// 私有方法:更新数据(支持传入连接对象)
|
|
313
|
-
async #
|
|
334
|
+
async #updDataWithConn(table, data, where, conn = null) {
|
|
314
335
|
if (!table || typeof table !== 'string') {
|
|
315
336
|
throw new Error('表名是必需的');
|
|
316
337
|
}
|
|
@@ -337,7 +358,7 @@ export default {
|
|
|
337
358
|
const { sql, params } = builder.toUpdateSql(table, updateData);
|
|
338
359
|
return await this.#executeWithConn(sql, params, conn);
|
|
339
360
|
} catch (error) {
|
|
340
|
-
Logger.error('
|
|
361
|
+
Logger.error('updData 执行失败:', error);
|
|
341
362
|
throw error;
|
|
342
363
|
}
|
|
343
364
|
}
|
|
@@ -362,6 +383,32 @@ export default {
|
|
|
362
383
|
}
|
|
363
384
|
}
|
|
364
385
|
|
|
386
|
+
// 私有方法:软删除数据(支持传入连接对象)
|
|
387
|
+
async #delData2WithConn(table, where, conn = null) {
|
|
388
|
+
if (!table || typeof table !== 'string') {
|
|
389
|
+
throw new Error('表名是必需的');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (!where) {
|
|
393
|
+
throw new Error('软删除操作需要 WHERE 条件');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
// 软删除:将 state 设置为 2,同时更新 updated_at
|
|
398
|
+
const updateData = {
|
|
399
|
+
state: 2,
|
|
400
|
+
updated_at: Date.now()
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
const builder = createQueryBuilder().where(where);
|
|
404
|
+
const { sql, params } = builder.toUpdateSql(table, updateData);
|
|
405
|
+
return await this.#executeWithConn(sql, params, conn);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
Logger.error('delData2 执行失败:', error);
|
|
408
|
+
throw error;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
365
412
|
// 私有方法:批量插入(支持传入连接对象)
|
|
366
413
|
async #insBatchWithConn(table, dataArray, conn = null) {
|
|
367
414
|
if (!table || typeof table !== 'string') {
|
|
@@ -392,7 +439,9 @@ export default {
|
|
|
392
439
|
const { where = {}, leftJoins = [] } = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
393
440
|
|
|
394
441
|
try {
|
|
395
|
-
|
|
442
|
+
// 添加默认的state过滤条件
|
|
443
|
+
const filteredWhere = this.#addDefaultStateFilter(where);
|
|
444
|
+
const builder = createQueryBuilder().from(table).where(filteredWhere);
|
|
396
445
|
|
|
397
446
|
// 添加 LEFT JOIN
|
|
398
447
|
leftJoins.forEach((join) => {
|
|
@@ -441,8 +490,8 @@ export default {
|
|
|
441
490
|
}
|
|
442
491
|
|
|
443
492
|
// 更新数据 - 增强版,自动添加 updated_at,过滤敏感字段
|
|
444
|
-
async
|
|
445
|
-
return await this.#
|
|
493
|
+
async updData(table, data, where) {
|
|
494
|
+
return await this.#updDataWithConn(table, data, where);
|
|
446
495
|
}
|
|
447
496
|
|
|
448
497
|
// 删除数据
|
|
@@ -450,6 +499,11 @@ export default {
|
|
|
450
499
|
return await this.#delDataWithConn(table, where);
|
|
451
500
|
}
|
|
452
501
|
|
|
502
|
+
// 软删除数据 - 将 state 设置为 2
|
|
503
|
+
async delData2(table, where) {
|
|
504
|
+
return await this.#delData2WithConn(table, where);
|
|
505
|
+
}
|
|
506
|
+
|
|
453
507
|
// 批量插入 - 增强版,自动添加 ID 和时间戳
|
|
454
508
|
async insBatch(table, dataArray) {
|
|
455
509
|
return await this.#insBatchWithConn(table, dataArray);
|
|
@@ -498,14 +552,18 @@ export default {
|
|
|
498
552
|
return await this.#insDataWithConn(table, data, conn);
|
|
499
553
|
},
|
|
500
554
|
|
|
501
|
-
|
|
502
|
-
return await this.#
|
|
555
|
+
updData: async (table, data, where) => {
|
|
556
|
+
return await this.#updDataWithConn(table, data, where, conn);
|
|
503
557
|
},
|
|
504
558
|
|
|
505
559
|
delData: async (table, where) => {
|
|
506
560
|
return await this.#delDataWithConn(table, where, conn);
|
|
507
561
|
},
|
|
508
562
|
|
|
563
|
+
delData2: async (table, where) => {
|
|
564
|
+
return await this.#delData2WithConn(table, where, conn);
|
|
565
|
+
},
|
|
566
|
+
|
|
509
567
|
getCount: async (table, options = {}) => {
|
|
510
568
|
return await this.#getCountWithConn(table, options, conn);
|
|
511
569
|
},
|
package/utils/curd.js
CHANGED
|
@@ -20,11 +20,82 @@ export class SqlBuilder {
|
|
|
20
20
|
return this;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// 字段转义方法 - 处理字段名和表名的着重号转义
|
|
24
|
+
_escapeField(field) {
|
|
25
|
+
if (typeof field !== 'string') {
|
|
26
|
+
return field;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 去除前后空格
|
|
30
|
+
field = field.trim();
|
|
31
|
+
|
|
32
|
+
// 如果是 * 或已经有着重号,直接返回
|
|
33
|
+
if (field === '*' || field.startsWith('`') || field.includes('(')) {
|
|
34
|
+
return field;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 处理别名(AS关键字)
|
|
38
|
+
if (field.toUpperCase().includes(' AS ')) {
|
|
39
|
+
const parts = field.split(/\s+AS\s+/i);
|
|
40
|
+
const fieldPart = parts[0].trim();
|
|
41
|
+
const aliasPart = parts[1].trim();
|
|
42
|
+
return `${this._escapeField(fieldPart)} AS ${aliasPart}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 处理表名.字段名的情况(多表联查)
|
|
46
|
+
if (field.includes('.')) {
|
|
47
|
+
const parts = field.split('.');
|
|
48
|
+
return parts
|
|
49
|
+
.map((part) => {
|
|
50
|
+
part = part.trim();
|
|
51
|
+
// 如果是 * 或已经有着重号,不再处理
|
|
52
|
+
if (part === '*' || part.startsWith('`')) {
|
|
53
|
+
return part;
|
|
54
|
+
}
|
|
55
|
+
return `\`${part}\``;
|
|
56
|
+
})
|
|
57
|
+
.join('.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 处理单个字段名
|
|
61
|
+
return `\`${field}\``;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 转义表名
|
|
65
|
+
_escapeTable(table) {
|
|
66
|
+
if (typeof table !== 'string') {
|
|
67
|
+
return table;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
table = table.trim();
|
|
71
|
+
|
|
72
|
+
// 如果已经有着重号,直接返回
|
|
73
|
+
if (table.startsWith('`')) {
|
|
74
|
+
return table;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 处理表别名(表名 + 空格 + 别名)
|
|
78
|
+
if (table.includes(' ')) {
|
|
79
|
+
const parts = table.split(/\s+/);
|
|
80
|
+
if (parts.length === 2) {
|
|
81
|
+
// 只有表名和别名的情况
|
|
82
|
+
const tableName = parts[0].trim();
|
|
83
|
+
const alias = parts[1].trim();
|
|
84
|
+
return `\`${tableName}\` ${alias}`;
|
|
85
|
+
} else {
|
|
86
|
+
// 复杂情况,直接返回
|
|
87
|
+
return table;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return `\`${table}\``;
|
|
92
|
+
}
|
|
93
|
+
|
|
23
94
|
select(fields = '*') {
|
|
24
95
|
if (Array.isArray(fields)) {
|
|
25
|
-
this._select = [...this._select, ...fields];
|
|
96
|
+
this._select = [...this._select, ...fields.map((field) => this._escapeField(field))];
|
|
26
97
|
} else if (typeof fields === 'string') {
|
|
27
|
-
this._select.push(fields);
|
|
98
|
+
this._select.push(this._escapeField(fields));
|
|
28
99
|
} else {
|
|
29
100
|
throw new Error('SELECT fields must be string or array');
|
|
30
101
|
}
|
|
@@ -35,7 +106,7 @@ export class SqlBuilder {
|
|
|
35
106
|
if (typeof table !== 'string' || !table.trim()) {
|
|
36
107
|
throw new Error('FROM table must be a non-empty string');
|
|
37
108
|
}
|
|
38
|
-
this._from = table.trim();
|
|
109
|
+
this._from = this._escapeTable(table.trim());
|
|
39
110
|
return this;
|
|
40
111
|
}
|
|
41
112
|
|
|
@@ -86,6 +157,7 @@ export class SqlBuilder {
|
|
|
86
157
|
// 一级属性格式:age$gt, role$in 等
|
|
87
158
|
const lastDollarIndex = key.lastIndexOf('$');
|
|
88
159
|
const fieldName = key.substring(0, lastDollarIndex);
|
|
160
|
+
const escapedFieldName = this._escapeField(fieldName);
|
|
89
161
|
const operator = '$' + key.substring(lastDollarIndex + 1);
|
|
90
162
|
|
|
91
163
|
this._validateParam(value);
|
|
@@ -93,13 +165,13 @@ export class SqlBuilder {
|
|
|
93
165
|
switch (operator) {
|
|
94
166
|
case '$ne':
|
|
95
167
|
case '$not':
|
|
96
|
-
this._where.push(`${
|
|
168
|
+
this._where.push(`${escapedFieldName} != ?`);
|
|
97
169
|
this._params.push(value);
|
|
98
170
|
break;
|
|
99
171
|
case '$in':
|
|
100
172
|
if (Array.isArray(value) && value.length > 0) {
|
|
101
173
|
const placeholders = value.map(() => '?').join(',');
|
|
102
|
-
this._where.push(`${
|
|
174
|
+
this._where.push(`${escapedFieldName} IN (${placeholders})`);
|
|
103
175
|
this._params.push(...value);
|
|
104
176
|
}
|
|
105
177
|
break;
|
|
@@ -107,64 +179,65 @@ export class SqlBuilder {
|
|
|
107
179
|
case '$notIn':
|
|
108
180
|
if (Array.isArray(value) && value.length > 0) {
|
|
109
181
|
const placeholders = value.map(() => '?').join(',');
|
|
110
|
-
this._where.push(`${
|
|
182
|
+
this._where.push(`${escapedFieldName} NOT IN (${placeholders})`);
|
|
111
183
|
this._params.push(...value);
|
|
112
184
|
}
|
|
113
185
|
break;
|
|
114
186
|
case '$like':
|
|
115
|
-
this._where.push(`${
|
|
187
|
+
this._where.push(`${escapedFieldName} LIKE ?`);
|
|
116
188
|
this._params.push(value);
|
|
117
189
|
break;
|
|
118
190
|
case '$notLike':
|
|
119
|
-
this._where.push(`${
|
|
191
|
+
this._where.push(`${escapedFieldName} NOT LIKE ?`);
|
|
120
192
|
this._params.push(value);
|
|
121
193
|
break;
|
|
122
194
|
case '$gt':
|
|
123
|
-
this._where.push(`${
|
|
195
|
+
this._where.push(`${escapedFieldName} > ?`);
|
|
124
196
|
this._params.push(value);
|
|
125
197
|
break;
|
|
126
198
|
case '$gte':
|
|
127
|
-
this._where.push(`${
|
|
199
|
+
this._where.push(`${escapedFieldName} >= ?`);
|
|
128
200
|
this._params.push(value);
|
|
129
201
|
break;
|
|
130
202
|
case '$lt':
|
|
131
|
-
this._where.push(`${
|
|
203
|
+
this._where.push(`${escapedFieldName} < ?`);
|
|
132
204
|
this._params.push(value);
|
|
133
205
|
break;
|
|
134
206
|
case '$lte':
|
|
135
|
-
this._where.push(`${
|
|
207
|
+
this._where.push(`${escapedFieldName} <= ?`);
|
|
136
208
|
this._params.push(value);
|
|
137
209
|
break;
|
|
138
210
|
case '$between':
|
|
139
211
|
if (Array.isArray(value) && value.length === 2) {
|
|
140
|
-
this._where.push(`${
|
|
212
|
+
this._where.push(`${escapedFieldName} BETWEEN ? AND ?`);
|
|
141
213
|
this._params.push(value[0], value[1]);
|
|
142
214
|
}
|
|
143
215
|
break;
|
|
144
216
|
case '$notBetween':
|
|
145
217
|
if (Array.isArray(value) && value.length === 2) {
|
|
146
|
-
this._where.push(`${
|
|
218
|
+
this._where.push(`${escapedFieldName} NOT BETWEEN ? AND ?`);
|
|
147
219
|
this._params.push(value[0], value[1]);
|
|
148
220
|
}
|
|
149
221
|
break;
|
|
150
222
|
case '$null':
|
|
151
223
|
if (value === true) {
|
|
152
|
-
this._where.push(`${
|
|
224
|
+
this._where.push(`${escapedFieldName} IS NULL`);
|
|
153
225
|
}
|
|
154
226
|
break;
|
|
155
227
|
case '$notNull':
|
|
156
228
|
if (value === true) {
|
|
157
|
-
this._where.push(`${
|
|
229
|
+
this._where.push(`${escapedFieldName} IS NOT NULL`);
|
|
158
230
|
}
|
|
159
231
|
break;
|
|
160
232
|
default:
|
|
161
|
-
this._where.push(`${
|
|
233
|
+
this._where.push(`${escapedFieldName} = ?`);
|
|
162
234
|
this._params.push(value);
|
|
163
235
|
}
|
|
164
236
|
} else {
|
|
165
237
|
// 简单的等于条件
|
|
166
238
|
this._validateParam(value);
|
|
167
|
-
this.
|
|
239
|
+
const escapedKey = this._escapeField(key);
|
|
240
|
+
this._where.push(`${escapedKey} = ?`);
|
|
168
241
|
this._params.push(value);
|
|
169
242
|
}
|
|
170
243
|
});
|
|
@@ -176,7 +249,8 @@ export class SqlBuilder {
|
|
|
176
249
|
this._processWhereConditions(condition);
|
|
177
250
|
} else if (value !== null) {
|
|
178
251
|
this._validateParam(value);
|
|
179
|
-
this.
|
|
252
|
+
const escapedCondition = this._escapeField(condition);
|
|
253
|
+
this._where.push(`${escapedCondition} = ?`);
|
|
180
254
|
this._params.push(value);
|
|
181
255
|
} else if (typeof condition === 'string') {
|
|
182
256
|
this._where.push(condition);
|
|
@@ -188,7 +262,8 @@ export class SqlBuilder {
|
|
|
188
262
|
if (typeof table !== 'string' || typeof on !== 'string') {
|
|
189
263
|
throw new Error('JOIN table and condition must be strings');
|
|
190
264
|
}
|
|
191
|
-
this.
|
|
265
|
+
const escapedTable = this._escapeTable(table);
|
|
266
|
+
this._joins.push(`LEFT JOIN ${escapedTable} ON ${on}`);
|
|
192
267
|
return this;
|
|
193
268
|
}
|
|
194
269
|
|
|
@@ -214,7 +289,8 @@ export class SqlBuilder {
|
|
|
214
289
|
throw new Error('ORDER BY direction must be ASC or DESC');
|
|
215
290
|
}
|
|
216
291
|
|
|
217
|
-
this.
|
|
292
|
+
const escapedField = this._escapeField(cleanField);
|
|
293
|
+
this._orderBy.push(`${escapedField} ${cleanDir}`);
|
|
218
294
|
});
|
|
219
295
|
|
|
220
296
|
return this;
|
|
@@ -222,9 +298,10 @@ export class SqlBuilder {
|
|
|
222
298
|
|
|
223
299
|
groupBy(field) {
|
|
224
300
|
if (Array.isArray(field)) {
|
|
225
|
-
|
|
301
|
+
const escapedFields = field.filter((f) => typeof f === 'string').map((f) => this._escapeField(f));
|
|
302
|
+
this._groupBy = [...this._groupBy, ...escapedFields];
|
|
226
303
|
} else if (typeof field === 'string') {
|
|
227
|
-
this._groupBy.push(field);
|
|
304
|
+
this._groupBy.push(this._escapeField(field));
|
|
228
305
|
}
|
|
229
306
|
return this;
|
|
230
307
|
}
|
|
@@ -309,6 +386,8 @@ export class SqlBuilder {
|
|
|
309
386
|
throw new Error('Data is required for INSERT');
|
|
310
387
|
}
|
|
311
388
|
|
|
389
|
+
const escapedTable = this._escapeTable(table);
|
|
390
|
+
|
|
312
391
|
if (Array.isArray(data)) {
|
|
313
392
|
if (data.length === 0) {
|
|
314
393
|
throw new Error('Insert data cannot be empty');
|
|
@@ -319,10 +398,11 @@ export class SqlBuilder {
|
|
|
319
398
|
throw new Error('Insert data must have at least one field');
|
|
320
399
|
}
|
|
321
400
|
|
|
401
|
+
const escapedFields = fields.map((field) => this._escapeField(field));
|
|
322
402
|
const placeholders = fields.map(() => '?').join(', ');
|
|
323
403
|
const values = data.map(() => `(${placeholders})`).join(', ');
|
|
324
404
|
|
|
325
|
-
const sql = `INSERT INTO ${
|
|
405
|
+
const sql = `INSERT INTO ${escapedTable} (${escapedFields.join(', ')}) VALUES ${values}`;
|
|
326
406
|
const params = data.flatMap((row) => fields.map((field) => row[field]));
|
|
327
407
|
|
|
328
408
|
return { sql, params };
|
|
@@ -332,8 +412,9 @@ export class SqlBuilder {
|
|
|
332
412
|
throw new Error('Insert data must have at least one field');
|
|
333
413
|
}
|
|
334
414
|
|
|
415
|
+
const escapedFields = fields.map((field) => this._escapeField(field));
|
|
335
416
|
const placeholders = fields.map(() => '?').join(', ');
|
|
336
|
-
const sql = `INSERT INTO ${
|
|
417
|
+
const sql = `INSERT INTO ${escapedTable} (${escapedFields.join(', ')}) VALUES (${placeholders})`;
|
|
337
418
|
const params = fields.map((field) => data[field]);
|
|
338
419
|
|
|
339
420
|
return { sql, params };
|
|
@@ -355,10 +436,11 @@ export class SqlBuilder {
|
|
|
355
436
|
throw new Error('Update data must have at least one field');
|
|
356
437
|
}
|
|
357
438
|
|
|
358
|
-
const
|
|
439
|
+
const escapedTable = this._escapeTable(table);
|
|
440
|
+
const setFields = fields.map((field) => `${this._escapeField(field)} = ?`);
|
|
359
441
|
const params = [...Object.values(data), ...this._params];
|
|
360
442
|
|
|
361
|
-
let sql = `UPDATE ${
|
|
443
|
+
let sql = `UPDATE ${escapedTable} SET ${setFields.join(', ')}`;
|
|
362
444
|
|
|
363
445
|
if (this._where.length > 0) {
|
|
364
446
|
sql += ' WHERE ' + this._where.join(' AND ');
|
|
@@ -375,7 +457,8 @@ export class SqlBuilder {
|
|
|
375
457
|
throw new Error('Table name is required for DELETE');
|
|
376
458
|
}
|
|
377
459
|
|
|
378
|
-
|
|
460
|
+
const escapedTable = this._escapeTable(table);
|
|
461
|
+
let sql = `DELETE FROM ${escapedTable}`;
|
|
379
462
|
|
|
380
463
|
if (this._where.length > 0) {
|
|
381
464
|
sql += ' WHERE ' + this._where.join(' AND ');
|