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
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
package/src/WOrmPostgresql.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
//
|
|
591
|
-
let
|
|
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
|
-
|
|
725
|
+
//insert, 以ON CONFLICT DO NOTHING令已存在主鍵者跳過而不中斷整批插入,
|
|
601
726
|
//由PostgreSQL於單一語句內原子完成[檢查主鍵未存在]與[寫入], 併發時同一主鍵僅有一次成功,
|
|
602
727
|
//同批含重複主鍵時亦僅首筆成功, 故不須逐筆插入即可取得實際插入筆數
|
|
603
|
-
|
|
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
|
-
//
|
|
609
|
-
|
|
610
|
-
|
|
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
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|