wok-server 0.5.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 +61 -0
- package/README.md +44 -29
- package/dist/cache/cache.js +98 -98
- package/dist/cache/config.js +19 -19
- package/dist/cache/index.js +27 -27
- package/dist/cache/purge-task.js +46 -46
- package/dist/cache/stat.js +47 -47
- package/dist/config/convert.js +36 -36
- package/dist/config/exception.js +14 -14
- package/dist/config/index.js +81 -81
- package/dist/http-client/index.js +136 -136
- package/dist/i18n/ar.js +17 -17
- package/dist/i18n/de.js +17 -17
- package/dist/i18n/en-us.js +17 -17
- package/dist/i18n/es.js +17 -17
- package/dist/i18n/fr.js +17 -17
- package/dist/i18n/i18n.js +231 -231
- package/dist/i18n/index.js +52 -52
- package/dist/i18n/ja.js +17 -17
- package/dist/i18n/ko.js +17 -17
- package/dist/i18n/msg.js +2 -2
- package/dist/i18n/pt.js +17 -17
- package/dist/i18n/ru.js +17 -17
- package/dist/i18n/tag.js +18 -18
- package/dist/i18n/zh-HK.js +17 -17
- package/dist/i18n/zh-TW.js +17 -17
- package/dist/i18n/zh-cn.js +17 -17
- package/dist/index.js +14 -14
- package/dist/lock/index.js +114 -114
- package/dist/log/config.js +35 -35
- package/dist/log/date.js +21 -21
- package/dist/log/file.js +198 -198
- package/dist/log/index.js +135 -135
- package/dist/log/level.js +33 -33
- package/dist/log/log.js +56 -56
- package/dist/log/store.js +19 -19
- package/dist/mongodb/collection.js +2 -2
- package/dist/mongodb/config.js +34 -34
- package/dist/mongodb/doc.js +2 -2
- package/dist/mongodb/exception.js +14 -14
- package/dist/mongodb/index.js +58 -58
- package/dist/mongodb/manager/base.js +563 -563
- package/dist/mongodb/manager/index.js +63 -63
- package/dist/mongodb/manager/tx-strict.js +84 -84
- package/dist/mongodb/manager/tx.js +30 -30
- package/dist/mongodb/migration.js +52 -52
- package/dist/mvc/access-log.js +33 -33
- package/dist/mvc/config.js +27 -27
- package/dist/mvc/exchange.js +113 -113
- package/dist/mvc/handler/index.js +7 -6
- package/dist/mvc/handler/json.js +65 -65
- package/dist/mvc/handler/restful.js +35 -35
- package/dist/mvc/handler/sse.js +65 -0
- package/dist/mvc/handler/upload.js +31 -31
- package/dist/mvc/index.js +50 -50
- package/dist/mvc/interceptor.js +2 -2
- package/dist/mvc/query.js +43 -43
- package/dist/mvc/render/file.js +132 -132
- package/dist/mvc/render/html/html.js +90 -90
- package/dist/mvc/render/html/index.js +18 -18
- package/dist/mvc/render/html/style.js +2 -2
- package/dist/mvc/render/index.js +7 -7
- package/dist/mvc/render/json.js +26 -26
- package/dist/mvc/render/text.js +16 -16
- package/dist/mvc/router.js +2 -2
- package/dist/mvc/server.js +272 -272
- package/dist/mvc/static/header.js +67 -67
- package/dist/mvc/static/index.js +6 -6
- package/dist/mvc/static/mime-type.js +84 -84
- package/dist/mvc/static/server-cache-config.js +66 -66
- package/dist/mvc/static/server-cache.js +133 -133
- package/dist/mvc/static/static-handler.js +372 -372
- package/dist/mysql/config.js +51 -51
- package/dist/mysql/exception.js +14 -14
- package/dist/mysql/index.js +87 -87
- package/dist/mysql/manager/base.js +278 -239
- package/dist/mysql/manager/index.js +107 -107
- package/dist/mysql/manager/ops/count.js +20 -20
- package/dist/mysql/manager/ops/criteria.js +381 -356
- package/dist/mysql/manager/ops/delete.js +59 -65
- package/dist/mysql/manager/ops/exist.js +26 -26
- package/dist/mysql/manager/ops/find.js +149 -169
- package/dist/mysql/manager/ops/index.js +16 -14
- package/dist/mysql/manager/ops/insert.js +132 -106
- package/dist/mysql/manager/ops/modify.js +10 -10
- package/dist/mysql/manager/ops/order-by.js +28 -0
- package/dist/mysql/manager/ops/paginate.js +48 -23
- package/dist/mysql/manager/ops/query.js +9 -9
- package/dist/mysql/manager/ops/update.js +222 -216
- package/dist/mysql/manager/ops/upsert.js +178 -0
- package/dist/mysql/manager/ops/utils.js +28 -24
- package/dist/mysql/manager/tx-strict.js +103 -103
- package/dist/mysql/manager/tx.js +30 -30
- package/dist/mysql/manager/utils.js +56 -56
- package/dist/mysql/migration.js +136 -136
- package/dist/mysql/table-info.js +8 -8
- package/dist/task/daily.js +59 -59
- package/dist/task/fixed-delay.js +38 -38
- package/dist/task/fixed-rate.js +42 -42
- package/dist/task/index.js +9 -9
- package/dist/task/task.js +56 -56
- package/dist/validation/exception.js +36 -36
- package/dist/validation/index.js +40 -40
- package/dist/validation/validator/array.js +34 -34
- package/dist/validation/validator/enum.js +28 -28
- package/dist/validation/validator/index.js +14 -14
- package/dist/validation/validator/length.js +40 -40
- package/dist/validation/validator/max-length.js +35 -35
- package/dist/validation/validator/max.js +29 -29
- package/dist/validation/validator/min-length.js +33 -33
- package/dist/validation/validator/min.js +29 -29
- package/dist/validation/validator/not-blank.js +33 -33
- package/dist/validation/validator/not-null.js +21 -21
- package/dist/validation/validator/plain-obj.js +32 -32
- package/dist/validation/validator/regexp.js +34 -34
- package/documentation/en/cache.md +56 -0
- package/documentation/en/config.md +96 -0
- package/documentation/en/engineering.md +256 -0
- package/documentation/en/http-client.md +32 -0
- package/documentation/en/i18n.md +143 -0
- package/documentation/en/index.md +24 -0
- package/documentation/en/lock.md +51 -0
- package/documentation/en/log.md +109 -0
- package/documentation/en/mongodb.md +256 -0
- package/documentation/en/mvc.md +688 -0
- package/documentation/en/mysql.md +682 -0
- package/documentation/en/task.md +45 -0
- package/documentation/en/test.md +56 -0
- package/documentation/en/validate.md +130 -0
- package/documentation/zh-cn/mvc.md +66 -24
- package/documentation/zh-cn/mysql.md +146 -17
- package/package.json +4 -1
- package/skills/wok-server-api-rules/SKILL.md +350 -0
- package/skills/wok-server-cache/SKILL.md +216 -0
- package/skills/wok-server-code-navigation/SKILL.md +153 -0
- package/skills/wok-server-config/SKILL.md +200 -0
- package/skills/wok-server-getting-started/SKILL.md +123 -0
- package/skills/wok-server-getting-started/references/engineering.md +169 -0
- package/skills/wok-server-http-client/SKILL.md +164 -0
- package/skills/wok-server-i18n/SKILL.md +214 -0
- package/skills/wok-server-lock/SKILL.md +144 -0
- package/skills/wok-server-log/SKILL.md +218 -0
- package/skills/wok-server-mongodb/SKILL.md +235 -0
- package/skills/wok-server-mvc/SKILL.md +251 -0
- package/skills/wok-server-mvc/references/respond-html.md +157 -0
- package/skills/wok-server-mvc/references/sse.md +121 -0
- package/skills/wok-server-mvc/references/static-files.md +47 -0
- package/skills/wok-server-mvc/references/upload.md +62 -0
- package/skills/wok-server-mvc/references/websocket.md +30 -0
- package/skills/wok-server-mysql/SKILL.md +388 -0
- package/skills/wok-server-mysql/references/multi-datasource.md +76 -0
- package/skills/wok-server-mysql/references/version-control.md +22 -0
- package/skills/wok-server-task/SKILL.md +158 -0
- package/skills/wok-server-validate/SKILL.md +167 -0
- package/src/cache/cache.ts +118 -0
- package/src/cache/config.ts +53 -0
- package/src/cache/index.ts +27 -0
- package/src/cache/purge-task.ts +53 -0
- package/src/cache/stat.ts +47 -0
- package/src/config/convert.ts +27 -0
- package/src/config/exception.ts +8 -0
- package/src/config/index.ts +92 -0
- package/src/http-client/index.ts +202 -0
- package/src/i18n/ar.ts +16 -0
- package/src/i18n/de.ts +16 -0
- package/src/i18n/en-us.ts +16 -0
- package/src/i18n/es.ts +16 -0
- package/src/i18n/fr.ts +16 -0
- package/src/i18n/i18n.ts +230 -0
- package/src/i18n/index.ts +50 -0
- package/src/i18n/ja.ts +16 -0
- package/src/i18n/ko.ts +16 -0
- package/src/i18n/msg.ts +50 -0
- package/src/i18n/pt.ts +16 -0
- package/src/i18n/ru.ts +16 -0
- package/src/i18n/tag.ts +18 -0
- package/src/i18n/zh-HK.ts +16 -0
- package/src/i18n/zh-TW.ts +16 -0
- package/src/i18n/zh-cn.ts +16 -0
- package/src/index.ts +11 -0
- package/src/lock/index.ts +164 -0
- package/src/log/config.ts +71 -0
- package/src/log/date.ts +19 -0
- package/src/log/file.ts +215 -0
- package/src/log/index.ts +136 -0
- package/src/log/level.ts +29 -0
- package/src/log/log.ts +77 -0
- package/src/log/store.ts +31 -0
- package/src/mongodb/collection.ts +25 -0
- package/src/mongodb/config.ts +69 -0
- package/src/mongodb/doc.ts +12 -0
- package/src/mongodb/exception.ts +8 -0
- package/src/mongodb/index.ts +71 -0
- package/src/mongodb/manager/base.ts +674 -0
- package/src/mongodb/manager/index.ts +80 -0
- package/src/mongodb/manager/tx-strict.ts +153 -0
- package/src/mongodb/manager/tx.ts +34 -0
- package/src/mongodb/migration.ts +66 -0
- package/src/mvc/access-log.ts +33 -0
- package/src/mvc/config.ts +70 -0
- package/src/mvc/exchange.ts +126 -0
- package/src/mvc/handler/index.ts +4 -0
- package/src/mvc/handler/json.ts +96 -0
- package/src/mvc/handler/restful.ts +39 -0
- package/src/mvc/handler/sse.ts +90 -0
- package/src/mvc/handler/upload.ts +54 -0
- package/src/mvc/index.ts +48 -0
- package/src/mvc/interceptor.ts +12 -0
- package/src/mvc/query.ts +36 -0
- package/src/mvc/render/file.ts +148 -0
- package/src/mvc/render/html/html.ts +187 -0
- package/src/mvc/render/html/index.ts +16 -0
- package/src/mvc/render/html/style.ts +1201 -0
- package/src/mvc/render/index.ts +4 -0
- package/src/mvc/render/json.ts +24 -0
- package/src/mvc/render/text.ts +14 -0
- package/src/mvc/router.ts +13 -0
- package/src/mvc/server.ts +315 -0
- package/src/mvc/static/header.ts +86 -0
- package/src/mvc/static/index.ts +3 -0
- package/src/mvc/static/mime-type.ts +81 -0
- package/src/mvc/static/server-cache-config.ts +92 -0
- package/src/mvc/static/server-cache.ts +171 -0
- package/src/mvc/static/static-handler.ts +445 -0
- package/src/mysql/config.ts +130 -0
- package/src/mysql/exception.ts +8 -0
- package/src/mysql/index.ts +88 -0
- package/src/mysql/manager/base.ts +332 -0
- package/src/mysql/manager/index.ts +112 -0
- package/src/mysql/manager/ops/count.ts +30 -0
- package/src/mysql/manager/ops/criteria.ts +446 -0
- package/src/mysql/manager/ops/delete.ts +91 -0
- package/src/mysql/manager/ops/exist.ts +41 -0
- package/src/mysql/manager/ops/find.ts +209 -0
- package/src/mysql/manager/ops/index.ts +13 -0
- package/src/mysql/manager/ops/insert.ts +158 -0
- package/src/mysql/manager/ops/modify.ts +14 -0
- package/src/mysql/manager/ops/order-by.ts +58 -0
- package/src/mysql/manager/ops/paginate.ts +100 -0
- package/src/mysql/manager/ops/query.ts +13 -0
- package/src/mysql/manager/ops/update.ts +318 -0
- package/src/mysql/manager/ops/upsert.ts +224 -0
- package/src/mysql/manager/ops/utils.ts +24 -0
- package/src/mysql/manager/tx-strict.ts +138 -0
- package/src/mysql/manager/tx.ts +31 -0
- package/src/mysql/manager/utils.ts +75 -0
- package/src/mysql/migration.ts +149 -0
- package/src/mysql/table-info.ts +41 -0
- package/src/task/daily.ts +70 -0
- package/src/task/fixed-delay.ts +45 -0
- package/src/task/fixed-rate.ts +49 -0
- package/src/task/index.ts +4 -0
- package/src/task/task.ts +70 -0
- package/src/validation/exception.ts +27 -0
- package/src/validation/index.ts +61 -0
- package/src/validation/validator/array.ts +32 -0
- package/src/validation/validator/enum.ts +25 -0
- package/src/validation/validator/index.ts +11 -0
- package/src/validation/validator/length.ts +42 -0
- package/src/validation/validator/max-length.ts +33 -0
- package/src/validation/validator/max.ts +26 -0
- package/src/validation/validator/min-length.ts +31 -0
- package/src/validation/validator/min.ts +26 -0
- package/src/validation/validator/not-blank.ts +31 -0
- package/src/validation/validator/not-null.ts +19 -0
- package/src/validation/validator/plain-obj.ts +30 -0
- package/src/validation/validator/regexp.ts +32 -0
- package/types/cache/cache.d.ts +52 -52
- package/types/cache/config.d.ts +32 -32
- package/types/cache/index.d.ts +2 -2
- package/types/cache/purge-task.d.ts +11 -11
- package/types/cache/stat.d.ts +26 -26
- package/types/config/convert.d.ts +6 -6
- package/types/config/exception.d.ts +7 -7
- package/types/config/index.d.ts +25 -25
- package/types/http-client/index.d.ts +71 -71
- package/types/i18n/ar.d.ts +2 -2
- package/types/i18n/de.d.ts +2 -2
- package/types/i18n/en-us.d.ts +2 -2
- package/types/i18n/es.d.ts +2 -2
- package/types/i18n/fr.d.ts +2 -2
- package/types/i18n/i18n.d.ts +102 -102
- package/types/i18n/index.d.ts +9 -9
- package/types/i18n/ja.d.ts +2 -2
- package/types/i18n/ko.d.ts +2 -2
- package/types/i18n/msg.d.ts +50 -50
- package/types/i18n/pt.d.ts +2 -2
- package/types/i18n/ru.d.ts +2 -2
- package/types/i18n/tag.d.ts +11 -11
- package/types/i18n/zh-HK.d.ts +2 -2
- package/types/i18n/zh-TW.d.ts +2 -2
- package/types/i18n/zh-cn.d.ts +2 -2
- package/types/index.d.ts +11 -11
- package/types/lock/index.d.ts +64 -64
- package/types/log/config.d.ts +35 -35
- package/types/log/date.d.ts +2 -2
- package/types/log/file.d.ts +13 -13
- package/types/log/index.d.ts +53 -53
- package/types/log/level.d.ts +14 -14
- package/types/log/log.d.ts +40 -40
- package/types/log/store.d.ts +19 -19
- package/types/mongodb/collection.d.ts +25 -25
- package/types/mongodb/config.d.ts +45 -45
- package/types/mongodb/doc.d.ts +11 -11
- package/types/mongodb/exception.d.ts +7 -7
- package/types/mongodb/index.d.ts +29 -29
- package/types/mongodb/manager/base.d.ts +188 -188
- package/types/mongodb/manager/index.d.ts +38 -38
- package/types/mongodb/manager/tx-strict.d.ts +41 -41
- package/types/mongodb/manager/tx.d.ts +21 -21
- package/types/mongodb/migration.d.ts +12 -12
- package/types/mvc/access-log.d.ts +7 -7
- package/types/mvc/config.d.ts +42 -42
- package/types/mvc/exchange.d.ts +72 -72
- package/types/mvc/handler/index.d.ts +4 -3
- package/types/mvc/handler/json.d.ts +44 -44
- package/types/mvc/handler/restful.d.ts +11 -11
- package/types/mvc/handler/sse.d.ts +34 -0
- package/types/mvc/handler/upload.d.ts +36 -36
- package/types/mvc/index.d.ts +22 -22
- package/types/mvc/interceptor.d.ts +11 -11
- package/types/mvc/query.d.ts +13 -13
- package/types/mvc/render/file.d.ts +10 -10
- package/types/mvc/render/html/html.d.ts +98 -98
- package/types/mvc/render/html/index.d.ts +11 -11
- package/types/mvc/render/html/style.d.ts +1201 -1201
- package/types/mvc/render/index.d.ts +4 -4
- package/types/mvc/render/json.d.ts +17 -17
- package/types/mvc/render/text.d.ts +10 -10
- package/types/mvc/router.d.ts +11 -11
- package/types/mvc/server.d.ts +90 -90
- package/types/mvc/static/header.d.ts +27 -27
- package/types/mvc/static/index.d.ts +3 -3
- package/types/mvc/static/mime-type.d.ts +2 -2
- package/types/mvc/static/server-cache-config.d.ts +30 -30
- package/types/mvc/static/server-cache.d.ts +76 -76
- package/types/mvc/static/static-handler.d.ts +77 -77
- package/types/mysql/config.d.ts +90 -90
- package/types/mysql/exception.d.ts +7 -7
- package/types/mysql/index.d.ts +16 -16
- package/types/mysql/manager/base.d.ts +196 -165
- package/types/mysql/manager/index.d.ts +36 -36
- package/types/mysql/manager/ops/count.d.ts +13 -13
- package/types/mysql/manager/ops/criteria.d.ts +144 -134
- package/types/mysql/manager/ops/delete.d.ts +47 -46
- package/types/mysql/manager/ops/exist.d.ts +6 -6
- package/types/mysql/manager/ops/find.d.ts +87 -86
- package/types/mysql/manager/ops/index.d.ts +12 -10
- package/types/mysql/manager/ops/insert.d.ts +32 -18
- package/types/mysql/manager/ops/modify.d.ts +3 -3
- package/types/mysql/manager/ops/order-by.d.ts +38 -0
- package/types/mysql/manager/ops/paginate.d.ts +53 -36
- package/types/mysql/manager/ops/query.d.ts +3 -3
- package/types/mysql/manager/ops/update.d.ts +99 -76
- package/types/mysql/manager/ops/upsert.d.ts +36 -0
- package/types/mysql/manager/ops/utils.d.ts +5 -5
- package/types/mysql/manager/tx-strict.d.ts +36 -36
- package/types/mysql/manager/tx.d.ts +15 -15
- package/types/mysql/manager/utils.d.ts +17 -17
- package/types/mysql/migration.d.ts +8 -8
- package/types/mysql/table-info.d.ts +36 -36
- package/types/task/daily.d.ts +16 -16
- package/types/task/fixed-delay.d.ts +9 -9
- package/types/task/fixed-rate.d.ts +9 -9
- package/types/task/index.d.ts +4 -4
- package/types/task/task.d.ts +34 -34
- package/types/validation/exception.d.ts +38 -38
- package/types/validation/index.d.ts +32 -32
- package/types/validation/validator/array.d.ts +5 -5
- package/types/validation/validator/enum.d.ts +8 -8
- package/types/validation/validator/index.d.ts +11 -11
- package/types/validation/validator/length.d.ts +10 -10
- package/types/validation/validator/max-length.d.ts +8 -8
- package/types/validation/validator/max.d.ts +7 -7
- package/types/validation/validator/min-length.d.ts +6 -6
- package/types/validation/validator/min.d.ts +7 -7
- package/types/validation/validator/not-blank.d.ts +7 -7
- package/types/validation/validator/not-null.d.ts +6 -6
- package/types/validation/validator/plain-obj.d.ts +7 -7
- package/types/validation/validator/regexp.d.ts +8 -8
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { PoolConnection, ResultSetHeader } from 'mysql2'
|
|
2
|
+
import { MysqlException } from '../../exception'
|
|
3
|
+
import { Table } from '../../table-info'
|
|
4
|
+
import { MixCriteria, buildQuery } from './criteria'
|
|
5
|
+
import { promiseQuery } from '../utils'
|
|
6
|
+
import { MysqlConfig } from '../../config'
|
|
7
|
+
import { processColumnValue } from './utils'
|
|
8
|
+
import { OrderBy, buildOrderBy } from './order-by'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 更新
|
|
12
|
+
* @param config
|
|
13
|
+
* @param connection
|
|
14
|
+
* @param mapping
|
|
15
|
+
* @param data
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export async function update<T>(
|
|
19
|
+
config: MysqlConfig,
|
|
20
|
+
connection: PoolConnection,
|
|
21
|
+
table: Table<T>,
|
|
22
|
+
data: T
|
|
23
|
+
): Promise<T> {
|
|
24
|
+
// 列信息
|
|
25
|
+
let columns: Array<keyof T> = [...table.columns]
|
|
26
|
+
// 创建时间不更新
|
|
27
|
+
if (table.createdDate) {
|
|
28
|
+
const { column } = table.createdDate
|
|
29
|
+
columns = columns.filter(col => col !== column)
|
|
30
|
+
}
|
|
31
|
+
if (table.updatedDate) {
|
|
32
|
+
const updatedDate = table.updatedDate.type === 'date' ? new Date() : new Date().getTime()
|
|
33
|
+
data[table.updatedDate.column] = updatedDate as any
|
|
34
|
+
columns.push(table.updatedDate.column)
|
|
35
|
+
}
|
|
36
|
+
// 构建 sql
|
|
37
|
+
const sql = `update ?? set ${columns.map(() => ' ?? = ? ').join(',')} where ?? = ?`
|
|
38
|
+
// 值
|
|
39
|
+
const values: any[] = [
|
|
40
|
+
table.tableName,
|
|
41
|
+
...columns.flatMap(col => [col, processColumnValue(data[col])]),
|
|
42
|
+
table.id,
|
|
43
|
+
data[table.id]
|
|
44
|
+
]
|
|
45
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
46
|
+
const packet = res as ResultSetHeader
|
|
47
|
+
if (packet.affectedRows !== 1) {
|
|
48
|
+
throw new MysqlException(
|
|
49
|
+
`Failed to update record, possibly due to non-existent record,table:${
|
|
50
|
+
table.tableName
|
|
51
|
+
},primary key: ${data[table.id]}`
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
return data
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 更新器
|
|
58
|
+
*/
|
|
59
|
+
export type Updater<T> = Partial<{
|
|
60
|
+
// 普通的更新赋值
|
|
61
|
+
[key in keyof T]:
|
|
62
|
+
| T[key]
|
|
63
|
+
// undefined 表示不参与更新,作用是方便编写一些特殊的逻辑,比如特定情况下不更新
|
|
64
|
+
| undefined
|
|
65
|
+
// 将字段置空,置空是不能使用 null 类型的,必须使用元组 ['setNull']
|
|
66
|
+
| ['setNull']
|
|
67
|
+
// 字段自增 +1,等价于 ['inc', 1]
|
|
68
|
+
| ['inc']
|
|
69
|
+
// 字段自增指定值
|
|
70
|
+
| ['inc', number]
|
|
71
|
+
// NOW() 快捷方式,等价于 ['expr', 'NOW()', []]
|
|
72
|
+
| ['now']
|
|
73
|
+
/**
|
|
74
|
+
* 设置一个字段的值,和直接赋值是一样的,作用是解决一些特殊的情况的冲突
|
|
75
|
+
* 比如将 json 字段的值设置为 ['setNull'] ,这就会被认为是要置空,
|
|
76
|
+
* 使用 ['set',['setNull']] 就可以解决这个问题
|
|
77
|
+
*/
|
|
78
|
+
| ['set', T[key]]
|
|
79
|
+
/**
|
|
80
|
+
* 字符串追加,如 ['concat', '/suffix'] 生成 col = CONCAT(IFNULL(col, ''), '/suffix')
|
|
81
|
+
* NULL 安全:字段为 NULL 时视作空字符串
|
|
82
|
+
*/
|
|
83
|
+
| ['concat', string]
|
|
84
|
+
/**
|
|
85
|
+
* 使用自定义表达式
|
|
86
|
+
* 如 ['expr', '?? * ?', ['score', 2]] 生成 score = score * 2
|
|
87
|
+
* 无参数时可省略第三个参数,如 ['expr', 'NOW()'] 等同 ['expr', 'NOW()', []]
|
|
88
|
+
*/
|
|
89
|
+
| ['expr', string, any[]]
|
|
90
|
+
| ['expr', string]
|
|
91
|
+
}>
|
|
92
|
+
/**
|
|
93
|
+
* 转换更新器
|
|
94
|
+
* @param table
|
|
95
|
+
* @param updater
|
|
96
|
+
* @param autoUpdateTime 是否自动添加更新时间
|
|
97
|
+
* @returns
|
|
98
|
+
*/
|
|
99
|
+
export function updatorToSql<T>(table: Table<T>, updater: Updater<T>): { sql: string; values: any[] } {
|
|
100
|
+
const values: any[] = []
|
|
101
|
+
const updateFragList: string[] = []
|
|
102
|
+
|
|
103
|
+
for (const column in updater) {
|
|
104
|
+
// 过滤掉 id
|
|
105
|
+
if (column === table.id) {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
// 过滤掉 createdDate / updatedDate(自动处理)
|
|
109
|
+
if ((table.createdDate && column === table.createdDate.column)
|
|
110
|
+
|| (table.updatedDate && column === table.updatedDate.column)) {
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
113
|
+
const val = updater[column]
|
|
114
|
+
// undefined 表示不参与更新
|
|
115
|
+
if (val === undefined) {
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
// 0.7.0 版本开始,null 和 undefined 一样被忽略更新
|
|
119
|
+
// 如需设置字段为 NULL,请使用 ['setNull']
|
|
120
|
+
if (val === null) {
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(val)) {
|
|
124
|
+
if (val[0] === 'setNull') {
|
|
125
|
+
updateFragList.push(' ?? = NULL ')
|
|
126
|
+
values.push(column)
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
if (val[0] === 'inc') {
|
|
130
|
+
const incBy = val.length === 1 ? 1 : val[1]
|
|
131
|
+
updateFragList.push(' ?? = ?? + ? ')
|
|
132
|
+
values.push(column, column, incBy)
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
if (val[0] === 'now') {
|
|
136
|
+
updateFragList.push(' ?? = NOW() ')
|
|
137
|
+
values.push(column)
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
if (val[0] === 'set') {
|
|
141
|
+
updateFragList.push(' ?? = ? ')
|
|
142
|
+
values.push(column, processColumnValue(val[1]))
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
if (val[0] === 'concat') {
|
|
146
|
+
updateFragList.push(' ?? = CONCAT(IFNULL(??, \'\'), ?) ')
|
|
147
|
+
values.push(column, column, val[1])
|
|
148
|
+
continue
|
|
149
|
+
}
|
|
150
|
+
if (val[0] === 'expr') {
|
|
151
|
+
updateFragList.push(' ?? = ' + val[1] + ' ')
|
|
152
|
+
values.push(column, ...(val[2] || []))
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
updateFragList.push(' ?? = ? ')
|
|
157
|
+
values.push(column, processColumnValue(val))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 如果没有有效更新字段,抛出异常
|
|
161
|
+
if (updateFragList.length === 0) {
|
|
162
|
+
throw new MysqlException(
|
|
163
|
+
`No effective fields to update (null values are ignored since v0.7.0), table: ${table.tableName}, updater: ${JSON.stringify(updater)}`
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 自动添加更新时间
|
|
168
|
+
if (table.updatedDate) {
|
|
169
|
+
const updatedDate = table.updatedDate.type === 'date' ? new Date() : new Date().getTime()
|
|
170
|
+
updateFragList.push(' ?? = ?')
|
|
171
|
+
values.push(table.updatedDate.column, updatedDate)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { sql: updateFragList.join(','), values }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 部分更新
|
|
179
|
+
* @param connection
|
|
180
|
+
* @param mapping
|
|
181
|
+
* @param type
|
|
182
|
+
* @param data
|
|
183
|
+
*/
|
|
184
|
+
export async function partialUpdate<T>(
|
|
185
|
+
config: MysqlConfig,
|
|
186
|
+
connection: PoolConnection,
|
|
187
|
+
table: Table<T>,
|
|
188
|
+
data: Updater<T>
|
|
189
|
+
): Promise<boolean> {
|
|
190
|
+
if (!data[table.id]) {
|
|
191
|
+
throw new MysqlException(
|
|
192
|
+
`Can't do a partial update, the data to be updated does not contain a primary key,table: ${
|
|
193
|
+
table.tableName
|
|
194
|
+
},column:${JSON.stringify(data)}`
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
const id = data[table.id]
|
|
198
|
+
if (typeof id !== 'string' && typeof id !== 'number') {
|
|
199
|
+
throw new MysqlException('Primary key can only be of string or number type')
|
|
200
|
+
}
|
|
201
|
+
const fieldNames = Object.keys(data)
|
|
202
|
+
for (const name of fieldNames) {
|
|
203
|
+
if (name !== table.id && !table.columns.some(col => col === name)) {
|
|
204
|
+
throw new MysqlException(
|
|
205
|
+
`Can't do a partial update,there are unconfigured columns in the data,table: ${table.tableName},unconfigured column:${name}`
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
let sql = ` update ?? `
|
|
210
|
+
const values: any[] = [table.tableName]
|
|
211
|
+
// 更新操作
|
|
212
|
+
const convertRes = updatorToSql(table, data)
|
|
213
|
+
values.push(...convertRes.values)
|
|
214
|
+
sql += ` set ${convertRes.sql} where ?? = ?`
|
|
215
|
+
values.push(table.id, id)
|
|
216
|
+
|
|
217
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
218
|
+
const packet = res as ResultSetHeader
|
|
219
|
+
return packet.affectedRows === 1
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 更新指定的一条记录
|
|
223
|
+
* @param config
|
|
224
|
+
* @param connection
|
|
225
|
+
* @param table
|
|
226
|
+
* @param query
|
|
227
|
+
* @param data
|
|
228
|
+
*/
|
|
229
|
+
export async function updateOne<T>(
|
|
230
|
+
config: MysqlConfig,
|
|
231
|
+
connection: PoolConnection,
|
|
232
|
+
table: Table<T>,
|
|
233
|
+
query: MixCriteria<T>,
|
|
234
|
+
updater: Updater<T>
|
|
235
|
+
): Promise<boolean> {
|
|
236
|
+
const values: any[] = []
|
|
237
|
+
const mysqlQuery = buildQuery(query)
|
|
238
|
+
if (!mysqlQuery) {
|
|
239
|
+
throw new MysqlException('No valid criteria specified.')
|
|
240
|
+
}
|
|
241
|
+
let sql = ` update ?? `
|
|
242
|
+
values.push(table.tableName)
|
|
243
|
+
// 更新操作
|
|
244
|
+
const convertRes = updatorToSql(table, updater)
|
|
245
|
+
sql += ` set ${convertRes.sql} `
|
|
246
|
+
values.push(...convertRes.values)
|
|
247
|
+
sql += ` where ${mysqlQuery.sql} limit 1`
|
|
248
|
+
values.push(...mysqlQuery.values)
|
|
249
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
250
|
+
const packet = res as ResultSetHeader
|
|
251
|
+
return packet.affectedRows === 1
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 更新选项
|
|
255
|
+
*/
|
|
256
|
+
export interface UpdateOpts<T> {
|
|
257
|
+
/**
|
|
258
|
+
* 表
|
|
259
|
+
*/
|
|
260
|
+
table: Table<T>
|
|
261
|
+
/**
|
|
262
|
+
* 查询条件
|
|
263
|
+
*/
|
|
264
|
+
query: MixCriteria<T>
|
|
265
|
+
/**
|
|
266
|
+
* 限制数量
|
|
267
|
+
*/
|
|
268
|
+
limit?: number
|
|
269
|
+
/**
|
|
270
|
+
* 排序规则,按先后顺序放入,每个规则是一个元组,第一个元素是字段名称,第二个元素是顺序
|
|
271
|
+
*/
|
|
272
|
+
orderBy?: OrderBy<T>
|
|
273
|
+
/**
|
|
274
|
+
* 更新设置
|
|
275
|
+
*/
|
|
276
|
+
updater: Updater<T>
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* 更新所有匹配条件的记录
|
|
281
|
+
* @param config
|
|
282
|
+
* @param connection 连接
|
|
283
|
+
* @param table 表
|
|
284
|
+
* @param query 查询条件
|
|
285
|
+
* @param updater 更新操作,支持置空和递增(需要使用元组)
|
|
286
|
+
*/
|
|
287
|
+
export async function updateMany<T>(
|
|
288
|
+
config: MysqlConfig,
|
|
289
|
+
connection: PoolConnection,
|
|
290
|
+
opts: UpdateOpts<T>
|
|
291
|
+
): Promise<number> {
|
|
292
|
+
const values: any[] = []
|
|
293
|
+
const mysqlQuery = buildQuery(opts.query)
|
|
294
|
+
if (!mysqlQuery) {
|
|
295
|
+
throw new MysqlException('No valid criteria specified.')
|
|
296
|
+
}
|
|
297
|
+
let sql = ` update ?? `
|
|
298
|
+
values.push(opts.table.tableName)
|
|
299
|
+
// 更新操作
|
|
300
|
+
const convertRes = updatorToSql(opts.table, opts.updater)
|
|
301
|
+
sql += ` set ${convertRes.sql} `
|
|
302
|
+
values.push(...convertRes.values)
|
|
303
|
+
sql += ` where ${mysqlQuery.sql} `
|
|
304
|
+
values.push(...mysqlQuery.values)
|
|
305
|
+
// 排序
|
|
306
|
+
if (opts.orderBy && opts.orderBy.length) {
|
|
307
|
+
const ob = buildOrderBy(opts.orderBy)
|
|
308
|
+
sql += ob.sql
|
|
309
|
+
values.push(...ob.values)
|
|
310
|
+
}
|
|
311
|
+
// 数量限制
|
|
312
|
+
if (opts.limit) {
|
|
313
|
+
sql += ` limit ${opts.limit} `
|
|
314
|
+
}
|
|
315
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
316
|
+
const packet = res as ResultSetHeader
|
|
317
|
+
return packet.affectedRows
|
|
318
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { PoolConnection, ResultSetHeader } from 'mysql2'
|
|
2
|
+
import { MysqlConfig } from '../../config'
|
|
3
|
+
import { Table } from '../../table-info'
|
|
4
|
+
import { promiseQuery } from '../utils'
|
|
5
|
+
import { InsertValue, processInsertValue } from './insert'
|
|
6
|
+
import { Updater, updatorToSql } from './update'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Upsert 单条数据
|
|
10
|
+
* 如果主键冲突则更新,否则插入
|
|
11
|
+
* @param config
|
|
12
|
+
* @param connection
|
|
13
|
+
* @param table
|
|
14
|
+
* @param data
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
export async function upsert<T>(
|
|
18
|
+
config: MysqlConfig,
|
|
19
|
+
connection: PoolConnection,
|
|
20
|
+
table: Table<T>,
|
|
21
|
+
data: InsertValue<T>
|
|
22
|
+
): Promise<T> {
|
|
23
|
+
let columnsSet: Set<keyof T> = new Set()
|
|
24
|
+
if (data[table.id]) {
|
|
25
|
+
columnsSet.add(table.id)
|
|
26
|
+
}
|
|
27
|
+
table.columns.forEach(col => columnsSet.add(col))
|
|
28
|
+
|
|
29
|
+
const now = new Date()
|
|
30
|
+
const nowTimestamp = now.getTime()
|
|
31
|
+
|
|
32
|
+
if (table.createdDate) {
|
|
33
|
+
const createdData = table.createdDate.type === 'date' ? now : nowTimestamp
|
|
34
|
+
data[table.createdDate.column] = createdData as any
|
|
35
|
+
columnsSet.add(table.createdDate.column)
|
|
36
|
+
}
|
|
37
|
+
if (table.updatedDate) {
|
|
38
|
+
const updatedDate = table.updatedDate.type === 'date' ? now : nowTimestamp
|
|
39
|
+
data[table.updatedDate.column] = updatedDate as any
|
|
40
|
+
columnsSet.add(table.updatedDate.column)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const columns = Array.from(columnsSet)
|
|
44
|
+
|
|
45
|
+
// 构建 insert values
|
|
46
|
+
const fragList: string[] = []
|
|
47
|
+
const insertValues: any[] = []
|
|
48
|
+
for (const col of columns) {
|
|
49
|
+
const { frag, values: vs } = processInsertValue(data[col])
|
|
50
|
+
fragList.push(frag)
|
|
51
|
+
insertValues.push(...vs)
|
|
52
|
+
}
|
|
53
|
+
const insertSql = `insert into ??(${columns.map(() => '??').join(',')}) values(${fragList.join(',')})`
|
|
54
|
+
|
|
55
|
+
// 构建 on duplicate key update(排除 id)
|
|
56
|
+
const updateColumns = columns.filter(col => col !== table.id)
|
|
57
|
+
const updateFragments: string[] = []
|
|
58
|
+
const updateValues: any[] = []
|
|
59
|
+
for (const col of updateColumns) {
|
|
60
|
+
const { frag, values: vs } = processInsertValue(data[col])
|
|
61
|
+
updateFragments.push(`?? = ${frag}`)
|
|
62
|
+
updateValues.push(col, ...vs)
|
|
63
|
+
}
|
|
64
|
+
const updateSql = ` on duplicate key update ${updateFragments.join(',')}`
|
|
65
|
+
|
|
66
|
+
const sql = insertSql + updateSql
|
|
67
|
+
|
|
68
|
+
const values = [table.tableName, ...columns, ...insertValues, ...updateValues]
|
|
69
|
+
|
|
70
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
71
|
+
const packet = res as ResultSetHeader
|
|
72
|
+
|
|
73
|
+
if (packet.insertId && (data[table.id] === undefined || data[table.id] === null)) {
|
|
74
|
+
data[table.id] = packet.insertId as any
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return data as unknown as T
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Upsert 多条数据
|
|
82
|
+
* 如果主键冲突则更新,否则插入
|
|
83
|
+
* @param config
|
|
84
|
+
* @param connection
|
|
85
|
+
* @param table
|
|
86
|
+
* @param list
|
|
87
|
+
* @returns 影响的行数
|
|
88
|
+
*/
|
|
89
|
+
export async function upsertMany<T>(
|
|
90
|
+
config: MysqlConfig,
|
|
91
|
+
connection: PoolConnection,
|
|
92
|
+
table: Table<T>,
|
|
93
|
+
list: InsertValue<T>[]
|
|
94
|
+
): Promise<number> {
|
|
95
|
+
if (!list.length) {
|
|
96
|
+
return 0
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let columnsSet: Set<keyof T> = new Set()
|
|
100
|
+
if (list[0][table.id]) {
|
|
101
|
+
columnsSet.add(table.id)
|
|
102
|
+
}
|
|
103
|
+
table.columns.forEach(col => columnsSet.add(col))
|
|
104
|
+
|
|
105
|
+
const now = new Date()
|
|
106
|
+
const nowTimestamp = now.getTime()
|
|
107
|
+
|
|
108
|
+
let createdData: Date | number | undefined = undefined
|
|
109
|
+
if (table.createdDate) {
|
|
110
|
+
createdData = table.createdDate.type === 'date' ? now : nowTimestamp
|
|
111
|
+
columnsSet.add(table.createdDate.column)
|
|
112
|
+
}
|
|
113
|
+
let updatedDate: Date | number | undefined = undefined
|
|
114
|
+
if (table.updatedDate) {
|
|
115
|
+
updatedDate = table.updatedDate.type === 'date' ? now : nowTimestamp
|
|
116
|
+
columnsSet.add(table.updatedDate.column)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const columns = Array.from(columnsSet)
|
|
120
|
+
|
|
121
|
+
let sql = `insert into ??(${columns.map(() => '??').join(',')}) values`
|
|
122
|
+
const values: any[] = [table.tableName, ...columns]
|
|
123
|
+
|
|
124
|
+
list.forEach((data, idx) => {
|
|
125
|
+
if (idx > 0) {
|
|
126
|
+
sql += ','
|
|
127
|
+
}
|
|
128
|
+
const fragList: string[] = []
|
|
129
|
+
const rowValues: any[] = []
|
|
130
|
+
if (table.createdDate) {
|
|
131
|
+
data[table.createdDate.column] = createdData as any
|
|
132
|
+
}
|
|
133
|
+
if (table.updatedDate) {
|
|
134
|
+
data[table.updatedDate.column] = updatedDate as any
|
|
135
|
+
}
|
|
136
|
+
for (const col of columns) {
|
|
137
|
+
const { frag, values: vs } = processInsertValue(data[col])
|
|
138
|
+
fragList.push(frag)
|
|
139
|
+
rowValues.push(...vs)
|
|
140
|
+
}
|
|
141
|
+
sql += `(${fragList.join(',')})`
|
|
142
|
+
values.push(...rowValues)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const updateColumns = columns.filter(col => col !== table.id)
|
|
146
|
+
sql += ` on duplicate key update ${updateColumns.map(() => '?? = values(??)').join(',')}`
|
|
147
|
+
updateColumns.forEach(col => values.push(col, col))
|
|
148
|
+
|
|
149
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
150
|
+
const packet = res as ResultSetHeader
|
|
151
|
+
|
|
152
|
+
return packet.affectedRows
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Upsert 单条数据(支持自定义更新器)
|
|
157
|
+
* 如果主键冲突则按自定义逻辑更新,否则插入
|
|
158
|
+
* @param config
|
|
159
|
+
* @param connection
|
|
160
|
+
* @param table
|
|
161
|
+
* @param data 插入的数据
|
|
162
|
+
* @param updater 冲突时的更新器
|
|
163
|
+
* @returns
|
|
164
|
+
*/
|
|
165
|
+
export async function upsertWithUpdater<T>(
|
|
166
|
+
config: MysqlConfig,
|
|
167
|
+
connection: PoolConnection,
|
|
168
|
+
table: Table<T>,
|
|
169
|
+
data: InsertValue<T>,
|
|
170
|
+
updater: Updater<T>
|
|
171
|
+
): Promise<T> {
|
|
172
|
+
let columnsSet: Set<keyof T> = new Set()
|
|
173
|
+
if (data[table.id]) {
|
|
174
|
+
columnsSet.add(table.id)
|
|
175
|
+
}
|
|
176
|
+
table.columns.forEach(col => {
|
|
177
|
+
if (data[col] !== undefined) {
|
|
178
|
+
columnsSet.add(col)
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
const now = new Date()
|
|
183
|
+
const nowTimestamp = now.getTime()
|
|
184
|
+
|
|
185
|
+
if (table.createdDate) {
|
|
186
|
+
const createdData = table.createdDate.type === 'date' ? now : nowTimestamp
|
|
187
|
+
data[table.createdDate.column] = createdData as any
|
|
188
|
+
columnsSet.add(table.createdDate.column)
|
|
189
|
+
}
|
|
190
|
+
if (table.updatedDate) {
|
|
191
|
+
const updatedDate = table.updatedDate.type === 'date' ? now : nowTimestamp
|
|
192
|
+
data[table.updatedDate.column] = updatedDate as any
|
|
193
|
+
columnsSet.add(table.updatedDate.column)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const columns = Array.from(columnsSet)
|
|
197
|
+
|
|
198
|
+
// 构建 insert values
|
|
199
|
+
const fragList: string[] = []
|
|
200
|
+
const insertValues: any[] = []
|
|
201
|
+
for (const col of columns) {
|
|
202
|
+
const { frag, values: vs } = processInsertValue(data[col])
|
|
203
|
+
fragList.push(frag)
|
|
204
|
+
insertValues.push(...vs)
|
|
205
|
+
}
|
|
206
|
+
const insertSql = `insert into ??(${columns.map(() => '??').join(',')}) values(${fragList.join(',')})`
|
|
207
|
+
|
|
208
|
+
const convertRes = updatorToSql(table, updater)
|
|
209
|
+
|
|
210
|
+
const updateSql = ` on duplicate key update ${convertRes.sql}`
|
|
211
|
+
|
|
212
|
+
const sql = insertSql + updateSql
|
|
213
|
+
|
|
214
|
+
const values = [table.tableName, ...columns, ...insertValues, ...convertRes.values]
|
|
215
|
+
|
|
216
|
+
const res = await promiseQuery(config, connection, sql, values)
|
|
217
|
+
const packet = res as ResultSetHeader
|
|
218
|
+
|
|
219
|
+
if (packet.insertId && (data[table.id] === undefined || data[table.id] === null)) {
|
|
220
|
+
data[table.id] = packet.insertId as any
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return data as unknown as T
|
|
224
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 处理列的值,对特殊类型 json 进行加工处理后返回
|
|
3
|
+
* @param value
|
|
4
|
+
*/
|
|
5
|
+
export function processColumnValue(value: any) {
|
|
6
|
+
// undefined/null 返回 null,mysql2 会正确处理为 SQL NULL
|
|
7
|
+
if (value === undefined || value === null) {
|
|
8
|
+
return null
|
|
9
|
+
}
|
|
10
|
+
// date 类型 typeof 也是 object ,先排除
|
|
11
|
+
if (value instanceof Date) {
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
// buffer 也是
|
|
15
|
+
if (value instanceof Buffer) {
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
// json
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
return JSON.stringify(value)
|
|
21
|
+
}
|
|
22
|
+
// 其它的情况直接返回
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PoolConnection } from 'mysql2'
|
|
2
|
+
import { MysqlConfig } from '../config'
|
|
3
|
+
import { MysqlTxSession } from './tx'
|
|
4
|
+
import { Table } from '../table-info'
|
|
5
|
+
import { MysqlException } from '../exception'
|
|
6
|
+
import {
|
|
7
|
+
DeleteManyOpts,
|
|
8
|
+
FindOpts,
|
|
9
|
+
FindSelectOpts,
|
|
10
|
+
MixCriteria,
|
|
11
|
+
MysqlPage,
|
|
12
|
+
MysqlPaginateOpts,
|
|
13
|
+
UpdateOpts,
|
|
14
|
+
Updater
|
|
15
|
+
} from './ops'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 严格 mysql 事务会话,会禁用一些操作.
|
|
19
|
+
*/
|
|
20
|
+
export class MysqlStrictTxSession extends MysqlTxSession {
|
|
21
|
+
#opsCount = 0
|
|
22
|
+
constructor(private config: MysqlConfig, conn: PoolConnection) {
|
|
23
|
+
super(config, conn)
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 为操作计数,检查是否操作次数过多.
|
|
27
|
+
*/
|
|
28
|
+
#checkAndAddOpsCount() {
|
|
29
|
+
if (this.#opsCount >= this.config.maxOpsInStrictTx) {
|
|
30
|
+
throw new MysqlException('Too many operations in a strict transaction.')
|
|
31
|
+
}
|
|
32
|
+
this.#opsCount++
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
findById<T>(table: Table<T>, id: string | number): Promise<T | null> {
|
|
36
|
+
this.#checkAndAddOpsCount()
|
|
37
|
+
return super.findById(table, id)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
findByIdIn<T>(table: Table<T>, ids: (string | number)[]): Promise<T[]> {
|
|
41
|
+
if (ids.length > 100) {
|
|
42
|
+
throw new MysqlException(
|
|
43
|
+
`The augument ids length(${ids.length}) passed to findByIdIn in a strict transaction is too large .`
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
this.#checkAndAddOpsCount()
|
|
47
|
+
return super.findByIdIn(table, ids)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
existsBy<T>(table: Table<T>, criteria?: MixCriteria<T> | undefined): Promise<boolean> {
|
|
51
|
+
this.#checkAndAddOpsCount()
|
|
52
|
+
return super.existsBy(table, criteria)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
existsById<T>(table: Table<T>, id: string | number): Promise<boolean> {
|
|
56
|
+
this.#checkAndAddOpsCount()
|
|
57
|
+
return super.existsById(table, id)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
deleteById<T>(table: Table<T>, id: string | number): Promise<boolean> {
|
|
61
|
+
this.#checkAndAddOpsCount()
|
|
62
|
+
return super.deleteById(table, id)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
deleteOne<T>(table: Table<T>, criteria: Partial<T>): Promise<boolean> {
|
|
66
|
+
this.#checkAndAddOpsCount()
|
|
67
|
+
return super.deleteOne(table, criteria)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
deleteMany<T>(opts: DeleteManyOpts<T>): Promise<number> {
|
|
71
|
+
throw new MysqlException('Prohibited to use deleteBy in a strict transaction.')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
findAll<T>(table: Table<T>): Promise<T[]> {
|
|
75
|
+
throw new MysqlException('Prohibited to use findAll in a strict transaction.')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
findFirst<T>(table: Table<T>, criteria?: MixCriteria<T> | undefined): Promise<T | null> {
|
|
79
|
+
this.#checkAndAddOpsCount()
|
|
80
|
+
return super.findFirst(table, criteria)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
insert<T>(table: Table<T>, data: T): Promise<T> {
|
|
84
|
+
this.#checkAndAddOpsCount()
|
|
85
|
+
return super.insert(table, data)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
insertMany<T>(table: Table<T>, list: T[]): Promise<void> {
|
|
89
|
+
throw new MysqlException('Prohibited to use insertMany in a strict transaction.')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
update<T>(table: Table<T>, data: T): Promise<T> {
|
|
93
|
+
this.#checkAndAddOpsCount()
|
|
94
|
+
return super.update(table, data)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
updateMany<T>(opts: UpdateOpts<T>): Promise<number> {
|
|
98
|
+
throw new MysqlException('Prohibited to use updateMany in a strict transaction.')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
updateOne<T>(
|
|
102
|
+
table: Table<T>,
|
|
103
|
+
query: Partial<T>,
|
|
104
|
+
updater: Partial<{ [key in keyof T]: ['setNull'] | ['inc', number] | T[key] | undefined }>
|
|
105
|
+
): Promise<boolean> {
|
|
106
|
+
this.#checkAndAddOpsCount()
|
|
107
|
+
return super.updateOne(table, query, updater)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
partialUpdate<T>(table: Table<T>, data: Updater<T>): Promise<boolean> {
|
|
111
|
+
this.#checkAndAddOpsCount()
|
|
112
|
+
return super.partialUpdate(table, data)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
find<T>(opts: FindOpts<T>): Promise<T[]> {
|
|
116
|
+
throw new MysqlException('Prohibited to use find in a strict transaction.')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
findSelect<T, K extends keyof T>(opts: FindSelectOpts<T, K>): Promise<Pick<T, K>[]> {
|
|
120
|
+
throw new MysqlException('Prohibited to use findSelect in a strict transaction.')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
count<T>(table: Table<T>, criteria?: MixCriteria<T> | undefined): Promise<number> {
|
|
124
|
+
throw new MysqlException('Prohibited to use count in a strict transaction.')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
paginate<T>(opts: MysqlPaginateOpts<T>): Promise<MysqlPage<T>> {
|
|
128
|
+
throw new MysqlException('Prohibited to use paginate in a strict transaction.')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
query<T>(sql: string, values?: any[] | undefined): Promise<T[]> {
|
|
132
|
+
throw new MysqlException('Prohibited to use query in a strict transaction.')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
modify(sql: string, values?: any[] | undefined): Promise<number> {
|
|
136
|
+
throw new MysqlException('Prohibited to use modify in a strict transaction.')
|
|
137
|
+
}
|
|
138
|
+
}
|