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/g-basic.mjs CHANGED
@@ -110,6 +110,19 @@ let rsa = [
110
110
  },
111
111
  ]
112
112
 
113
+ let rsb = [
114
+ {
115
+ time: '2025-01-01T00:20:00Z',
116
+ name: 'bulk-1',
117
+ value: 201,
118
+ },
119
+ {
120
+ time: '2025-01-01T00:21:00Z',
121
+ name: 'bulk-2',
122
+ value: 202,
123
+ },
124
+ ]
125
+
113
126
  async function test() {
114
127
 
115
128
  //wo
@@ -132,6 +145,9 @@ async function test() {
132
145
  wo.on('change', function(mode, data, res) {
133
146
  console.log('change', mode)
134
147
  })
148
+ wo.on('error', function(mode, data, err) {
149
+ console.log('error', mode, err)
150
+ })
135
151
 
136
152
  //delAll
137
153
  await wo.delAll()
@@ -151,6 +167,24 @@ async function test() {
151
167
  console.log('insert catch', msg)
152
168
  })
153
169
 
170
+ //insertBulk, 全批視為一個單位, 全部插入成功或一筆都不寫入
171
+ await wo.insertBulk(rsb)
172
+ .then(function(msg) {
173
+ console.log('insertBulk then', msg)
174
+ })
175
+ .catch(function(msg) {
176
+ console.log('insertBulk catch', msg)
177
+ })
178
+
179
+ //insertBulk by pk existed, 任一筆之主鍵已存在即整批reject且不寫入任何一筆
180
+ await wo.insertBulk(rsb)
181
+ .then(function(msg) {
182
+ console.log('insertBulk by pk existed then', msg)
183
+ })
184
+ .catch(function(msg) {
185
+ console.log('insertBulk by pk existed catch', `${msg}`) //reject回傳Error物件, 以樣板字串取其訊息以免印出堆疊
186
+ })
187
+
154
188
  //save
155
189
  await wo.save(rsm, { autoInsert: false })
156
190
  .then(function(msg) {
@@ -213,6 +247,15 @@ async function test() {
213
247
  console.log('del catch', msg)
214
248
  })
215
249
 
250
+ //del by data without pk, 該筆無法處理故ok為0並附err, 整批仍resolve且另發出error事件
251
+ await wo.del({ name: 'no-pk' })
252
+ .then(function(msg) {
253
+ console.log('del by data without pk then', msg)
254
+ })
255
+ .catch(function(msg) {
256
+ console.log('del by data without pk catch', msg)
257
+ })
258
+
216
259
  //del
217
260
  let ssDel = await wo.select()
218
261
  let ds = ssDel.filter(function(v) {
@@ -298,6 +341,10 @@ test()
298
341
  // delAll then { n: 0, nDeleted: 0, ok: 1 }
299
342
  // change insert
300
343
  // insert then { n: 13, nInserted: 13, ok: 1 }
344
+ // change insertBulk
345
+ // insertBulk then { n: 2, nInserted: 2, ok: 1 }
346
+ // error insertBulk duplicate key value violates unique constraint "users_pkey"
347
+ // insertBulk by pk existed catch error: duplicate key value violates unique constraint "users_pkey"
301
348
  // change save
302
349
  // save then [
303
350
  // { n: 1, nInserted: 0, nModified: 0, ok: 1 },
@@ -317,6 +364,8 @@ test()
317
364
  // { time: 2025-01-01T00:07:00.000Z, name: 'rosemary', value: 124.76 },
318
365
  // { time: 2025-01-01T00:08:00.000Z, name: 'kettle', value: 524 },
319
366
  // { time: 2025-01-01T00:09:00.000Z, name: 'peter', value: 127 },
367
+ // { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
368
+ // { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
320
369
  // {
321
370
  // time: 2025-01-01T00:10:00.000Z,
322
371
  // name: 'rosemary(modify)',
@@ -352,6 +401,8 @@ test()
352
401
  // { time: 2025-01-01T00:03:00.000Z, name: 'peter', value: 200 },
353
402
  // { time: 2025-01-01T00:05:00.000Z, name: 'kettle', value: 488 },
354
403
  // { time: 2025-01-01T00:08:00.000Z, name: 'kettle', value: 524 },
404
+ // { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
405
+ // { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
355
406
  // {
356
407
  // time: 2025-01-01T00:11:00.000Z,
357
408
  // name: 'kettle(modify)',
@@ -369,10 +420,14 @@ test()
369
420
  // value: 447
370
421
  // }
371
422
  // ]
423
+ // change insert
372
424
  // change save
373
425
  // save then [ { n: 1, nInserted: 1, nModified: 0, ok: 1 } ]
374
426
  // change del
375
427
  // del then [ { n: 0, nDeleted: 0, ok: 1 } ]
428
+ // error del invalid time[undefined]
429
+ // change del
430
+ // del by data without pk then [ { n: 0, nDeleted: 0, ok: 0, err: 'invalid time[undefined]' } ]
376
431
  // change del
377
432
  // del then [
378
433
  // { n: 1, nDeleted: 1, ok: 1 },
@@ -390,6 +445,8 @@ test()
390
445
  // { time: 2025-01-01T00:01:00.000Z, name: 'rosemary', value: 123.456 },
391
446
  // { time: 2025-01-01T00:04:00.000Z, name: 'rosemary', value: 123.1236 },
392
447
  // { time: 2025-01-01T00:07:00.000Z, name: 'rosemary', value: 124.76 },
448
+ // { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
449
+ // { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
393
450
  // {
394
451
  // time: 2025-01-01T00:10:00.000Z,
395
452
  // name: 'rosemary(modify)',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-orm-postgresql",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "main": "dist/w-orm-postgresql.umd.js",
5
5
  "dependencies": {
6
6
  "mongo-sql": "^6.2.0",
@@ -1,4 +1,3 @@
1
- import events from 'events'
2
1
  import pg from 'pg'
3
2
  import mongoSql from 'mongo-sql'
4
3
  import size from 'lodash-es/size.js'
@@ -20,6 +19,7 @@ import isint from 'wsemi/src/isint.mjs'
20
19
  import isbol from 'wsemi/src/isbol.mjs'
21
20
  import isDate from 'wsemi/src/isDate.mjs'
22
21
  import haskey from 'wsemi/src/haskey.mjs'
22
+ import evem from 'wsemi/src/evem.mjs'
23
23
  import pmSeries from 'wsemi/src/pmSeries.mjs'
24
24
 
25
25
 
@@ -173,8 +173,40 @@ function WOrmPostgresql(opt = {}) {
173
173
  let connectionString = `${url}/${db}`
174
174
  // console.log('connectionString', connectionString)
175
175
 
176
- //ee
177
- let ee = new events.EventEmitter()
176
+ //ee, 採eventemitter3而不採Node內建之events.EventEmitter,
177
+ //因後者於'error'無監聽者時會將錯誤直接拋出, 將使操作行為隨呼叫端是否註冊監聽而異
178
+ let ee = evem()
179
+
180
+ //getErrMsg, 取錯誤訊息字串, 供逐筆結果之err欄位與error事件使用
181
+ let getErrMsg = (err) => {
182
+ let m = get(err, 'message')
183
+ if (isestr(m)) {
184
+ return m
185
+ }
186
+ return String(err)
187
+ }
188
+
189
+ //emitChange, 資料實際異動成功後發出, 事件僅為附加通知不承擔回傳義務
190
+ //訂閱函數拋錯不得影響本次操作, 故一律以try/catch包覆, 收斂於此以免逐處遺漏
191
+ let emitChange = (mode, data, res) => {
192
+ try {
193
+ ee.emit('change', mode, data, res)
194
+ }
195
+ catch (errEmit) {
196
+ console.log(errEmit)
197
+ }
198
+ }
199
+
200
+ //emitError, 操作發生錯誤時發出, 錯誤訊息一律轉為字串
201
+ //正常結果(如查無數據、主鍵未命中、內容相同而未寫入)不得發出, 以免監聽者將常態當異常
202
+ let emitError = (mode, data, err) => {
203
+ try {
204
+ ee.emit('error', mode, data, getErrMsg(err))
205
+ }
206
+ catch (errEmit) {
207
+ console.log(errEmit)
208
+ }
209
+ }
178
210
 
179
211
  //PgClient
180
212
  let PgClient = pg.Client
@@ -213,6 +245,77 @@ function WOrmPostgresql(opt = {}) {
213
245
  _cache[key] = cloneDeep(data) //與外部使用數據脫勾
214
246
  }
215
247
 
248
+ //insertBatches, 分批送出插入語句並以交易包覆, 回傳實際插入筆數, 供insert與insertBulk共用
249
+ //PostgreSQL之協定以int16記綁定參數個數故上限為65535, 單一語句可送之筆數受欄位數所限,
250
+ //超出者須分批送出; 分批後單語句之原子性已不足以維持[失敗即不留下部份寫入], 故一律以交易包覆,
251
+ //令單批與分批之保證來源一致而不因批數而異
252
+ //兩函數之衝突政策由useConflict區分, 語句各自獨立:
253
+ // true : 添加ON CONFLICT DO NOTHING, 已存在主鍵者跳過而不中斷整批, 為insert之語義
254
+ // false: 不添加, 任一筆撞主鍵之唯一約束即整句失敗且不寫入任何一筆, 為insertBulk之全有全無語義
255
+ let insertBatches = async (client, data, useConflict) => {
256
+
257
+ //nCols, 取各筆欄位數之最大值
258
+ let nCols = 1
259
+ data.forEach(function(v) {
260
+ nCols = Math.max(nCols, size(keys(v)))
261
+ })
262
+
263
+ //nPerBatch
264
+ let nPerBatch = Math.max(1, Math.floor(65535 / nCols))
265
+
266
+ //ltdata, 分批
267
+ let ltdata = []
268
+ for (let i = 0; i < size(data); i += nPerBatch) {
269
+ ltdata.push(data.slice(i, i + nPerBatch))
270
+ }
271
+
272
+ //transaction
273
+ await client.query('BEGIN')
274
+
275
+ try {
276
+
277
+ //nIns
278
+ let nIns = 0
279
+
280
+ //each batch
281
+ for (let dt of ltdata) {
282
+
283
+ //mr
284
+ let mr = mongoSql.sql({
285
+ type: 'insert',
286
+ table: cl,
287
+ values: dt,
288
+ })
289
+
290
+ //sql
291
+ let sql = mr.query
292
+ if (useConflict) {
293
+ sql = `${sql} ON CONFLICT (${pkName}) DO NOTHING`
294
+ }
295
+
296
+ //insert
297
+ let r = await client.query(sql, mr.values)
298
+
299
+ //nIns
300
+ nIns += r.rowCount
301
+
302
+ }
303
+
304
+ //commit
305
+ await client.query('COMMIT')
306
+
307
+ return nIns
308
+ }
309
+ catch (err) {
310
+
311
+ //rollback, 令已送出之批次一併回滾
312
+ await client.query('ROLLBACK').catch(() => {})
313
+
314
+ throw err
315
+ }
316
+
317
+ }
318
+
216
319
  /**
217
320
  * 創建資料表
218
321
  * 註: pk未給時採建構時之opt.pk。因insert與save倚賴主鍵之唯一約束達成原子性,
@@ -252,6 +355,10 @@ function WOrmPostgresql(opt = {}) {
252
355
 
253
356
  //check
254
357
  if (isErr) {
358
+
359
+ //emit, 整批性錯誤於reject之前發出
360
+ emitError('createTable', arr, res)
361
+
255
362
  return Promise.reject(res)
256
363
  }
257
364
 
@@ -302,6 +409,10 @@ function WOrmPostgresql(opt = {}) {
302
409
 
303
410
  //check
304
411
  if (isErr) {
412
+
413
+ //emit, 整批性錯誤於reject之前發出
414
+ emitError('createTable', arr, res)
415
+
305
416
  return Promise.reject(res)
306
417
  }
307
418
 
@@ -346,6 +457,10 @@ function WOrmPostgresql(opt = {}) {
346
457
 
347
458
  //check
348
459
  if (isErr) {
460
+
461
+ //emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
462
+ emitError('select', null, res)
463
+
349
464
  return Promise.reject(res)
350
465
  }
351
466
 
@@ -394,6 +509,10 @@ function WOrmPostgresql(opt = {}) {
394
509
 
395
510
  //check
396
511
  if (isErr) {
512
+
513
+ //emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
514
+ emitError('select', null, res)
515
+
397
516
  return Promise.reject(res)
398
517
  }
399
518
 
@@ -452,6 +571,10 @@ function WOrmPostgresql(opt = {}) {
452
571
 
453
572
  //check
454
573
  if (isErr) {
574
+
575
+ //emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
576
+ emitError('selectByPk', null, res)
577
+
455
578
  return Promise.reject(res)
456
579
  }
457
580
 
@@ -518,6 +641,11 @@ function WOrmPostgresql(opt = {}) {
518
641
 
519
642
  //check
520
643
  if (isErr) {
644
+
645
+ //emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
646
+ //主鍵未命中與主鍵值無效皆為正常結果而不設isErr, 故不會誤發error
647
+ emitError('selectByPk', null, res)
648
+
521
649
  return Promise.reject(res)
522
650
  }
523
651
 
@@ -569,6 +697,10 @@ function WOrmPostgresql(opt = {}) {
569
697
 
570
698
  //check
571
699
  if (isErr) {
700
+
701
+ //emit, 整批性錯誤於reject之前發出
702
+ emitError('insert', data, res)
703
+
572
704
  return Promise.reject(res)
573
705
  }
574
706
 
@@ -587,40 +719,137 @@ function WOrmPostgresql(opt = {}) {
587
719
  return v
588
720
  })
589
721
 
590
- //mr
591
- let mr = mongoSql.sql({
592
- type: 'insert',
593
- table: cl,
594
- values: data,
595
- })
596
- // console.log('mr', mr)
597
- // console.log('mr.query', mr.query)
598
- // console.log('mr.values', mr.values)
722
+ //nAll
723
+ let nAll = size(data)
599
724
 
600
- //添加conflict, 令已存在主鍵者跳過而不中斷整批插入, 主鍵認定與genConflictSQL一致
725
+ //insert, 以ON CONFLICT DO NOTHING令已存在主鍵者跳過而不中斷整批插入,
601
726
  //由PostgreSQL於單一語句內原子完成[檢查主鍵未存在]與[寫入], 併發時同一主鍵僅有一次成功,
602
727
  //同批含重複主鍵時亦僅首筆成功, 故不須逐筆插入即可取得實際插入筆數
603
- let sql = `${mr.query} ON CONFLICT (${pkName}) DO NOTHING`
728
+ //筆數過多而超出綁定參數上限者由insertBatches分批送出, 主鍵認定與genConflictSQL一致
729
+ let nIns = await insertBatches(client, data, true)
730
+
731
+ //res
732
+ res = {
733
+ n: nAll,
734
+ nInserted: nIns,
735
+ ok: 1,
736
+ }
737
+
738
+ }
739
+ catch (err) {
740
+ isErr = true
741
+ res = err
742
+ }
743
+ finally {
744
+ await client.end()
745
+ client = null
746
+ }
747
+
748
+ //update
749
+ if (useCache) {
750
+ clearCache()
751
+ }
752
+
753
+ //emit
754
+ if (!isErr) {
755
+ emitChange('insert', data, res)
756
+ }
757
+
758
+ //check
759
+ if (isErr) {
760
+
761
+ //emit, 整批性錯誤於reject之前發出
762
+ emitError('insert', data, res)
763
+
764
+ return Promise.reject(res)
765
+ }
766
+
767
+ return res
768
+ }
769
+
770
+ /**
771
+ * 批次插入數據,全批視為一個單位,全部插入成功或一筆都不寫入
772
+ *
773
+ * 本函數非insert之加速版,兩者衝突政策不同:insert於主鍵已存在時跳過該筆且整批ok為1,
774
+ * 本函數則於任一筆之主鍵已存在時整批reject且不寫入任何一筆,同批含重複主鍵者亦視為衝突。
775
+ * n為輸入筆數,nInserted為實際插入筆數且成功時恆等於n。
776
+ * 不提供逐筆結果,故不出現ok:0與err,需要逐筆處置者改用insert。
777
+ * 因主鍵得承載業務語義,未帶有效主鍵值時不自動補值,一律以reject回報,
778
+ * 且主鍵檢查於任何寫入之前一次完成,故整批reject時同批之有效筆數亦不會被寫入。
779
+ *
780
+ * @memberOf WOrmPostgresql
781
+ * @param {Object|Array} data 輸入數據物件或陣列
782
+ * @returns {Promise} 回傳Promise,resolve回傳插入結果物件{n,nInserted,ok},reject回傳錯誤訊息
783
+ */
784
+ async function insertBulk(data) {
785
+ let isErr = false
786
+ let res = null
787
+
788
+ //check
789
+ if (!iseobj(data) && !isearr(data)) {
790
+ return {
791
+ n: 0,
792
+ nInserted: 0,
793
+ ok: 1,
794
+ }
795
+ }
796
+
797
+ //cloneDeep
798
+ data = cloneDeep(data)
799
+
800
+ //client
801
+ let client = new PgClient({ connectionString })
802
+
803
+ //connect
804
+ try {
805
+
806
+ //connect
807
+ await client.connect()
808
+
809
+ }
810
+ catch (err) {
811
+ isErr = true
812
+ res = err
813
+ client = null
814
+ }
815
+
816
+ //check
817
+ if (isErr) {
818
+
819
+ //emit, 整批性錯誤於reject之前發出
820
+ emitError('insertBulk', data, res)
821
+
822
+ return Promise.reject(res)
823
+ }
824
+
825
+ try {
826
+
827
+ //check
828
+ if (!isarr(data)) {
829
+ data = [data]
830
+ }
831
+
832
+ //check pk, 因主鍵得承載業務語義故不自動補值, 未帶有效主鍵值者屬整批性錯誤
833
+ data = map(data, function(v, k) {
834
+ if (!checkPk(get(v, pkName))) {
835
+ throw new Error(`invalid data[${k}].${pkName}[${get(v, pkName)}]`)
836
+ }
837
+ return v
838
+ })
604
839
 
605
840
  //nAll
606
841
  let nAll = size(data)
607
842
 
608
- //insert, ON CONFLICT DO NOTHING時rowCount即為實際插入筆數
609
- await client.query(sql, mr.values)
610
- .then((r) => {
611
-
612
- //res
613
- res = {
614
- n: nAll,
615
- nInserted: r.rowCount,
616
- ok: 1,
617
- }
843
+ //insertBulk, 不添加conflict, 令任一筆撞主鍵之唯一約束即整句失敗且不寫入任何一筆,
844
+ //同批含重複主鍵者亦於此被偵測為衝突; 筆數過多者由insertBatches分批送出並以交易維持全有全無
845
+ let nIns = await insertBatches(client, data, false)
618
846
 
619
- })
620
- .catch((err) => {
621
- isErr = true
622
- res = err.message
623
- })
847
+ //res
848
+ res = {
849
+ n: nAll,
850
+ nInserted: nIns,
851
+ ok: 1,
852
+ }
624
853
 
625
854
  }
626
855
  catch (err) {
@@ -639,16 +868,15 @@ function WOrmPostgresql(opt = {}) {
639
868
 
640
869
  //emit
641
870
  if (!isErr) {
642
- try {
643
- ee.emit('change', 'insert', data, res)
644
- }
645
- catch (err) {
646
- console.log(err)
647
- }
871
+ emitChange('insertBulk', data, res)
648
872
  }
649
873
 
650
874
  //check
651
875
  if (isErr) {
876
+
877
+ //emit, 整批性錯誤於reject之前發出
878
+ emitError('insertBulk', data, res)
879
+
652
880
  return Promise.reject(res)
653
881
  }
654
882
 
@@ -656,7 +884,7 @@ function WOrmPostgresql(opt = {}) {
656
884
  }
657
885
 
658
886
  /**
659
- * 儲存數據,以主鍵time為準更新既有數據,未給之欄位保留
887
+ * 儲存數據,以主鍵為準更新既有數據,未給之欄位保留
660
888
  *
661
889
  * 回傳陣列恆與輸入等長,輸入單一物件亦回傳長度1之陣列。
662
890
  * 各筆之n為主鍵命中筆數,值為0或1,命中(不論內容有無變更)或經插入而產生皆為1;
@@ -705,6 +933,10 @@ function WOrmPostgresql(opt = {}) {
705
933
 
706
934
  //check
707
935
  if (isErr) {
936
+
937
+ //emit, 整批性錯誤於reject之前發出
938
+ emitError('save', data, res)
939
+
708
940
  return Promise.reject(res)
709
941
  }
710
942
 
@@ -970,6 +1202,16 @@ function WOrmPostgresql(opt = {}) {
970
1202
 
971
1203
  }
972
1204
 
1205
+ //emit, 該筆經插入而產生者另發mode為insert之change事件, 供呼叫端區辨新增與更新
1206
+ if (rest.nInserted === 1) {
1207
+ emitChange('insert', [v], rest)
1208
+ }
1209
+
1210
+ //emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
1211
+ if (rest.ok === 0) {
1212
+ emitError('save', [v], rest.err)
1213
+ }
1214
+
973
1215
  return rest
974
1216
  })
975
1217
 
@@ -990,16 +1232,15 @@ function WOrmPostgresql(opt = {}) {
990
1232
 
991
1233
  //emit
992
1234
  if (!isErr) {
993
- try {
994
- ee.emit('change', 'save', data, res)
995
- }
996
- catch (err) {
997
- console.log(err)
998
- }
1235
+ emitChange('save', data, res)
999
1236
  }
1000
1237
 
1001
1238
  //check
1002
1239
  if (isErr) {
1240
+
1241
+ //emit, 整批性錯誤於reject之前發出
1242
+ emitError('save', data, res)
1243
+
1003
1244
  return Promise.reject(res)
1004
1245
  }
1005
1246
 
@@ -1048,6 +1289,10 @@ function WOrmPostgresql(opt = {}) {
1048
1289
 
1049
1290
  //check
1050
1291
  if (isErr) {
1292
+
1293
+ //emit, 整批性錯誤於reject之前發出
1294
+ emitError('del', data, res)
1295
+
1051
1296
  return Promise.reject(res)
1052
1297
  }
1053
1298
 
@@ -1083,6 +1328,9 @@ function WOrmPostgresql(opt = {}) {
1083
1328
  err: `invalid ${pkName}[${pkv}]`,
1084
1329
  }
1085
1330
 
1331
+ //emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
1332
+ emitError('del', [v], rest.err)
1333
+
1086
1334
  return rest
1087
1335
  }
1088
1336
 
@@ -1122,6 +1370,11 @@ function WOrmPostgresql(opt = {}) {
1122
1370
 
1123
1371
  })
1124
1372
 
1373
+ //emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
1374
+ if (rest.ok === 0) {
1375
+ emitError('del', [v], rest.err)
1376
+ }
1377
+
1125
1378
  return rest
1126
1379
  })
1127
1380
 
@@ -1142,16 +1395,15 @@ function WOrmPostgresql(opt = {}) {
1142
1395
 
1143
1396
  //emit
1144
1397
  if (!isErr) {
1145
- try {
1146
- ee.emit('change', 'del', data, res)
1147
- }
1148
- catch (err) {
1149
- console.log(err)
1150
- }
1398
+ emitChange('del', data, res)
1151
1399
  }
1152
1400
 
1153
1401
  //check
1154
1402
  if (isErr) {
1403
+
1404
+ //emit, 整批性錯誤於reject之前發出
1405
+ emitError('del', data, res)
1406
+
1155
1407
  return Promise.reject(res)
1156
1408
  }
1157
1409
 
@@ -1190,6 +1442,10 @@ function WOrmPostgresql(opt = {}) {
1190
1442
 
1191
1443
  //check
1192
1444
  if (isErr) {
1445
+
1446
+ //emit, 整批性錯誤於reject之前發出, 無輸入數據故data為null
1447
+ emitError('delAll', null, res)
1448
+
1193
1449
  return Promise.reject(res)
1194
1450
  }
1195
1451
 
@@ -1253,16 +1509,15 @@ function WOrmPostgresql(opt = {}) {
1253
1509
 
1254
1510
  //emit
1255
1511
  if (!isErr) {
1256
- try {
1257
- ee.emit('change', 'delAll', null, res)
1258
- }
1259
- catch (err) {
1260
- console.log(err)
1261
- }
1512
+ emitChange('delAll', null, res)
1262
1513
  }
1263
1514
 
1264
1515
  //check
1265
1516
  if (isErr) {
1517
+
1518
+ //emit, 整批性錯誤於reject之前發出
1519
+ emitError('delAll', null, res)
1520
+
1266
1521
  return Promise.reject(res)
1267
1522
  }
1268
1523
 
@@ -1274,6 +1529,7 @@ function WOrmPostgresql(opt = {}) {
1274
1529
  ee.select = select
1275
1530
  ee.selectByPk = selectByPk
1276
1531
  ee.insert = insert
1532
+ ee.insertBulk = insertBulk
1277
1533
  ee.save = save
1278
1534
  ee.del = del
1279
1535
  ee.delAll = delAll