w-orm-postgresql 1.0.11 → 1.0.13
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 +83 -0
- package/dist/w-orm-postgresql.umd.js +2 -2
- package/dist/w-orm-postgresql.umd.js.map +1 -1
- package/docs/WOrmPostgresql.html +312 -14
- package/docs/WOrmPostgresql.mjs.html +286 -35
- package/docs/index.html +2 -2
- package/g-basic.mjs +83 -0
- package/package.json +1 -1
- package/src/WOrmPostgresql.mjs +284 -33
- package/test/api-postgresql.test.mjs +452 -0
- package/toolg/gDistRollup.mjs +1 -1
|
@@ -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="WOrmPostgresql.html">WOrmPostgresql</a><ul class='methods'><li data-type='method'><a href="WOrmPostgresql.html#.createTable">createTable</a></li><li data-type='method'><a href="WOrmPostgresql.html#.del">del</a></li><li data-type='method'><a href="WOrmPostgresql.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insert">insert</a></li><li data-type='method'><a href="WOrmPostgresql.html#.save">save</a></li><li data-type='method'><a href="WOrmPostgresql.html#.select">select</a></li><li data-type='method'><a href="WOrmPostgresql.html#.selectByPk">selectByPk</a></li></ul></li></ul>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmPostgresql.html">WOrmPostgresql</a><ul class='methods'><li data-type='method'><a href="WOrmPostgresql.html#.createTable">createTable</a></li><li data-type='method'><a href="WOrmPostgresql.html#.del">del</a></li><li data-type='method'><a href="WOrmPostgresql.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insert">insert</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insertBulk">insertBulk</a></li><li data-type='method'><a href="WOrmPostgresql.html#.save">save</a></li><li data-type='method'><a href="WOrmPostgresql.html#.select">select</a></li><li data-type='method'><a href="WOrmPostgresql.html#.selectByPk">selectByPk</a></li></ul></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -292,6 +292,134 @@ function WOrmPostgresql(opt = {}) {
|
|
|
292
292
|
_cache[key] = cloneDeep(data) //與外部使用數據脫勾
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
//insertBatches, 分批送出插入語句並以交易包覆, 回傳實際插入筆數, 供insert與insertBulk共用
|
|
296
|
+
//PostgreSQL之協定以int16記綁定參數個數故上限為65535, 單一語句可送之筆數受欄位數所限,
|
|
297
|
+
//超出者須分批送出; 分批後單語句之原子性已不足以維持[失敗即不留下部份寫入], 故一律以交易包覆,
|
|
298
|
+
//令單批與分批之保證來源一致而不因批數而異
|
|
299
|
+
//兩函數之衝突政策由useConflict區分, 語句各自獨立:
|
|
300
|
+
// true : 添加ON CONFLICT DO NOTHING, 已存在主鍵者跳過而不中斷整批, 為insert之語義
|
|
301
|
+
// false: 不添加, 任一筆撞主鍵之唯一約束即整句失敗且不寫入任何一筆, 為insertBulk之全有全無語義
|
|
302
|
+
let insertBatches = async (client, data, useConflict, returnPk = false) => {
|
|
303
|
+
|
|
304
|
+
//nCols, 取各筆欄位數之最大值
|
|
305
|
+
let nCols = 1
|
|
306
|
+
data.forEach(function(v) {
|
|
307
|
+
nCols = Math.max(nCols, size(keys(v)))
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
//nPerBatch
|
|
311
|
+
let nPerBatch = Math.max(1, Math.floor(65535 / nCols))
|
|
312
|
+
|
|
313
|
+
//ltdata, 分批
|
|
314
|
+
let ltdata = []
|
|
315
|
+
for (let i = 0; i < size(data); i += nPerBatch) {
|
|
316
|
+
ltdata.push(data.slice(i, i + nPerBatch))
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
//transaction
|
|
320
|
+
await client.query('BEGIN')
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
|
|
324
|
+
//nIns, rows
|
|
325
|
+
let nIns = 0
|
|
326
|
+
let rows = []
|
|
327
|
+
|
|
328
|
+
//each batch
|
|
329
|
+
for (let dt of ltdata) {
|
|
330
|
+
|
|
331
|
+
//mr
|
|
332
|
+
let mr = mongoSql.sql({
|
|
333
|
+
type: 'insert',
|
|
334
|
+
table: cl,
|
|
335
|
+
values: dt,
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
//sql
|
|
339
|
+
let sql = mr.query
|
|
340
|
+
if (useConflict) {
|
|
341
|
+
sql = `${sql} ON CONFLICT (${pkName}) DO NOTHING`
|
|
342
|
+
}
|
|
343
|
+
if (returnPk) {
|
|
344
|
+
//RETURNING僅回傳實際插入之列, 供逐筆結果映回輸入序
|
|
345
|
+
sql = `${sql} RETURNING ${pkName}`
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
//insert
|
|
349
|
+
let r = await client.query(sql, mr.values)
|
|
350
|
+
|
|
351
|
+
//nIns
|
|
352
|
+
nIns += r.rowCount
|
|
353
|
+
|
|
354
|
+
//rows, 分批時逐批收集再串接
|
|
355
|
+
if (returnPk) {
|
|
356
|
+
rows = rows.concat(get(r, 'rows', []))
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
//commit
|
|
362
|
+
await client.query('COMMIT')
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
nIns,
|
|
366
|
+
rows,
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
|
|
371
|
+
//rollback, 令已送出之批次一併回滾
|
|
372
|
+
await client.query('ROLLBACK').catch(() => {})
|
|
373
|
+
|
|
374
|
+
throw err
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
//genInsertList, 依RETURNING所回傳之主鍵值映回輸入序, 產生與輸入等長且保序之逐筆結果
|
|
380
|
+
//後端回傳之型別未必與輸入相同(如TIMESTAMPTZ欄位輸入字串而回傳Date物件), 直接比對必然落空,
|
|
381
|
+
//故依回傳值之實際型別決定正規化方式, 且兩側共用同一函數
|
|
382
|
+
//不採[一律嘗試解析為日期]之通用寫法, 因主鍵為文字欄位而值形如'2025'與'2025-01-01'者
|
|
383
|
+
//將正規化為同值而誤判, 依實際型別分流則無此問題
|
|
384
|
+
//同批含重複主鍵時RETURNING僅回傳一次, 故以首次出現者為已插入, 其餘視為已存在而跳過
|
|
385
|
+
let genInsertList = (data, rows) => {
|
|
386
|
+
|
|
387
|
+
//isDateCol, 以回傳值之實際型別判定
|
|
388
|
+
let isDateCol = size(rows) > 0 && rows[0][pkName] instanceof Date
|
|
389
|
+
|
|
390
|
+
//normPk
|
|
391
|
+
let normPk = (v) => {
|
|
392
|
+
if (isDateCol) {
|
|
393
|
+
return new Date(v).toISOString()
|
|
394
|
+
}
|
|
395
|
+
return String(v)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
//setIns, 實際插入之主鍵
|
|
399
|
+
let setIns = new Set()
|
|
400
|
+
rows.forEach(function(v) {
|
|
401
|
+
setIns.add(normPk(get(v, pkName)))
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
//ltres
|
|
405
|
+
let setSeen = new Set()
|
|
406
|
+
return map(data, function(v) {
|
|
407
|
+
|
|
408
|
+
//pkv
|
|
409
|
+
let pkv = normPk(get(v, pkName))
|
|
410
|
+
|
|
411
|
+
//inserted
|
|
412
|
+
let inserted = setIns.has(pkv) && !setSeen.has(pkv)
|
|
413
|
+
setSeen.add(pkv)
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
n: 1,
|
|
417
|
+
nInserted: inserted ? 1 : 0,
|
|
418
|
+
ok: 1,
|
|
419
|
+
}
|
|
420
|
+
})
|
|
421
|
+
}
|
|
422
|
+
|
|
295
423
|
/**
|
|
296
424
|
* 創建資料表
|
|
297
425
|
* 註: pk未給時採建構時之opt.pk。因insert與save倚賴主鍵之唯一約束達成原子性,
|
|
@@ -631,20 +759,38 @@ function WOrmPostgresql(opt = {}) {
|
|
|
631
759
|
/**
|
|
632
760
|
* 插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫
|
|
633
761
|
*
|
|
634
|
-
* n
|
|
635
|
-
*
|
|
762
|
+
* 預設回傳單一聚合物件,n為輸入筆數即本次嘗試插入之基準;nInserted為實際插入筆數,
|
|
763
|
+
* 全數已存在而nInserted為0屬正常結果,不視為錯誤。同批含重複主鍵時僅首筆計入nInserted。
|
|
636
764
|
* 因主鍵得承載業務語義,未帶有效主鍵值時不自動補值,一律以reject回報。
|
|
637
765
|
*
|
|
766
|
+
* option.returnList為true時改回傳與輸入等長且保序之逐筆陣列,令呼叫端得知[是哪幾筆]為新數據,
|
|
767
|
+
* 而非僅知[有幾筆]。各元素之n恆為1、ok恆為1,因insert之任何錯誤皆屬整批性錯誤而reject,
|
|
768
|
+
* 故逐筆元素不出現ok:0與err;同批含重複主鍵者以首次出現者之nInserted為1,其餘為0。
|
|
769
|
+
* 兩種取值下之不變式為陣列長度等於輸入筆數,且nInserted為1者之筆數等於聚合模式之nInserted。
|
|
770
|
+
*
|
|
638
771
|
* @memberOf WOrmPostgresql
|
|
639
772
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
640
|
-
* @
|
|
773
|
+
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
774
|
+
* @param {Boolean} [option.returnList=false] 輸入是否改回傳逐筆結果陣列,預設為false
|
|
775
|
+
* @returns {Promise} 回傳Promise,resolve於returnList為false時回傳插入結果物件{n,nInserted,ok},
|
|
776
|
+
* 為true時回傳逐筆結果陣列[{n,nInserted,ok}],reject回傳錯誤訊息
|
|
641
777
|
*/
|
|
642
|
-
async function insert(data) {
|
|
778
|
+
async function insert(data, option = {}) {
|
|
643
779
|
let isErr = false
|
|
644
780
|
let res = null
|
|
645
781
|
|
|
782
|
+
//returnList
|
|
783
|
+
let returnList = get(option, 'returnList', false)
|
|
784
|
+
if (!isbol(returnList)) {
|
|
785
|
+
returnList = false
|
|
786
|
+
}
|
|
787
|
+
|
|
646
788
|
//check
|
|
789
|
+
//輸入無效時, returnList為true者回傳空陣列以對齊save與del之規定
|
|
647
790
|
if (!iseobj(data) && !isearr(data)) {
|
|
791
|
+
if (returnList) {
|
|
792
|
+
return []
|
|
793
|
+
}
|
|
648
794
|
return {
|
|
649
795
|
n: 0,
|
|
650
796
|
nInserted: 0,
|
|
@@ -695,40 +841,144 @@ function WOrmPostgresql(opt = {}) {
|
|
|
695
841
|
return v
|
|
696
842
|
})
|
|
697
843
|
|
|
698
|
-
//
|
|
699
|
-
let
|
|
700
|
-
type: 'insert',
|
|
701
|
-
table: cl,
|
|
702
|
-
values: data,
|
|
703
|
-
})
|
|
704
|
-
// console.log('mr', mr)
|
|
705
|
-
// console.log('mr.query', mr.query)
|
|
706
|
-
// console.log('mr.values', mr.values)
|
|
844
|
+
//nAll
|
|
845
|
+
let nAll = size(data)
|
|
707
846
|
|
|
708
|
-
|
|
847
|
+
//insert, 以ON CONFLICT DO NOTHING令已存在主鍵者跳過而不中斷整批插入,
|
|
709
848
|
//由PostgreSQL於單一語句內原子完成[檢查主鍵未存在]與[寫入], 併發時同一主鍵僅有一次成功,
|
|
710
849
|
//同批含重複主鍵時亦僅首筆成功, 故不須逐筆插入即可取得實際插入筆數
|
|
711
|
-
|
|
850
|
+
//筆數過多而超出綁定參數上限者由insertBatches分批送出, 主鍵認定與genConflictSQL一致
|
|
851
|
+
//returnList為true時另附RETURNING, 以實際插入之主鍵映回輸入序而得逐筆結果
|
|
852
|
+
let { nIns, rows } = await insertBatches(client, data, true, returnList)
|
|
853
|
+
|
|
854
|
+
//res
|
|
855
|
+
if (returnList) {
|
|
856
|
+
res = genInsertList(data, rows)
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
res = {
|
|
860
|
+
n: nAll,
|
|
861
|
+
nInserted: nIns,
|
|
862
|
+
ok: 1,
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
}
|
|
867
|
+
catch (err) {
|
|
868
|
+
isErr = true
|
|
869
|
+
res = err
|
|
870
|
+
}
|
|
871
|
+
finally {
|
|
872
|
+
await client.end()
|
|
873
|
+
client = null
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
//update
|
|
877
|
+
if (useCache) {
|
|
878
|
+
clearCache()
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
//emit
|
|
882
|
+
if (!isErr) {
|
|
883
|
+
emitChange('insert', data, res)
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
//check
|
|
887
|
+
if (isErr) {
|
|
888
|
+
|
|
889
|
+
//emit, 整批性錯誤於reject之前發出
|
|
890
|
+
emitError('insert', data, res)
|
|
891
|
+
|
|
892
|
+
return Promise.reject(res)
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
return res
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* 批次插入數據,全批視為一個單位,全部插入成功或一筆都不寫入
|
|
900
|
+
*
|
|
901
|
+
* 本函數非insert之加速版,兩者衝突政策不同:insert於主鍵已存在時跳過該筆且整批ok為1,
|
|
902
|
+
* 本函數則於任一筆之主鍵已存在時整批reject且不寫入任何一筆,同批含重複主鍵者亦視為衝突。
|
|
903
|
+
* n為輸入筆數,nInserted為實際插入筆數且成功時恆等於n。
|
|
904
|
+
* 不提供逐筆結果,故不出現ok:0與err,需要逐筆處置者改用insert。
|
|
905
|
+
* 因主鍵得承載業務語義,未帶有效主鍵值時不自動補值,一律以reject回報,
|
|
906
|
+
* 且主鍵檢查於任何寫入之前一次完成,故整批reject時同批之有效筆數亦不會被寫入。
|
|
907
|
+
*
|
|
908
|
+
* @memberOf WOrmPostgresql
|
|
909
|
+
* @param {Object|Array} data 輸入數據物件或陣列
|
|
910
|
+
* @returns {Promise} 回傳Promise,resolve回傳插入結果物件{n,nInserted,ok},reject回傳錯誤訊息
|
|
911
|
+
*/
|
|
912
|
+
async function insertBulk(data) {
|
|
913
|
+
let isErr = false
|
|
914
|
+
let res = null
|
|
915
|
+
|
|
916
|
+
//check
|
|
917
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
918
|
+
return {
|
|
919
|
+
n: 0,
|
|
920
|
+
nInserted: 0,
|
|
921
|
+
ok: 1,
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
//cloneDeep
|
|
926
|
+
data = cloneDeep(data)
|
|
927
|
+
|
|
928
|
+
//client
|
|
929
|
+
let client = new PgClient({ connectionString })
|
|
930
|
+
|
|
931
|
+
//connect
|
|
932
|
+
try {
|
|
933
|
+
|
|
934
|
+
//connect
|
|
935
|
+
await client.connect()
|
|
936
|
+
|
|
937
|
+
}
|
|
938
|
+
catch (err) {
|
|
939
|
+
isErr = true
|
|
940
|
+
res = err
|
|
941
|
+
client = null
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
//check
|
|
945
|
+
if (isErr) {
|
|
946
|
+
|
|
947
|
+
//emit, 整批性錯誤於reject之前發出
|
|
948
|
+
emitError('insertBulk', data, res)
|
|
949
|
+
|
|
950
|
+
return Promise.reject(res)
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
try {
|
|
954
|
+
|
|
955
|
+
//check
|
|
956
|
+
if (!isarr(data)) {
|
|
957
|
+
data = [data]
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
//check pk, 因主鍵得承載業務語義故不自動補值, 未帶有效主鍵值者屬整批性錯誤
|
|
961
|
+
data = map(data, function(v, k) {
|
|
962
|
+
if (!checkPk(get(v, pkName))) {
|
|
963
|
+
throw new Error(`invalid data[${k}].${pkName}[${get(v, pkName)}]`)
|
|
964
|
+
}
|
|
965
|
+
return v
|
|
966
|
+
})
|
|
712
967
|
|
|
713
968
|
//nAll
|
|
714
969
|
let nAll = size(data)
|
|
715
970
|
|
|
716
|
-
//
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
//res
|
|
721
|
-
res = {
|
|
722
|
-
n: nAll,
|
|
723
|
-
nInserted: r.rowCount,
|
|
724
|
-
ok: 1,
|
|
725
|
-
}
|
|
971
|
+
//insertBulk, 不添加conflict, 令任一筆撞主鍵之唯一約束即整句失敗且不寫入任何一筆,
|
|
972
|
+
//同批含重複主鍵者亦於此被偵測為衝突; 筆數過多者由insertBatches分批送出並以交易維持全有全無
|
|
973
|
+
//不附RETURNING, 因成功時逐筆恆為已插入而nInserted恆等於n, 取回主鍵值無資訊量
|
|
974
|
+
let { nIns } = await insertBatches(client, data, false)
|
|
726
975
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
976
|
+
//res
|
|
977
|
+
res = {
|
|
978
|
+
n: nAll,
|
|
979
|
+
nInserted: nIns,
|
|
980
|
+
ok: 1,
|
|
981
|
+
}
|
|
732
982
|
|
|
733
983
|
}
|
|
734
984
|
catch (err) {
|
|
@@ -747,14 +997,14 @@ function WOrmPostgresql(opt = {}) {
|
|
|
747
997
|
|
|
748
998
|
//emit
|
|
749
999
|
if (!isErr) {
|
|
750
|
-
emitChange('
|
|
1000
|
+
emitChange('insertBulk', data, res)
|
|
751
1001
|
}
|
|
752
1002
|
|
|
753
1003
|
//check
|
|
754
1004
|
if (isErr) {
|
|
755
1005
|
|
|
756
1006
|
//emit, 整批性錯誤於reject之前發出
|
|
757
|
-
emitError('
|
|
1007
|
+
emitError('insertBulk', data, res)
|
|
758
1008
|
|
|
759
1009
|
return Promise.reject(res)
|
|
760
1010
|
}
|
|
@@ -763,7 +1013,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
763
1013
|
}
|
|
764
1014
|
|
|
765
1015
|
/**
|
|
766
|
-
*
|
|
1016
|
+
* 儲存數據,以主鍵為準更新既有數據,未給之欄位保留
|
|
767
1017
|
*
|
|
768
1018
|
* 回傳陣列恆與輸入等長,輸入單一物件亦回傳長度1之陣列。
|
|
769
1019
|
* 各筆之n為主鍵命中筆數,值為0或1,命中(不論內容有無變更)或經插入而產生皆為1;
|
|
@@ -1408,6 +1658,7 @@ function WOrmPostgresql(opt = {}) {
|
|
|
1408
1658
|
ee.select = select
|
|
1409
1659
|
ee.selectByPk = selectByPk
|
|
1410
1660
|
ee.insert = insert
|
|
1661
|
+
ee.insertBulk = insertBulk
|
|
1411
1662
|
ee.save = save
|
|
1412
1663
|
ee.del = del
|
|
1413
1664
|
ee.delAll = delAll
|
|
@@ -1431,7 +1682,7 @@ export default WOrmPostgresql
|
|
|
1431
1682
|
<br class="clear">
|
|
1432
1683
|
|
|
1433
1684
|
<footer>
|
|
1434
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026
|
|
1685
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 18:44:49 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1435
1686
|
</footer>
|
|
1436
1687
|
|
|
1437
1688
|
<script>prettyPrint();</script>
|
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="WOrmPostgresql.html">WOrmPostgresql</a><ul class='methods'><li data-type='method'><a href="WOrmPostgresql.html#.createTable">createTable</a></li><li data-type='method'><a href="WOrmPostgresql.html#.del">del</a></li><li data-type='method'><a href="WOrmPostgresql.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insert">insert</a></li><li data-type='method'><a href="WOrmPostgresql.html#.save">save</a></li><li data-type='method'><a href="WOrmPostgresql.html#.select">select</a></li><li data-type='method'><a href="WOrmPostgresql.html#.selectByPk">selectByPk</a></li></ul></li></ul>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmPostgresql.html">WOrmPostgresql</a><ul class='methods'><li data-type='method'><a href="WOrmPostgresql.html#.createTable">createTable</a></li><li data-type='method'><a href="WOrmPostgresql.html#.del">del</a></li><li data-type='method'><a href="WOrmPostgresql.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insert">insert</a></li><li data-type='method'><a href="WOrmPostgresql.html#.insertBulk">insertBulk</a></li><li data-type='method'><a href="WOrmPostgresql.html#.save">save</a></li><li data-type='method'><a href="WOrmPostgresql.html#.select">select</a></li><li data-type='method'><a href="WOrmPostgresql.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
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 18:44:49 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
|
@@ -110,6 +110,32 @@ 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
|
+
|
|
126
|
+
let rsr = [
|
|
127
|
+
{ //已存在, 為前次insertBulk所插入
|
|
128
|
+
time: '2025-01-01T00:20:00Z',
|
|
129
|
+
name: 'bulk-1',
|
|
130
|
+
value: 201,
|
|
131
|
+
},
|
|
132
|
+
{ //不存在須新增
|
|
133
|
+
time: '2025-01-01T00:22:00Z',
|
|
134
|
+
name: 'ret-new',
|
|
135
|
+
value: 203,
|
|
136
|
+
},
|
|
137
|
+
]
|
|
138
|
+
|
|
113
139
|
async function test() {
|
|
114
140
|
|
|
115
141
|
//wo
|
|
@@ -132,6 +158,9 @@ async function test() {
|
|
|
132
158
|
wo.on('change', function(mode, data, res) {
|
|
133
159
|
console.log('change', mode)
|
|
134
160
|
})
|
|
161
|
+
wo.on('error', function(mode, data, err) {
|
|
162
|
+
console.log('error', mode, err)
|
|
163
|
+
})
|
|
135
164
|
|
|
136
165
|
//delAll
|
|
137
166
|
await wo.delAll()
|
|
@@ -151,6 +180,33 @@ async function test() {
|
|
|
151
180
|
console.log('insert catch', msg)
|
|
152
181
|
})
|
|
153
182
|
|
|
183
|
+
//insertBulk, 全批視為一個單位, 全部插入成功或一筆都不寫入
|
|
184
|
+
await wo.insertBulk(rsb)
|
|
185
|
+
.then(function(msg) {
|
|
186
|
+
console.log('insertBulk then', msg)
|
|
187
|
+
})
|
|
188
|
+
.catch(function(msg) {
|
|
189
|
+
console.log('insertBulk catch', msg)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
//insertBulk by pk existed, 任一筆之主鍵已存在即整批reject且不寫入任何一筆
|
|
193
|
+
await wo.insertBulk(rsb)
|
|
194
|
+
.then(function(msg) {
|
|
195
|
+
console.log('insertBulk by pk existed then', msg)
|
|
196
|
+
})
|
|
197
|
+
.catch(function(msg) {
|
|
198
|
+
console.log('insertBulk by pk existed catch', `${msg}`) //reject回傳Error物件, 以樣板字串取其訊息以免印出堆疊
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
//insert by returnList, 改回傳與輸入等長且保序之逐筆結果, 令呼叫端得知是哪幾筆為新數據
|
|
202
|
+
await wo.insert(rsr, { returnList: true })
|
|
203
|
+
.then(function(msg) {
|
|
204
|
+
console.log('insert by returnList then', msg)
|
|
205
|
+
})
|
|
206
|
+
.catch(function(msg) {
|
|
207
|
+
console.log('insert by returnList catch', `${msg}`)
|
|
208
|
+
})
|
|
209
|
+
|
|
154
210
|
//save
|
|
155
211
|
await wo.save(rsm, { autoInsert: false })
|
|
156
212
|
.then(function(msg) {
|
|
@@ -213,6 +269,15 @@ async function test() {
|
|
|
213
269
|
console.log('del catch', msg)
|
|
214
270
|
})
|
|
215
271
|
|
|
272
|
+
//del by data without pk, 該筆無法處理故ok為0並附err, 整批仍resolve且另發出error事件
|
|
273
|
+
await wo.del({ name: 'no-pk' })
|
|
274
|
+
.then(function(msg) {
|
|
275
|
+
console.log('del by data without pk then', msg)
|
|
276
|
+
})
|
|
277
|
+
.catch(function(msg) {
|
|
278
|
+
console.log('del by data without pk catch', msg)
|
|
279
|
+
})
|
|
280
|
+
|
|
216
281
|
//del
|
|
217
282
|
let ssDel = await wo.select()
|
|
218
283
|
let ds = ssDel.filter(function(v) {
|
|
@@ -298,6 +363,12 @@ test()
|
|
|
298
363
|
// delAll then { n: 0, nDeleted: 0, ok: 1 }
|
|
299
364
|
// change insert
|
|
300
365
|
// insert then { n: 13, nInserted: 13, ok: 1 }
|
|
366
|
+
// change insertBulk
|
|
367
|
+
// insertBulk then { n: 2, nInserted: 2, ok: 1 }
|
|
368
|
+
// error insertBulk duplicate key value violates unique constraint "users_pkey"
|
|
369
|
+
// insertBulk by pk existed catch error: duplicate key value violates unique constraint "users_pkey"
|
|
370
|
+
// change insert
|
|
371
|
+
// insert by returnList then [ { n: 1, nInserted: 0, ok: 1 }, { n: 1, nInserted: 1, ok: 1 } ]
|
|
301
372
|
// change save
|
|
302
373
|
// save then [
|
|
303
374
|
// { n: 1, nInserted: 0, nModified: 0, ok: 1 },
|
|
@@ -317,6 +388,9 @@ test()
|
|
|
317
388
|
// { time: 2025-01-01T00:07:00.000Z, name: 'rosemary', value: 124.76 },
|
|
318
389
|
// { time: 2025-01-01T00:08:00.000Z, name: 'kettle', value: 524 },
|
|
319
390
|
// { time: 2025-01-01T00:09:00.000Z, name: 'peter', value: 127 },
|
|
391
|
+
// { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
|
|
392
|
+
// { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
|
|
393
|
+
// { time: 2025-01-01T00:22:00.000Z, name: 'ret-new', value: 203 },
|
|
320
394
|
// {
|
|
321
395
|
// time: 2025-01-01T00:10:00.000Z,
|
|
322
396
|
// name: 'rosemary(modify)',
|
|
@@ -352,6 +426,9 @@ test()
|
|
|
352
426
|
// { time: 2025-01-01T00:03:00.000Z, name: 'peter', value: 200 },
|
|
353
427
|
// { time: 2025-01-01T00:05:00.000Z, name: 'kettle', value: 488 },
|
|
354
428
|
// { time: 2025-01-01T00:08:00.000Z, name: 'kettle', value: 524 },
|
|
429
|
+
// { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
|
|
430
|
+
// { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
|
|
431
|
+
// { time: 2025-01-01T00:22:00.000Z, name: 'ret-new', value: 203 },
|
|
355
432
|
// {
|
|
356
433
|
// time: 2025-01-01T00:11:00.000Z,
|
|
357
434
|
// name: 'kettle(modify)',
|
|
@@ -374,6 +451,9 @@ test()
|
|
|
374
451
|
// save then [ { n: 1, nInserted: 1, nModified: 0, ok: 1 } ]
|
|
375
452
|
// change del
|
|
376
453
|
// del then [ { n: 0, nDeleted: 0, ok: 1 } ]
|
|
454
|
+
// error del invalid time[undefined]
|
|
455
|
+
// change del
|
|
456
|
+
// del by data without pk then [ { n: 0, nDeleted: 0, ok: 0, err: 'invalid time[undefined]' } ]
|
|
377
457
|
// change del
|
|
378
458
|
// del then [
|
|
379
459
|
// { n: 1, nDeleted: 1, ok: 1 },
|
|
@@ -391,6 +471,9 @@ test()
|
|
|
391
471
|
// { time: 2025-01-01T00:01:00.000Z, name: 'rosemary', value: 123.456 },
|
|
392
472
|
// { time: 2025-01-01T00:04:00.000Z, name: 'rosemary', value: 123.1236 },
|
|
393
473
|
// { time: 2025-01-01T00:07:00.000Z, name: 'rosemary', value: 124.76 },
|
|
474
|
+
// { time: 2025-01-01T00:20:00.000Z, name: 'bulk-1', value: 201 },
|
|
475
|
+
// { time: 2025-01-01T00:21:00.000Z, name: 'bulk-2', value: 202 },
|
|
476
|
+
// { time: 2025-01-01T00:22:00.000Z, name: 'ret-new', value: 203 },
|
|
394
477
|
// {
|
|
395
478
|
// time: 2025-01-01T00:10:00.000Z,
|
|
396
479
|
// name: 'rosemary(modify)',
|