wok-server 0.6.0 → 0.7.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.
- package/README.en.md +1 -1
- package/dist/mysql/config.js +1 -1
- package/dist/mysql/manager/base.js +39 -0
- package/dist/mysql/manager/ops/criteria.js +25 -0
- package/dist/mysql/manager/ops/delete.js +4 -10
- package/dist/mysql/manager/ops/find.js +10 -30
- package/dist/mysql/manager/ops/index.js +2 -0
- package/dist/mysql/manager/ops/insert.js +39 -13
- package/dist/mysql/manager/ops/order-by.js +28 -0
- package/dist/mysql/manager/ops/paginate.js +26 -1
- package/dist/mysql/manager/ops/update.js +43 -37
- package/dist/mysql/manager/ops/upsert.js +178 -0
- package/dist/mysql/manager/ops/utils.js +4 -0
- package/documentation/en/mysql.md +135 -5
- package/documentation/zh-cn/mysql.md +146 -17
- package/package.json +2 -1
- package/skills/wok-server-code-navigation/SKILL.md +153 -0
- package/skills/wok-server-mysql/SKILL.md +76 -3
- package/src/mysql/config.ts +2 -2
- package/src/mysql/manager/base.ts +51 -4
- package/src/mysql/manager/ops/criteria.ts +34 -0
- package/src/mysql/manager/ops/delete.ts +5 -10
- package/src/mysql/manager/ops/find.ts +12 -29
- package/src/mysql/manager/ops/index.ts +2 -0
- package/src/mysql/manager/ops/insert.ts +53 -15
- package/src/mysql/manager/ops/order-by.ts +58 -0
- package/src/mysql/manager/ops/paginate.ts +42 -2
- package/src/mysql/manager/ops/update.ts +66 -42
- package/src/mysql/manager/ops/upsert.ts +224 -0
- package/src/mysql/manager/ops/utils.ts +4 -0
- package/types/mysql/config.d.ts +1 -1
- package/types/mysql/manager/base.d.ts +35 -4
- package/types/mysql/manager/ops/criteria.d.ts +10 -0
- package/types/mysql/manager/ops/delete.d.ts +2 -1
- package/types/mysql/manager/ops/find.d.ts +3 -2
- package/types/mysql/manager/ops/index.d.ts +2 -0
- package/types/mysql/manager/ops/insert.d.ts +16 -2
- package/types/mysql/manager/ops/order-by.d.ts +38 -0
- package/types/mysql/manager/ops/paginate.d.ts +18 -1
- package/types/mysql/manager/ops/update.d.ts +26 -3
- package/types/mysql/manager/ops/upsert.d.ts +36 -0
package/README.en.md
CHANGED
|
@@ -44,7 +44,7 @@ startWebServer({
|
|
|
44
44
|
|
|
45
45
|
Visit `http://localhost:8080` to see the output.
|
|
46
46
|
|
|
47
|
-
For more configuration via environment variables, see the [full documentation](https://gitee.com/tai/wok-server/blob/master/documentation/
|
|
47
|
+
For more configuration via environment variables, see the [full documentation](https://gitee.com/tai/wok-server/blob/master/documentation/en/index.md).
|
|
48
48
|
|
|
49
49
|
### Install AI Skills
|
|
50
50
|
|
package/dist/mysql/config.js
CHANGED
|
@@ -44,7 +44,7 @@ exports.configValidation = {
|
|
|
44
44
|
maxIdle: [(0, validation_1.notNull)(), (0, validation_1.min)(1), (0, validation_1.max)(999)],
|
|
45
45
|
idleTimeout: [(0, validation_1.notNull)(), (0, validation_1.min)(1000), (0, validation_1.max)(60000)],
|
|
46
46
|
slowSqlWarn: [(0, validation_1.notNull)()],
|
|
47
|
-
slowSqlMs: [(0, validation_1.notNull)(), (0, validation_1.min)(
|
|
47
|
+
slowSqlMs: [(0, validation_1.notNull)(), (0, validation_1.min)(0), (0, validation_1.max)(3600000)],
|
|
48
48
|
transactionTimeout: [(0, validation_1.notNull)(), (0, validation_1.min)(0), (0, validation_1.max)(60000)],
|
|
49
49
|
transactionStrict: [(0, validation_1.notNull)()],
|
|
50
50
|
maxOpsInStrictTx: [(0, validation_1.notNull)(), (0, validation_1.min)(1)]
|
|
@@ -147,6 +147,37 @@ class BaseMysqlManager {
|
|
|
147
147
|
insertMany(table, list) {
|
|
148
148
|
return this.queryWithConnection(conn => (0, ops_1.insertMany)(this.opts.config, conn, table, list));
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Upsert 单条数据
|
|
152
|
+
* 如果主键冲突则更新,否则插入
|
|
153
|
+
* @param table 表信息
|
|
154
|
+
* @param data 数据
|
|
155
|
+
* @returns
|
|
156
|
+
*/
|
|
157
|
+
upsert(table, data) {
|
|
158
|
+
return this.queryWithConnection(conn => (0, ops_1.upsert)(this.opts.config, conn, table, data));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Upsert 多条数据
|
|
162
|
+
* 如果主键冲突则更新,否则插入
|
|
163
|
+
* @param table 表
|
|
164
|
+
* @param list 要插入的数据列表
|
|
165
|
+
* @returns 影响的行数
|
|
166
|
+
*/
|
|
167
|
+
upsertMany(table, list) {
|
|
168
|
+
return this.queryWithConnection(conn => (0, ops_1.upsertMany)(this.opts.config, conn, table, list));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Upsert 单条数据(支持自定义更新器)
|
|
172
|
+
* 如果主键冲突则按自定义逻辑更新,否则插入
|
|
173
|
+
* @param table 表信息
|
|
174
|
+
* @param data 插入的数据
|
|
175
|
+
* @param updater 冲突时的更新器
|
|
176
|
+
* @returns
|
|
177
|
+
*/
|
|
178
|
+
upsertWithUpdater(table, data, updater) {
|
|
179
|
+
return this.queryWithConnection(conn => (0, ops_1.upsertWithUpdater)(this.opts.config, conn, table, data, updater));
|
|
180
|
+
}
|
|
150
181
|
/**
|
|
151
182
|
* 更新
|
|
152
183
|
* @param table 表信息
|
|
@@ -217,6 +248,14 @@ class BaseMysqlManager {
|
|
|
217
248
|
paginate(opts) {
|
|
218
249
|
return this.queryWithConnection(conn => (0, ops_1.paginate)(this.opts.config, conn, opts));
|
|
219
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* 指定字段分页查询
|
|
253
|
+
* @param opts
|
|
254
|
+
* @returns
|
|
255
|
+
*/
|
|
256
|
+
paginateSelect(opts) {
|
|
257
|
+
return this.queryWithConnection(conn => (0, ops_1.paginateSelect)(this.opts.config, conn, opts));
|
|
258
|
+
}
|
|
220
259
|
/**
|
|
221
260
|
* 自定义查询,指定 sql 、参数和返回值类型
|
|
222
261
|
* @param sql 预编译 sql ,参数使用 ”?“(英文问号) 占位,注意查询的字段名称会与返回值类型的字段映射,如果 sql 中的字段名称很特殊(比如纯数字等),需要设置别名,避免产生映射错误
|
|
@@ -164,6 +164,19 @@ class MysqlCriteria {
|
|
|
164
164
|
this.criteria.push({ type: 'isNotNull', key: field });
|
|
165
165
|
return this;
|
|
166
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* 自定义表达式查询
|
|
169
|
+
* 如 .expr('?? * ? > ?', ['balance', 2, 50])
|
|
170
|
+
* 如 .expr('MATCH(??, ??) AGAINST(? IN BOOLEAN MODE)', ['title', 'content', keyword])
|
|
171
|
+
* 如 .expr('VECTOR_DISTANCE(??, STRING_TO_VECTOR(?)) < ?', ['content_vec', embedding, threshold])
|
|
172
|
+
* @param sql SQL 片段,使用 ?? 引用列名,? 引用参数值
|
|
173
|
+
* @param values 参数值数组,按 SQL 中占位符顺序传入
|
|
174
|
+
* @returns
|
|
175
|
+
*/
|
|
176
|
+
expr(sql, values) {
|
|
177
|
+
this.criteria.push({ type: 'expr', exprSql: sql, exprValues: values || [] });
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
167
180
|
/**
|
|
168
181
|
* 判定是否空,未设置条件.
|
|
169
182
|
* @returns
|
|
@@ -176,6 +189,12 @@ class MysqlCriteria {
|
|
|
176
189
|
*/
|
|
177
190
|
check() {
|
|
178
191
|
for (const criterion of this.criteria) {
|
|
192
|
+
if (criterion.type === 'expr') {
|
|
193
|
+
if (!criterion.exprSql) {
|
|
194
|
+
throw new exception_1.MysqlException('expr clause exprSql cannot be empty');
|
|
195
|
+
}
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
179
198
|
if (criterion.type === 'or' || criterion.type === 'and') {
|
|
180
199
|
if (!criterion.criteria) {
|
|
181
200
|
throw new exception_1.MysqlException(`${criterion.type} clause cannot be empty`);
|
|
@@ -303,6 +322,12 @@ class MysqlCriteria {
|
|
|
303
322
|
continue;
|
|
304
323
|
}
|
|
305
324
|
}
|
|
325
|
+
// 自定义表达式
|
|
326
|
+
else if (criterion.type === 'expr' && criterion.exprSql) {
|
|
327
|
+
sqlFragments.push(`and ${criterion.exprSql} `);
|
|
328
|
+
values.push(...(criterion.exprValues || []));
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
306
331
|
}
|
|
307
332
|
if (!sqlFragments.length) {
|
|
308
333
|
throw new exception_1.MysqlException('No valid query criteria have been set.');
|
|
@@ -4,6 +4,7 @@ exports.deleteMany = exports.deleteById = void 0;
|
|
|
4
4
|
const exception_1 = require("../../exception");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const criteria_1 = require("./criteria");
|
|
7
|
+
const order_by_1 = require("./order-by");
|
|
7
8
|
/**
|
|
8
9
|
* 按 id 删除.
|
|
9
10
|
*
|
|
@@ -44,16 +45,9 @@ async function deleteMany(config, connection, opts) {
|
|
|
44
45
|
}
|
|
45
46
|
// 排序
|
|
46
47
|
if (opts.orderBy && opts.orderBy.length) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
sql += ` order by ?? ${sort} `;
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
sql += ` , ?? ${sort} `;
|
|
54
|
-
}
|
|
55
|
-
values.push(field);
|
|
56
|
-
});
|
|
48
|
+
const ob = (0, order_by_1.buildOrderBy)(opts.orderBy);
|
|
49
|
+
sql += ob.sql;
|
|
50
|
+
values.push(...ob.values);
|
|
57
51
|
}
|
|
58
52
|
// 数量限制
|
|
59
53
|
if (opts.limit) {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.findFirst = exports.findByIdIn = exports.findSelect = exports.find = exports.findAll = exports.findById = void 0;
|
|
4
4
|
const criteria_1 = require("./criteria");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
|
+
const order_by_1 = require("./order-by");
|
|
6
7
|
/**
|
|
7
8
|
* 按 id 查询
|
|
8
9
|
* @param connection
|
|
@@ -51,16 +52,9 @@ async function find(config, conn, opts) {
|
|
|
51
52
|
}
|
|
52
53
|
// 排序
|
|
53
54
|
if (opts.orderBy && opts.orderBy.length) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sql += ` order by ?? ${sort} `;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
sql += ` , ?? ${sort} `;
|
|
61
|
-
}
|
|
62
|
-
values.push(field);
|
|
63
|
-
});
|
|
55
|
+
const ob = (0, order_by_1.buildOrderBy)(opts.orderBy);
|
|
56
|
+
sql += ob.sql;
|
|
57
|
+
values.push(...ob.values);
|
|
64
58
|
}
|
|
65
59
|
// 数量限制
|
|
66
60
|
if (opts.limit) {
|
|
@@ -90,16 +84,9 @@ async function findSelect(config, conn, opts) {
|
|
|
90
84
|
}
|
|
91
85
|
// 排序
|
|
92
86
|
if (opts.orderBy && opts.orderBy.length) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
sql += ` order by ?? ${sort} `;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
sql += ` , ?? ${sort} `;
|
|
100
|
-
}
|
|
101
|
-
values.push(field);
|
|
102
|
-
});
|
|
87
|
+
const ob = (0, order_by_1.buildOrderBy)(opts.orderBy);
|
|
88
|
+
sql += ob.sql;
|
|
89
|
+
values.push(...ob.values);
|
|
103
90
|
}
|
|
104
91
|
// 数量限制
|
|
105
92
|
if (opts.limit) {
|
|
@@ -150,16 +137,9 @@ orderBy) {
|
|
|
150
137
|
}
|
|
151
138
|
// 排序
|
|
152
139
|
if (orderBy && orderBy.length) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
sql += ` order by ?? ${sort} `;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
sql += ` , ?? ${sort} `;
|
|
160
|
-
}
|
|
161
|
-
values.push(field);
|
|
162
|
-
});
|
|
140
|
+
const ob = (0, order_by_1.buildOrderBy)(orderBy);
|
|
141
|
+
sql += ob.sql;
|
|
142
|
+
values.push(...ob.values);
|
|
163
143
|
}
|
|
164
144
|
sql += ' limit 1';
|
|
165
145
|
const res = await (0, utils_1.promiseQuery)(config, conn, sql, values);
|
|
@@ -9,6 +9,8 @@ tslib_1.__exportStar(require("./exist"), exports);
|
|
|
9
9
|
tslib_1.__exportStar(require("./find"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./insert"), exports);
|
|
11
11
|
tslib_1.__exportStar(require("./modify"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./order-by"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./upsert"), exports);
|
|
12
14
|
tslib_1.__exportStar(require("./paginate"), exports);
|
|
13
15
|
tslib_1.__exportStar(require("./query"), exports);
|
|
14
16
|
tslib_1.__exportStar(require("./update"), exports);
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.insertMany = exports.insert = void 0;
|
|
3
|
+
exports.insertMany = exports.insert = exports.processInsertValue = void 0;
|
|
4
4
|
const exception_1 = require("../../exception");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const utils_2 = require("./utils");
|
|
7
|
+
/**
|
|
8
|
+
* 处理 insert value,支持表达式
|
|
9
|
+
* @returns { frag: SQL 片段, values: 参数值数组 }
|
|
10
|
+
*/
|
|
11
|
+
function processInsertValue(value) {
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
if (value[0] === 'now') {
|
|
14
|
+
return { frag: 'NOW()', values: [] };
|
|
15
|
+
}
|
|
16
|
+
if (value[0] === 'set') {
|
|
17
|
+
return { frag: '?', values: [(0, utils_2.processColumnValue)(value[1])] };
|
|
18
|
+
}
|
|
19
|
+
if (value[0] === 'expr') {
|
|
20
|
+
return { frag: value[1], values: value[2] || [] };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { frag: '?', values: [(0, utils_2.processColumnValue)(value)] };
|
|
24
|
+
}
|
|
25
|
+
exports.processInsertValue = processInsertValue;
|
|
7
26
|
/**
|
|
8
27
|
* 为表插入数据
|
|
9
28
|
* @param connection
|
|
@@ -12,7 +31,6 @@ const utils_2 = require("./utils");
|
|
|
12
31
|
* @returns
|
|
13
32
|
*/
|
|
14
33
|
async function insert(config, connection, table, data) {
|
|
15
|
-
// 插入后的新数据
|
|
16
34
|
// 列信息,使用 set 防止 columns 中重复配置 id 和更新创建时间列
|
|
17
35
|
let columnsSet = new Set();
|
|
18
36
|
// 判定下 id ,如果有值,才在 insert 语句中出现 id 列,否则不出现
|
|
@@ -31,15 +49,16 @@ async function insert(config, connection, table, data) {
|
|
|
31
49
|
columnsSet.add(table.updatedDate.column);
|
|
32
50
|
}
|
|
33
51
|
const columns = Array.from(columnsSet);
|
|
34
|
-
// 构建 sql
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
// 构建 sql,逐列处理以支持表达式
|
|
53
|
+
const fragList = [];
|
|
54
|
+
const insertValues = [];
|
|
55
|
+
for (const col of columns) {
|
|
56
|
+
const { frag, values: vs } = processInsertValue(data[col]);
|
|
57
|
+
fragList.push(frag);
|
|
58
|
+
insertValues.push(...vs);
|
|
59
|
+
}
|
|
60
|
+
const sql = `insert into ??(${columns.map(() => '??').join(',')}) values(${fragList.join(',')})`;
|
|
61
|
+
const values = [table.tableName, ...columns, ...insertValues];
|
|
43
62
|
const res = await (0, utils_1.promiseQuery)(config, connection, sql, values);
|
|
44
63
|
const packet = res;
|
|
45
64
|
if (packet.affectedRows !== 1) {
|
|
@@ -87,14 +106,21 @@ async function insertMany(config, connection, table, list) {
|
|
|
87
106
|
if (idx > 0) {
|
|
88
107
|
sql += ',';
|
|
89
108
|
}
|
|
90
|
-
|
|
109
|
+
const fragList = [];
|
|
110
|
+
const rowValues = [];
|
|
91
111
|
if (table.createdDate) {
|
|
92
112
|
data[table.createdDate.column] = createdData;
|
|
93
113
|
}
|
|
94
114
|
if (table.updatedDate) {
|
|
95
115
|
data[table.updatedDate.column] = updatedDate;
|
|
96
116
|
}
|
|
97
|
-
|
|
117
|
+
for (const col of columns) {
|
|
118
|
+
const { frag, values: vs } = processInsertValue(data[col]);
|
|
119
|
+
fragList.push(frag);
|
|
120
|
+
rowValues.push(...vs);
|
|
121
|
+
}
|
|
122
|
+
sql += `(${fragList.join(',')})`;
|
|
123
|
+
values.push(...rowValues);
|
|
98
124
|
});
|
|
99
125
|
const res = await (0, utils_1.promiseQuery)(config, connection, sql, values);
|
|
100
126
|
const rsh = res;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildOrderBy = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 构建 ORDER BY 子句.
|
|
6
|
+
*
|
|
7
|
+
* @param orderBy 排序规则
|
|
8
|
+
* @returns { sql: SQL 片段, values: 参数值数组 }
|
|
9
|
+
*/
|
|
10
|
+
function buildOrderBy(orderBy) {
|
|
11
|
+
const fragments = [];
|
|
12
|
+
const values = [];
|
|
13
|
+
orderBy.forEach((item, idx) => {
|
|
14
|
+
const prefix = idx === 0 ? ' order by ' : ' , ';
|
|
15
|
+
if (item.length === 4 && item[0] === 'expr') {
|
|
16
|
+
const [, exprSql, exprValues, sort] = item;
|
|
17
|
+
fragments.push(`${prefix}${exprSql} ${sort}`);
|
|
18
|
+
values.push(...exprValues);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const [field, sort] = item;
|
|
22
|
+
fragments.push(`${prefix}?? ${sort}`);
|
|
23
|
+
values.push(field);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return { sql: fragments.join(''), values };
|
|
27
|
+
}
|
|
28
|
+
exports.buildOrderBy = buildOrderBy;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.paginate = void 0;
|
|
3
|
+
exports.paginateSelect = exports.paginate = void 0;
|
|
4
4
|
const count_1 = require("./count");
|
|
5
5
|
const find_1 = require("./find");
|
|
6
6
|
async function paginate(config, conn, opts) {
|
|
@@ -21,3 +21,28 @@ async function paginate(config, conn, opts) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
exports.paginate = paginate;
|
|
24
|
+
/**
|
|
25
|
+
* 指定字段分页查询
|
|
26
|
+
* @param config
|
|
27
|
+
* @param conn
|
|
28
|
+
* @param opts
|
|
29
|
+
*/
|
|
30
|
+
async function paginateSelect(config, conn, opts) {
|
|
31
|
+
const pn = opts.pn && opts.pn >= 1 ? opts.pn : 1;
|
|
32
|
+
const limit = opts.pz && opts.pz >= 1 && opts.pz <= 1000 ? opts.pz : 20;
|
|
33
|
+
const offset = (pn - 1) * limit;
|
|
34
|
+
const list = await (0, find_1.findSelect)(config, conn, {
|
|
35
|
+
table: opts.table,
|
|
36
|
+
criteria: opts.criteria,
|
|
37
|
+
offset,
|
|
38
|
+
limit,
|
|
39
|
+
orderBy: opts.orderBy,
|
|
40
|
+
select: opts.select
|
|
41
|
+
});
|
|
42
|
+
const total = await (0, count_1.count)(config, conn, opts.table, opts.criteria);
|
|
43
|
+
return {
|
|
44
|
+
total,
|
|
45
|
+
list
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
exports.paginateSelect = paginateSelect;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.updateMany = exports.updateOne = exports.partialUpdate = exports.update = void 0;
|
|
3
|
+
exports.updateMany = exports.updateOne = exports.partialUpdate = exports.updatorToSql = exports.update = void 0;
|
|
4
4
|
const exception_1 = require("../../exception");
|
|
5
5
|
const criteria_1 = require("./criteria");
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const utils_2 = require("./utils");
|
|
8
|
+
const order_by_1 = require("./order-by");
|
|
8
9
|
/**
|
|
9
10
|
* 更新
|
|
10
11
|
* @param config
|
|
@@ -47,44 +48,47 @@ exports.update = update;
|
|
|
47
48
|
* 转换更新器
|
|
48
49
|
* @param table
|
|
49
50
|
* @param updater
|
|
51
|
+
* @param autoUpdateTime 是否自动添加更新时间
|
|
50
52
|
* @returns
|
|
51
53
|
*/
|
|
52
54
|
function updatorToSql(table, updater) {
|
|
53
55
|
const values = [];
|
|
54
|
-
// 更新操作
|
|
55
56
|
const updateFragList = [];
|
|
56
|
-
// 更新时间
|
|
57
|
-
if (table.updatedDate) {
|
|
58
|
-
const updatedDate = table.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
59
|
-
updateFragList.push(' ?? = ?');
|
|
60
|
-
values.push(table.updatedDate.column, updatedDate);
|
|
61
|
-
}
|
|
62
57
|
for (const column in updater) {
|
|
63
|
-
// 过滤掉id
|
|
58
|
+
// 过滤掉 id
|
|
64
59
|
if (column === table.id) {
|
|
65
60
|
continue;
|
|
66
61
|
}
|
|
62
|
+
// 过滤掉 createdDate / updatedDate(自动处理)
|
|
63
|
+
if ((table.createdDate && column === table.createdDate.column)
|
|
64
|
+
|| (table.updatedDate && column === table.updatedDate.column)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
67
|
const val = updater[column];
|
|
68
|
-
// undefined
|
|
68
|
+
// undefined 表示不参与更新
|
|
69
69
|
if (val === undefined) {
|
|
70
70
|
continue;
|
|
71
71
|
}
|
|
72
|
-
//
|
|
72
|
+
// 0.7.0 版本开始,null 和 undefined 一样被忽略更新
|
|
73
|
+
// 如需设置字段为 NULL,请使用 ['setNull']
|
|
73
74
|
if (val === null) {
|
|
74
|
-
updateFragList.push(' ?? = NULL ');
|
|
75
|
-
values.push(column);
|
|
76
75
|
continue;
|
|
77
76
|
}
|
|
78
77
|
if (Array.isArray(val)) {
|
|
79
|
-
// set null
|
|
80
78
|
if (val[0] === 'setNull') {
|
|
81
79
|
updateFragList.push(' ?? = NULL ');
|
|
82
80
|
values.push(column);
|
|
83
81
|
continue;
|
|
84
82
|
}
|
|
85
83
|
if (val[0] === 'inc') {
|
|
84
|
+
const incBy = val.length === 1 ? 1 : val[1];
|
|
86
85
|
updateFragList.push(' ?? = ?? + ? ');
|
|
87
|
-
values.push(column, column,
|
|
86
|
+
values.push(column, column, incBy);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (val[0] === 'now') {
|
|
90
|
+
updateFragList.push(' ?? = NOW() ');
|
|
91
|
+
values.push(column);
|
|
88
92
|
continue;
|
|
89
93
|
}
|
|
90
94
|
if (val[0] === 'set') {
|
|
@@ -92,12 +96,33 @@ function updatorToSql(table, updater) {
|
|
|
92
96
|
values.push(column, (0, utils_2.processColumnValue)(val[1]));
|
|
93
97
|
continue;
|
|
94
98
|
}
|
|
99
|
+
if (val[0] === 'concat') {
|
|
100
|
+
updateFragList.push(' ?? = CONCAT(IFNULL(??, \'\'), ?) ');
|
|
101
|
+
values.push(column, column, val[1]);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (val[0] === 'expr') {
|
|
105
|
+
updateFragList.push(' ?? = ' + val[1] + ' ');
|
|
106
|
+
values.push(column, ...(val[2] || []));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
updateFragList.push(' ?? = ? ');
|
|
97
111
|
values.push(column, (0, utils_2.processColumnValue)(val));
|
|
98
112
|
}
|
|
113
|
+
// 如果没有有效更新字段,抛出异常
|
|
114
|
+
if (updateFragList.length === 0) {
|
|
115
|
+
throw new exception_1.MysqlException(`No effective fields to update (null values are ignored since v0.7.0), table: ${table.tableName}, updater: ${JSON.stringify(updater)}`);
|
|
116
|
+
}
|
|
117
|
+
// 自动添加更新时间
|
|
118
|
+
if (table.updatedDate) {
|
|
119
|
+
const updatedDate = table.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
120
|
+
updateFragList.push(' ?? = ?');
|
|
121
|
+
values.push(table.updatedDate.column, updatedDate);
|
|
122
|
+
}
|
|
99
123
|
return { sql: updateFragList.join(','), values };
|
|
100
124
|
}
|
|
125
|
+
exports.updatorToSql = updatorToSql;
|
|
101
126
|
/**
|
|
102
127
|
* 部分更新
|
|
103
128
|
* @param connection
|
|
@@ -113,9 +138,6 @@ async function partialUpdate(config, connection, table, data) {
|
|
|
113
138
|
if (typeof id !== 'string' && typeof id !== 'number') {
|
|
114
139
|
throw new exception_1.MysqlException('Primary key can only be of string or number type');
|
|
115
140
|
}
|
|
116
|
-
if (Object.keys(data).length < 2) {
|
|
117
|
-
throw new exception_1.MysqlException(`Can't do a partial update, data must contain at least one column outside of the primary key,table: ${table.tableName},column:${JSON.stringify(data)}`);
|
|
118
|
-
}
|
|
119
141
|
const fieldNames = Object.keys(data);
|
|
120
142
|
for (const name of fieldNames) {
|
|
121
143
|
if (name !== table.id && !table.columns.some(col => col === name)) {
|
|
@@ -126,9 +148,6 @@ async function partialUpdate(config, connection, table, data) {
|
|
|
126
148
|
const values = [table.tableName];
|
|
127
149
|
// 更新操作
|
|
128
150
|
const convertRes = updatorToSql(table, data);
|
|
129
|
-
if (!convertRes.sql) {
|
|
130
|
-
throw new exception_1.MysqlException('No fields were specified to be updated!');
|
|
131
|
-
}
|
|
132
151
|
values.push(...convertRes.values);
|
|
133
152
|
sql += ` set ${convertRes.sql} where ?? = ?`;
|
|
134
153
|
values.push(table.id, id);
|
|
@@ -155,9 +174,6 @@ async function updateOne(config, connection, table, query, updater) {
|
|
|
155
174
|
values.push(table.tableName);
|
|
156
175
|
// 更新操作
|
|
157
176
|
const convertRes = updatorToSql(table, updater);
|
|
158
|
-
if (!convertRes.sql) {
|
|
159
|
-
throw new exception_1.MysqlException('No fields were specified to be updated!');
|
|
160
|
-
}
|
|
161
177
|
sql += ` set ${convertRes.sql} `;
|
|
162
178
|
values.push(...convertRes.values);
|
|
163
179
|
sql += ` where ${mysqlQuery.sql} limit 1`;
|
|
@@ -185,25 +201,15 @@ async function updateMany(config, connection, opts) {
|
|
|
185
201
|
values.push(opts.table.tableName);
|
|
186
202
|
// 更新操作
|
|
187
203
|
const convertRes = updatorToSql(opts.table, opts.updater);
|
|
188
|
-
if (!convertRes.sql) {
|
|
189
|
-
throw new exception_1.MysqlException('No fields were specified to be updated!');
|
|
190
|
-
}
|
|
191
204
|
sql += ` set ${convertRes.sql} `;
|
|
192
205
|
values.push(...convertRes.values);
|
|
193
206
|
sql += ` where ${mysqlQuery.sql} `;
|
|
194
207
|
values.push(...mysqlQuery.values);
|
|
195
208
|
// 排序
|
|
196
209
|
if (opts.orderBy && opts.orderBy.length) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
sql += ` order by ?? ${sort} `;
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
sql += ` , ?? ${sort} `;
|
|
204
|
-
}
|
|
205
|
-
values.push(field);
|
|
206
|
-
});
|
|
210
|
+
const ob = (0, order_by_1.buildOrderBy)(opts.orderBy);
|
|
211
|
+
sql += ob.sql;
|
|
212
|
+
values.push(...ob.values);
|
|
207
213
|
}
|
|
208
214
|
// 数量限制
|
|
209
215
|
if (opts.limit) {
|