w-orm-mongodb 1.1.39 → 1.1.41

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.
@@ -10,7 +10,7 @@ let ctDb = 'worm'
10
10
  let ctPort = null //容器對外埠, 由startContainer動態取得
11
11
 
12
12
 
13
- //genOpt
13
+ //genOpt, 不帶autoGenPk以驗證其預設值
14
14
  let genOpt = (cl) => {
15
15
  return {
16
16
  url: genUrl(ctPort),
@@ -19,6 +19,16 @@ let genOpt = (cl) => {
19
19
  }
20
20
  }
21
21
 
22
+ //genOptPk, 明確指定autoGenPk
23
+ let genOptPk = (cl, autoGenPk) => {
24
+ return {
25
+ url: genUrl(ctPort),
26
+ db: ctDb,
27
+ cl,
28
+ autoGenPk,
29
+ }
30
+ }
31
+
22
32
  //genKeys, 取回傳物件之鍵集合, 用於驗證鍵集合固定
23
33
  let genKeys = (v) => {
24
34
  return Object.keys(v).sort().join(',')
@@ -1077,6 +1087,251 @@ describe('delAll', function() {
1077
1087
  })
1078
1088
 
1079
1089
 
1090
+ describe('error event', function() {
1091
+ let vans = {}
1092
+ let vget = {}
1093
+
1094
+ before(async function() {
1095
+ this.timeout(120000)
1096
+
1097
+ //collect, 收集事件
1098
+ let collect = (wo) => {
1099
+ let evs = []
1100
+ wo.on('error', function(mode, data, err) {
1101
+ evs.push({ mode, data, err })
1102
+ })
1103
+ return evs
1104
+ }
1105
+
1106
+ //整批性錯誤須於reject前發出, 且err與reject訊息一致
1107
+ let woB = WOrm(genOptPk('everrbatch', false))
1108
+ await woB.delAll()
1109
+ let evsB = collect(woB)
1110
+ let msgB = null
1111
+ await woB.insert({ name: 'no-id' }).catch((err) => {
1112
+ msgB = err.toString()
1113
+ })
1114
+ vget[1] = evsB.length
1115
+ vget[2] = evsB[0].mode
1116
+ vget[3] = typeof evsB[0].err
1117
+ vget[4] = msgB.indexOf(evsB[0].err) >= 0
1118
+
1119
+ //save之整批性錯誤
1120
+ evsB.length = 0
1121
+ await woB.save({ name: 'no-id' }).catch(() => {})
1122
+ vget[5] = evsB.map((v) => v.mode)
1123
+
1124
+ //逐筆失敗須於該筆定案後發出, 每筆一次, err與該筆err欄位一致
1125
+ let woS = WOrm(genOpt('everrsave'))
1126
+ await woS.delAll()
1127
+ await woS.insert([{ id: 'f1' }, { id: 'f2' }, { id: 'f3' }])
1128
+ let evsS = collect(woS)
1129
+ let rs = await woS.save([
1130
+ { id: 'f1', name: 'ok1' },
1131
+ { id: 'f2', $bad: 1 },
1132
+ { id: 'f3', name: 'ok3' },
1133
+ ])
1134
+ vget[6] = evsS.length
1135
+ vget[7] = evsS[0].mode
1136
+ vget[8] = evsS[0].err === rs[1].err
1137
+
1138
+ //del之逐筆失敗, 未帶有效id者亦須發出
1139
+ let woD = WOrm(genOpt('everrdel'))
1140
+ await woD.delAll()
1141
+ await woD.insert({ id: 'd1' })
1142
+ let evsD = collect(woD)
1143
+ let rd = await woD.del([{ id: 'd1' }, { name: 'no-id' }])
1144
+ vget[9] = evsD.length
1145
+ vget[10] = evsD[0].mode
1146
+ vget[11] = evsD[0].err === rd[1].err
1147
+
1148
+ //正常結果不得發出error
1149
+ let woN = WOrm(genOpt('everrnormal'))
1150
+ await woN.delAll()
1151
+ let evsN = collect(woN)
1152
+ await woN.insert({ id: 'n1', name: 'a' })
1153
+ await woN.insert({ id: 'n1', name: 'a' }) //全數已存在
1154
+ await woN.save({ id: 'n1', name: 'a' }) //合併後內容相同
1155
+ await woN.del({ id: 'n-not-existed' }) //主鍵未命中
1156
+ await woN.delAll({ name: 'not-existed' }) //條件無命中
1157
+ await woN.selectByPk('n-not-existed') //查無數據
1158
+ await woN.selectByPk('') //主鍵值無效
1159
+ await woN.select({ name: 'not-existed' }) //無符合數據
1160
+ vget[12] = evsN.length
1161
+
1162
+ //同批既有逐筆失敗又整批resolve時, 逐筆error先於整批change
1163
+ let woO = WOrm(genOpt('everrorder'))
1164
+ await woO.delAll()
1165
+ await woO.insert([{ id: 'o1' }, { id: 'o2' }])
1166
+ let seq = []
1167
+ woO.on('error', function(mode) {
1168
+ seq.push(`error:${mode}`)
1169
+ })
1170
+ woO.on('change', function(mode) {
1171
+ seq.push(`change:${mode}`)
1172
+ })
1173
+ await woO.save([{ id: 'o1', name: 'ok' }, { id: 'o2', $bad: 1 }])
1174
+ vget[13] = seq
1175
+
1176
+ //訂閱函數拋錯不得影響本次操作之結果
1177
+ let woT = WOrm(genOpt('everrthrow'))
1178
+ await woT.delAll()
1179
+ woT.on('error', function() {
1180
+ throw new Error('訂閱者拋錯')
1181
+ })
1182
+ await woT.insert({ id: 't1' })
1183
+ vget[14] = await woT.del([{ id: 't1' }, { name: 'no-id' }])
1184
+
1185
+ })
1186
+
1187
+ vans[1] = 1
1188
+ it(`should get ${JSON.stringify(vans[1])} for count of error event in batch error`, async function() {
1189
+ assert.strict.deepStrictEqual(vget[1], vans[1])
1190
+ })
1191
+
1192
+ vans[2] = 'insert'
1193
+ it(`should get ${JSON.stringify(vans[2])} for mode of error event in batch error`, async function() {
1194
+ assert.strict.deepStrictEqual(vget[2], vans[2])
1195
+ })
1196
+
1197
+ vans[3] = 'string'
1198
+ it(`should get ${JSON.stringify(vans[3])} for type of err in error event`, async function() {
1199
+ assert.strict.deepStrictEqual(vget[3], vans[3])
1200
+ })
1201
+
1202
+ vans[4] = true
1203
+ it(`should get ${JSON.stringify(vans[4])} for same err between error event and reject`, async function() {
1204
+ assert.strict.deepStrictEqual(vget[4], vans[4])
1205
+ })
1206
+
1207
+ vans[5] = ['save']
1208
+ it(`should get ${JSON.stringify(vans[5])} for mode of error event in save batch error`, async function() {
1209
+ assert.strict.deepStrictEqual(vget[5], vans[5])
1210
+ })
1211
+
1212
+ vans[6] = 1
1213
+ it(`should get ${JSON.stringify(vans[6])} for count of error event in save single failure`, async function() {
1214
+ assert.strict.deepStrictEqual(vget[6], vans[6])
1215
+ })
1216
+
1217
+ vans[7] = 'save'
1218
+ it(`should get ${JSON.stringify(vans[7])} for mode of error event in save single failure`, async function() {
1219
+ assert.strict.deepStrictEqual(vget[7], vans[7])
1220
+ })
1221
+
1222
+ vans[8] = true
1223
+ it(`should get ${JSON.stringify(vans[8])} for same err between error event and result of save`, async function() {
1224
+ assert.strict.deepStrictEqual(vget[8], vans[8])
1225
+ })
1226
+
1227
+ vans[9] = 1
1228
+ it(`should get ${JSON.stringify(vans[9])} for count of error event in del single failure`, async function() {
1229
+ assert.strict.deepStrictEqual(vget[9], vans[9])
1230
+ })
1231
+
1232
+ vans[10] = 'del'
1233
+ it(`should get ${JSON.stringify(vans[10])} for mode of error event in del single failure`, async function() {
1234
+ assert.strict.deepStrictEqual(vget[10], vans[10])
1235
+ })
1236
+
1237
+ vans[11] = true
1238
+ it(`should get ${JSON.stringify(vans[11])} for same err between error event and result of del`, async function() {
1239
+ assert.strict.deepStrictEqual(vget[11], vans[11])
1240
+ })
1241
+
1242
+ vans[12] = 0
1243
+ it(`should get ${JSON.stringify(vans[12])} for count of error event in normal results`, async function() {
1244
+ assert.strict.deepStrictEqual(vget[12], vans[12])
1245
+ })
1246
+
1247
+ vans[13] = ['error:save', 'change:save']
1248
+ it(`should get ${JSON.stringify(vans[13])} for order of error and change`, async function() {
1249
+ assert.strict.deepStrictEqual(vget[13], vans[13])
1250
+ })
1251
+
1252
+ vans[14] = [
1253
+ { n: 1, nDeleted: 1, ok: 1 },
1254
+ { n: 0, nDeleted: 0, ok: 0, err: 'invalid id[undefined]' }
1255
+ ]
1256
+ it(`should get ${JSON.stringify(vans[14])} for result with throwing error listener`, async function() {
1257
+ assert.strict.deepStrictEqual(vget[14], vans[14])
1258
+ })
1259
+
1260
+ })
1261
+
1262
+
1263
+ describe('error listener does not change behavior', function() {
1264
+ let vans = {}
1265
+ let vget = {}
1266
+
1267
+ before(async function() {
1268
+ this.timeout(120000)
1269
+
1270
+ //run, 以同一組操作跑兩次, 差別僅在有無註冊error監聽
1271
+ //T10.1第2條: 操作行為不得因監聽者之有無而改變
1272
+ let run = async (cl, withListener) => {
1273
+ let wo = WOrm(genOpt(cl))
1274
+ if (withListener) {
1275
+ wo.on('error', function() {})
1276
+ }
1277
+ await wo.delAll()
1278
+
1279
+ let out = []
1280
+
1281
+ //整批性錯誤
1282
+ let woOff = WOrm(genOptPk(`${cl}off`, false))
1283
+ if (withListener) {
1284
+ woOff.on('error', function() {})
1285
+ }
1286
+ await woOff.delAll()
1287
+ await woOff.insert({ name: 'no-id' })
1288
+ .then((r) => out.push({ t: 'resolve', r }))
1289
+ .catch((e) => out.push({ t: 'reject', e: e.toString() }))
1290
+
1291
+ //逐筆失敗
1292
+ await wo.insert([{ id: 'a1' }, { id: 'a2' }])
1293
+ let rs = await wo.save([{ id: 'a1', name: 'ok' }, { id: 'a2', $bad: 1 }])
1294
+ out.push({ t: 'save', ok: rs.map((v) => v.ok), n: rs.map((v) => v.n) })
1295
+
1296
+ //del逐筆失敗
1297
+ let rd = await wo.del([{ id: 'a1' }, { name: 'no-id' }])
1298
+ out.push({ t: 'del', r: rd })
1299
+
1300
+ //讀取函數之整批性錯誤
1301
+ await wo.selectByPk('not-existed')
1302
+ .then((r) => out.push({ t: 'selectByPk', r }))
1303
+ .catch((e) => out.push({ t: 'selectByPkReject', e: e.toString() }))
1304
+
1305
+ return out
1306
+ }
1307
+
1308
+ let a = await run('evnolisten', false)
1309
+ let b = await run('evlisten', true)
1310
+
1311
+ vget[1] = JSON.stringify(a) === JSON.stringify(b)
1312
+ vget[2] = a[0].t
1313
+ vget[3] = a[1].ok
1314
+
1315
+ })
1316
+
1317
+ vans[1] = true
1318
+ it(`should get ${JSON.stringify(vans[1])} for same result with and without error listener`, async function() {
1319
+ assert.strict.deepStrictEqual(vget[1], vans[1])
1320
+ })
1321
+
1322
+ vans[2] = 'reject'
1323
+ it(`should get ${JSON.stringify(vans[2])} for reject without error listener`, async function() {
1324
+ assert.strict.deepStrictEqual(vget[2], vans[2])
1325
+ })
1326
+
1327
+ vans[3] = [1, 0]
1328
+ it(`should get ${JSON.stringify(vans[3])} for ok of save without error listener`, async function() {
1329
+ assert.strict.deepStrictEqual(vget[3], vans[3])
1330
+ })
1331
+
1332
+ })
1333
+
1334
+
1080
1335
  describe('change event', function() {
1081
1336
  let vans = {}
1082
1337
  let vget = {}
@@ -1129,6 +1384,224 @@ describe('change event', function() {
1129
1384
  })
1130
1385
 
1131
1386
 
1387
+ describe('autoGenPk', function() {
1388
+ let rt = null
1389
+ let vans = {}
1390
+ let vget = {}
1391
+
1392
+ before(async function() {
1393
+ this.timeout(120000)
1394
+
1395
+ //woDef, 未給autoGenPk以驗證其預設值為true
1396
+ let woDef = WOrm(genOpt('pkdefault'))
1397
+ await woDef.delAll()
1398
+
1399
+ //預設未帶id者須自動產生, 且產生之id須為有效字串
1400
+ vget[1] = await woDef.insert({ name: 'no-id' })
1401
+ let ssDef = await woDef.select()
1402
+ vget[2] = ssDef.length
1403
+ vget[3] = typeof ssDef[0].id === 'string' && ssDef[0].id.length > 0
1404
+
1405
+ //預設之save未帶id者亦須自動產生
1406
+ vget[4] = await woDef.save({ name: 'no-id-save' })
1407
+ vget[5] = (await woDef.select()).length
1408
+
1409
+ //woOn, 明確開啟
1410
+ let woOn = WOrm(genOptPk('pkon', true))
1411
+ await woOn.delAll()
1412
+ vget[6] = await woOn.insert({ name: 'no-id' })
1413
+ vget[7] = (await woOn.select()).length
1414
+
1415
+ //woOff, 關閉後主鍵須由呼叫端自備
1416
+ let woOff = WOrm(genOptPk('pkoff', false))
1417
+ await woOff.delAll()
1418
+
1419
+ //帶id者正常寫入
1420
+ vget[8] = await woOff.insert({ id: 'p1', name: 'given' })
1421
+ vget[9] = await woOff.selectByPk('p1')
1422
+
1423
+ //未帶id者須reject, 屬整批性錯誤而不進入逐筆結果
1424
+ rt = null
1425
+ // vans[10] = 'Error: invalid data[0].id, autoGenPk is false'
1426
+ await woOff.insert({ name: 'no-id' })
1427
+ .then(function(msg) {
1428
+ rt = `不應resolve: ${JSON.stringify(msg)}`
1429
+ })
1430
+ .catch(function(msg) {
1431
+ rt = msg.toString()
1432
+ })
1433
+ vget[10] = rt
1434
+
1435
+ //save未帶id者亦須reject, autoInsert兩種取值皆同
1436
+ rt = null
1437
+ // vans[11] = 'Error: invalid data[0].id, autoGenPk is false'
1438
+ await woOff.save({ name: 'no-id' })
1439
+ .then(function(msg) {
1440
+ rt = `不應resolve: ${JSON.stringify(msg)}`
1441
+ })
1442
+ .catch(function(msg) {
1443
+ rt = msg.toString()
1444
+ })
1445
+ vget[11] = rt
1446
+
1447
+ rt = null
1448
+ // vans[12] = 'Error: invalid data[0].id, autoGenPk is false'
1449
+ await woOff.save({ name: 'no-id' }, { autoInsert: false })
1450
+ .then(function(msg) {
1451
+ rt = `不應resolve: ${JSON.stringify(msg)}`
1452
+ })
1453
+ .catch(function(msg) {
1454
+ rt = msg.toString()
1455
+ })
1456
+ vget[12] = rt
1457
+
1458
+ //整批reject時, 同批之有效筆數亦不得被寫入
1459
+ rt = null
1460
+ // vans[13] = 'Error: invalid data[1].id, autoGenPk is false'
1461
+ await woOff.insert([
1462
+ { id: 'p-ok1', name: 'ok1' },
1463
+ { name: 'no-id' },
1464
+ { id: 'p-ok2', name: 'ok2' },
1465
+ ])
1466
+ .then(function(msg) {
1467
+ rt = `不應resolve: ${JSON.stringify(msg)}`
1468
+ })
1469
+ .catch(function(msg) {
1470
+ rt = msg.toString()
1471
+ })
1472
+ vget[13] = rt
1473
+ vget[14] = [
1474
+ await woOff.selectByPk('p-ok1'),
1475
+ await woOff.selectByPk('p-ok2'),
1476
+ ]
1477
+
1478
+ //save之整批reject亦同
1479
+ await woOff.insert({ id: 'p-base', name: 'base' })
1480
+ await woOff.save([
1481
+ { id: 'p-base', name: 'should-not-write' },
1482
+ { name: 'no-id' },
1483
+ ]).catch(() => {})
1484
+ vget[15] = (await woOff.selectByPk('p-base')).name
1485
+
1486
+ //del不受autoGenPk影響, 未帶有效id仍為該筆ok為0而非reject
1487
+ vget[16] = await woOff.del({ name: 'no-id' })
1488
+
1489
+ //autoGenPk為建構層設定, 不得於option逐次覆寫
1490
+ rt = null
1491
+ // vans[17] = 'Error: invalid data[0].id, autoGenPk is false'
1492
+ await woOff.save({ name: 'no-id' }, { autoGenPk: true })
1493
+ .then(function(msg) {
1494
+ rt = `不應resolve: ${JSON.stringify(msg)}`
1495
+ })
1496
+ .catch(function(msg) {
1497
+ rt = msg.toString()
1498
+ })
1499
+ vget[17] = rt
1500
+
1501
+ //輸入無效仍依T5回空結果, 不因autoGenPk為false而reject
1502
+ vget[18] = await woOff.insert(null)
1503
+ vget[19] = await woOff.save(null)
1504
+
1505
+ })
1506
+
1507
+ vans[1] = { n: 1, nInserted: 1, ok: 1 }
1508
+ it(`should get ${JSON.stringify(vans[1])} for insert without id by default autoGenPk`, async function() {
1509
+ assert.strict.deepStrictEqual(vget[1], vans[1])
1510
+ })
1511
+
1512
+ vans[2] = 1
1513
+ it(`should get ${JSON.stringify(vans[2])} for records after insert without id by default autoGenPk`, async function() {
1514
+ assert.strict.deepStrictEqual(vget[2], vans[2])
1515
+ })
1516
+
1517
+ vans[3] = true
1518
+ it(`should get ${JSON.stringify(vans[3])} for generated id by default autoGenPk`, async function() {
1519
+ assert.strict.deepStrictEqual(vget[3], vans[3])
1520
+ })
1521
+
1522
+ vans[4] = [{ n: 1, nInserted: 1, nModified: 0, ok: 1 }]
1523
+ it(`should get ${JSON.stringify(vans[4])} for save without id by default autoGenPk`, async function() {
1524
+ assert.strict.deepStrictEqual(vget[4], vans[4])
1525
+ })
1526
+
1527
+ vans[5] = 2
1528
+ it(`should get ${JSON.stringify(vans[5])} for records after save without id by default autoGenPk`, async function() {
1529
+ assert.strict.deepStrictEqual(vget[5], vans[5])
1530
+ })
1531
+
1532
+ vans[6] = { n: 1, nInserted: 1, ok: 1 }
1533
+ it(`should get ${JSON.stringify(vans[6])} for insert without id by autoGenPk=true`, async function() {
1534
+ assert.strict.deepStrictEqual(vget[6], vans[6])
1535
+ })
1536
+
1537
+ vans[7] = 1
1538
+ it(`should get ${JSON.stringify(vans[7])} for records after insert without id by autoGenPk=true`, async function() {
1539
+ assert.strict.deepStrictEqual(vget[7], vans[7])
1540
+ })
1541
+
1542
+ vans[8] = { n: 1, nInserted: 1, ok: 1 }
1543
+ it(`should get ${JSON.stringify(vans[8])} for insert with id by autoGenPk=false`, async function() {
1544
+ assert.strict.deepStrictEqual(vget[8], vans[8])
1545
+ })
1546
+
1547
+ vans[9] = { id: 'p1', name: 'given' }
1548
+ it(`should get ${JSON.stringify(vans[9])} for record after insert with id by autoGenPk=false`, async function() {
1549
+ assert.strict.deepStrictEqual(vget[9], vans[9])
1550
+ })
1551
+
1552
+ vans[10] = 'Error: invalid data[0].id, autoGenPk is false'
1553
+ it(`should get ${JSON.stringify(vans[10])} for insert without id by autoGenPk=false`, async function() {
1554
+ assert.strict.deepStrictEqual(vget[10], vans[10])
1555
+ })
1556
+
1557
+ vans[11] = 'Error: invalid data[0].id, autoGenPk is false'
1558
+ it(`should get ${JSON.stringify(vans[11])} for save without id by autoGenPk=false`, async function() {
1559
+ assert.strict.deepStrictEqual(vget[11], vans[11])
1560
+ })
1561
+
1562
+ vans[12] = 'Error: invalid data[0].id, autoGenPk is false'
1563
+ it(`should get ${JSON.stringify(vans[12])} for save(autoInsert=false) without id by autoGenPk=false`, async function() {
1564
+ assert.strict.deepStrictEqual(vget[12], vans[12])
1565
+ })
1566
+
1567
+ vans[13] = 'Error: invalid data[1].id, autoGenPk is false'
1568
+ it(`should get ${JSON.stringify(vans[13])} for insert with 1 record without id by autoGenPk=false`, async function() {
1569
+ assert.strict.deepStrictEqual(vget[13], vans[13])
1570
+ })
1571
+
1572
+ vans[14] = [null, null]
1573
+ it(`should get ${JSON.stringify(vans[14])} for not writing valid records in rejected batch`, async function() {
1574
+ assert.strict.deepStrictEqual(vget[14], vans[14])
1575
+ })
1576
+
1577
+ vans[15] = 'base'
1578
+ it(`should get ${JSON.stringify(vans[15])} for not writing valid records in rejected save batch`, async function() {
1579
+ assert.strict.deepStrictEqual(vget[15], vans[15])
1580
+ })
1581
+
1582
+ vans[16] = [{ n: 0, nDeleted: 0, ok: 0, err: 'invalid id[undefined]' }]
1583
+ it(`should get ${JSON.stringify(vans[16])} for del without id by autoGenPk=false`, async function() {
1584
+ assert.strict.deepStrictEqual(vget[16], vans[16])
1585
+ })
1586
+
1587
+ vans[17] = 'Error: invalid data[0].id, autoGenPk is false'
1588
+ it(`should get ${JSON.stringify(vans[17])} for not overriding autoGenPk by option`, async function() {
1589
+ assert.strict.deepStrictEqual(vget[17], vans[17])
1590
+ })
1591
+
1592
+ vans[18] = { n: 0, nInserted: 0, ok: 1 }
1593
+ it(`should get ${JSON.stringify(vans[18])} for insert with invalid data by autoGenPk=false`, async function() {
1594
+ assert.strict.deepStrictEqual(vget[18], vans[18])
1595
+ })
1596
+
1597
+ vans[19] = []
1598
+ it(`should get ${JSON.stringify(vans[19])} for save with invalid data by autoGenPk=false`, async function() {
1599
+ assert.strict.deepStrictEqual(vget[19], vans[19])
1600
+ })
1601
+
1602
+ })
1603
+
1604
+
1132
1605
  describe('cross process concurrency', function() {
1133
1606
  let vans = {}
1134
1607
  let vget = {}