w-orm-lmdb 1.0.17 → 1.0.19

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/docs/index.html CHANGED
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmLmdb.html">WOrmLmdb</a><ul class='methods'><li data-type='method'><a href="WOrmLmdb.html#.del">del</a></li><li data-type='method'><a href="WOrmLmdb.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmLmdb.html#.insert">insert</a></li><li data-type='method'><a href="WOrmLmdb.html#.save">save</a></li><li data-type='method'><a href="WOrmLmdb.html#.select">select</a></li><li data-type='method'><a href="WOrmLmdb.html#.selectByPk">selectByPk</a></li></ul></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmLmdb.html">WOrmLmdb</a><ul class='methods'><li data-type='method'><a href="WOrmLmdb.html#.del">del</a></li><li data-type='method'><a href="WOrmLmdb.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmLmdb.html#.insert">insert</a></li><li data-type='method'><a href="WOrmLmdb.html#.insertBulk">insertBulk</a></li><li data-type='method'><a href="WOrmLmdb.html#.save">save</a></li><li data-type='method'><a href="WOrmLmdb.html#.select">select</a></li><li data-type='method'><a href="WOrmLmdb.html#.selectByPk">selectByPk</a></li></ul></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -71,7 +71,7 @@
71
71
  <br class="clear">
72
72
 
73
73
  <footer>
74
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 07:05:30 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 11:00:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
75
  </footer>
76
76
 
77
77
  <script>prettyPrint();</script>
package/g-basic.mjs CHANGED
@@ -62,6 +62,9 @@ async function test() {
62
62
  wo.on('change', function(mode, data, res) {
63
63
  console.log('change', mode)
64
64
  })
65
+ wo.on('error', function(mode, data, err) {
66
+ console.log('error', mode, err)
67
+ })
65
68
 
66
69
  //delAll
67
70
  await wo.delAll()
@@ -145,6 +148,38 @@ async function test() {
145
148
  console.log('del catch', msg)
146
149
  })
147
150
 
151
+ //del by data without id, 該筆無法處理故ok為0並附err, 整批仍resolve且另發出error事件
152
+ await wo.del({ name: 'no-id' })
153
+ .then(function(msg) {
154
+ console.log('del by data without id then', msg)
155
+ })
156
+ .catch(function(msg) {
157
+ console.log('del by data without id catch', msg)
158
+ })
159
+
160
+ //insertBulk, 全批視為一個單位, 無衝突時nInserted恆等於n
161
+ await wo.insertBulk([{ id: 'id-bulk1', name: 'bulk1' }, { id: 'id-bulk2', name: 'bulk2' }])
162
+ .then(function(msg) {
163
+ console.log('insertBulk then', msg)
164
+ })
165
+ .catch(function(msg) {
166
+ console.log('insertBulk catch', msg)
167
+ })
168
+
169
+ //insertBulk by data with existed id, 非insert之加速版而係衝突政策不同
170
+ //insert於主鍵已存在時跳過該筆而整批ok為1, insertBulk則整批reject且不寫入任何一筆
171
+ await wo.insertBulk([{ id: 'id-bulk3', name: 'bulk3' }, { id: 'id-peter', name: 'conflict' }])
172
+ .then(function(msg) {
173
+ console.log('insertBulk by data with existed id then', msg)
174
+ })
175
+ .catch(function(msg) {
176
+ console.log('insertBulk by data with existed id catch', msg.toString())
177
+ })
178
+
179
+ //select all, 可見id-bulk3因整批reject而未寫入
180
+ let sb2 = await wo.select()
181
+ console.log('ids after insertBulk', _.map(_.sortBy(sb2, 'id'), 'id'))
182
+
148
183
  }
149
184
  test()
150
185
  // change delAll
@@ -193,6 +228,14 @@ test()
193
228
  // save then [ { n: 1, nInserted: 0, nModified: 1, ok: 1 } ]
194
229
  // change del
195
230
  // del then [ { n: 1, nDeleted: 1, ok: 1 } ]
231
+ // error del can not delete by invalid id[]
232
+ // change del
233
+ // del by data without id then [ { n: 0, nDeleted: 0, ok: 0, err: 'can not delete by invalid id[]' } ]
234
+ // change insertBulk
235
+ // insertBulk then { n: 2, nInserted: 2, ok: 1 }
236
+ // error insertBulk can not insertBulk by existed id[id-peter]
237
+ // insertBulk by data with existed id catch Error: can not insertBulk by existed id[id-peter]
238
+ // ids after insertBulk [ 'id-bulk1', 'id-bulk2', 'id-peter', 'id-rosemary' ]
196
239
 
197
240
 
198
241
  //node g-basic.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-orm-lmdb",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "main": "dist/w-orm-lmdb.umd.js",
5
5
  "dependencies": {
6
6
  "lmdb": "^3.5.6",
package/src/WOrmLmdb.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { open } from 'lmdb'
1
+ import { open, ABORT } from 'lmdb'
2
2
  // import mingo from 'mingo' //mingo內未更新import寫法, 會導致ERR_UNSUPPORTED_DIR_IMPORT, 故須改用require引入使用
3
3
  import mingo from './reqMingo.js'
4
4
  import size from 'lodash-es/size.js'
@@ -23,6 +23,23 @@ import waitFun from 'wsemi/src/waitFun.mjs'
23
23
  /**
24
24
  * 操作資料庫(LMDB)
25
25
  *
26
+ * 回傳物件為EventEmitter,除各操作函數外另發出change與error兩事件,供呼叫端於單一處集中觀察資料異動與失敗。
27
+ * 事件僅為附加通知,其所送出之資訊皆另有正規管道(操作結果經resolve、整批性錯誤經reject、逐筆失敗經該筆之err欄位),
28
+ * 故不監聽亦能取得完整資訊,且監聽與否不改變任何操作之回傳值。
29
+ *
30
+ * change事件,參數為(mode, data, res),於資料實際異動成功後發出:
31
+ * mode為操作別字串,可為'insert'、'insertBulk'、'save'、'del'、'delAll';save內若逐筆走自動插入則該筆另發出mode為'insert'之事件。
32
+ * data為本次操作之輸入數據,delAll固定為null。
33
+ * res為本次操作之回傳結果。
34
+ * 逐筆函數以整批為單位發出一次而不逐筆發出,select與selectByPk不發出本事件。
35
+ *
36
+ * error事件,參數為(mode, data, err),於操作發生錯誤時發出:
37
+ * mode為操作別字串,可為'select'、'selectByPk'、'insert'、'insertBulk'、'save'、'del'、'delAll'。
38
+ * data為本次操作之輸入數據,無輸入數據者為null。
39
+ * err為錯誤訊息字串,內容與正規管道所送出者一致。
40
+ * 整批性錯誤於reject之前發出;逐筆失敗於該筆結果定案後發出,每筆一次。
41
+ * 註: 逐筆失敗時整批仍resolve,故收到本事件不表示該次呼叫失敗;正常結果(如查無數據、主鍵未命中、全數已存在)不發出本事件。
42
+ *
26
43
  * @class
27
44
  * @param {Object} [opt={}] 輸入設定物件,預設{}
28
45
  * @param {String} [opt.url='_db'] 輸入資料庫用資料夾字串,預設'_db'
@@ -118,7 +135,30 @@ function WOrmLmdb(opt = {}) {
118
135
  })
119
136
  }
120
137
 
121
- //getErrMsg, 取錯誤訊息字串, 供逐筆結果之err欄位使用
138
+ //emitChange, 資料實際異動成功後發出, 事件僅為附加通知不承擔回傳義務
139
+ //一律包try/catch, 令訂閱函數自身拋錯不影響本次操作之結果
140
+ let emitChange = (mode, data, res) => {
141
+ try {
142
+ ee.emit('change', mode, data, res)
143
+ }
144
+ catch (err) {
145
+ console.log(err)
146
+ }
147
+ }
148
+
149
+ //emitError, 操作發生錯誤時發出, 錯誤訊息一律轉為字串
150
+ //此try/catch除攔訂閱函數之例外外另有必要: Node之EventEmitter於'error'無監聽者時會將錯誤直接拋出,
151
+ //若不攔則同一次操作會因呼叫端有無註冊監聽而走向不同結果
152
+ let emitError = (mode, data, err) => {
153
+ try {
154
+ ee.emit('error', mode, data, getErrMsg(err))
155
+ }
156
+ catch (errEmit) {
157
+ console.log(errEmit)
158
+ }
159
+ }
160
+
161
+ //getErrMsg, 取錯誤訊息字串, 供逐筆結果之err欄位與error事件使用
122
162
  let getErrMsg = (err) => {
123
163
  let m = get(err, 'message')
124
164
  if (isestr(m)) {
@@ -212,6 +252,10 @@ function WOrmLmdb(opt = {}) {
212
252
 
213
253
  //check
214
254
  if (isErr) {
255
+
256
+ //emit, 整批性錯誤須於reject之前發出
257
+ emitError('select', null, res)
258
+
215
259
  return Promise.reject(res)
216
260
  }
217
261
 
@@ -261,6 +305,10 @@ function WOrmLmdb(opt = {}) {
261
305
 
262
306
  //check
263
307
  if (isErr) {
308
+
309
+ //emit, 整批性錯誤須於reject之前發出
310
+ emitError('selectByPk', null, res)
311
+
264
312
  return Promise.reject(res)
265
313
  }
266
314
 
@@ -344,19 +392,109 @@ function WOrmLmdb(opt = {}) {
344
392
 
345
393
  //emit, 於change可能須使用select, 故須放在重設快取之後
346
394
  if (!isErr) {
347
- try {
395
+ emitChange('insert', data, res)
396
+ }
397
+
398
+ //check
399
+ if (isErr) {
400
+
401
+ //emit, 整批性錯誤須於reject之前發出
402
+ emitError('insert', data, res)
403
+
404
+ return Promise.reject(res)
405
+ }
406
+
407
+ return res
408
+ }
348
409
 
349
- //emit
350
- ee.emit('change', 'insert', data, res)
410
+ /**
411
+ * 批次插入數據,全批視為一個單位,全部插入成功或一筆都不寫入
412
+ * 註: 本函數非insert之加速版,兩者衝突政策不同。insert於主鍵已存在時跳過該筆而整批ok為1,
413
+ * 本函數則整批reject且不寫入任何一筆;同批含重複主鍵者亦視為衝突。確無衝突時兩者結果相同
414
+ * 註: 於本套件不會較insert快,因insert本即以Promise.all一次送出全部條件寫入而非逐筆await,
415
+ * 提供本函數係為與其他w-orm系列套件維持同一組函數,令呼叫端得於各套件間替換而不須改寫呼叫
416
+ *
417
+ * @memberOf WOrmLmdb
418
+ * @param {Object|Array} data 輸入數據物件或陣列
419
+ * @returns {Promise} 回傳Promise,resolve回傳插入結果物件{n,nInserted,ok},n為輸入筆數、nInserted成功時恆等於n,任一筆主鍵已存在則reject回傳錯誤訊息
420
+ */
421
+ async function insertBulk(data) {
422
+ let isErr = false
423
+
424
+ //check
425
+ if (!iseobj(data) && !isearr(data)) {
426
+ return {
427
+ n: 0,
428
+ nInserted: 0,
429
+ ok: 1,
430
+ }
431
+ }
432
+
433
+ //cloneDeep, 與外部數據脫勾
434
+ data = cloneDeep(data)
435
+
436
+ //res
437
+ let res = null
438
+ try {
439
+
440
+ //check
441
+ if (!isarr(data)) {
442
+ data = [data]
443
+ }
444
+
445
+ //check id
446
+ data = procPk(data, 'insertBulk')
447
+
448
+ //nAll
449
+ let nAll = size(data)
450
+
451
+ //childTransaction, 全有全無由交易回滾保證
452
+ //註: 非同步之client.transaction於中止時並不回滾, 實測其內之put仍會落盤, 故此處須用childTransaction
453
+ //註: 交易內之client.get讀得到同一交易稍早之put, 故同批含重複主鍵者亦會於此被偵測為衝突
454
+ //註: 存在與否採鍵層判定, 與insert之ifNoExists一致
455
+ let pkConflict = null
456
+ await client.childTransaction(() => {
457
+ for (let v of data) {
458
+ if (client.get(v.id) !== undefined) {
459
+ pkConflict = v.id
460
+ return ABORT
461
+ }
462
+ client.put(v.id, v)
463
+ }
464
+ })
351
465
 
466
+ //check, 衝突則整批視為失敗, 交易已回滾故無任何寫入
467
+ if (isestr(pkConflict)) {
468
+ throw new Error(`can not insertBulk by existed id[${pkConflict}]`)
352
469
  }
353
- catch (err) {
354
- console.log(err)
470
+
471
+ //res, 未衝突則全數插入, 故nInserted恆等於n
472
+ res = {
473
+ n: nAll,
474
+ nInserted: nAll,
475
+ ok: 1,
355
476
  }
477
+
478
+ }
479
+ catch (err) {
480
+ isErr = true
481
+ res = err
482
+ }
483
+
484
+ //update, 不能保證插入多少, 一律重設快取
485
+ _cache = null
486
+
487
+ //emit, 於change可能須使用select, 故須放在重設快取之後
488
+ if (!isErr) {
489
+ emitChange('insertBulk', data, res)
356
490
  }
357
491
 
358
492
  //check
359
493
  if (isErr) {
494
+
495
+ //emit, 整批性錯誤須於reject之前發出
496
+ emitError('insertBulk', data, res)
497
+
360
498
  return Promise.reject(res)
361
499
  }
362
500
 
@@ -525,16 +663,15 @@ function WOrmLmdb(opt = {}) {
525
663
  //update, 不能保證插入多少, 一律重設快取
526
664
  _cache = null
527
665
 
528
- try {
666
+ //emit
667
+ emitChange('insert', [v], rest)
529
668
 
530
- //emit
531
- ee.emit('change', 'insert', [v], rest)
532
-
533
- }
534
- catch (err) {
535
- console.log(err)
536
- }
669
+ }
537
670
 
671
+ //emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
672
+ //此事件之發出不表示整批失敗, 整批仍resolve, 該筆以ok為0回報
673
+ if (rest.ok === 0) {
674
+ emitError('save', [v], rest.err)
538
675
  }
539
676
 
540
677
  return rest
@@ -550,20 +687,17 @@ function WOrmLmdb(opt = {}) {
550
687
  _cache = null
551
688
 
552
689
  //emit, 於change可能須使用select, 故須放在重設快取之後
690
+ //逐筆失敗之error事件已於各筆定案時發出, 故必早於本整批change
553
691
  if (!isErr) {
554
- try {
555
-
556
- //emit
557
- ee.emit('change', 'save', data, res)
558
-
559
- }
560
- catch (err) {
561
- console.log(err)
562
- }
692
+ emitChange('save', data, res)
563
693
  }
564
694
 
565
695
  //check
566
696
  if (isErr) {
697
+
698
+ //emit, 整批性錯誤須於reject之前發出
699
+ emitError('save', data, res)
700
+
567
701
  return Promise.reject(res)
568
702
  }
569
703
 
@@ -612,38 +746,42 @@ function WOrmLmdb(opt = {}) {
612
746
  if (!isestr(id)) {
613
747
  //未給有效v.id視為該筆數據有問題而無法處理, 以ok為0並附err回報,
614
748
  //與[已給v.id但查無數據]之ok為1有別, 二者須可由ok分辨
615
- return {
749
+ //註: 此處不可直接return, 否則會跳過本回調末尾之error事件發出
750
+ rest = {
616
751
  n: 0,
617
752
  nDeleted: 0,
618
753
  ok: 0,
619
754
  err: `can not delete by invalid id[${id}]`,
620
755
  }
621
756
  }
757
+ else {
622
758
 
623
- //查找資料表內v.id
624
- let vv = await getValue(id) //不會有catch
759
+ //查找資料表內v.id
760
+ let vv = await getValue(id) //不會有catch
625
761
 
626
- //check
627
- if (iseobj(vv)) {
628
- //已存在v.id則須刪除
762
+ //check
763
+ if (iseobj(vv)) {
764
+ //已存在v.id則須刪除
629
765
 
630
- //del
631
- await client.del(id)
766
+ //del
767
+ await client.del(id)
768
+
769
+ //rest
770
+ rest = {
771
+ n: 1,
772
+ nDeleted: 1,
773
+ ok: 1,
774
+ }
632
775
 
633
- //rest
634
- rest = {
635
- n: 1,
636
- nDeleted: 1,
637
- ok: 1,
638
776
  }
777
+ else {
778
+ //不存在v.id則不刪除, 未命中故n為0
779
+ rest = {
780
+ n: 0,
781
+ nDeleted: 0,
782
+ ok: 1,
783
+ }
639
784
 
640
- }
641
- else {
642
- //不存在v.id則不刪除, 未命中故n為0
643
- rest = {
644
- n: 0,
645
- nDeleted: 0,
646
- ok: 1,
647
785
  }
648
786
 
649
787
  }
@@ -661,6 +799,12 @@ function WOrmLmdb(opt = {}) {
661
799
 
662
800
  }
663
801
 
802
+ //emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
803
+ //此事件之發出不表示整批失敗, 整批仍resolve, 該筆以ok為0回報
804
+ if (rest.ok === 0) {
805
+ emitError('del', [v], rest.err)
806
+ }
807
+
664
808
  return rest
665
809
  })
666
810
 
@@ -674,20 +818,17 @@ function WOrmLmdb(opt = {}) {
674
818
  _cache = null
675
819
 
676
820
  //emit, 於change可能須使用select, 故須放在重設快取之後
821
+ //逐筆失敗之error事件已於各筆定案時發出, 故必早於本整批change
677
822
  if (!isErr) {
678
- try {
679
-
680
- //emit
681
- ee.emit('change', 'del', data, res)
682
-
683
- }
684
- catch (err) {
685
- console.log(err)
686
- }
823
+ emitChange('del', data, res)
687
824
  }
688
825
 
689
826
  //check
690
827
  if (isErr) {
828
+
829
+ //emit, 整批性錯誤須於reject之前發出
830
+ emitError('del', data, res)
831
+
691
832
  return Promise.reject(res)
692
833
  }
693
834
 
@@ -789,19 +930,15 @@ function WOrmLmdb(opt = {}) {
789
930
 
790
931
  //emit, 於change可能須使用select, 故須放在重設快取之後
791
932
  if (!isErr) {
792
- try {
793
-
794
- //emit
795
- ee.emit('change', 'delAll', null, res)
796
-
797
- }
798
- catch (err) {
799
- console.log(err)
800
- }
933
+ emitChange('delAll', null, res)
801
934
  }
802
935
 
803
936
  //check
804
937
  if (isErr) {
938
+
939
+ //emit, 整批性錯誤須於reject之前發出
940
+ emitError('delAll', null, res)
941
+
805
942
  return Promise.reject(res)
806
943
  }
807
944
 
@@ -819,6 +956,7 @@ function WOrmLmdb(opt = {}) {
819
956
  ee.select = select
820
957
  ee.selectByPk = selectByPk
821
958
  ee.insert = insert
959
+ ee.insertBulk = insertBulk
822
960
  ee.save = save
823
961
  ee.del = del
824
962
  ee.delAll = delAll