w-orm-postgresql 1.0.9 → 1.0.11
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 +9 -8
- package/dist/w-orm-postgresql.umd.js +2 -2
- package/dist/w-orm-postgresql.umd.js.map +1 -1
- package/docs/WOrmPostgresql.html +119 -27
- package/docs/WOrmPostgresql.mjs.html +208 -77
- package/docs/index.html +2 -2
- package/g-basic.mjs +9 -8
- package/package.json +1 -1
- package/src/WOrmPostgresql.mjs +205 -74
- package/test/api-postgresql.test.mjs +408 -36
package/g-basic.mjs
CHANGED
|
@@ -168,13 +168,13 @@ async function test() {
|
|
|
168
168
|
let so = await wo.select({ name: 'rosemary' })
|
|
169
169
|
console.log('select by name', so)
|
|
170
170
|
|
|
171
|
-
//
|
|
172
|
-
let sb = await wo.
|
|
173
|
-
console.log('
|
|
171
|
+
//selectByPk
|
|
172
|
+
let sb = await wo.selectByPk('2025-01-01T00:10:00Z')
|
|
173
|
+
console.log('selectByPk', sb)
|
|
174
174
|
|
|
175
|
-
//
|
|
176
|
-
let sbn = await wo.
|
|
177
|
-
console.log('
|
|
175
|
+
//selectByPk by pk not existed
|
|
176
|
+
let sbn = await wo.selectByPk('2024-01-01T00:00:00Z')
|
|
177
|
+
console.log('selectByPk by pk not existed', sbn)
|
|
178
178
|
|
|
179
179
|
//select by $and, $gt, $lt
|
|
180
180
|
let spa = await wo.select({ '$and': [{ value: { '$gt': 123 } }, { value: { '$lt': 200 } }] })
|
|
@@ -334,12 +334,12 @@ test()
|
|
|
334
334
|
// { time: 2025-01-01T00:04:00.000Z, name: 'rosemary', value: 123.1236 },
|
|
335
335
|
// { time: 2025-01-01T00:07:00.000Z, name: 'rosemary', value: 124.76 }
|
|
336
336
|
// ]
|
|
337
|
-
//
|
|
337
|
+
// selectByPk {
|
|
338
338
|
// time: 2025-01-01T00:10:00.000Z,
|
|
339
339
|
// name: 'rosemary(modify)',
|
|
340
340
|
// value: 113.98
|
|
341
341
|
// }
|
|
342
|
-
//
|
|
342
|
+
// selectByPk by pk not existed null
|
|
343
343
|
// select by $and, $gt, $lt [
|
|
344
344
|
// { time: 2025-01-01T00:01:00.000Z, name: 'rosemary', value: 123.456 },
|
|
345
345
|
// { time: 2025-01-01T00:04:00.000Z, name: 'rosemary', value: 123.1236 },
|
|
@@ -369,6 +369,7 @@ test()
|
|
|
369
369
|
// value: 447
|
|
370
370
|
// }
|
|
371
371
|
// ]
|
|
372
|
+
// change insert
|
|
372
373
|
// change save
|
|
373
374
|
// save then [ { n: 1, nInserted: 1, nModified: 0, ok: 1 } ]
|
|
374
375
|
// change del
|
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,17 +19,23 @@ 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
|
|
|
26
26
|
/**
|
|
27
27
|
* 操作資料庫(PostgreSQL)
|
|
28
28
|
*
|
|
29
|
+
* 本套件之主鍵欄位由opt.pk指定,預設為time,select以外之五函數皆以此欄位認定主鍵。
|
|
30
|
+
* 因主鍵得為承載業務語義之欄位(如時序資料之觀測時間),insert與save於輸入未帶有效主鍵值時不自動補值,
|
|
31
|
+
* 一律以reject回報;del亦不補值,該筆回ok:0與err。
|
|
32
|
+
*
|
|
29
33
|
* @class
|
|
30
34
|
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
31
35
|
* @param {String} [opt.url='postgresql://127.0.0.1:5432'] 輸入連接資料庫字串,預設'postgresql://127.0.0.1:5432'
|
|
32
36
|
* @param {String} [opt.db='worm'] 輸入使用資料庫名稱字串,預設'worm'
|
|
33
37
|
* @param {String} [opt.cl='test'] 輸入使用資料表名稱字串,預設'test'
|
|
38
|
+
* @param {String} [opt.pk='time'] 輸入主鍵欄位名字串,預設'time'
|
|
34
39
|
* @param {Boolean} [opt.useCache=false] 輸入是否使用select快取,適用於單程序操作,預設false
|
|
35
40
|
* @returns {Object} 回傳操作資料庫物件,各事件功能詳見說明
|
|
36
41
|
*/
|
|
@@ -63,6 +68,26 @@ function WOrmPostgresql(opt = {}) {
|
|
|
63
68
|
useCache = false
|
|
64
69
|
}
|
|
65
70
|
|
|
71
|
+
//pkName, 主鍵欄位名, select以外之五函數皆以此欄位認定主鍵, 預設為time
|
|
72
|
+
let pkName = get(opt, 'pk')
|
|
73
|
+
if (!isestr(pkName)) {
|
|
74
|
+
pkName = 'time'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//checkPk, 判定主鍵值是否有效
|
|
78
|
+
//因主鍵欄位得由呼叫端指定, 其型別隨欄位而異, 故此處僅要求有給值而不限定型別,
|
|
79
|
+
//型別與欄位不符者由PostgreSQL回報, 各函數再依其規格處置
|
|
80
|
+
function checkPk(pkv) {
|
|
81
|
+
return isestr(pkv) || isnum(pkv) || isbol(pkv) || isDate(pkv)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//isErrPkType, 判定錯誤是否為[主鍵值型別與欄位不符]
|
|
85
|
+
//22P02為invalid_text_representation, 22007為invalid_datetime_format
|
|
86
|
+
function isErrPkType(err) {
|
|
87
|
+
let code = get(err, 'code')
|
|
88
|
+
return code === '22P02' || code === '22007'
|
|
89
|
+
}
|
|
90
|
+
|
|
66
91
|
//getValueType
|
|
67
92
|
function getValueType(value) {
|
|
68
93
|
if (isstr(value)) {
|
|
@@ -115,7 +140,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
115
140
|
let allKeys = keys(obj)
|
|
116
141
|
|
|
117
142
|
//conflictKeys
|
|
118
|
-
let conflictKeys = [
|
|
143
|
+
let conflictKeys = [pkName]
|
|
119
144
|
|
|
120
145
|
//updateKeys
|
|
121
146
|
let updateKeys = filter(allKeys, (k) => {
|
|
@@ -148,8 +173,40 @@ function WOrmPostgresql(opt = {}) {
|
|
|
148
173
|
let connectionString = `${url}/${db}`
|
|
149
174
|
// console.log('connectionString', connectionString)
|
|
150
175
|
|
|
151
|
-
//ee
|
|
152
|
-
|
|
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
|
+
}
|
|
153
210
|
|
|
154
211
|
//PgClient
|
|
155
212
|
let PgClient = pg.Client
|
|
@@ -190,14 +247,22 @@ function WOrmPostgresql(opt = {}) {
|
|
|
190
247
|
|
|
191
248
|
/**
|
|
192
249
|
* 創建資料表
|
|
250
|
+
* 註: pk未給時採建構時之opt.pk。因insert與save倚賴主鍵之唯一約束達成原子性,
|
|
251
|
+
* 若給予與opt.pk不同之欄位,將建出其餘函數無法正確操作之資料表,故一般應留空或給予相同值
|
|
193
252
|
*
|
|
194
253
|
* @memberOf WOrmPostgresql
|
|
195
254
|
* @param {String} cl 輸入資料表名字串
|
|
196
|
-
* @param {String} pk
|
|
255
|
+
* @param {String} [pk=opt.pk] 輸入主鍵欄位名字串,預設為建構時之opt.pk
|
|
197
256
|
* @param {Array|Object} arr 輸入數據物件陣列或數據物件
|
|
198
257
|
* @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息
|
|
199
258
|
*/
|
|
200
259
|
async function createTable(cl, pk, arr) {
|
|
260
|
+
|
|
261
|
+
//pk, 未給時採建構時設定之主鍵欄位
|
|
262
|
+
if (!isestr(pk)) {
|
|
263
|
+
pk = pkName
|
|
264
|
+
}
|
|
265
|
+
|
|
201
266
|
let isErr = false
|
|
202
267
|
let res = null
|
|
203
268
|
|
|
@@ -219,6 +284,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
219
284
|
|
|
220
285
|
//check
|
|
221
286
|
if (isErr) {
|
|
287
|
+
|
|
288
|
+
//emit, 整批性錯誤於reject之前發出
|
|
289
|
+
emitError('createTable', arr, res)
|
|
290
|
+
|
|
222
291
|
return Promise.reject(res)
|
|
223
292
|
}
|
|
224
293
|
|
|
@@ -269,6 +338,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
269
338
|
|
|
270
339
|
//check
|
|
271
340
|
if (isErr) {
|
|
341
|
+
|
|
342
|
+
//emit, 整批性錯誤於reject之前發出
|
|
343
|
+
emitError('createTable', arr, res)
|
|
344
|
+
|
|
272
345
|
return Promise.reject(res)
|
|
273
346
|
}
|
|
274
347
|
|
|
@@ -313,6 +386,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
313
386
|
|
|
314
387
|
//check
|
|
315
388
|
if (isErr) {
|
|
389
|
+
|
|
390
|
+
//emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
|
|
391
|
+
emitError('select', null, res)
|
|
392
|
+
|
|
316
393
|
return Promise.reject(res)
|
|
317
394
|
}
|
|
318
395
|
|
|
@@ -361,6 +438,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
361
438
|
|
|
362
439
|
//check
|
|
363
440
|
if (isErr) {
|
|
441
|
+
|
|
442
|
+
//emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
|
|
443
|
+
emitError('select', null, res)
|
|
444
|
+
|
|
364
445
|
return Promise.reject(res)
|
|
365
446
|
}
|
|
366
447
|
|
|
@@ -368,29 +449,29 @@ function WOrmPostgresql(opt = {}) {
|
|
|
368
449
|
}
|
|
369
450
|
|
|
370
451
|
/**
|
|
371
|
-
*
|
|
452
|
+
* 由主鍵查詢單筆數據,因直接由資料表主鍵索引取值,不需如select提取數據至前端再處理,故數據量大時效能較佳
|
|
453
|
+
* 註: 本套件之主鍵欄位由建構時之opt.pk指定,預設為time
|
|
372
454
|
*
|
|
373
|
-
* 函數名依主鍵欄位命名為selectByTime而不另掛selectById別名,因本套件之主鍵為具業務語義之time,
|
|
374
|
-
* 與以無語義識別碼為主鍵者性質不同,該差異須由呼叫端知悉而非由別名掩蓋。
|
|
375
455
|
* 主鍵未命中或主鍵值無效皆回傳null而不reject,命中之判定基準與insert、save、del內對既有數據之認定一致。
|
|
456
|
+
* 主鍵值之型別與欄位不符時PostgreSQL回報22P02或22007,亦屬主鍵值無效而回傳null。
|
|
376
457
|
*
|
|
377
458
|
* @memberOf WOrmPostgresql
|
|
378
|
-
* @param {String|Date}
|
|
379
|
-
* @returns {Promise} 回傳Promise,resolve
|
|
459
|
+
* @param {String|Number|Date} pk 輸入主鍵值,即數據之主鍵欄位值
|
|
460
|
+
* @returns {Promise} 回傳Promise,resolve回傳數據物件,若無此主鍵則回傳null,reject回傳錯誤訊息
|
|
380
461
|
*/
|
|
381
|
-
async function
|
|
462
|
+
async function selectByPk(pk) {
|
|
382
463
|
let isErr = false
|
|
383
464
|
let res = null
|
|
384
465
|
|
|
385
466
|
//check
|
|
386
|
-
if (!
|
|
387
|
-
//未給有效主鍵值視為查無數據, 判定基準與insert、save、del
|
|
467
|
+
if (!checkPk(pk)) {
|
|
468
|
+
//未給有效主鍵值視為查無數據, 判定基準與insert、save、del內對主鍵之認定一致
|
|
388
469
|
return null
|
|
389
470
|
}
|
|
390
471
|
|
|
391
|
-
//find,
|
|
472
|
+
//find, 以建構時設定之主鍵欄位查找, 與insert、save、del、genConflictSQL之認定一致
|
|
392
473
|
let find = {
|
|
393
|
-
|
|
474
|
+
[pkName]: pk,
|
|
394
475
|
}
|
|
395
476
|
|
|
396
477
|
//cache, 與select共用快取, 因快取鍵值由find與order組成, 故此處等同select(find)之結果
|
|
@@ -419,6 +500,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
419
500
|
|
|
420
501
|
//check
|
|
421
502
|
if (isErr) {
|
|
503
|
+
|
|
504
|
+
//emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
|
|
505
|
+
emitError('selectByPk', null, res)
|
|
506
|
+
|
|
422
507
|
return Promise.reject(res)
|
|
423
508
|
}
|
|
424
509
|
|
|
@@ -444,7 +529,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
444
529
|
|
|
445
530
|
//check
|
|
446
531
|
if (!isarr(rows)) {
|
|
447
|
-
throw new Error(`can not select by
|
|
532
|
+
throw new Error(`can not select by pk[${pk}]`)
|
|
448
533
|
}
|
|
449
534
|
|
|
450
535
|
//cache
|
|
@@ -460,14 +545,22 @@ function WOrmPostgresql(opt = {}) {
|
|
|
460
545
|
res = v
|
|
461
546
|
}
|
|
462
547
|
else {
|
|
463
|
-
|
|
548
|
+
//不存在主鍵, 回傳null
|
|
464
549
|
res = null
|
|
465
550
|
}
|
|
466
551
|
|
|
467
552
|
}
|
|
468
553
|
catch (err) {
|
|
469
|
-
|
|
470
|
-
|
|
554
|
+
|
|
555
|
+
//check, 主鍵值之型別與欄位不符者亦屬主鍵值無效, 依規格回傳null而不reject
|
|
556
|
+
if (isErrPkType(err)) {
|
|
557
|
+
res = null
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
isErr = true
|
|
561
|
+
res = err
|
|
562
|
+
}
|
|
563
|
+
|
|
471
564
|
}
|
|
472
565
|
finally {
|
|
473
566
|
await client.end()
|
|
@@ -477,6 +570,11 @@ function WOrmPostgresql(opt = {}) {
|
|
|
477
570
|
|
|
478
571
|
//check
|
|
479
572
|
if (isErr) {
|
|
573
|
+
|
|
574
|
+
//emit, 整批性錯誤於reject之前發出, 讀取函數無輸入數據故data為null
|
|
575
|
+
//主鍵未命中與主鍵值無效皆為正常結果而不設isErr, 故不會誤發error
|
|
576
|
+
emitError('selectByPk', null, res)
|
|
577
|
+
|
|
480
578
|
return Promise.reject(res)
|
|
481
579
|
}
|
|
482
580
|
|
|
@@ -484,11 +582,11 @@ function WOrmPostgresql(opt = {}) {
|
|
|
484
582
|
}
|
|
485
583
|
|
|
486
584
|
/**
|
|
487
|
-
*
|
|
585
|
+
* 插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫
|
|
488
586
|
*
|
|
489
587
|
* n為輸入筆數,即本次嘗試插入之基準;nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果,
|
|
490
|
-
*
|
|
491
|
-
*
|
|
588
|
+
* 不視為錯誤。同批含重複主鍵時僅首筆計入nInserted。
|
|
589
|
+
* 因主鍵得承載業務語義,未帶有效主鍵值時不自動補值,一律以reject回報。
|
|
492
590
|
*
|
|
493
591
|
* @memberOf WOrmPostgresql
|
|
494
592
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
@@ -528,6 +626,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
528
626
|
|
|
529
627
|
//check
|
|
530
628
|
if (isErr) {
|
|
629
|
+
|
|
630
|
+
//emit, 整批性錯誤於reject之前發出
|
|
631
|
+
emitError('insert', data, res)
|
|
632
|
+
|
|
531
633
|
return Promise.reject(res)
|
|
532
634
|
}
|
|
533
635
|
|
|
@@ -538,10 +640,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
538
640
|
data = [data]
|
|
539
641
|
}
|
|
540
642
|
|
|
541
|
-
//check
|
|
643
|
+
//check pk, 因主鍵得承載業務語義故不自動補值, 未帶有效主鍵值者屬整批性錯誤
|
|
542
644
|
data = map(data, function(v, k) {
|
|
543
|
-
if (!
|
|
544
|
-
throw new Error(`invalid data[${k}]
|
|
645
|
+
if (!checkPk(get(v, pkName))) {
|
|
646
|
+
throw new Error(`invalid data[${k}].${pkName}[${get(v, pkName)}]`)
|
|
545
647
|
}
|
|
546
648
|
return v
|
|
547
649
|
})
|
|
@@ -556,10 +658,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
556
658
|
// console.log('mr.query', mr.query)
|
|
557
659
|
// console.log('mr.values', mr.values)
|
|
558
660
|
|
|
559
|
-
//添加conflict,
|
|
560
|
-
//由PostgreSQL於單一語句內原子完成[
|
|
561
|
-
|
|
562
|
-
let sql = `${mr.query} ON CONFLICT (
|
|
661
|
+
//添加conflict, 令已存在主鍵者跳過而不中斷整批插入, 主鍵認定與genConflictSQL一致
|
|
662
|
+
//由PostgreSQL於單一語句內原子完成[檢查主鍵未存在]與[寫入], 併發時同一主鍵僅有一次成功,
|
|
663
|
+
//同批含重複主鍵時亦僅首筆成功, 故不須逐筆插入即可取得實際插入筆數
|
|
664
|
+
let sql = `${mr.query} ON CONFLICT (${pkName}) DO NOTHING`
|
|
563
665
|
|
|
564
666
|
//nAll
|
|
565
667
|
let nAll = size(data)
|
|
@@ -598,16 +700,15 @@ function WOrmPostgresql(opt = {}) {
|
|
|
598
700
|
|
|
599
701
|
//emit
|
|
600
702
|
if (!isErr) {
|
|
601
|
-
|
|
602
|
-
ee.emit('change', 'insert', data, res)
|
|
603
|
-
}
|
|
604
|
-
catch (err) {
|
|
605
|
-
console.log(err)
|
|
606
|
-
}
|
|
703
|
+
emitChange('insert', data, res)
|
|
607
704
|
}
|
|
608
705
|
|
|
609
706
|
//check
|
|
610
707
|
if (isErr) {
|
|
708
|
+
|
|
709
|
+
//emit, 整批性錯誤於reject之前發出
|
|
710
|
+
emitError('insert', data, res)
|
|
711
|
+
|
|
611
712
|
return Promise.reject(res)
|
|
612
713
|
}
|
|
613
714
|
|
|
@@ -623,7 +724,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
623
724
|
* [內容相同]之判定基準為待寫入物件合併進現值後與現值相同,非待寫入物件與現值全等,
|
|
624
725
|
* 故只給部份欄位且該些欄位值皆與現值相同時,合併結果等於現值,nModified為0,
|
|
625
726
|
* 令nModified忠實反映資料庫端是否真的寫入。
|
|
626
|
-
*
|
|
727
|
+
* 因主鍵得承載業務語義,未帶有效主鍵值時不自動補值,一律以reject回報。
|
|
627
728
|
*
|
|
628
729
|
* @memberOf WOrmPostgresql
|
|
629
730
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
@@ -664,6 +765,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
664
765
|
|
|
665
766
|
//check
|
|
666
767
|
if (isErr) {
|
|
768
|
+
|
|
769
|
+
//emit, 整批性錯誤於reject之前發出
|
|
770
|
+
emitError('save', data, res)
|
|
771
|
+
|
|
667
772
|
return Promise.reject(res)
|
|
668
773
|
}
|
|
669
774
|
|
|
@@ -674,10 +779,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
674
779
|
data = [data]
|
|
675
780
|
}
|
|
676
781
|
|
|
677
|
-
//check
|
|
782
|
+
//check pk, 因主鍵得承載業務語義故不自動補值, 未帶有效主鍵值者屬整批性錯誤
|
|
678
783
|
data = map(data, function(v, k) {
|
|
679
|
-
if (!
|
|
680
|
-
throw new Error(`invalid data[${k}]
|
|
784
|
+
if (!checkPk(get(v, pkName))) {
|
|
785
|
+
throw new Error(`invalid data[${k}].${pkName}[${get(v, pkName)}]`)
|
|
681
786
|
}
|
|
682
787
|
return v
|
|
683
788
|
})
|
|
@@ -688,6 +793,9 @@ function WOrmPostgresql(opt = {}) {
|
|
|
688
793
|
//rest
|
|
689
794
|
let rest = null
|
|
690
795
|
|
|
796
|
+
//pkv
|
|
797
|
+
let pkv = get(v, pkName)
|
|
798
|
+
|
|
691
799
|
//_v
|
|
692
800
|
let _v = null
|
|
693
801
|
if (true) {
|
|
@@ -697,7 +805,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
697
805
|
type: 'select',
|
|
698
806
|
table: cl,
|
|
699
807
|
where: {
|
|
700
|
-
|
|
808
|
+
[pkName]: pkv,
|
|
701
809
|
},
|
|
702
810
|
// limit: 10,
|
|
703
811
|
// order,
|
|
@@ -726,7 +834,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
726
834
|
if (iseobj(_v)) {
|
|
727
835
|
|
|
728
836
|
//_vt
|
|
729
|
-
let _vt = omit(_v,
|
|
837
|
+
let _vt = omit(_v, pkName)
|
|
730
838
|
// console.log('_vt', _vt)
|
|
731
839
|
|
|
732
840
|
//vt, [內容相同]之判定基準為[待寫入物件合併進現值後與現值相同],
|
|
@@ -734,7 +842,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
734
842
|
//合併採淺層覆蓋, 與後端以EXCLUDED整欄取代之寫入行為一致
|
|
735
843
|
let vt = {
|
|
736
844
|
..._vt,
|
|
737
|
-
...omit(v,
|
|
845
|
+
...omit(v, pkName),
|
|
738
846
|
}
|
|
739
847
|
// console.log('vt', vt)
|
|
740
848
|
|
|
@@ -789,11 +897,11 @@ function WOrmPostgresql(opt = {}) {
|
|
|
789
897
|
// console.log('mr.query', mr.query)
|
|
790
898
|
// console.log('mr.values', mr.values)
|
|
791
899
|
|
|
792
|
-
//添加conflict,
|
|
793
|
-
//此時退回DO NOTHING,
|
|
900
|
+
//添加conflict, 僅有主鍵欄位時genConflictSQL無可更新欄位而回傳空字串,
|
|
901
|
+
//此時退回DO NOTHING, 以免併發插入同一主鍵者報錯
|
|
794
902
|
let conflict = genConflictSQL(v)
|
|
795
903
|
if (!isestr(conflict)) {
|
|
796
|
-
conflict =
|
|
904
|
+
conflict = `ON CONFLICT (${pkName}) DO NOTHING`
|
|
797
905
|
}
|
|
798
906
|
|
|
799
907
|
//sql, xmax為0表該列由本語句插入, 非0表係由DO UPDATE更新而來,
|
|
@@ -864,15 +972,15 @@ function WOrmPostgresql(opt = {}) {
|
|
|
864
972
|
}
|
|
865
973
|
else {
|
|
866
974
|
//未開啟autoInsert則僅能更新既有數據, 不可用INSERT以免無中生有,
|
|
867
|
-
//由UPDATE...WHERE
|
|
975
|
+
//由UPDATE...WHERE主鍵原子完成[查找主鍵]與[更新], 併發時不會遺失更新
|
|
868
976
|
|
|
869
977
|
//mr
|
|
870
978
|
let mr = mongoSql.sql({
|
|
871
979
|
type: 'update',
|
|
872
980
|
table: cl,
|
|
873
|
-
updates: omit(v,
|
|
981
|
+
updates: omit(v, pkName),
|
|
874
982
|
where: {
|
|
875
|
-
|
|
983
|
+
[pkName]: pkv,
|
|
876
984
|
},
|
|
877
985
|
})
|
|
878
986
|
// console.log('mr', mr)
|
|
@@ -926,6 +1034,16 @@ function WOrmPostgresql(opt = {}) {
|
|
|
926
1034
|
|
|
927
1035
|
}
|
|
928
1036
|
|
|
1037
|
+
//emit, 該筆經插入而產生者另發mode為insert之change事件, 供呼叫端區辨新增與更新
|
|
1038
|
+
if (rest.nInserted === 1) {
|
|
1039
|
+
emitChange('insert', [v], rest)
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
//emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
|
|
1043
|
+
if (rest.ok === 0) {
|
|
1044
|
+
emitError('save', [v], rest.err)
|
|
1045
|
+
}
|
|
1046
|
+
|
|
929
1047
|
return rest
|
|
930
1048
|
})
|
|
931
1049
|
|
|
@@ -946,16 +1064,15 @@ function WOrmPostgresql(opt = {}) {
|
|
|
946
1064
|
|
|
947
1065
|
//emit
|
|
948
1066
|
if (!isErr) {
|
|
949
|
-
|
|
950
|
-
ee.emit('change', 'save', data, res)
|
|
951
|
-
}
|
|
952
|
-
catch (err) {
|
|
953
|
-
console.log(err)
|
|
954
|
-
}
|
|
1067
|
+
emitChange('save', data, res)
|
|
955
1068
|
}
|
|
956
1069
|
|
|
957
1070
|
//check
|
|
958
1071
|
if (isErr) {
|
|
1072
|
+
|
|
1073
|
+
//emit, 整批性錯誤於reject之前發出
|
|
1074
|
+
emitError('save', data, res)
|
|
1075
|
+
|
|
959
1076
|
return Promise.reject(res)
|
|
960
1077
|
}
|
|
961
1078
|
|
|
@@ -967,7 +1084,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
967
1084
|
*
|
|
968
1085
|
* 回傳陣列恆與輸入等長,各筆之n與nDeleted皆為主鍵命中筆數,值為0或1,未命中為0且屬正常結果。
|
|
969
1086
|
* 判斷某筆是否真的被刪除一律以nDeleted為準。
|
|
970
|
-
*
|
|
1087
|
+
* 未帶有效主鍵值者為該筆之輸入問題,回ok:0與err且不送查詢,不中斷其餘筆數,
|
|
971
1088
|
* 以此與[主鍵未命中]之ok:1區辨。
|
|
972
1089
|
*
|
|
973
1090
|
* @memberOf WOrmPostgresql
|
|
@@ -1004,6 +1121,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1004
1121
|
|
|
1005
1122
|
//check
|
|
1006
1123
|
if (isErr) {
|
|
1124
|
+
|
|
1125
|
+
//emit, 整批性錯誤於reject之前發出
|
|
1126
|
+
emitError('del', data, res)
|
|
1127
|
+
|
|
1007
1128
|
return Promise.reject(res)
|
|
1008
1129
|
}
|
|
1009
1130
|
|
|
@@ -1024,21 +1145,24 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1024
1145
|
//rest
|
|
1025
1146
|
let rest = null
|
|
1026
1147
|
|
|
1027
|
-
//
|
|
1028
|
-
let
|
|
1148
|
+
//pkv
|
|
1149
|
+
let pkv = get(v, pkName)
|
|
1029
1150
|
|
|
1030
|
-
//check
|
|
1151
|
+
//check pk, 未帶有效主鍵者不補值亦不送查詢,
|
|
1031
1152
|
//因mongo-sql會將無效值轉為null而誤中其他數據, 故直接視為該筆無法處理
|
|
1032
|
-
if (!
|
|
1153
|
+
if (!checkPk(pkv)) {
|
|
1033
1154
|
|
|
1034
1155
|
//rest
|
|
1035
1156
|
rest = {
|
|
1036
1157
|
n: 0,
|
|
1037
1158
|
nDeleted: 0,
|
|
1038
1159
|
ok: 0,
|
|
1039
|
-
err: `invalid
|
|
1160
|
+
err: `invalid ${pkName}[${pkv}]`,
|
|
1040
1161
|
}
|
|
1041
1162
|
|
|
1163
|
+
//emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
|
|
1164
|
+
emitError('del', [v], rest.err)
|
|
1165
|
+
|
|
1042
1166
|
return rest
|
|
1043
1167
|
}
|
|
1044
1168
|
|
|
@@ -1047,7 +1171,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1047
1171
|
type: 'delete',
|
|
1048
1172
|
table: cl,
|
|
1049
1173
|
where: {
|
|
1050
|
-
|
|
1174
|
+
[pkName]: pkv,
|
|
1051
1175
|
},
|
|
1052
1176
|
})
|
|
1053
1177
|
// console.log('mr', mr)
|
|
@@ -1078,6 +1202,11 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1078
1202
|
|
|
1079
1203
|
})
|
|
1080
1204
|
|
|
1205
|
+
//emit, 逐筆失敗於該筆結果定案後發出, 每筆一次
|
|
1206
|
+
if (rest.ok === 0) {
|
|
1207
|
+
emitError('del', [v], rest.err)
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1081
1210
|
return rest
|
|
1082
1211
|
})
|
|
1083
1212
|
|
|
@@ -1098,16 +1227,15 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1098
1227
|
|
|
1099
1228
|
//emit
|
|
1100
1229
|
if (!isErr) {
|
|
1101
|
-
|
|
1102
|
-
ee.emit('change', 'del', data, res)
|
|
1103
|
-
}
|
|
1104
|
-
catch (err) {
|
|
1105
|
-
console.log(err)
|
|
1106
|
-
}
|
|
1230
|
+
emitChange('del', data, res)
|
|
1107
1231
|
}
|
|
1108
1232
|
|
|
1109
1233
|
//check
|
|
1110
1234
|
if (isErr) {
|
|
1235
|
+
|
|
1236
|
+
//emit, 整批性錯誤於reject之前發出
|
|
1237
|
+
emitError('del', data, res)
|
|
1238
|
+
|
|
1111
1239
|
return Promise.reject(res)
|
|
1112
1240
|
}
|
|
1113
1241
|
|
|
@@ -1146,6 +1274,10 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1146
1274
|
|
|
1147
1275
|
//check
|
|
1148
1276
|
if (isErr) {
|
|
1277
|
+
|
|
1278
|
+
//emit, 整批性錯誤於reject之前發出, 無輸入數據故data為null
|
|
1279
|
+
emitError('delAll', null, res)
|
|
1280
|
+
|
|
1149
1281
|
return Promise.reject(res)
|
|
1150
1282
|
}
|
|
1151
1283
|
|
|
@@ -1209,16 +1341,15 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1209
1341
|
|
|
1210
1342
|
//emit
|
|
1211
1343
|
if (!isErr) {
|
|
1212
|
-
|
|
1213
|
-
ee.emit('change', 'delAll', null, res)
|
|
1214
|
-
}
|
|
1215
|
-
catch (err) {
|
|
1216
|
-
console.log(err)
|
|
1217
|
-
}
|
|
1344
|
+
emitChange('delAll', null, res)
|
|
1218
1345
|
}
|
|
1219
1346
|
|
|
1220
1347
|
//check
|
|
1221
1348
|
if (isErr) {
|
|
1349
|
+
|
|
1350
|
+
//emit, 整批性錯誤於reject之前發出
|
|
1351
|
+
emitError('delAll', null, res)
|
|
1352
|
+
|
|
1222
1353
|
return Promise.reject(res)
|
|
1223
1354
|
}
|
|
1224
1355
|
|
|
@@ -1228,7 +1359,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1228
1359
|
//save
|
|
1229
1360
|
ee.createTable = createTable
|
|
1230
1361
|
ee.select = select
|
|
1231
|
-
ee.
|
|
1362
|
+
ee.selectByPk = selectByPk
|
|
1232
1363
|
ee.insert = insert
|
|
1233
1364
|
ee.save = save
|
|
1234
1365
|
ee.del = del
|