w-orm-reladb 1.0.48 → 1.0.50
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 +20 -0
- package/dist/w-orm-reladb.umd.js +2 -2
- package/dist/w-orm-reladb.umd.js.map +1 -1
- package/docs/WOrmReladb.html +60 -16
- package/docs/WOrmReladb.mjs.html +139 -19
- package/docs/index.html +1 -1
- package/package.json +3 -3
- package/src/WOrmReladb.mjs +138 -18
- package/test/api-suite.mjs +145 -0
- package/toolg/gDistRollup.mjs +1 -0
package/src/WOrmReladb.mjs
CHANGED
|
@@ -260,6 +260,66 @@ function WOrmReladb(opt = {}) {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
|
|
263
|
+
/**
|
|
264
|
+
* 檢查呼叫端所給之實例是否已關閉,已關閉者拋出令各函數於入口快速失敗
|
|
265
|
+
* 註: 實例已關閉為終態,後續操作必然失敗,屬影響全部數據之整批性錯誤,
|
|
266
|
+
* 故不得降為逐筆ok為0而整批resolve,亦不得以正常空結果(null、未命中、空陣列)回應——
|
|
267
|
+
* 後者使[已關閉]與[查無資料]同形,去重類呼叫端將把每筆判為未存在而靜默fail-open
|
|
268
|
+
* 註: closeSequelize於關閉後將sequelize設為null,故據此判定即為精確訊號,
|
|
269
|
+
* 不須倚賴驅動層之錯誤訊息比對(連線管理器關閉後所拋者為原生Error而非sequelize之錯誤類別)
|
|
270
|
+
* 註: 內部自行初始化者(instance為null)每次呼叫各自開關連線,不受本檢查影響
|
|
271
|
+
*
|
|
272
|
+
* @ignore
|
|
273
|
+
* @param {Object|null} instance 輸入呼叫端所給之實例物件
|
|
274
|
+
* @returns {undefined} 無回傳值
|
|
275
|
+
*/
|
|
276
|
+
function procClosed(instance) {
|
|
277
|
+
|
|
278
|
+
//check
|
|
279
|
+
if (instance === null) {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
//check
|
|
284
|
+
if (sequelize === null) {
|
|
285
|
+
throw new Error(`instance is closed, need to use init() to get a new instance`)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 判定錯誤是否影響後續所有筆數而應視為整批性錯誤
|
|
293
|
+
* 註: 依T4之判別原則,錯誤只影響該筆資料者為逐筆失敗,影響後續所有筆數者為整批性錯誤;
|
|
294
|
+
* 連線層錯誤屬後者,故於逐筆函數內攔得時須往外拋而不得降為該筆ok為0
|
|
295
|
+
* 註: 連線管理器關閉後所拋者為原生Error而非sequelize之ConnectionError,故另以訊息辨識
|
|
296
|
+
*
|
|
297
|
+
* @ignore
|
|
298
|
+
* @param {Error} err 輸入錯誤物件
|
|
299
|
+
* @returns {Boolean} 回傳是否為整批性錯誤布林值
|
|
300
|
+
*/
|
|
301
|
+
function isBatchLevelError(err) {
|
|
302
|
+
|
|
303
|
+
//check, sequelize之連線層錯誤家族
|
|
304
|
+
if (err instanceof Sequelize.ConnectionError) {
|
|
305
|
+
return true
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
//msg
|
|
309
|
+
let msg = getErrMsg(err)
|
|
310
|
+
|
|
311
|
+
//check
|
|
312
|
+
if (msg.indexOf('connection manager was closed') >= 0) {
|
|
313
|
+
return true
|
|
314
|
+
}
|
|
315
|
+
if (msg.indexOf('SQLITE_MISUSE') >= 0) {
|
|
316
|
+
return true
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return false
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
263
323
|
/**
|
|
264
324
|
* 檢查並補齊單筆數據之主鍵
|
|
265
325
|
* autoGenPk為true時未帶有效主鍵者自動產生,為false時往外拋
|
|
@@ -573,17 +633,26 @@ function WOrmReladb(opt = {}) {
|
|
|
573
633
|
*/
|
|
574
634
|
async function selectByPk(pk, option = {}) {
|
|
575
635
|
|
|
576
|
-
//check, 未給有效主鍵值視為查無數據, 不送查詢以免無效值被轉為null而誤中其他數據
|
|
577
|
-
if (!isEffPk(pk)) {
|
|
578
|
-
return null
|
|
579
|
-
}
|
|
580
|
-
|
|
581
636
|
//instance
|
|
582
637
|
let instance = get(option, 'instance', null)
|
|
583
638
|
|
|
584
639
|
//transaction
|
|
585
640
|
let transaction = get(option, 'transaction', null)
|
|
586
641
|
|
|
642
|
+
//check, 實例已關閉之判定須先於[主鍵值無效回null], 否則兩者同形而使[已關閉]被誤讀為[查無資料]
|
|
643
|
+
try {
|
|
644
|
+
procClosed(instance)
|
|
645
|
+
}
|
|
646
|
+
catch (err) {
|
|
647
|
+
emitError('selectByPk', null, err)
|
|
648
|
+
return Promise.reject(err)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
//check, 未給有效主鍵值視為查無數據, 不送查詢以免無效值被轉為null而誤中其他數據
|
|
652
|
+
if (!isEffPk(pk)) {
|
|
653
|
+
return null
|
|
654
|
+
}
|
|
655
|
+
|
|
587
656
|
//check
|
|
588
657
|
if (opt.useEncryption && dialect === 'sqlite') {
|
|
589
658
|
if (transaction !== null) {
|
|
@@ -603,6 +672,9 @@ function WOrmReladb(opt = {}) {
|
|
|
603
672
|
|
|
604
673
|
try {
|
|
605
674
|
|
|
675
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
676
|
+
procClosed(instance)
|
|
677
|
+
|
|
606
678
|
//check
|
|
607
679
|
if (si.err) {
|
|
608
680
|
throw si.err
|
|
@@ -664,18 +736,29 @@ function WOrmReladb(opt = {}) {
|
|
|
664
736
|
* 註: n為輸入筆數即本次嘗試插入之基準,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
|
|
665
737
|
* 註: 同批含重複主鍵時僅首筆計入nInserted,其餘視為已存在
|
|
666
738
|
* 註: opt.autoGenPk為true(預設)時未帶有效主鍵者自動產生,為false時未帶有效主鍵即reject且同批皆不寫入
|
|
739
|
+
* 註: option.returnList開啟時改回與輸入等長且保序之逐筆結果陣列[{n,nInserted,ok}],
|
|
740
|
+
* 聚合計數只答得出[有幾筆是新的]而答不出[是哪幾筆],而後者正是去重之產出物;
|
|
741
|
+
* 逐筆元素之n與ok恆為1,資訊由nInserted承載,不變式為
|
|
742
|
+
* 陣列長度等於輸入筆數且filter(v => v.nInserted === 1).length等於聚合模式之nInserted
|
|
667
743
|
*
|
|
668
744
|
* @memberOf WOrmReladb
|
|
669
745
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
670
746
|
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
671
747
|
* @param {Object} [option.instance=null] 輸入實例instance物件,預設為null
|
|
672
748
|
* @param {Object} [option.transaction=null] 輸入交易(transaction)物件,預設為null
|
|
673
|
-
* @
|
|
749
|
+
* @param {Boolean} [option.returnList=false] 輸入是否改回逐筆結果陣列布林值,預設false
|
|
750
|
+
* @returns {Promise} 回傳Promise,resolve回傳插入結果{n,nInserted,ok},或於returnList開啟時回傳[{n,nInserted,ok}],reject回傳錯誤訊息
|
|
674
751
|
*/
|
|
675
752
|
async function insert(data, option = {}) {
|
|
676
753
|
|
|
754
|
+
//returnList, 回傳形式之切換為靜態, 僅由本選項之取值決定, 不因數據內容或執行結果而變
|
|
755
|
+
let returnList = get(option, 'returnList', false) === true
|
|
756
|
+
|
|
677
757
|
//check
|
|
678
758
|
if (!iseobj(data) && !isearr(data)) {
|
|
759
|
+
if (returnList) {
|
|
760
|
+
return []
|
|
761
|
+
}
|
|
679
762
|
return {
|
|
680
763
|
n: 0,
|
|
681
764
|
nInserted: 0,
|
|
@@ -711,6 +794,9 @@ function WOrmReladb(opt = {}) {
|
|
|
711
794
|
|
|
712
795
|
try {
|
|
713
796
|
|
|
797
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
798
|
+
procClosed(instance)
|
|
799
|
+
|
|
714
800
|
//check
|
|
715
801
|
if (si.err) {
|
|
716
802
|
throw si.err
|
|
@@ -741,8 +827,8 @@ function WOrmReladb(opt = {}) {
|
|
|
741
827
|
//create, 逐筆插入以取得精確之nInserted
|
|
742
828
|
//註: 不採bulkCreate配合ignoreDuplicates, 因mssql未宣告該能力而選項會被靜默忽略仍撞唯一約束,
|
|
743
829
|
//且bulkCreate無從回報實際插入筆數; 單筆INSERT本即由主鍵之唯一約束原子完成檢查與寫入
|
|
744
|
-
|
|
745
|
-
await pmSeries(data, async(v) => {
|
|
830
|
+
//註: bIns即逐筆判定, 與輸入等長且保序, 供returnList直接包裝而不須另行推導
|
|
831
|
+
let bInss = await pmSeries(data, async(v) => {
|
|
746
832
|
|
|
747
833
|
//bIns, 撞既有主鍵者視為已存在而跳過, 其餘錯誤影響全部數據須往外拋
|
|
748
834
|
let bIns = await md.create(v, setting)
|
|
@@ -756,19 +842,31 @@ function WOrmReladb(opt = {}) {
|
|
|
756
842
|
throw err
|
|
757
843
|
})
|
|
758
844
|
|
|
759
|
-
//nInserted
|
|
760
|
-
if (bIns) {
|
|
761
|
-
nInserted += 1
|
|
762
|
-
}
|
|
763
|
-
|
|
764
845
|
return bIns
|
|
765
846
|
})
|
|
766
847
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
n
|
|
770
|
-
nInserted
|
|
771
|
-
|
|
848
|
+
if (returnList) {
|
|
849
|
+
|
|
850
|
+
//res, 與輸入等長且保序之逐筆結果; 各筆之n恆為1(該筆主鍵或為命中既有或經插入而產生),
|
|
851
|
+
//ok恆為1(insert之任何錯誤皆屬整批性錯誤而reject), 資訊由nInserted承載
|
|
852
|
+
res = map(bInss, (bIns) => {
|
|
853
|
+
return {
|
|
854
|
+
n: 1,
|
|
855
|
+
nInserted: bIns ? 1 : 0,
|
|
856
|
+
ok: 1,
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
|
|
863
|
+
//res, 全數已存在而nInserted為0屬正常結果, 不視為錯誤
|
|
864
|
+
res = {
|
|
865
|
+
n: nAll,
|
|
866
|
+
nInserted: size(bInss.filter((v) => v === true)),
|
|
867
|
+
ok: 1,
|
|
868
|
+
}
|
|
869
|
+
|
|
772
870
|
}
|
|
773
871
|
|
|
774
872
|
}
|
|
@@ -860,6 +958,9 @@ function WOrmReladb(opt = {}) {
|
|
|
860
958
|
|
|
861
959
|
try {
|
|
862
960
|
|
|
961
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
962
|
+
procClosed(instance)
|
|
963
|
+
|
|
863
964
|
//check
|
|
864
965
|
if (si.err) {
|
|
865
966
|
throw si.err
|
|
@@ -1086,6 +1187,11 @@ function WOrmReladb(opt = {}) {
|
|
|
1086
1187
|
}
|
|
1087
1188
|
catch (err) {
|
|
1088
1189
|
|
|
1190
|
+
//check, 連線層錯誤影響後續所有筆數, 依T4屬整批性錯誤, 往外拋而不降為本筆ok為0
|
|
1191
|
+
if (isBatchLevelError(err)) {
|
|
1192
|
+
throw err
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1089
1195
|
//其餘錯誤視為本筆失敗, 不中斷整批, 由呼叫端以ok與err判讀
|
|
1090
1196
|
rest = {
|
|
1091
1197
|
n: 1,
|
|
@@ -1178,6 +1284,9 @@ function WOrmReladb(opt = {}) {
|
|
|
1178
1284
|
|
|
1179
1285
|
try {
|
|
1180
1286
|
|
|
1287
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
1288
|
+
procClosed(instance)
|
|
1289
|
+
|
|
1181
1290
|
//check
|
|
1182
1291
|
if (si.err) {
|
|
1183
1292
|
throw si.err
|
|
@@ -1282,6 +1391,9 @@ function WOrmReladb(opt = {}) {
|
|
|
1282
1391
|
|
|
1283
1392
|
try {
|
|
1284
1393
|
|
|
1394
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
1395
|
+
procClosed(instance)
|
|
1396
|
+
|
|
1285
1397
|
//check
|
|
1286
1398
|
if (si.err) {
|
|
1287
1399
|
throw si.err
|
|
@@ -1346,6 +1458,11 @@ function WOrmReladb(opt = {}) {
|
|
|
1346
1458
|
})
|
|
1347
1459
|
.catch((err) => {
|
|
1348
1460
|
|
|
1461
|
+
//check, 連線層錯誤影響後續所有筆數, 依T4屬整批性錯誤, 往外拋而不降為本筆ok為0
|
|
1462
|
+
if (isBatchLevelError(err)) {
|
|
1463
|
+
throw err
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1349
1466
|
//rest, 本筆失敗不中斷整批
|
|
1350
1467
|
rest = {
|
|
1351
1468
|
n: 1,
|
|
@@ -1435,6 +1552,9 @@ function WOrmReladb(opt = {}) {
|
|
|
1435
1552
|
|
|
1436
1553
|
try {
|
|
1437
1554
|
|
|
1555
|
+
//check, 實例已關閉屬整批性錯誤, 於入口快速失敗
|
|
1556
|
+
procClosed(instance)
|
|
1557
|
+
|
|
1438
1558
|
//check
|
|
1439
1559
|
if (si.err) {
|
|
1440
1560
|
throw si.err
|
package/test/api-suite.mjs
CHANGED
|
@@ -307,6 +307,151 @@ export function defineSuites(label, getOpt) {
|
|
|
307
307
|
})
|
|
308
308
|
|
|
309
309
|
|
|
310
|
+
describe(`${label} insert returnList`, function() {
|
|
311
|
+
|
|
312
|
+
let w = null
|
|
313
|
+
|
|
314
|
+
before(async function() {
|
|
315
|
+
w = wo(getOpt())
|
|
316
|
+
await w.createStorage()
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
beforeEach(async function() {
|
|
320
|
+
await w.delAll()
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('兩種取值下之形狀: 預設回單一物件, 開啟回陣列', async function() {
|
|
324
|
+
let m1 = await w.insert([{ id: 'k1' }, { id: 'k2' }])
|
|
325
|
+
assert.ok(!Array.isArray(m1))
|
|
326
|
+
await w.delAll()
|
|
327
|
+
let m2 = await w.insert([{ id: 'k1' }, { id: 'k2' }], { returnList: true })
|
|
328
|
+
assert.ok(Array.isArray(m2))
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
it('開啟時與輸入等長保序且對位正確', async function() {
|
|
332
|
+
await w.insert({ id: 'k2', name: 'pre' })
|
|
333
|
+
let msg = await w.insert([{ id: 'k1' }, { id: 'k2' }, { id: 'k3' }], { returnList: true })
|
|
334
|
+
assert.strictEqual(msg.length, 3)
|
|
335
|
+
assert.deepStrictEqual(msg, [
|
|
336
|
+
{ n: 1, nInserted: 1, ok: 1 },
|
|
337
|
+
{ n: 1, nInserted: 0, ok: 1 }, //k2已存在
|
|
338
|
+
{ n: 1, nInserted: 1, ok: 1 },
|
|
339
|
+
])
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('同批重複主鍵僅首筆nInserted為1', async function() {
|
|
343
|
+
let msg = await w.insert([{ id: 'k1' }, { id: 'k1' }, { id: 'k2' }], { returnList: true })
|
|
344
|
+
assert.deepStrictEqual(msg, [
|
|
345
|
+
{ n: 1, nInserted: 1, ok: 1 },
|
|
346
|
+
{ n: 1, nInserted: 0, ok: 1 },
|
|
347
|
+
{ n: 1, nInserted: 1, ok: 1 },
|
|
348
|
+
])
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('filter計數等於聚合模式之nInserted', async function() {
|
|
352
|
+
await w.insert({ id: 'k2', name: 'pre' })
|
|
353
|
+
let rs = [{ id: 'k1' }, { id: 'k2' }, { id: 'k3' }, { id: 'k1' }]
|
|
354
|
+
let ml = await w.insert(rs, { returnList: true })
|
|
355
|
+
await w.delAll()
|
|
356
|
+
await w.insert({ id: 'k2', name: 'pre' })
|
|
357
|
+
let ma = await w.insert(rs)
|
|
358
|
+
assert.strictEqual(ml.filter((v) => v.nInserted === 1).length, ma.nInserted)
|
|
359
|
+
assert.strictEqual(ml.length, ma.n)
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('輸入無效時開啟回[], 關閉回聚合空結果', async function() {
|
|
363
|
+
for (let v of [null, undefined, '', 0, [], {}]) {
|
|
364
|
+
assert.deepStrictEqual(await w.insert(v, { returnList: true }), [])
|
|
365
|
+
assert.deepStrictEqual(await w.insert(v), { n: 0, nInserted: 0, ok: 1 })
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('逐筆元素鍵集合恰為{n,nInserted,ok}', async function() {
|
|
370
|
+
let msg = await w.insert([{ id: 'k1' }], { returnList: true })
|
|
371
|
+
assert.deepStrictEqual(Object.keys(msg[0]).sort(), ['n', 'nInserted', 'ok'])
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
it('change事件之res即實際回傳值', async function() {
|
|
375
|
+
let evs = []
|
|
376
|
+
let fn = (mode, data, res) => evs.push(res)
|
|
377
|
+
w.on('change', fn)
|
|
378
|
+
let msg = await w.insert([{ id: 'k1' }], { returnList: true })
|
|
379
|
+
w.off('change', fn)
|
|
380
|
+
assert.strictEqual(evs.length, 1)
|
|
381
|
+
assert.deepStrictEqual(evs[0], msg)
|
|
382
|
+
assert.ok(Array.isArray(evs[0]))
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('autoGenPk為false且未帶主鍵時仍為整批reject而不降為逐筆', async function() {
|
|
386
|
+
let wNoGen = wo(getOpt({ autoGenPk: false }))
|
|
387
|
+
let r = await wNoGen.insert([{ id: 'k1' }, { name: 'no-pk' }], { returnList: true })
|
|
388
|
+
.then(() => null)
|
|
389
|
+
.catch((err) => err)
|
|
390
|
+
assert.ok(r !== null, '未reject')
|
|
391
|
+
assert.ok(String(r.message || r).indexOf('autoGenPk is false') >= 0)
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
describe(`${label} closed instance`, function() {
|
|
398
|
+
|
|
399
|
+
let w = null
|
|
400
|
+
|
|
401
|
+
before(async function() {
|
|
402
|
+
w = wo(getOpt())
|
|
403
|
+
await w.createStorage()
|
|
404
|
+
await w.delAll()
|
|
405
|
+
await w.insert([{ id: 'k1', name: 'A' }, { id: 'k2', name: 'B' }])
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it('close後七函數皆須以整批性錯誤reject, 不得以正常空結果或逐筆ok為0回應', async function() {
|
|
409
|
+
let instance = await w.init()
|
|
410
|
+
await instance.close()
|
|
411
|
+
let cs = { instance }
|
|
412
|
+
|
|
413
|
+
let chk = async (t, fn) => {
|
|
414
|
+
let r = await fn()
|
|
415
|
+
.then((v) => ({ RESOLVE: v }))
|
|
416
|
+
.catch((err) => ({ REJECT: String(err.message || err) }))
|
|
417
|
+
assert.ok(r.REJECT !== undefined, `${t} 未reject, 實得 ${JSON.stringify(r.RESOLVE)}`)
|
|
418
|
+
assert.ok(r.REJECT.indexOf('closed') >= 0, `${t} 之錯誤訊息未指明已關閉: ${r.REJECT}`)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
await chk('select', () => w.select(null, cs))
|
|
422
|
+
await chk('selectByPk', () => w.selectByPk('k1', cs))
|
|
423
|
+
await chk('insert', () => w.insert({ id: 'k9' }, cs))
|
|
424
|
+
await chk('insertBulk', () => w.insertBulk({ id: 'k8' }, cs))
|
|
425
|
+
await chk('save', () => w.save({ id: 'k1', name: 'Z' }, cs))
|
|
426
|
+
await chk('del', () => w.del({ id: 'k1' }, cs))
|
|
427
|
+
await chk('delAll', () => w.delAll({}, cs))
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it('close後selectByPk給無效主鍵亦須reject而非回null', async function() {
|
|
431
|
+
let instance = await w.init()
|
|
432
|
+
await instance.close()
|
|
433
|
+
let r = await w.selectByPk(null, { instance })
|
|
434
|
+
.then((v) => ({ RESOLVE: v }))
|
|
435
|
+
.catch((err) => ({ REJECT: String(err.message || err) }))
|
|
436
|
+
assert.ok(r.REJECT !== undefined, `未reject, 實得 ${JSON.stringify(r.RESOLVE)}`)
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
it('close後亦須發出error事件', async function() {
|
|
440
|
+
let instance = await w.init()
|
|
441
|
+
await instance.close()
|
|
442
|
+
let evs = []
|
|
443
|
+
let fn = (mode, data, err) => evs.push({ mode, err })
|
|
444
|
+
w.on('error', fn)
|
|
445
|
+
await w.del({ id: 'k1' }, { instance }).catch(() => {})
|
|
446
|
+
w.off('error', fn)
|
|
447
|
+
assert.strictEqual(evs.length, 1)
|
|
448
|
+
assert.strictEqual(evs[0].mode, 'del')
|
|
449
|
+
assert.ok(evs[0].err.indexOf('closed') >= 0)
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
|
|
310
455
|
describe(`${label} insertBulk`, function() {
|
|
311
456
|
|
|
312
457
|
let w = null
|