w-orm-mongodb 1.1.41 → 1.1.43
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 +46 -4
- package/dist/w-orm-mongodb.umd.js +2 -2
- package/dist/w-orm-mongodb.umd.js.map +1 -1
- package/docs/WOrmMongodb.html +181 -13
- package/docs/WOrmMongodb.mjs.html +213 -5
- package/docs/index.html +2 -2
- package/g-basic.mjs +7 -1
- package/g-gfs.mjs +7 -1
- package/package.json +1 -1
- package/src/WOrmMongodb.mjs +211 -3
- package/test/api-basic.test.mjs +200 -0
- package/test/api-insertbulk-rs.test.mjs +290 -0
- package/test/lib/api-setup.mjs +93 -12
package/src/WOrmMongodb.mjs
CHANGED
|
@@ -2,13 +2,14 @@ import mongodb from 'mongodb'
|
|
|
2
2
|
import stream from 'stream'
|
|
3
3
|
import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
4
4
|
import every from 'lodash-es/every.js'
|
|
5
|
+
import filter from 'lodash-es/filter.js'
|
|
5
6
|
import get from 'lodash-es/get.js'
|
|
6
7
|
import map from 'lodash-es/map.js'
|
|
7
8
|
import omit from 'lodash-es/omit.js'
|
|
8
9
|
import size from 'lodash-es/size.js'
|
|
9
10
|
import evem from 'wsemi/src/evem.mjs'
|
|
10
11
|
import genPm from 'wsemi/src/genPm.mjs'
|
|
11
|
-
import
|
|
12
|
+
import genIDSeq from 'wsemi/src/genIDSeq.mjs'
|
|
12
13
|
import isbol from 'wsemi/src/isbol.mjs'
|
|
13
14
|
import isestr from 'wsemi/src/isestr.mjs'
|
|
14
15
|
import isarr from 'wsemi/src/isarr.mjs'
|
|
@@ -63,6 +64,10 @@ function WOrmMongodb(opt = {}) {
|
|
|
63
64
|
let _indexGfsReady = false
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
//_canUseTx, 拓樸判定只須一次, 以旗標記錄避免每次操作皆多一次round-trip
|
|
68
|
+
let _canUseTx = null
|
|
69
|
+
|
|
70
|
+
|
|
66
71
|
//ee, 採wsemi之evem(即eventemitter3), 其於'error'無監聽者時僅回傳false而不拋出,
|
|
67
72
|
//故本套件之操作行為不因呼叫端有無註冊監聽而改變; Node內建之EventEmitter具該拋出語義, 不可用
|
|
68
73
|
let ee = evem()
|
|
@@ -154,8 +159,8 @@ function WOrmMongodb(opt = {}) {
|
|
|
154
159
|
throw new Error(`invalid data[${k}].id, autoGenPk is false`)
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
//
|
|
158
|
-
v.id =
|
|
162
|
+
//genIDSeq
|
|
163
|
+
v.id = genIDSeq()
|
|
159
164
|
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -514,6 +519,208 @@ function WOrmMongodb(opt = {}) {
|
|
|
514
519
|
}
|
|
515
520
|
|
|
516
521
|
|
|
522
|
+
/**
|
|
523
|
+
* 判定本次部署是否支援交易
|
|
524
|
+
* 註: MongoDB之交易須replica set或分片叢集,standalone不支援
|
|
525
|
+
* 判定依據為hello回應:replica set帶setName,連至mongos者msg為isdbgrid,standalone兩者皆無
|
|
526
|
+
*
|
|
527
|
+
* @ignore
|
|
528
|
+
* @param {Object} client 輸入MongoClient物件
|
|
529
|
+
* @returns {Promise} 回傳Promise,resolve回傳是否支援交易布林值,reject回傳錯誤訊息
|
|
530
|
+
*/
|
|
531
|
+
async function canUseTx(client) {
|
|
532
|
+
|
|
533
|
+
//check
|
|
534
|
+
if (isbol(_canUseTx)) {
|
|
535
|
+
return _canUseTx
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
//hello
|
|
539
|
+
let hello = await client.db(opt.db).admin().command({ hello: 1 })
|
|
540
|
+
|
|
541
|
+
//_canUseTx
|
|
542
|
+
_canUseTx = isestr(get(hello, 'setName')) || get(hello, 'msg') === 'isdbgrid'
|
|
543
|
+
|
|
544
|
+
return _canUseTx
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* 以交易達成insertBulk之全有全無
|
|
550
|
+
* 交易內任一筆失敗即整批回滾,故不會寫入任何一筆,無須補償動作
|
|
551
|
+
*
|
|
552
|
+
* @ignore
|
|
553
|
+
* @param {Object} client 輸入MongoClient物件
|
|
554
|
+
* @param {Object} collection 輸入資料表物件
|
|
555
|
+
* @param {Array} data 輸入數據陣列
|
|
556
|
+
* @returns {Promise} 回傳Promise,resolve回傳undefined,reject回傳錯誤訊息
|
|
557
|
+
*/
|
|
558
|
+
async function _insertBulkByTx(client, collection, data) {
|
|
559
|
+
|
|
560
|
+
//session
|
|
561
|
+
let session = client.startSession()
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
|
|
565
|
+
//withTransaction, ordered:true令首筆衝突即停止, 由交易回滾保證未寫入任何一筆
|
|
566
|
+
await session.withTransaction(async () => {
|
|
567
|
+
await collection.insertMany(data, { session, ordered: true })
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
}
|
|
571
|
+
finally {
|
|
572
|
+
await session.endSession()
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* 以補償動作達成insertBulk之全有全無,供無交易可用之standalone使用
|
|
580
|
+
* 註: 補償係刪除本次呼叫已寫入者,其_id由驅動於送出前在用戶端產生,
|
|
581
|
+
* 與呼叫前既有數據之_id必不相同,故縱使該筆之id已存在亦不會誤刪既有數據;
|
|
582
|
+
* 刪除未寫入者為無操作,故不須精確得知哪幾筆已寫入
|
|
583
|
+
* 註: 行程若於補償途中中止(斷電、強制終止),已寫入之部份可能殘留,此為無交易可用之固有限制
|
|
584
|
+
*
|
|
585
|
+
* @ignore
|
|
586
|
+
* @param {Object} collection 輸入資料表物件
|
|
587
|
+
* @param {Array} data 輸入數據陣列
|
|
588
|
+
* @returns {Promise} 回傳Promise,resolve回傳undefined,reject回傳錯誤訊息
|
|
589
|
+
*/
|
|
590
|
+
async function _insertBulkByCompensate(collection, data) {
|
|
591
|
+
|
|
592
|
+
//errIns
|
|
593
|
+
let errIns = null
|
|
594
|
+
|
|
595
|
+
try {
|
|
596
|
+
await collection.insertMany(data, { ordered: false })
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
errIns = err
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
//check, 全數插入成功即無須補償
|
|
603
|
+
if (errIns === null) {
|
|
604
|
+
return
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
//idDels, 取本次由驅動所產生之全部_id
|
|
608
|
+
let idDels = map(data, function(v) {
|
|
609
|
+
return v._id
|
|
610
|
+
})
|
|
611
|
+
idDels = filter(idDels, function(v) {
|
|
612
|
+
return v !== undefined && v !== null
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
//補償, 刪除本次已寫入者
|
|
616
|
+
if (size(idDels) > 0) {
|
|
617
|
+
await collection.deleteMany({ _id: { $in: idDels } })
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
throw errIns
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* 批次插入數據,全批視為一個單位:全部插入成功,或一筆都不寫入
|
|
626
|
+
* 任一筆之id已存在(含同批含重複id)即以reject拋出整批性錯誤,且不寫入任何一筆
|
|
627
|
+
* 註: 本函數非insert之加速版,兩者衝突政策不同——insert跳過已存在者而整批ok為1,
|
|
628
|
+
* 本函數則整批reject;需要逐筆處置者改用insert
|
|
629
|
+
* 註: n為輸入筆數,nInserted於成功時恆等於n;不提供逐筆結果,故不出現ok為0與err
|
|
630
|
+
* 註: opt.autoGenPk為true(預設)時未帶有效id者自動產生,為false時未帶有效id即reject且同批皆不寫入
|
|
631
|
+
* 註: 全有全無之達成方式依部署而異——具replica set或分片叢集者以交易包覆,
|
|
632
|
+
* standalone無交易可用而以補償動作達成,其限制詳見_insertBulkByCompensate
|
|
633
|
+
*
|
|
634
|
+
* @memberOf WOrmMongodb
|
|
635
|
+
* @param {Object|Array} data 輸入數據物件或陣列
|
|
636
|
+
* @returns {Promise} 回傳Promise,resolve回傳插入結果,reject回傳錯誤訊息
|
|
637
|
+
*/
|
|
638
|
+
async function insertBulk(data) {
|
|
639
|
+
let isErr = false
|
|
640
|
+
|
|
641
|
+
//check
|
|
642
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
643
|
+
return {
|
|
644
|
+
n: 0,
|
|
645
|
+
nInserted: 0,
|
|
646
|
+
ok: 1,
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
//cloneDeep
|
|
651
|
+
data = cloneDeep(data)
|
|
652
|
+
|
|
653
|
+
//client
|
|
654
|
+
let client = new MongoClient(opt.url)
|
|
655
|
+
|
|
656
|
+
//res
|
|
657
|
+
let res = null
|
|
658
|
+
try {
|
|
659
|
+
|
|
660
|
+
//connect, 令連線失敗於寫入前即拋出, 屬影響全部數據之整批性錯誤
|
|
661
|
+
await client.connect()
|
|
662
|
+
|
|
663
|
+
//database, collection
|
|
664
|
+
let database = client.db(opt.db)
|
|
665
|
+
let collection = database.collection(opt.cl)
|
|
666
|
+
|
|
667
|
+
//check
|
|
668
|
+
if (!isarr(data)) {
|
|
669
|
+
data = [data]
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
//check id, 須於任何寫入之前一次完成
|
|
673
|
+
data = map(data, procPk)
|
|
674
|
+
|
|
675
|
+
//ensureIndex
|
|
676
|
+
await ensureIndex(collection)
|
|
677
|
+
|
|
678
|
+
//nAll, n之基準為輸入筆數
|
|
679
|
+
let nAll = size(data)
|
|
680
|
+
|
|
681
|
+
//check, 有交易可用者一律優先採用交易, 其回滾即為全有全無之保證
|
|
682
|
+
let bTx = await canUseTx(client)
|
|
683
|
+
if (bTx) {
|
|
684
|
+
await _insertBulkByTx(client, collection, data)
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
await _insertBulkByCompensate(collection, data)
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
//res, 執行至此表全數插入成功, 故nInserted恆等於n
|
|
691
|
+
res = {
|
|
692
|
+
n: nAll,
|
|
693
|
+
nInserted: nAll,
|
|
694
|
+
ok: 1,
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
}
|
|
698
|
+
catch (err) {
|
|
699
|
+
isErr = true
|
|
700
|
+
res = err
|
|
701
|
+
}
|
|
702
|
+
finally {
|
|
703
|
+
await client.close()
|
|
704
|
+
client = null
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
//emit
|
|
708
|
+
if (!isErr) {
|
|
709
|
+
emitChange('insertBulk', data, res)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
//check
|
|
713
|
+
if (isErr) {
|
|
714
|
+
|
|
715
|
+
//emit, 整批性錯誤須於reject之前發出
|
|
716
|
+
emitError('insertBulk', data, res)
|
|
717
|
+
|
|
718
|
+
return Promise.reject(res)
|
|
719
|
+
}
|
|
720
|
+
return res
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
|
|
517
724
|
/**
|
|
518
725
|
* 儲存單筆數據,由MongoDB於單一updateOne內原子完成[查找id]與[更新或插入]
|
|
519
726
|
* 註: MongoDB單一文件操作本即為原子,故不須開啟transaction(transaction另須replica set,standalone不支援)
|
|
@@ -1380,6 +1587,7 @@ function WOrmMongodb(opt = {}) {
|
|
|
1380
1587
|
ee.select = select
|
|
1381
1588
|
ee.selectByPk = selectByPk
|
|
1382
1589
|
ee.insert = insert
|
|
1590
|
+
ee.insertBulk = insertBulk
|
|
1383
1591
|
ee.save = save
|
|
1384
1592
|
ee.del = del
|
|
1385
1593
|
ee.delAll = delAll
|
package/test/api-basic.test.mjs
CHANGED
|
@@ -599,6 +599,206 @@ describe('insert', function() {
|
|
|
599
599
|
})
|
|
600
600
|
|
|
601
601
|
|
|
602
|
+
//insertBulk之語義與insert不同: insert跳過已存在者而整批ok為1, insertBulk則整批reject且不寫入任何一筆
|
|
603
|
+
//本檔之容器為standalone, 無交易可用, 故走補償動作路徑; 交易路徑另見api-insertbulk-rs.test.mjs
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
describe('insertBulk', function() {
|
|
607
|
+
let rt = null
|
|
608
|
+
let vans = {}
|
|
609
|
+
let vget = {}
|
|
610
|
+
|
|
611
|
+
before(async function() {
|
|
612
|
+
this.timeout(120000)
|
|
613
|
+
|
|
614
|
+
let cl = 'bulkcnt'
|
|
615
|
+
let wo = WOrm(genOpt(cl))
|
|
616
|
+
await wo.delAll()
|
|
617
|
+
|
|
618
|
+
//全新3筆, nInserted須等於n
|
|
619
|
+
vget[1] = await wo.insertBulk([
|
|
620
|
+
{ id: 'b1', name: 'peter' },
|
|
621
|
+
{ id: 'b2', name: 'rosemary' },
|
|
622
|
+
{ id: 'b3', name: 'kettle' },
|
|
623
|
+
])
|
|
624
|
+
vget[2] = (await wo.select()).length
|
|
625
|
+
|
|
626
|
+
//撞既有主鍵須整批reject
|
|
627
|
+
rt = null
|
|
628
|
+
let nBefore = (await wo.select()).length
|
|
629
|
+
await wo.insertBulk([
|
|
630
|
+
{ id: 'b4', name: 'new1' },
|
|
631
|
+
{ id: 'b2', name: 'dup' },
|
|
632
|
+
{ id: 'b5', name: 'new2' },
|
|
633
|
+
])
|
|
634
|
+
.then(function(msg) {
|
|
635
|
+
rt = `不應resolve: ${JSON.stringify(msg)}`
|
|
636
|
+
})
|
|
637
|
+
.catch(function(msg) {
|
|
638
|
+
rt = msg.toString()
|
|
639
|
+
})
|
|
640
|
+
vget[3] = rt.indexOf('E11000') >= 0 || rt.indexOf('duplicate key') >= 0
|
|
641
|
+
|
|
642
|
+
//失敗後資料表不得有任何新增
|
|
643
|
+
vget[4] = (await wo.select()).length - nBefore
|
|
644
|
+
vget[5] = [
|
|
645
|
+
await wo.selectByPk('b4'),
|
|
646
|
+
await wo.selectByPk('b5'),
|
|
647
|
+
]
|
|
648
|
+
|
|
649
|
+
//撞既有主鍵者本身不得被改動
|
|
650
|
+
vget[6] = (await wo.selectByPk('b2')).name
|
|
651
|
+
|
|
652
|
+
//同批含重複主鍵須整批reject
|
|
653
|
+
rt = null
|
|
654
|
+
nBefore = (await wo.select()).length
|
|
655
|
+
await wo.insertBulk([
|
|
656
|
+
{ id: 'b6', name: 'a' },
|
|
657
|
+
{ id: 'b6', name: 'b' },
|
|
658
|
+
{ id: 'b7', name: 'c' },
|
|
659
|
+
])
|
|
660
|
+
.then(function(msg) {
|
|
661
|
+
rt = `不應resolve: ${JSON.stringify(msg)}`
|
|
662
|
+
})
|
|
663
|
+
.catch(function(msg) {
|
|
664
|
+
rt = msg.toString()
|
|
665
|
+
})
|
|
666
|
+
vget[7] = rt.indexOf('E11000') >= 0 || rt.indexOf('duplicate key') >= 0
|
|
667
|
+
vget[8] = (await wo.select()).length - nBefore
|
|
668
|
+
vget[9] = [
|
|
669
|
+
await wo.selectByPk('b6'),
|
|
670
|
+
await wo.selectByPk('b7'),
|
|
671
|
+
]
|
|
672
|
+
|
|
673
|
+
//單一物件輸入亦須可用
|
|
674
|
+
vget[10] = await wo.insertBulk({ id: 'b8', name: 'single' })
|
|
675
|
+
|
|
676
|
+
//輸入無效視為空結果
|
|
677
|
+
vget[11] = await wo.insertBulk(null)
|
|
678
|
+
|
|
679
|
+
//鍵集合須與insert完全相同
|
|
680
|
+
let ri = await wo.insert({ id: 'b9', name: 'x' })
|
|
681
|
+
vget[12] = [genKeys(vget[1]), genKeys(vget[10]), genKeys(vget[11]), genKeys(ri)]
|
|
682
|
+
|
|
683
|
+
//autoGenPk預設為true, 未帶id者自動產生
|
|
684
|
+
vget[13] = await wo.insertBulk([{ name: 'nopk1' }, { name: 'nopk2' }])
|
|
685
|
+
|
|
686
|
+
//autoGenPk為false且未帶id者須reject, 且同批之有效筆數不得被寫入
|
|
687
|
+
let woOff = WOrm(genOptPk('bulkpkoff', false))
|
|
688
|
+
await woOff.delAll()
|
|
689
|
+
rt = null
|
|
690
|
+
await woOff.insertBulk([
|
|
691
|
+
{ id: 'p-ok1', name: 'ok1' },
|
|
692
|
+
{ name: 'no-id' },
|
|
693
|
+
])
|
|
694
|
+
.then(function(msg) {
|
|
695
|
+
rt = `不應resolve: ${JSON.stringify(msg)}`
|
|
696
|
+
})
|
|
697
|
+
.catch(function(msg) {
|
|
698
|
+
rt = msg.toString()
|
|
699
|
+
})
|
|
700
|
+
vget[14] = rt
|
|
701
|
+
vget[15] = await woOff.selectByPk('p-ok1')
|
|
702
|
+
|
|
703
|
+
//事件, 成功時發change, 失敗時發error且mode為insertBulk
|
|
704
|
+
let woEv = WOrm(genOpt('bulkevent'))
|
|
705
|
+
await woEv.delAll()
|
|
706
|
+
let evs = []
|
|
707
|
+
woEv.on('change', function(mode) {
|
|
708
|
+
evs.push(`change:${mode}`)
|
|
709
|
+
})
|
|
710
|
+
woEv.on('error', function(mode) {
|
|
711
|
+
evs.push(`error:${mode}`)
|
|
712
|
+
})
|
|
713
|
+
await woEv.insertBulk({ id: 'e1', name: 'a' })
|
|
714
|
+
await woEv.insertBulk({ id: 'e1', name: 'b' }).catch(() => {})
|
|
715
|
+
vget[16] = evs
|
|
716
|
+
|
|
717
|
+
})
|
|
718
|
+
|
|
719
|
+
vans[1] = { n: 3, nInserted: 3, ok: 1 }
|
|
720
|
+
it(`should get ${JSON.stringify(vans[1])} for insertBulk 3 new records`, async function() {
|
|
721
|
+
assert.strict.deepStrictEqual(vget[1], vans[1])
|
|
722
|
+
})
|
|
723
|
+
|
|
724
|
+
vans[2] = 3
|
|
725
|
+
it(`should get ${JSON.stringify(vans[2])} for records after insertBulk`, async function() {
|
|
726
|
+
assert.strict.deepStrictEqual(vget[2], vans[2])
|
|
727
|
+
})
|
|
728
|
+
|
|
729
|
+
vans[3] = true
|
|
730
|
+
it(`should get ${JSON.stringify(vans[3])} for reject of insertBulk with existed id`, async function() {
|
|
731
|
+
assert.strict.deepStrictEqual(vget[3], vans[3])
|
|
732
|
+
})
|
|
733
|
+
|
|
734
|
+
vans[4] = 0
|
|
735
|
+
it(`should get ${JSON.stringify(vans[4])} for no record added after rejected insertBulk`, async function() {
|
|
736
|
+
assert.strict.deepStrictEqual(vget[4], vans[4])
|
|
737
|
+
})
|
|
738
|
+
|
|
739
|
+
vans[5] = [null, null]
|
|
740
|
+
it(`should get ${JSON.stringify(vans[5])} for not writing any record in rejected insertBulk`, async function() {
|
|
741
|
+
assert.strict.deepStrictEqual(vget[5], vans[5])
|
|
742
|
+
})
|
|
743
|
+
|
|
744
|
+
vans[6] = 'rosemary'
|
|
745
|
+
it(`should get ${JSON.stringify(vans[6])} for not modifying existed record by rejected insertBulk`, async function() {
|
|
746
|
+
assert.strict.deepStrictEqual(vget[6], vans[6])
|
|
747
|
+
})
|
|
748
|
+
|
|
749
|
+
vans[7] = true
|
|
750
|
+
it(`should get ${JSON.stringify(vans[7])} for reject of insertBulk with duplicated id in same batch`, async function() {
|
|
751
|
+
assert.strict.deepStrictEqual(vget[7], vans[7])
|
|
752
|
+
})
|
|
753
|
+
|
|
754
|
+
vans[8] = 0
|
|
755
|
+
it(`should get ${JSON.stringify(vans[8])} for no record added after insertBulk with duplicated id`, async function() {
|
|
756
|
+
assert.strict.deepStrictEqual(vget[8], vans[8])
|
|
757
|
+
})
|
|
758
|
+
|
|
759
|
+
vans[9] = [null, null]
|
|
760
|
+
it(`should get ${JSON.stringify(vans[9])} for not writing any record by duplicated id in same batch`, async function() {
|
|
761
|
+
assert.strict.deepStrictEqual(vget[9], vans[9])
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
vans[10] = { n: 1, nInserted: 1, ok: 1 }
|
|
765
|
+
it(`should get ${JSON.stringify(vans[10])} for insertBulk with single object`, async function() {
|
|
766
|
+
assert.strict.deepStrictEqual(vget[10], vans[10])
|
|
767
|
+
})
|
|
768
|
+
|
|
769
|
+
vans[11] = { n: 0, nInserted: 0, ok: 1 }
|
|
770
|
+
it(`should get ${JSON.stringify(vans[11])} for insertBulk with invalid data`, async function() {
|
|
771
|
+
assert.strict.deepStrictEqual(vget[11], vans[11])
|
|
772
|
+
})
|
|
773
|
+
|
|
774
|
+
vans[12] = ['n,nInserted,ok', 'n,nInserted,ok', 'n,nInserted,ok', 'n,nInserted,ok']
|
|
775
|
+
it(`should get ${JSON.stringify(vans[12])} for same key set between insertBulk and insert`, async function() {
|
|
776
|
+
assert.strict.deepStrictEqual(vget[12], vans[12])
|
|
777
|
+
})
|
|
778
|
+
|
|
779
|
+
vans[13] = { n: 2, nInserted: 2, ok: 1 }
|
|
780
|
+
it(`should get ${JSON.stringify(vans[13])} for insertBulk without id by default autoGenPk`, async function() {
|
|
781
|
+
assert.strict.deepStrictEqual(vget[13], vans[13])
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
vans[14] = 'Error: invalid data[1].id, autoGenPk is false'
|
|
785
|
+
it(`should get ${JSON.stringify(vans[14])} for insertBulk without id by autoGenPk=false`, async function() {
|
|
786
|
+
assert.strict.deepStrictEqual(vget[14], vans[14])
|
|
787
|
+
})
|
|
788
|
+
|
|
789
|
+
vans[15] = null
|
|
790
|
+
it(`should get ${JSON.stringify(vans[15])} for not writing valid records in rejected insertBulk by autoGenPk`, async function() {
|
|
791
|
+
assert.strict.deepStrictEqual(vget[15], vans[15])
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
vans[16] = ['change:insertBulk', 'error:insertBulk']
|
|
795
|
+
it(`should get ${JSON.stringify(vans[16])} for events of insertBulk`, async function() {
|
|
796
|
+
assert.strict.deepStrictEqual(vget[16], vans[16])
|
|
797
|
+
})
|
|
798
|
+
|
|
799
|
+
})
|
|
800
|
+
|
|
801
|
+
|
|
602
802
|
describe('save', function() {
|
|
603
803
|
let vans = {}
|
|
604
804
|
let vget = {}
|