w-orm-reladb 1.1.6 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -3
- package/dist/w-orm-reladb.umd.js +2 -2
- package/dist/w-orm-reladb.umd.js.map +1 -1
- package/docs/WOrmReladb.html +39 -21
- package/docs/WOrmReladb.mjs.html +206 -131
- package/docs/cvFind.mjs.html +861 -0
- package/docs/global.html +1716 -0
- package/docs/importModels.mjs.html +255 -0
- package/docs/index.html +2 -2
- package/g-mssql.mjs +1 -1
- package/g-sqlite-encryption.mjs +1 -1
- package/g-sqlite.mjs +1 -1
- package/models/tcond.js +74 -0
- package/models/tpkdec.js +20 -0
- package/models/tpkint.js +20 -0
- package/package.json +3 -3
- package/src/WOrmReladb.mjs +204 -129
- package/src/cvFind.mjs +789 -0
- package/src/importModels.mjs +180 -114
- package/src/requireModel.js +13 -5
- package/test/api-dist.test.mjs +112 -0
- package/test/api-init.test.mjs +50 -0
- package/test/api-models.test.mjs +216 -0
- package/test/api-suite.mjs +492 -3
- package/test/tools/modelsWorker.mjs +35 -0
- package/test/unit-cvfind.test.mjs +393 -0
- package/toolg/gDistRollup.mjs +2 -0
- package/src/modifyModel.mjs +0 -113
package/src/importModels.mjs
CHANGED
|
@@ -1,117 +1,183 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import JSON5 from 'json5'
|
|
4
|
-
import Sequelize from 'sequelize'
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import JSON5 from 'json5'
|
|
4
|
+
import Sequelize from 'sequelize'
|
|
5
5
|
import each from 'lodash-es/each.js'
|
|
6
6
|
import get from 'lodash-es/get.js'
|
|
7
7
|
import isBoolean from 'lodash-es/isBoolean.js'
|
|
8
|
-
import genPm from 'wsemi/src/genPm.mjs'
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
let
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
8
|
+
import genPm from 'wsemi/src/genPm.mjs'
|
|
9
|
+
import requireModel from './requireModel.js'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
//匯入資料表設定檔(models)
|
|
13
|
+
//
|
|
14
|
+
//model內之id欄位須為主鍵, 否則sequelize拒絕匯入(model.js: A column called 'id' was added ... but not marked with 'primaryKey: true')
|
|
15
|
+
//原版以modifyModel於[每一次]匯入時無條件重寫呼叫端之model原始檔(逐行trim、刪空行並改為LF)以補上主鍵設定,
|
|
16
|
+
//而本套件每次操作(含select、selectByPk)皆匯入一次, 故讀取函數亦改變可被觀察之狀態(規格T9),
|
|
17
|
+
//且多行程併發時一方正截斷檔案而另一方讀取, 即讀到空內容並寫回空檔而[永久損毀](已實機重現: 4行程併發, 4/4輪model檔被截為0位元組)
|
|
18
|
+
//
|
|
19
|
+
//本版改於記憶體內補上主鍵設定, 一律不寫model檔:
|
|
20
|
+
// js格式於呼叫model之定義函數期間暫時包裝sequelize.define, 於定義前補上id之primaryKey
|
|
21
|
+
// json格式於解析後、define前補上
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 令欄位定義之id為主鍵, 不改動傳入之物件
|
|
26
|
+
* 註: 僅於model完全沒有主鍵設定而有id欄時補上(sequelize於此情形拒絕匯入);
|
|
27
|
+
* model已有其他主鍵時不改動, 否則成為(既有主鍵, id)之複合主鍵而使主鍵去重失效(原版modifyModel有此缺陷)
|
|
28
|
+
*
|
|
29
|
+
* @ignore
|
|
30
|
+
* @param {Object} attrs 輸入欄位定義物件
|
|
31
|
+
* @returns {Object} 回傳欄位定義物件
|
|
32
|
+
*/
|
|
33
|
+
function patchIdPk(attrs) {
|
|
34
|
+
|
|
35
|
+
//check
|
|
36
|
+
if (!attrs || !Object.prototype.hasOwnProperty.call(attrs, 'id')) {
|
|
37
|
+
return attrs
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//check, 已有任一主鍵設定者不改動
|
|
41
|
+
let hasPk = Object.keys(attrs).some((k) => get(attrs[k], 'primaryKey') === true)
|
|
42
|
+
if (hasPk) {
|
|
43
|
+
return attrs
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//id
|
|
47
|
+
let id = attrs.id
|
|
48
|
+
|
|
49
|
+
//idNew, id可為欄位設定物件或直接為型別
|
|
50
|
+
let idNew = Object.prototype.toString.call(id) === '[object Object]' && get(id, 'type') !== undefined
|
|
51
|
+
? { ...id, primaryKey: true }
|
|
52
|
+
: { type: id, primaryKey: true }
|
|
53
|
+
|
|
54
|
+
return { ...attrs, id: idNew }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 讀取js格式之model
|
|
60
|
+
* 註: 於呼叫model之定義函數期間暫時以實例自有屬性包裝define, 結束後刪除該屬性即回復原型上之define
|
|
61
|
+
*
|
|
62
|
+
* @ignore
|
|
63
|
+
*/
|
|
64
|
+
function readJsModel(fn, sequelize) {
|
|
65
|
+
let define = sequelize.define
|
|
66
|
+
sequelize.define = function(name, attrs, options) {
|
|
67
|
+
return define.call(sequelize, name, patchIdPk(attrs), options)
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return requireModel(fn, sequelize, Sequelize.DataTypes)
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
delete sequelize.define
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 讀取json格式之model
|
|
80
|
+
*
|
|
81
|
+
* @ignore
|
|
82
|
+
*/
|
|
83
|
+
function readJsonModel(fn, sequelize) {
|
|
84
|
+
|
|
85
|
+
//s
|
|
86
|
+
let j = fs.readFileSync(fn, 'utf8')
|
|
87
|
+
let s = JSON5.parse(j)
|
|
88
|
+
|
|
89
|
+
//抽換DataTypes, 例如將'DataTypes.TEXT'改為DataTypes.TEXT
|
|
90
|
+
each(s.fields, (v) => {
|
|
91
|
+
v.type = get(Sequelize, v.type, null)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
//model, 使用define產生model, 定義前於記憶體內補上id之主鍵設定
|
|
95
|
+
let model = sequelize.define(s.table, patchIdPk(s.fields), s.options)
|
|
96
|
+
|
|
97
|
+
return model
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 匯入資料表設定檔
|
|
103
|
+
*
|
|
104
|
+
* 註: 不寫入model檔, id之主鍵設定於記憶體內補上
|
|
105
|
+
*
|
|
106
|
+
* @param {String} fdModels 輸入models所在資料夾字串
|
|
107
|
+
* @param {Object} sequelize 輸入sequelize實例
|
|
108
|
+
* @param {String} name 輸入資料表名稱字串
|
|
109
|
+
* @param {Object} [opt={}] 輸入設定物件
|
|
110
|
+
* @param {String} [opt.type='js'] 輸入資料表設定檔類型字串,可有'js'、'json'
|
|
111
|
+
* @param {Boolean} [opt.sync=false] 輸入是否將models資料同步至資料庫
|
|
112
|
+
* @returns {Promise} 回傳Promise,resolve回傳models物件,reject回傳錯誤訊息
|
|
113
|
+
*/
|
|
114
|
+
async function importModels(fdModels, sequelize, name, opt = {}) {
|
|
115
|
+
|
|
116
|
+
//type
|
|
117
|
+
let type = get(opt, 'type')
|
|
118
|
+
if (type !== 'js' && type !== 'json') {
|
|
119
|
+
type = 'js'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//sync
|
|
123
|
+
let sync = get(opt, 'sync')
|
|
124
|
+
if (!isBoolean(sync)) {
|
|
125
|
+
sync = false
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//pm
|
|
129
|
+
let pm = genPm()
|
|
130
|
+
|
|
131
|
+
//file
|
|
132
|
+
let file = `${name}.${type}`
|
|
133
|
+
|
|
134
|
+
//fparent
|
|
135
|
+
let fparent = path.resolve(fdModels) + path.sep
|
|
136
|
+
|
|
137
|
+
//fn
|
|
138
|
+
let fn = fparent + file
|
|
139
|
+
|
|
140
|
+
//import
|
|
141
|
+
let model
|
|
142
|
+
try {
|
|
143
|
+
if (type === 'js') {
|
|
144
|
+
model = readJsModel(fn, sequelize)
|
|
145
|
+
}
|
|
146
|
+
else if (type === 'json') {
|
|
147
|
+
model = readJsonModel(fn, sequelize)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
pm.reject(err)
|
|
152
|
+
return pm
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//sync
|
|
156
|
+
try {
|
|
157
|
+
if (sync) {
|
|
158
|
+
await model.sync() //{ force: true }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
pm.reject(err)
|
|
163
|
+
return pm
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//models
|
|
167
|
+
let models = {}
|
|
168
|
+
try {
|
|
169
|
+
models[model.name] = model
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
pm.reject(err)
|
|
173
|
+
return pm
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//resolve
|
|
177
|
+
pm.resolve(models)
|
|
178
|
+
|
|
179
|
+
return pm
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
export default importModels
|
package/src/requireModel.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const { createRequire } = require('module')
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
//載入js格式之model檔並呼叫其定義函數
|
|
5
|
+
//註: 不可直接以require(fn)載入: 發布用dist經rollup之commonjs外掛打包時, 引數非字面值之require會被換成必拋[Could not dynamically require]之樁,
|
|
6
|
+
//故以Node內建module之createRequire依model檔之絕對路徑產生require函數載入, 其解析與模組快取皆同require
|
|
7
|
+
//註: fn須為絕對路徑, 呼叫端(本套件與w-orm-mdb之importModels)皆以path.resolve產生; 被w-orm-mdb等深層引用, 勿改簽章或路徑
|
|
8
|
+
function requireModel(fn, sequelize, DataTypes) {
|
|
9
|
+
let req = createRequire(fn)
|
|
10
|
+
return req(fn)(sequelize, DataTypes)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = requireModel
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import assert from 'assert'
|
|
4
|
+
import { execFile } from 'child_process'
|
|
5
|
+
import { createRequire } from 'module'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
//rulebook R10: 經package.json之main(dist)使用時, js型model之importModels與各函數須與經src使用時同樣可用
|
|
9
|
+
//修正前dist內src/requireModel.js之require(fn)被rollup之commonjs外掛換成必拋[Could not dynamically require]之樁, 而測試只跑src未曾發現
|
|
10
|
+
//作法: 以toolg/gDistRollup.mjs原檔之設定只換輸出夾, 由目前src建置至已安裝佈局(app/node_modules/w-orm-reladb/dist), 再由app以套件名require
|
|
11
|
+
//僅以sqlite驗證, 因model檔之載入與資料庫種類無關
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
let fd = './test/_tmp/api-dist'
|
|
15
|
+
let fdApp = `${fd}/app`
|
|
16
|
+
let fdPkg = `${fdApp}/node_modules/w-orm-reladb`
|
|
17
|
+
let fdDist = `${fdPkg}/dist`
|
|
18
|
+
let fdModels = `${fd}/models`
|
|
19
|
+
let fpBundle = `${fdDist}/w-orm-reladb.umd.js`
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
//buildDist, 複製gDistRollup.mjs並只把fdTar換成已安裝佈局之dist後, 以子行程於專案根目錄執行(同發布時之cwd, 故babel.config.js與package.json同發布)
|
|
23
|
+
let buildDist = () => {
|
|
24
|
+
let c = fs.readFileSync('./toolg/gDistRollup.mjs', 'utf8')
|
|
25
|
+
let from = `let fdTar = './dist'`
|
|
26
|
+
assert.strictEqual(c.split(from).length - 1, 1, `toolg/gDistRollup.mjs須恰有一處[${from}]供替換輸出夾`)
|
|
27
|
+
c = c.replace(from, `let fdTar = '${fdDist}'`)
|
|
28
|
+
let fpGen = `${fd}/gDistRollup.mjs`
|
|
29
|
+
fs.writeFileSync(fpGen, c, 'utf8')
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
execFile(process.execPath, [fpGen], { maxBuffer: 64 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
32
|
+
if (err) {
|
|
33
|
+
reject(new Error(`build dist failed: ${err.message}\n${stderr}`))
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
resolve(stdout)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe('dist (installed layout)', function() {
|
|
43
|
+
|
|
44
|
+
let wo = null
|
|
45
|
+
|
|
46
|
+
before(async function() {
|
|
47
|
+
|
|
48
|
+
fs.rmSync(fd, { recursive: true, force: true })
|
|
49
|
+
fs.mkdirSync(fdDist, { recursive: true })
|
|
50
|
+
|
|
51
|
+
//build
|
|
52
|
+
await buildDist()
|
|
53
|
+
|
|
54
|
+
//已安裝佈局: 套件夾內之package.json(main指向dist), 相依(sequelize等)沿上層node_modules解析
|
|
55
|
+
fs.copyFileSync('./package.json', `${fdPkg}/package.json`)
|
|
56
|
+
|
|
57
|
+
//models, 複製至暫存夾, 不動版控中之models
|
|
58
|
+
fs.mkdirSync(fdModels, { recursive: true })
|
|
59
|
+
fs.copyFileSync('./models/users.js', `${fdModels}/users.js`)
|
|
60
|
+
fs.copyFileSync('./models/users.json', `${fdModels}/users.json`)
|
|
61
|
+
|
|
62
|
+
//require, 由app以套件名解析
|
|
63
|
+
let req = createRequire(path.resolve(fdApp, 'index.js'))
|
|
64
|
+
assert.strictEqual(req.resolve('w-orm-reladb'), path.resolve(fpBundle), '套件名須經package.json之main解析至建出之dist')
|
|
65
|
+
wo = req('w-orm-reladb')
|
|
66
|
+
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
after(function() {
|
|
70
|
+
fs.rmSync(fd, { recursive: true, force: true })
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('建出之dist不含rollup動態require之樁', function() {
|
|
74
|
+
//rulebook R10: 建置產物不得含[Could not dynamically require](含被打包之相依)
|
|
75
|
+
let code = fs.readFileSync(fpBundle, 'utf8')
|
|
76
|
+
assert.ok(code.length > 0)
|
|
77
|
+
assert.strictEqual(code.indexOf('Could not dynamically require'), -1)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('js型model: createStorage、insert、select、selectByPk、del皆成功且不發error事件', async function() {
|
|
81
|
+
//rulebook R10: 預設modelType為js, 經main使用時importModels須可載入js型model
|
|
82
|
+
assert.strictEqual(typeof wo, 'function')
|
|
83
|
+
let w = wo({ url: 'sqlite://:', db: 'worm', cl: 'users', fdModels, storage: `${fd}/js.sqlite` })
|
|
84
|
+
let errs = []
|
|
85
|
+
w.on('error', (mode, data, err) => {
|
|
86
|
+
errs.push([mode, err])
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
assert.strictEqual(await w.createStorage(), 'created')
|
|
90
|
+
assert.deepStrictEqual(await w.insert({ id: 'a1', name: 'A', value: 1.5 }), { n: 1, nInserted: 1, ok: 1 })
|
|
91
|
+
assert.deepStrictEqual(await w.select({ id: 'a1' }), [{ id: 'a1', name: 'A', value: 1.5 }])
|
|
92
|
+
assert.deepStrictEqual(await w.selectByPk('a1'), { id: 'a1', name: 'A', value: 1.5 })
|
|
93
|
+
assert.deepStrictEqual(await w.del({ id: 'a1' }), [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
94
|
+
assert.deepStrictEqual(await w.select(), [])
|
|
95
|
+
assert.deepStrictEqual(errs, [])
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('json型model(對照): createStorage、insert、select皆成功且不發error事件', async function() {
|
|
99
|
+
//rulebook R10: 兩種modelType經main皆須可用; json型不經requireModel, 修正前即可用
|
|
100
|
+
let w = wo({ url: 'sqlite://:', db: 'worm', cl: 'users', fdModels, modelType: 'json', storage: `${fd}/json.sqlite` })
|
|
101
|
+
let errs = []
|
|
102
|
+
w.on('error', (mode, data, err) => {
|
|
103
|
+
errs.push([mode, err])
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
assert.strictEqual(await w.createStorage(), 'created')
|
|
107
|
+
assert.deepStrictEqual(await w.insert({ id: 'b1', name: 'B', value: 2 }), { n: 1, nInserted: 1, ok: 1 })
|
|
108
|
+
assert.deepStrictEqual(await w.select({ id: 'b1' }), [{ id: 'b1', name: 'B', value: 2 }])
|
|
109
|
+
assert.deepStrictEqual(errs, [])
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import wo from '../src/WOrmReladb.mjs'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
//rulebook R7: 七函數之內部初始化(initSequelize)在主try內, 其建構期例外與其他整批性錯誤同樣於reject前發一次error事件(規格T10.3)
|
|
6
|
+
//觸發: 本套件不相依mysql2, 以mysql://建構sequelize時即拋[Please install mysql2 package manually]; 若環境另裝mysql2則前提不成立, 斷言訊息會指出
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
describe('initSequelize throws', function() {
|
|
10
|
+
|
|
11
|
+
it('七函數皆reject, 且於reject前各發一次error事件, mode為函數名、data為輸入數據或null、err與reject訊息一致', async function() {
|
|
12
|
+
let w = wo({ url: 'mysql://username:password@localhost:3306', db: 'worm', cl: 'users', fdModels: './models' })
|
|
13
|
+
let settled = false
|
|
14
|
+
let evs = []
|
|
15
|
+
w.on('error', (mode, data, err) => {
|
|
16
|
+
evs.push({ mode, data, err, settled })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
let cases = [
|
|
20
|
+
['select', null, () => w.select({ id: 'k1' })],
|
|
21
|
+
['selectByPk', null, () => w.selectByPk('k1')],
|
|
22
|
+
['insert', { id: 'k1', name: 'A' }, (d) => w.insert(d)],
|
|
23
|
+
['insertBulk', [{ id: 'k2', name: 'B' }], (d) => w.insertBulk(d)],
|
|
24
|
+
['save', [{ id: 'k1', name: 'Z' }], (d) => w.save(d)],
|
|
25
|
+
['del', [{ id: 'k1' }], (d) => w.del(d)],
|
|
26
|
+
['delAll', null, () => w.delAll({ id: 'k1' })],
|
|
27
|
+
]
|
|
28
|
+
for (let [mode, data, fn] of cases) {
|
|
29
|
+
settled = false
|
|
30
|
+
evs = []
|
|
31
|
+
let r = await fn(data)
|
|
32
|
+
.then((v) => ({ RESOLVE: v }), (err) => ({ REJECT: String(err.message || err) }))
|
|
33
|
+
.finally(() => {
|
|
34
|
+
settled = true
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
//整批性錯誤經Promise.reject(規格T4)
|
|
38
|
+
assert.ok(r.REJECT !== undefined, `${mode} 未reject, 實得 ${JSON.stringify(r.RESOLVE)}`)
|
|
39
|
+
assert.ok(r.REJECT.indexOf('Please install mysql2') >= 0, `${mode} 之reject非建構期例外(前提: 本機未裝mysql2): ${r.REJECT}`)
|
|
40
|
+
|
|
41
|
+
//規格T10.3: 整批性錯誤於reject之前發出一次, mode取函數名, err與reject之訊息一致, data為本次輸入數據(無輸入數據者為null)
|
|
42
|
+
assert.strictEqual(evs.length, 1, `${mode} 之error事件數 ${evs.length}`)
|
|
43
|
+
assert.strictEqual(evs[0].mode, mode)
|
|
44
|
+
assert.strictEqual(evs[0].err, r.REJECT)
|
|
45
|
+
assert.deepStrictEqual(evs[0].data, data)
|
|
46
|
+
assert.strictEqual(evs[0].settled, false, `${mode} 之error事件須於reject之前發出`)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
})
|