w-orm-postgresql 1.0.10 → 1.0.12
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 +57 -0
- package/dist/w-orm-postgresql.umd.js +2 -2
- package/dist/w-orm-postgresql.umd.js.map +1 -1
- package/docs/WOrmPostgresql.html +177 -10
- package/docs/WOrmPostgresql.mjs.html +313 -57
- package/docs/index.html +2 -2
- package/g-basic.mjs +57 -0
- package/package.json +1 -1
- package/src/WOrmPostgresql.mjs +310 -54
- package/test/api-postgresql.test.mjs +500 -0
|
@@ -957,6 +957,32 @@ describe('insert nInserted', function() {
|
|
|
957
957
|
let vdup = await wo.selectByPk('2025-02-01T00:05:00Z')
|
|
958
958
|
vget[8] = vdup.name
|
|
959
959
|
|
|
960
|
+
//跨批次之插入
|
|
961
|
+
//欄位數愈多則單一語句可送之筆數愈少, 以21欄之資料表令每批上限為3120筆, 送3200筆即須分為2批
|
|
962
|
+
//其中既有主鍵者跳過而其餘照插, 與insertBulk之全有全無不同
|
|
963
|
+
let clBat = 'insertbatch'
|
|
964
|
+
let woBat = WOrm(genOpt(clBat))
|
|
965
|
+
let vSample = { time: '2000-01-01T00:00:00Z' }
|
|
966
|
+
Array.from({ length: 20 }, (v, k) => k).forEach((k) => {
|
|
967
|
+
vSample[`f${k}`] = 'abc'
|
|
968
|
+
})
|
|
969
|
+
await woBat.createTable(clBat, null, vSample).catch(() => {})
|
|
970
|
+
await woBat.delAll()
|
|
971
|
+
|
|
972
|
+
//genRec
|
|
973
|
+
let genRec = (k) => {
|
|
974
|
+
let v = { time: new Date(Date.UTC(2025, 8, 1, 0, 0, 0) + k * 1000).toISOString() }
|
|
975
|
+
Array.from({ length: 20 }, (v2, k2) => k2).forEach((k2) => {
|
|
976
|
+
v[`f${k2}`] = `v${k}-${k2}`
|
|
977
|
+
})
|
|
978
|
+
return v
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
//先插入末筆之主鍵, 令後續之大批次於第2批撞上該筆
|
|
982
|
+
await woBat.insert(genRec(3199))
|
|
983
|
+
vget[9] = await woBat.insert(Array.from({ length: 3200 }, (v, k) => genRec(k)))
|
|
984
|
+
vget[10] = (await woBat.select()).length
|
|
985
|
+
|
|
960
986
|
})
|
|
961
987
|
|
|
962
988
|
vans[1] = { n: 3, nInserted: 3, ok: 1 }
|
|
@@ -999,6 +1025,16 @@ describe('insert nInserted', function() {
|
|
|
999
1025
|
assert.strict.deepStrictEqual(vget[8], vans[8])
|
|
1000
1026
|
})
|
|
1001
1027
|
|
|
1028
|
+
vans[9] = { n: 3200, nInserted: 3199, ok: 1 }
|
|
1029
|
+
it(`should get ${JSON.stringify(vans[9])} for insert across batches with 1 pk existed`, async function() {
|
|
1030
|
+
assert.strict.deepStrictEqual(vget[9], vans[9])
|
|
1031
|
+
})
|
|
1032
|
+
|
|
1033
|
+
vans[10] = 3200
|
|
1034
|
+
it(`should get ${JSON.stringify(vans[10])} for records after insert across batches`, async function() {
|
|
1035
|
+
assert.strict.deepStrictEqual(vget[10], vans[10])
|
|
1036
|
+
})
|
|
1037
|
+
|
|
1002
1038
|
})
|
|
1003
1039
|
|
|
1004
1040
|
|
|
@@ -1434,6 +1470,470 @@ describe('custom pk', function() {
|
|
|
1434
1470
|
})
|
|
1435
1471
|
|
|
1436
1472
|
|
|
1473
|
+
describe('events', function() {
|
|
1474
|
+
let vans = {}
|
|
1475
|
+
let vget = {}
|
|
1476
|
+
|
|
1477
|
+
before(async function() {
|
|
1478
|
+
this.timeout(120000)
|
|
1479
|
+
|
|
1480
|
+
//wo
|
|
1481
|
+
let cl = 'events'
|
|
1482
|
+
let wo = WOrm(genOpt(cl))
|
|
1483
|
+
|
|
1484
|
+
//createTable
|
|
1485
|
+
await wo.createTable(cl, null, {
|
|
1486
|
+
time: '2000-01-01T00:00:00Z',
|
|
1487
|
+
name: 'abc',
|
|
1488
|
+
value: 0.1,
|
|
1489
|
+
}).catch(() => {})
|
|
1490
|
+
await wo.delAll()
|
|
1491
|
+
|
|
1492
|
+
//evChange, evError, 收集事件供斷言
|
|
1493
|
+
let evChange = []
|
|
1494
|
+
let evError = []
|
|
1495
|
+
wo.on('change', (mode, data, res) => {
|
|
1496
|
+
evChange.push({ mode, res })
|
|
1497
|
+
})
|
|
1498
|
+
wo.on('error', (mode, data, err) => {
|
|
1499
|
+
evError.push({ mode, err })
|
|
1500
|
+
})
|
|
1501
|
+
|
|
1502
|
+
//reset
|
|
1503
|
+
let reset = () => {
|
|
1504
|
+
evChange = []
|
|
1505
|
+
evError = []
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
//t
|
|
1509
|
+
let t1 = '2025-07-01T00:00:00Z'
|
|
1510
|
+
let t2 = '2025-07-01T00:01:00Z'
|
|
1511
|
+
let t3 = '2025-07-01T00:02:00Z'
|
|
1512
|
+
let t4 = '2025-07-01T00:03:00Z'
|
|
1513
|
+
let tNone = '2025-07-01T23:00:00Z'
|
|
1514
|
+
|
|
1515
|
+
//insert正常, 發change且不發error
|
|
1516
|
+
reset()
|
|
1517
|
+
await wo.insert([
|
|
1518
|
+
{ time: t1, name: 'peter', value: 1 },
|
|
1519
|
+
{ time: t2, name: 'rosemary', value: 2 },
|
|
1520
|
+
])
|
|
1521
|
+
vget[1] = evChange.map((v) => v.mode)
|
|
1522
|
+
vget[2] = evError.length
|
|
1523
|
+
|
|
1524
|
+
//insert全數已存在為正常結果, 不得發error
|
|
1525
|
+
reset()
|
|
1526
|
+
await wo.insert({ time: t1, name: 'peter', value: 1 })
|
|
1527
|
+
vget[3] = evError.length
|
|
1528
|
+
|
|
1529
|
+
//save之逐筆插入另發mode為insert之change, 整批再發save
|
|
1530
|
+
reset()
|
|
1531
|
+
await wo.save({ time: t3, name: 'sandler' })
|
|
1532
|
+
vget[4] = evChange.map((v) => v.mode)
|
|
1533
|
+
|
|
1534
|
+
//save合併後內容相同為正常結果, 不得發error
|
|
1535
|
+
reset()
|
|
1536
|
+
await wo.save({ time: t3, name: 'sandler' })
|
|
1537
|
+
vget[5] = evError.length
|
|
1538
|
+
|
|
1539
|
+
//save逐筆失敗發error且整批仍resolve
|
|
1540
|
+
reset()
|
|
1541
|
+
let rsf = await wo.save([
|
|
1542
|
+
{ time: t1, name: 'ok' },
|
|
1543
|
+
{ time: t4, notexistcol: 1 },
|
|
1544
|
+
])
|
|
1545
|
+
vget[6] = evError.map((v) => v.mode)
|
|
1546
|
+
vget[7] = isestr(evError[0].err)
|
|
1547
|
+
vget[8] = rsf.length
|
|
1548
|
+
vget[9] = evChange.map((v) => v.mode)
|
|
1549
|
+
|
|
1550
|
+
//del未帶有效主鍵為逐筆失敗, 發error
|
|
1551
|
+
reset()
|
|
1552
|
+
await wo.del([{ name: 'no-pk' }])
|
|
1553
|
+
vget[10] = evError.map((v) => v.mode)
|
|
1554
|
+
|
|
1555
|
+
//del主鍵未命中為正常結果, 不得發error
|
|
1556
|
+
reset()
|
|
1557
|
+
await wo.del({ time: tNone })
|
|
1558
|
+
vget[11] = evError.length
|
|
1559
|
+
|
|
1560
|
+
//selectByPk查無數據為正常結果, 不得發error
|
|
1561
|
+
reset()
|
|
1562
|
+
await wo.selectByPk(tNone)
|
|
1563
|
+
vget[12] = evError.length
|
|
1564
|
+
|
|
1565
|
+
//selectByPk主鍵值無效為正常結果, 不得發error
|
|
1566
|
+
reset()
|
|
1567
|
+
await wo.selectByPk('abc')
|
|
1568
|
+
vget[13] = evError.length
|
|
1569
|
+
|
|
1570
|
+
//delAll條件無命中為正常結果, 不得發error
|
|
1571
|
+
reset()
|
|
1572
|
+
await wo.delAll({ name: 'notexist' })
|
|
1573
|
+
vget[14] = evError.length
|
|
1574
|
+
|
|
1575
|
+
//整批性錯誤於reject之前發出error
|
|
1576
|
+
reset()
|
|
1577
|
+
vget[15] = await wo.insert({ name: 'no-pk' })
|
|
1578
|
+
.then(() => 'resolved')
|
|
1579
|
+
.catch(() => 'rejected')
|
|
1580
|
+
vget[16] = evError.map((v) => v.mode)
|
|
1581
|
+
|
|
1582
|
+
//T10.1第2條, 操作行為不得因監聽者之有無而改變
|
|
1583
|
+
//woNo未註冊任何監聽, woOn註冊error監聽, 兩者之回傳值須完全相同
|
|
1584
|
+
let woNo = WOrm(genOpt(cl))
|
|
1585
|
+
let woOn = WOrm(genOpt(cl))
|
|
1586
|
+
woOn.on('error', () => {})
|
|
1587
|
+
|
|
1588
|
+
//整批性錯誤
|
|
1589
|
+
let rNo1 = await woNo.insert({ name: 'no-pk' })
|
|
1590
|
+
.then(() => 'resolved')
|
|
1591
|
+
.catch((err) => `rejected:${err}`)
|
|
1592
|
+
let rOn1 = await woOn.insert({ name: 'no-pk' })
|
|
1593
|
+
.then(() => 'resolved')
|
|
1594
|
+
.catch((err) => `rejected:${err}`)
|
|
1595
|
+
vget[17] = rNo1 === rOn1
|
|
1596
|
+
vget[18] = rNo1.indexOf('rejected:') === 0
|
|
1597
|
+
|
|
1598
|
+
//逐筆失敗
|
|
1599
|
+
let rNo2 = await woNo.del([{ name: 'no-pk' }])
|
|
1600
|
+
let rOn2 = await woOn.del([{ name: 'no-pk' }])
|
|
1601
|
+
vget[19] = JSON.stringify(rNo2) === JSON.stringify(rOn2)
|
|
1602
|
+
|
|
1603
|
+
//正常操作
|
|
1604
|
+
let rNo3 = await woNo.selectByPk(t1)
|
|
1605
|
+
let rOn3 = await woOn.selectByPk(t1)
|
|
1606
|
+
vget[20] = JSON.stringify(rNo3) === JSON.stringify(rOn3)
|
|
1607
|
+
|
|
1608
|
+
})
|
|
1609
|
+
|
|
1610
|
+
vans[1] = ['insert']
|
|
1611
|
+
it(`should get ${JSON.stringify(vans[1])} for change modes by insert`, async function() {
|
|
1612
|
+
assert.strict.deepStrictEqual(vget[1], vans[1])
|
|
1613
|
+
})
|
|
1614
|
+
|
|
1615
|
+
vans[2] = 0
|
|
1616
|
+
it(`should get ${JSON.stringify(vans[2])} for error count by insert`, async function() {
|
|
1617
|
+
assert.strict.deepStrictEqual(vget[2], vans[2])
|
|
1618
|
+
})
|
|
1619
|
+
|
|
1620
|
+
vans[3] = 0
|
|
1621
|
+
it(`should get ${JSON.stringify(vans[3])} for error count by insert with all existed`, async function() {
|
|
1622
|
+
assert.strict.deepStrictEqual(vget[3], vans[3])
|
|
1623
|
+
})
|
|
1624
|
+
|
|
1625
|
+
vans[4] = ['insert', 'save']
|
|
1626
|
+
it(`should get ${JSON.stringify(vans[4])} for change modes by save with autoInsert`, async function() {
|
|
1627
|
+
assert.strict.deepStrictEqual(vget[4], vans[4])
|
|
1628
|
+
})
|
|
1629
|
+
|
|
1630
|
+
vans[5] = 0
|
|
1631
|
+
it(`should get ${JSON.stringify(vans[5])} for error count by save with same content`, async function() {
|
|
1632
|
+
assert.strict.deepStrictEqual(vget[5], vans[5])
|
|
1633
|
+
})
|
|
1634
|
+
|
|
1635
|
+
vans[6] = ['save']
|
|
1636
|
+
it(`should get ${JSON.stringify(vans[6])} for error modes by save with 1 failed record`, async function() {
|
|
1637
|
+
assert.strict.deepStrictEqual(vget[6], vans[6])
|
|
1638
|
+
})
|
|
1639
|
+
|
|
1640
|
+
vans[7] = true
|
|
1641
|
+
it(`should get ${JSON.stringify(vans[7])} for err of error event being string`, async function() {
|
|
1642
|
+
assert.strict.deepStrictEqual(vget[7], vans[7])
|
|
1643
|
+
})
|
|
1644
|
+
|
|
1645
|
+
vans[8] = 2
|
|
1646
|
+
it(`should get ${JSON.stringify(vans[8])} for length of save result while 1 record failed`, async function() {
|
|
1647
|
+
assert.strict.deepStrictEqual(vget[8], vans[8])
|
|
1648
|
+
})
|
|
1649
|
+
|
|
1650
|
+
vans[9] = ['save']
|
|
1651
|
+
it(`should get ${JSON.stringify(vans[9])} for change modes by save while 1 record failed`, async function() {
|
|
1652
|
+
assert.strict.deepStrictEqual(vget[9], vans[9])
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
vans[10] = ['del']
|
|
1656
|
+
it(`should get ${JSON.stringify(vans[10])} for error modes by del without valid pk`, async function() {
|
|
1657
|
+
assert.strict.deepStrictEqual(vget[10], vans[10])
|
|
1658
|
+
})
|
|
1659
|
+
|
|
1660
|
+
vans[11] = 0
|
|
1661
|
+
it(`should get ${JSON.stringify(vans[11])} for error count by del with pk not existed`, async function() {
|
|
1662
|
+
assert.strict.deepStrictEqual(vget[11], vans[11])
|
|
1663
|
+
})
|
|
1664
|
+
|
|
1665
|
+
vans[12] = 0
|
|
1666
|
+
it(`should get ${JSON.stringify(vans[12])} for error count by selectByPk with pk not existed`, async function() {
|
|
1667
|
+
assert.strict.deepStrictEqual(vget[12], vans[12])
|
|
1668
|
+
})
|
|
1669
|
+
|
|
1670
|
+
vans[13] = 0
|
|
1671
|
+
it(`should get ${JSON.stringify(vans[13])} for error count by selectByPk with pk invalid`, async function() {
|
|
1672
|
+
assert.strict.deepStrictEqual(vget[13], vans[13])
|
|
1673
|
+
})
|
|
1674
|
+
|
|
1675
|
+
vans[14] = 0
|
|
1676
|
+
it(`should get ${JSON.stringify(vans[14])} for error count by delAll with find matched nothing`, async function() {
|
|
1677
|
+
assert.strict.deepStrictEqual(vget[14], vans[14])
|
|
1678
|
+
})
|
|
1679
|
+
|
|
1680
|
+
vans[15] = 'rejected'
|
|
1681
|
+
it(`should get ${JSON.stringify(vans[15])} for insert without valid pk`, async function() {
|
|
1682
|
+
assert.strict.deepStrictEqual(vget[15], vans[15])
|
|
1683
|
+
})
|
|
1684
|
+
|
|
1685
|
+
vans[16] = ['insert']
|
|
1686
|
+
it(`should get ${JSON.stringify(vans[16])} for error modes by insert without valid pk`, async function() {
|
|
1687
|
+
assert.strict.deepStrictEqual(vget[16], vans[16])
|
|
1688
|
+
})
|
|
1689
|
+
|
|
1690
|
+
vans[17] = true
|
|
1691
|
+
it(`should get ${JSON.stringify(vans[17])} for same reject value with and without error listener`, async function() {
|
|
1692
|
+
assert.strict.deepStrictEqual(vget[17], vans[17])
|
|
1693
|
+
})
|
|
1694
|
+
|
|
1695
|
+
vans[18] = true
|
|
1696
|
+
it(`should get ${JSON.stringify(vans[18])} for still rejecting without error listener`, async function() {
|
|
1697
|
+
assert.strict.deepStrictEqual(vget[18], vans[18])
|
|
1698
|
+
})
|
|
1699
|
+
|
|
1700
|
+
vans[19] = true
|
|
1701
|
+
it(`should get ${JSON.stringify(vans[19])} for same del result with and without error listener`, async function() {
|
|
1702
|
+
assert.strict.deepStrictEqual(vget[19], vans[19])
|
|
1703
|
+
})
|
|
1704
|
+
|
|
1705
|
+
vans[20] = true
|
|
1706
|
+
it(`should get ${JSON.stringify(vans[20])} for same selectByPk result with and without error listener`, async function() {
|
|
1707
|
+
assert.strict.deepStrictEqual(vget[20], vans[20])
|
|
1708
|
+
})
|
|
1709
|
+
|
|
1710
|
+
})
|
|
1711
|
+
|
|
1712
|
+
|
|
1713
|
+
describe('insertBulk', function() {
|
|
1714
|
+
let vans = {}
|
|
1715
|
+
let vget = {}
|
|
1716
|
+
|
|
1717
|
+
before(async function() {
|
|
1718
|
+
this.timeout(300000)
|
|
1719
|
+
|
|
1720
|
+
//wo
|
|
1721
|
+
let cl = 'bulk'
|
|
1722
|
+
let wo = WOrm(genOpt(cl))
|
|
1723
|
+
|
|
1724
|
+
//createTable
|
|
1725
|
+
await wo.createTable(cl, null, {
|
|
1726
|
+
time: '2000-01-01T00:00:00Z',
|
|
1727
|
+
name: 'abc',
|
|
1728
|
+
value: 0.1,
|
|
1729
|
+
}).catch(() => {})
|
|
1730
|
+
await wo.delAll()
|
|
1731
|
+
|
|
1732
|
+
//genTime, 依序產生不重複之主鍵值
|
|
1733
|
+
let genTime = (k) => {
|
|
1734
|
+
return new Date(Date.UTC(2025, 7, 1, 0, 0, 0) + k * 1000).toISOString()
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
//evChange, evError
|
|
1738
|
+
let evChange = []
|
|
1739
|
+
let evError = []
|
|
1740
|
+
wo.on('change', (mode) => {
|
|
1741
|
+
evChange.push(mode)
|
|
1742
|
+
})
|
|
1743
|
+
wo.on('error', (mode) => {
|
|
1744
|
+
evError.push(mode)
|
|
1745
|
+
})
|
|
1746
|
+
|
|
1747
|
+
//nRec, 取得目前筆數
|
|
1748
|
+
let nRec = async () => {
|
|
1749
|
+
return (await wo.select()).length
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
//無衝突, nInserted須等於n
|
|
1753
|
+
vget[1] = await wo.insertBulk([
|
|
1754
|
+
{ time: genTime(0), name: 'peter', value: 1 },
|
|
1755
|
+
{ time: genTime(1), name: 'rosemary', value: 2 },
|
|
1756
|
+
{ time: genTime(2), name: 'kettle', value: 3 },
|
|
1757
|
+
])
|
|
1758
|
+
vget[2] = await nRec()
|
|
1759
|
+
vget[3] = evChange.slice()
|
|
1760
|
+
|
|
1761
|
+
//撞既有主鍵, 整批reject且不寫入任何一筆
|
|
1762
|
+
evChange = []
|
|
1763
|
+
evError = []
|
|
1764
|
+
vget[4] = await wo.insertBulk([
|
|
1765
|
+
{ time: genTime(10), name: 'new-1', value: 11 },
|
|
1766
|
+
{ time: genTime(0), name: 'conflict', value: 12 },
|
|
1767
|
+
{ time: genTime(11), name: 'new-2', value: 13 },
|
|
1768
|
+
])
|
|
1769
|
+
.then(() => 'resolved')
|
|
1770
|
+
.catch(() => 'rejected')
|
|
1771
|
+
vget[5] = await nRec()
|
|
1772
|
+
vget[6] = evError.slice()
|
|
1773
|
+
vget[7] = evChange.slice()
|
|
1774
|
+
|
|
1775
|
+
//同批含重複主鍵, 亦視為衝突而整批reject
|
|
1776
|
+
evChange = []
|
|
1777
|
+
evError = []
|
|
1778
|
+
vget[8] = await wo.insertBulk([
|
|
1779
|
+
{ time: genTime(20), name: 'dup-1', value: 21 },
|
|
1780
|
+
{ time: genTime(20), name: 'dup-2', value: 22 },
|
|
1781
|
+
{ time: genTime(21), name: 'uniq', value: 23 },
|
|
1782
|
+
])
|
|
1783
|
+
.then(() => 'resolved')
|
|
1784
|
+
.catch(() => 'rejected')
|
|
1785
|
+
vget[9] = await nRec()
|
|
1786
|
+
|
|
1787
|
+
//未帶有效主鍵, 不補值而整批reject
|
|
1788
|
+
vget[10] = await wo.insertBulk([
|
|
1789
|
+
{ time: genTime(30), name: 'ok', value: 31 },
|
|
1790
|
+
{ name: 'no-pk', value: 32 },
|
|
1791
|
+
])
|
|
1792
|
+
.then(() => 'resolved')
|
|
1793
|
+
.catch(() => 'rejected')
|
|
1794
|
+
vget[11] = await nRec()
|
|
1795
|
+
|
|
1796
|
+
//輸入無效
|
|
1797
|
+
vget[12] = await wo.insertBulk(null)
|
|
1798
|
+
|
|
1799
|
+
//單一物件亦回傳單一物件
|
|
1800
|
+
vget[13] = await wo.insertBulk({ time: genTime(40), name: 'single', value: 41 })
|
|
1801
|
+
vget[14] = await nRec()
|
|
1802
|
+
|
|
1803
|
+
//跨批次之回滾
|
|
1804
|
+
//欄位數愈多則單一語句可送之筆數愈少, 以21欄之資料表令每批上限為3120筆,
|
|
1805
|
+
//送3200筆即須分為2批, 末筆撞既有主鍵時第1批已送出, 須由交易回滾方能維持全有全無
|
|
1806
|
+
let clBat = 'bulkbatch'
|
|
1807
|
+
let woBat = WOrm(genOpt(clBat))
|
|
1808
|
+
let vSample = { time: '2000-01-01T00:00:00Z' }
|
|
1809
|
+
Array.from({ length: 20 }, (v, k) => k).forEach((k) => {
|
|
1810
|
+
vSample[`f${k}`] = 'abc'
|
|
1811
|
+
})
|
|
1812
|
+
await woBat.createTable(clBat, null, vSample).catch(() => {})
|
|
1813
|
+
await woBat.delAll()
|
|
1814
|
+
|
|
1815
|
+
//genRec
|
|
1816
|
+
let genRec = (k) => {
|
|
1817
|
+
let v = { time: genTime(k) }
|
|
1818
|
+
Array.from({ length: 20 }, (v2, k2) => k2).forEach((k2) => {
|
|
1819
|
+
v[`f${k2}`] = `v${k}-${k2}`
|
|
1820
|
+
})
|
|
1821
|
+
return v
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
//先插入末筆之主鍵, 令後續之大批次於第2批撞上
|
|
1825
|
+
let kLast = 3199
|
|
1826
|
+
await woBat.insert(genRec(kLast))
|
|
1827
|
+
let nBefore = (await woBat.select()).length
|
|
1828
|
+
|
|
1829
|
+
//3200筆之批次, 末筆與既有衝突
|
|
1830
|
+
vget[15] = await woBat.insertBulk(Array.from({ length: 3200 }, (v, k) => genRec(k)))
|
|
1831
|
+
.then(() => 'resolved')
|
|
1832
|
+
.catch(() => 'rejected')
|
|
1833
|
+
|
|
1834
|
+
//失敗後資料表不得有任何新增
|
|
1835
|
+
vget[16] = (await woBat.select()).length - nBefore
|
|
1836
|
+
|
|
1837
|
+
//跨批次且無衝突者須全數寫入
|
|
1838
|
+
await woBat.delAll()
|
|
1839
|
+
vget[17] = await woBat.insertBulk(Array.from({ length: 3200 }, (v, k) => genRec(k)))
|
|
1840
|
+
vget[18] = (await woBat.select()).length
|
|
1841
|
+
|
|
1842
|
+
})
|
|
1843
|
+
|
|
1844
|
+
vans[1] = { n: 3, nInserted: 3, ok: 1 }
|
|
1845
|
+
it(`should get ${JSON.stringify(vans[1])} for insertBulk without conflict`, async function() {
|
|
1846
|
+
assert.strict.deepStrictEqual(vget[1], vans[1])
|
|
1847
|
+
})
|
|
1848
|
+
|
|
1849
|
+
vans[2] = 3
|
|
1850
|
+
it(`should get ${JSON.stringify(vans[2])} for records after insertBulk without conflict`, async function() {
|
|
1851
|
+
assert.strict.deepStrictEqual(vget[2], vans[2])
|
|
1852
|
+
})
|
|
1853
|
+
|
|
1854
|
+
vans[3] = ['insertBulk']
|
|
1855
|
+
it(`should get ${JSON.stringify(vans[3])} for change modes by insertBulk`, async function() {
|
|
1856
|
+
assert.strict.deepStrictEqual(vget[3], vans[3])
|
|
1857
|
+
})
|
|
1858
|
+
|
|
1859
|
+
vans[4] = 'rejected'
|
|
1860
|
+
it(`should get ${JSON.stringify(vans[4])} for insertBulk with pk existed`, async function() {
|
|
1861
|
+
assert.strict.deepStrictEqual(vget[4], vans[4])
|
|
1862
|
+
})
|
|
1863
|
+
|
|
1864
|
+
vans[5] = 3
|
|
1865
|
+
it(`should get ${JSON.stringify(vans[5])} for records after insertBulk with pk existed`, async function() {
|
|
1866
|
+
assert.strict.deepStrictEqual(vget[5], vans[5])
|
|
1867
|
+
})
|
|
1868
|
+
|
|
1869
|
+
vans[6] = ['insertBulk']
|
|
1870
|
+
it(`should get ${JSON.stringify(vans[6])} for error modes by insertBulk with pk existed`, async function() {
|
|
1871
|
+
assert.strict.deepStrictEqual(vget[6], vans[6])
|
|
1872
|
+
})
|
|
1873
|
+
|
|
1874
|
+
vans[7] = []
|
|
1875
|
+
it(`should get ${JSON.stringify(vans[7])} for change modes by insertBulk rejected`, async function() {
|
|
1876
|
+
assert.strict.deepStrictEqual(vget[7], vans[7])
|
|
1877
|
+
})
|
|
1878
|
+
|
|
1879
|
+
vans[8] = 'rejected'
|
|
1880
|
+
it(`should get ${JSON.stringify(vans[8])} for insertBulk with duplicated pk in same batch`, async function() {
|
|
1881
|
+
assert.strict.deepStrictEqual(vget[8], vans[8])
|
|
1882
|
+
})
|
|
1883
|
+
|
|
1884
|
+
vans[9] = 3
|
|
1885
|
+
it(`should get ${JSON.stringify(vans[9])} for records after insertBulk with duplicated pk`, async function() {
|
|
1886
|
+
assert.strict.deepStrictEqual(vget[9], vans[9])
|
|
1887
|
+
})
|
|
1888
|
+
|
|
1889
|
+
vans[10] = 'rejected'
|
|
1890
|
+
it(`should get ${JSON.stringify(vans[10])} for insertBulk without valid pk`, async function() {
|
|
1891
|
+
assert.strict.deepStrictEqual(vget[10], vans[10])
|
|
1892
|
+
})
|
|
1893
|
+
|
|
1894
|
+
vans[11] = 3
|
|
1895
|
+
it(`should get ${JSON.stringify(vans[11])} for records after insertBulk without valid pk`, async function() {
|
|
1896
|
+
assert.strict.deepStrictEqual(vget[11], vans[11])
|
|
1897
|
+
})
|
|
1898
|
+
|
|
1899
|
+
vans[12] = { n: 0, nInserted: 0, ok: 1 }
|
|
1900
|
+
it(`should get ${JSON.stringify(vans[12])} for insertBulk with invalid data`, async function() {
|
|
1901
|
+
assert.strict.deepStrictEqual(vget[12], vans[12])
|
|
1902
|
+
})
|
|
1903
|
+
|
|
1904
|
+
vans[13] = { n: 1, nInserted: 1, ok: 1 }
|
|
1905
|
+
it(`should get ${JSON.stringify(vans[13])} for insertBulk with single object`, async function() {
|
|
1906
|
+
assert.strict.deepStrictEqual(vget[13], vans[13])
|
|
1907
|
+
})
|
|
1908
|
+
|
|
1909
|
+
vans[14] = 4
|
|
1910
|
+
it(`should get ${JSON.stringify(vans[14])} for records after insertBulk with single object`, async function() {
|
|
1911
|
+
assert.strict.deepStrictEqual(vget[14], vans[14])
|
|
1912
|
+
})
|
|
1913
|
+
|
|
1914
|
+
vans[15] = 'rejected'
|
|
1915
|
+
it(`should get ${JSON.stringify(vans[15])} for insertBulk across batches with pk existed`, async function() {
|
|
1916
|
+
assert.strict.deepStrictEqual(vget[15], vans[15])
|
|
1917
|
+
})
|
|
1918
|
+
|
|
1919
|
+
vans[16] = 0
|
|
1920
|
+
it(`should get ${JSON.stringify(vans[16])} for increment of records after insertBulk across batches failed`, async function() {
|
|
1921
|
+
assert.strict.deepStrictEqual(vget[16], vans[16])
|
|
1922
|
+
})
|
|
1923
|
+
|
|
1924
|
+
vans[17] = { n: 3200, nInserted: 3200, ok: 1 }
|
|
1925
|
+
it(`should get ${JSON.stringify(vans[17])} for insertBulk across batches without conflict`, async function() {
|
|
1926
|
+
assert.strict.deepStrictEqual(vget[17], vans[17])
|
|
1927
|
+
})
|
|
1928
|
+
|
|
1929
|
+
vans[18] = 3200
|
|
1930
|
+
it(`should get ${JSON.stringify(vans[18])} for records after insertBulk across batches`, async function() {
|
|
1931
|
+
assert.strict.deepStrictEqual(vget[18], vans[18])
|
|
1932
|
+
})
|
|
1933
|
+
|
|
1934
|
+
})
|
|
1935
|
+
|
|
1936
|
+
|
|
1437
1937
|
//runProc, 另起行程對同一資料表操作, 用於驗證跨行程之原子性
|
|
1438
1938
|
//子行程以--input-type=module執行, 並以pathToFileURL轉換src路徑, 避免專案路徑含非ASCII字元而無法import
|
|
1439
1939
|
function runProc(tag, opt, mode, payload) {
|