w-orm-reladb 1.1.6 → 1.1.8

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.
@@ -3,7 +3,6 @@ import Sequelize from 'sequelize'
3
3
  import cloneDeep from 'lodash-es/cloneDeep.js'
4
4
  import get from 'lodash-es/get.js'
5
5
  import map from 'lodash-es/map.js'
6
- import each from 'lodash-es/each.js'
7
6
  import size from 'lodash-es/size.js'
8
7
  import split from 'lodash-es/split.js'
9
8
  import keys from 'lodash-es/keys.js'
@@ -15,7 +14,6 @@ import genPm from 'wsemi/src/genPm.mjs'
15
14
  import genIDSeq from 'wsemi/src/genIDSeq.mjs'
16
15
  import isarr from 'wsemi/src/isarr.mjs'
17
16
  import isearr from 'wsemi/src/isearr.mjs'
18
- import isobj from 'wsemi/src/isobj.mjs'
19
17
  import iseobj from 'wsemi/src/iseobj.mjs'
20
18
  import isbol from 'wsemi/src/isbol.mjs'
21
19
  import isnum from 'wsemi/src/isnum.mjs'
@@ -27,6 +25,7 @@ import pmQueue from 'wsemi/src/pmQueue.mjs'
27
25
  import WAutoSequelize from 'w-auto-sequelize/src/WAutoSequelize.mjs'
28
26
  import importModels from './importModels.mjs'
29
27
  import _genModelsByTabs from './genModelsByTabs.mjs'
28
+ import cvFind, { getColKind, getColScale, normPk } from './cvFind.mjs'
30
29
 
31
30
 
32
31
  //放置於全域宣告, 若使用useStable=true才可於當創建多實例時仍能全域控管
@@ -94,10 +93,6 @@ function WOrmReladb(opt = {}) {
94
93
  }
95
94
 
96
95
 
97
- //Op
98
- let Op = Sequelize.Op
99
-
100
-
101
96
  //ee, 採wsemi之evem(即eventemitter3), 其於'error'無監聽者時僅回傳false而不拋出,
102
97
  //故本套件之操作行為不因呼叫端有無註冊監聽而改變; Node內建之EventEmitter具該拋出語義, 不可用
103
98
  let ee = evem()
@@ -224,26 +219,16 @@ function WOrmReladb(opt = {}) {
224
219
 
225
220
 
226
221
  /**
227
- * 判定主鍵值是否有效
228
- * 註: select以外之五函數對主鍵之認定一律以本函數為準,令selectByPk之[命中]與insert、save、del內對既有數據之認定一致
222
+ * 判定主鍵值是否有效(與主鍵欄型別無關之判定)
223
+ * 註: select以外之五函數對主鍵之認定一律以本函數與normPkOf為準,令selectByPk之[命中]與insert、save、del內對既有數據之認定一致
224
+ * 註: 有效即非空字串或有限數值(含0), new String與new Number取原始值; NaN、±Infinity、布林、物件等為無效(見cvFind.mjs之normPk)
229
225
  *
230
226
  * @ignore
231
227
  * @param {*} v 輸入主鍵值
232
228
  * @returns {Boolean} 回傳主鍵值是否有效布林值
233
229
  */
234
230
  function isEffPk(v) {
235
-
236
- //非空字串
237
- if (isestr(v)) {
238
- return true
239
- }
240
-
241
- //數值, 含0, 供整數型主鍵使用
242
- if (isnum(v)) {
243
- return true
244
- }
245
-
246
- return false
231
+ return normPk(v, 'any').kind !== 'invalid'
247
232
  }
248
233
 
249
234
 
@@ -320,6 +305,80 @@ function WOrmReladb(opt = {}) {
320
305
  }
321
306
 
322
307
 
308
+ /**
309
+ * 取cvFind所需之依賴物件
310
+ * 註: escape依方言產生字串常值(如mssql之N'...'), attrs供依欄位型別檢核條件之純量, dialect供判定方言能力,
311
+ * pk令主鍵欄之條件值依normPk正規化而與主鍵函數一致
312
+ *
313
+ * @ignore
314
+ * @param {Object} md 輸入資料表model物件
315
+ * @returns {Object} 回傳{escape, attrs, dialect, pk}
316
+ */
317
+ function getFindCtx(md) {
318
+ return {
319
+ escape: (v) => md.sequelize.escape(v),
320
+ attrs: get(md, 'rawAttributes', {}),
321
+ dialect,
322
+ pk: opt.pk,
323
+ }
324
+ }
325
+
326
+
327
+ /**
328
+ * 檢查model之預設scope是否會使select與delAll之對象分歧
329
+ * 註: defaultScope帶limit或offset時, select依其order取前幾筆, 而sequelize之限量刪除不採order(sqlite為rowid IN子查詢),
330
+ * 兩者命中之數據不同而會刪錯列, 故delAll遇此類model即拒絕
331
+ *
332
+ * @ignore
333
+ * @param {Object} md 輸入資料表model物件
334
+ * @returns {undefined} 無回傳值
335
+ */
336
+ function chkScopeForDelAll(md) {
337
+ let sc = get(md, '_scope', {})
338
+ if (get(sc, 'limit') !== undefined || get(sc, 'offset') !== undefined) {
339
+ throw new Error(`model [${opt.cl}] has defaultScope with limit or offset, delAll can not delete the same rows as select`)
340
+ }
341
+ }
342
+
343
+
344
+ /**
345
+ * 正規化各筆數據之主鍵值並就地寫回, 型別不符者整批拋出
346
+ * 註: 須於procPk之後、任何寫入之前一次完成; 已給主鍵而型別不符屬呼叫端未履行契約, 不以自動產生之主鍵取代
347
+ * 註: 正規化值寫回數據, 令寫入值與其後各函數之比對值一致(如字串類主鍵欄之123存為'123'), 事件之數據亦為實際寫入者
348
+ *
349
+ * @ignore
350
+ * @param {Object} md 輸入資料表model物件
351
+ * @param {Array} data 輸入已補齊主鍵之數據陣列
352
+ * @returns {undefined} 無回傳值
353
+ */
354
+ function normPks(md, data) {
355
+ data.forEach((v, k) => {
356
+ let r = normPkOf(md, get(v, opt.pk))
357
+ if (r.kind !== 'ok') {
358
+ throw new Error(`invalid data[${k}].${opt.pk}[${get(v, opt.pk)}], type does not match pk column [${opt.pk}]`)
359
+ }
360
+ v[opt.pk] = r.v
361
+ })
362
+ }
363
+
364
+
365
+ /**
366
+ * 依model之主鍵欄型別正規化主鍵值
367
+ * 註: 規則見cvFind.mjs之normPk(與w-orm-mdb同一規則), 用於selectByPk、del、save、insert與insertBulk,
368
+ * 並與select、delAll之主鍵欄條件共用, 令各函數對主鍵之命中判定一致; 字串類主鍵欄之有限數字以String(v)處置,
369
+ * 整數類收安全整數與標準整數寫法之字串, DECIMAL之小數位不得多於scale, 型別不符者即規格之[主鍵值無效(型別不符)]而不送查詢
370
+ *
371
+ * @ignore
372
+ * @param {Object} md 輸入資料表model物件
373
+ * @param {*} v 輸入主鍵值
374
+ * @returns {Object} 回傳{kind,v}, kind為'ok'、'invalid'或'mismatch'
375
+ */
376
+ function normPkOf(md, v) {
377
+ let attrs = get(md, 'rawAttributes', {})
378
+ return normPk(v, getColKind(attrs, opt.pk), getColScale(attrs, opt.pk))
379
+ }
380
+
381
+
323
382
  /**
324
383
  * 檢查並補齊單筆數據之主鍵
325
384
  * autoGenPk為true時未帶有效主鍵者自動產生,為false時往外拋
@@ -474,77 +533,25 @@ function WOrmReladb(opt = {}) {
474
533
  /**
475
534
  * 查詢數據
476
535
  *
536
+ * 註: find由cvFind轉譯且與delAll共用, 同一find於兩函數由同一SQL謂詞決定命中
537
+ * 註: 支援欄位等值({欄位:值}, 值為null時比對IS NULL)與$eq、$ne、$gt、$gte、$lt、$lte、$in、$nin、$not、$regex($options僅i)、$exists, 以及$and、$or、$nor
538
+ * 註: 不支援之運算子、非純量之值、與欄位型別不符之純量(如數值欄給'abc')一律reject並發出error事件, 不靜默忽略或改變語意
539
+ * 註: 主鍵欄之條件值依主鍵欄型別正規化而與selectByPk等一致(如字串類主鍵欄之{id:123}即{id:'123'}, 整數類主鍵欄之'12'即12), 型別不符或無效者reject
540
+ * 註: NULL依SQL三值邏輯, 故$ne、$nin、$not、$nor不含該欄為NULL之數據; $exists:false即IS NULL
541
+ * 註: $regex僅支援字面子字串(含未跳脫正規式元字元者reject, 可用反斜線跳脫), 給i時不分大小寫, 未給i時大小寫依資料庫定序(sqlite之LIKE與mssql預設定序皆不分)
542
+ * 註: 欄位值為陣列時視同$in, 與MongoDB之陣列比對不同
543
+ * 註: find未給或為空物件時回傳全部數據; find非物件時亦回傳全部數據(現況保留)
544
+ * 註: 恆回傳陣列, 無符合數據回傳空陣列
545
+ *
477
546
  * @memberOf WOrmReladb
478
547
  * @param {Object} [find={}] 輸入查詢條件物件
479
548
  * @param {Object} [option={}] 輸入設定物件,預設為{}
480
549
  * @param {Object} [option.instance=null] 輸入實例instance物件,預設為null
481
550
  * @param {Object} [option.transaction=null] 輸入交易(transaction)物件,預設為null
482
- * @returns {Promise} 回傳Promise,resolve回傳數據,reject回傳錯誤訊息
551
+ * @returns {Promise} 回傳Promise,resolve回傳數據陣列,reject回傳錯誤訊息
483
552
  */
484
553
  async function select(find = {}, option = {}) {
485
554
 
486
- function cvObj(o) {
487
- let oNew = {}
488
- each(o, (v, k) => {
489
- let kNew = k
490
- if (k.indexOf('$') >= 0) {
491
- k = k.replace('$', '')
492
- if (k === 'regex') {
493
- kNew = Op.substring
494
- }
495
- else if (k === 'options') {
496
- kNew = null
497
- }
498
- else if (k === 'nin') {
499
- kNew = Op.notIn
500
- }
501
- else {
502
- kNew = Op[k]
503
- }
504
- }
505
- let vNew = v
506
- if (isarr(v)) {
507
- vNew = cvArray(v)
508
- }
509
- else if (isobj(v)) {
510
- vNew = cvObj(v)
511
- }
512
- if (kNew !== null) {
513
- oNew[kNew] = vNew
514
- }
515
- })
516
- return oNew
517
- }
518
-
519
- function cvArray(o) {
520
- let oNew = []
521
- each(o, (v) => {
522
- let vNew = v
523
- if (isarr(v)) {
524
- vNew = cvArray(v)
525
- }
526
- else if (isobj(v)) {
527
- vNew = cvObj(v)
528
- }
529
- oNew.push(vNew)
530
- })
531
- return oNew
532
- }
533
-
534
- function cvFind(o) {
535
- let oNew = cvObj(o)
536
- return oNew
537
- }
538
-
539
- //find
540
- if (!isobj(find)) {
541
- find = {}
542
- }
543
- find = cloneDeep(find)
544
-
545
- //useFind
546
- let useFind = cvFind(find)
547
-
548
555
  //instance
549
556
  let instance = get(option, 'instance', null)
550
557
 
@@ -564,12 +571,17 @@ function WOrmReladb(opt = {}) {
564
571
 
565
572
  //si
566
573
  let si = instance
567
- if (instance === null) {
568
- si = await initSequelize()
569
- }
570
574
 
571
575
  try {
572
576
 
577
+ //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
578
+ procClosed(instance)
579
+
580
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
581
+ if (instance === null) {
582
+ si = await initSequelize()
583
+ }
584
+
573
585
  //check, 連線或匯入models失敗影響本次操作之全部數據, 屬整批性錯誤
574
586
  if (si.err) {
575
587
  throw si.err
@@ -578,6 +590,9 @@ function WOrmReladb(opt = {}) {
578
590
  //md
579
591
  let md = si.mds[opt.cl]
580
592
 
593
+ //useFind, 與delAll共用cvFind, 條件不合法者於此拋錯而reject並發出error事件
594
+ let useFind = cvFind(find, getFindCtx(md))
595
+
581
596
  //setting, raw令回傳純數據物件而不含資料庫內部欄位
582
597
  let setting = {
583
598
  where: useFind,
@@ -622,6 +637,8 @@ function WOrmReladb(opt = {}) {
622
637
  *
623
638
  * 註: 主鍵欄位取自opt.pk,預設為id,支援由呼叫端指定
624
639
  * 註: 主鍵未命中或主鍵值無效皆回傳null而不reject,[命中]之判定基準與insert、save、del內對既有數據之認定一致
640
+ * 註: 主鍵值依主鍵欄型別正規化後查詢: 字串類主鍵欄之有限數字以String(v)處置(selectByPk(123)即查'123'), 整數類主鍵欄之標準整數寫法字串轉為數值;
641
+ * 型別不符(整數類主鍵欄給'012'、12.4、'abc'等)亦屬主鍵值無效而回傳null
625
642
  * 註: 本函數不得有副作用,故不創建資料表
626
643
  *
627
644
  * @memberOf WOrmReladb
@@ -666,15 +683,17 @@ function WOrmReladb(opt = {}) {
666
683
 
667
684
  //si
668
685
  let si = instance
669
- if (instance === null) {
670
- si = await initSequelize()
671
- }
672
686
 
673
687
  try {
674
688
 
675
689
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
676
690
  procClosed(instance)
677
691
 
692
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
693
+ if (instance === null) {
694
+ si = await initSequelize()
695
+ }
696
+
678
697
  //check
679
698
  if (si.err) {
680
699
  throw si.err
@@ -683,25 +702,34 @@ function WOrmReladb(opt = {}) {
683
702
  //md
684
703
  let md = si.mds[opt.cl]
685
704
 
686
- //setting
687
- let setting = {
688
- where: { [opt.pk]: pk },
689
- raw: true,
690
- }
691
- if (transaction !== null) {
692
- setting.transaction = transaction
705
+ //normPkOf, 依主鍵欄型別正規化, 型別不符即主鍵值無效而回null且不送查詢(送出時兩方言皆會把整數欄之'012'轉為12而命中)
706
+ let r = normPkOf(md, pk)
707
+ if (r.kind !== 'ok') {
708
+ res = null
693
709
  }
710
+ else {
694
711
 
695
- //findOne
696
- let v = await md.findOne(setting)
712
+ //setting
713
+ let setting = {
714
+ where: { [opt.pk]: r.v },
715
+ raw: true,
716
+ }
717
+ if (transaction !== null) {
718
+ setting.transaction = transaction
719
+ }
720
+
721
+ //findOne
722
+ let v = await md.findOne(setting)
723
+
724
+ //check, 判定基準與insert、save、del內對既有數據之認定一致
725
+ if (iseobj(v)) {
726
+ res = v
727
+ }
728
+ else {
729
+ //不存在主鍵, 回傳null
730
+ res = null
731
+ }
697
732
 
698
- //check, 判定基準與insert、save、del內對既有數據之認定一致
699
- if (iseobj(v)) {
700
- res = v
701
- }
702
- else {
703
- //不存在主鍵, 回傳null
704
- res = null
705
733
  }
706
734
 
707
735
  }
@@ -736,6 +764,7 @@ function WOrmReladb(opt = {}) {
736
764
  * 註: n為輸入筆數即本次嘗試插入之基準,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
737
765
  * 註: 同批含重複主鍵時僅首筆計入nInserted,其餘視為已存在
738
766
  * 註: opt.autoGenPk為true(預設)時未帶有效主鍵者自動產生,為false時未帶有效主鍵即reject且同批皆不寫入
767
+ * 註: 主鍵值依主鍵欄型別正規化後寫入(字串類主鍵欄之123存為'123');型別不符(整數類主鍵欄給'012'等)即reject且同批皆不寫入,不以自動產生之主鍵取代
739
768
  * 註: option.returnList開啟時改回與輸入等長且保序之逐筆結果陣列[{n,nInserted,ok}],
740
769
  * 聚合計數只答得出[有幾筆是新的]而答不出[是哪幾筆],而後者正是去重之產出物;
741
770
  * 逐筆元素之n與ok恆為1,資訊由nInserted承載,不變式為
@@ -788,15 +817,17 @@ function WOrmReladb(opt = {}) {
788
817
 
789
818
  //si
790
819
  let si = instance
791
- if (instance === null) {
792
- si = await initSequelize()
793
- }
794
820
 
795
821
  try {
796
822
 
797
823
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
798
824
  procClosed(instance)
799
825
 
826
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
827
+ if (instance === null) {
828
+ si = await initSequelize()
829
+ }
830
+
800
831
  //check
801
832
  if (si.err) {
802
833
  throw si.err
@@ -815,6 +846,9 @@ function WOrmReladb(opt = {}) {
815
846
  return procPk(md, v, k)
816
847
  })
817
848
 
849
+ //normPks, 主鍵值依主鍵欄型別正規化後寫回, 型別不符者整批reject且不寫入任何一筆, 令insert對既有數據之認定與selectByPk一致
850
+ normPks(md, data)
851
+
818
852
  //nAll, n之基準為輸入筆數
819
853
  let nAll = size(data)
820
854
 
@@ -907,6 +941,7 @@ function WOrmReladb(opt = {}) {
907
941
  * 令呼叫端得與insert共用同一段結果處理程式碼
908
942
  * 註: 不提供逐筆結果,故不出現ok為0與err;需要逐筆處置者改用insert
909
943
  * 註: opt.autoGenPk為true(預設)時未帶有效主鍵者自動產生,為false時未帶有效主鍵即reject且同批皆不寫入
944
+ * 註: 主鍵值依主鍵欄型別正規化後寫入(字串類主鍵欄之123存為'123');型別不符(整數類主鍵欄給'012'等)即reject且同批皆不寫入
910
945
  * 註: [全有全無]為獨立於T7之額外要求——T7僅保證每筆之[檢查主鍵不存在]與[寫入]為原子,不保證整批。
911
946
  * mssql因綁定參數數量上限會由驅動層自動拆為多語句送出,實測1000筆之批次於末筆撞主鍵時已有946筆落盤,
912
947
  * 故一律以交易包覆並於失敗時回滾;呼叫端已給transaction時改以巢狀交易(SAVEPOINT)包覆,
@@ -952,15 +987,17 @@ function WOrmReladb(opt = {}) {
952
987
 
953
988
  //si
954
989
  let si = instance
955
- if (instance === null) {
956
- si = await initSequelize()
957
- }
958
990
 
959
991
  try {
960
992
 
961
993
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
962
994
  procClosed(instance)
963
995
 
996
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
997
+ if (instance === null) {
998
+ si = await initSequelize()
999
+ }
1000
+
964
1001
  //check
965
1002
  if (si.err) {
966
1003
  throw si.err
@@ -979,6 +1016,9 @@ function WOrmReladb(opt = {}) {
979
1016
  return procPk(md, v, k)
980
1017
  })
981
1018
 
1019
+ //normPks, 主鍵值依主鍵欄型別正規化後寫回, 型別不符者整批reject且不寫入任何一筆
1020
+ normPks(md, data)
1021
+
982
1022
  //nAll, n之基準為輸入筆數
983
1023
  let nAll = size(data)
984
1024
 
@@ -1237,6 +1277,7 @@ function WOrmReladb(opt = {}) {
1237
1277
  * 故只給部份欄位且該些欄位值皆與現值相同時,合併結果等於現值,nModified為0
1238
1278
  * 註: 本筆失敗不中斷整批,該筆以ok為0並附err回報
1239
1279
  * 註: opt.autoGenPk為true(預設)時未帶有效主鍵者自動產生,為false時未帶有效主鍵即reject且同批皆不寫入
1280
+ * 註: 主鍵值依主鍵欄型別正規化(字串類主鍵欄之123即'123');型別不符(整數類主鍵欄給'012'等)屬呼叫端未履行契約,整批reject且同批皆不寫入
1240
1281
  *
1241
1282
  * @memberOf WOrmReladb
1242
1283
  * @param {Object|Array} data 輸入數據物件或陣列
@@ -1278,15 +1319,17 @@ function WOrmReladb(opt = {}) {
1278
1319
 
1279
1320
  //si
1280
1321
  let si = instance
1281
- if (instance === null) {
1282
- si = await initSequelize()
1283
- }
1284
1322
 
1285
1323
  try {
1286
1324
 
1287
1325
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
1288
1326
  procClosed(instance)
1289
1327
 
1328
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
1329
+ if (instance === null) {
1330
+ si = await initSequelize()
1331
+ }
1332
+
1290
1333
  //check
1291
1334
  if (si.err) {
1292
1335
  throw si.err
@@ -1305,6 +1348,9 @@ function WOrmReladb(opt = {}) {
1305
1348
  return procPk(md, v, k)
1306
1349
  })
1307
1350
 
1351
+ //normPks, 主鍵值依主鍵欄型別正規化後寫回, 型別不符者整批reject且不寫入任何一筆
1352
+ normPks(md, data)
1353
+
1308
1354
  //ks, model之欄位名, 供合併後比對時濾除非欄位之鍵
1309
1355
  let ks = keys(get(md, 'rawAttributes', {}))
1310
1356
 
@@ -1346,7 +1392,8 @@ function WOrmReladb(opt = {}) {
1346
1392
  * 註: 回傳陣列恆與輸入等長,各筆之n與nDeleted皆為主鍵命中筆數,值為0或1,未命中為0且屬正常結果
1347
1393
  * 註: 判斷某筆是否真的被刪除一律以nDeleted為準
1348
1394
  * 註: 未帶有效主鍵者為該筆之輸入問題,回ok為0與err且不送查詢條件(以免無效值被轉為null而誤中其他數據),
1349
- * 不中斷其餘筆數,以此與[主鍵未命中]之ok為1區辨
1395
+ * 不中斷其餘筆數,以此與[主鍵未命中]之ok為1區辨;主鍵值與主鍵欄型別不符者(整數類主鍵欄給'012'等)亦同
1396
+ * 註: 主鍵值依主鍵欄型別正規化後刪除(字串類主鍵欄之123即'123'),正規化值寫回該筆數據
1350
1397
  * 註: 本函數不受opt.autoGenPk影響,於任一設定下皆不補值
1351
1398
  *
1352
1399
  * @memberOf WOrmReladb
@@ -1385,15 +1432,17 @@ function WOrmReladb(opt = {}) {
1385
1432
 
1386
1433
  //si
1387
1434
  let si = instance
1388
- if (instance === null) {
1389
- si = await initSequelize()
1390
- }
1391
1435
 
1392
1436
  try {
1393
1437
 
1394
1438
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
1395
1439
  procClosed(instance)
1396
1440
 
1441
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
1442
+ if (instance === null) {
1443
+ si = await initSequelize()
1444
+ }
1445
+
1397
1446
  //check
1398
1447
  if (si.err) {
1399
1448
  throw si.err
@@ -1433,9 +1482,30 @@ function WOrmReladb(opt = {}) {
1433
1482
  return rest
1434
1483
  }
1435
1484
 
1485
+ //normPkOf, 主鍵值與主鍵欄型別不符亦屬未帶有效主鍵, 不送查詢(送出時兩方言皆會把整數欄之'012'轉為12而誤刪)
1486
+ let r = normPkOf(md, pkv)
1487
+ if (r.kind !== 'ok') {
1488
+
1489
+ //rest
1490
+ rest = {
1491
+ n: 0,
1492
+ nDeleted: 0,
1493
+ ok: 0,
1494
+ err: `invalid ${opt.pk}[${pkv}], type does not match pk column`,
1495
+ }
1496
+
1497
+ //emit
1498
+ emitError('del', [v], rest.err)
1499
+
1500
+ return rest
1501
+ }
1502
+
1503
+ //寫回正規化值, 令事件之數據與實際送出者一致
1504
+ v[opt.pk] = r.v
1505
+
1436
1506
  //setting
1437
1507
  let setting = {
1438
- where: { [opt.pk]: pkv },
1508
+ where: { [opt.pk]: r.v },
1439
1509
  }
1440
1510
  if (transaction !== null) {
1441
1511
  setting.transaction = transaction //destroy的說明寫不需transaction但實際需要 (2020/10/07)
@@ -1511,6 +1581,9 @@ function WOrmReladb(opt = {}) {
1511
1581
  *
1512
1582
  * 註: n與nDeleted皆為實際刪除筆數,兩者恆相等,n不得取全表筆數
1513
1583
  * 註: find未給或為空物件時刪除全部數據;條件無命中時回{n:0,nDeleted:0,ok:1},不視為錯誤
1584
+ * 註: find由cvFind轉譯且與select共用,刪除之數據即select(find)命中之數據;支援之條件與限制同select
1585
+ * 註: 不支援之運算子、非純量之值、與欄位型別不符之純量一律reject並發出error事件,不刪除任何數據;主鍵欄之條件值依主鍵欄型別正規化,同select
1586
+ * 註: find非物件(null、陣列、字串、數字)時刪除全部數據,此為現況保留,系列規格另案處理
1514
1587
  *
1515
1588
  * @memberOf WOrmReladb
1516
1589
  * @param {Object} [find={}] 輸入刪除條件物件,不給予find則代表刪除全部數據
@@ -1521,12 +1594,6 @@ function WOrmReladb(opt = {}) {
1521
1594
  */
1522
1595
  async function delAll(find = {}, option = {}) {
1523
1596
 
1524
- //find
1525
- if (!isobj(find)) {
1526
- find = {}
1527
- }
1528
- find = cloneDeep(find)
1529
-
1530
1597
  //instance
1531
1598
  let instance = get(option, 'instance', null)
1532
1599
 
@@ -1546,15 +1613,17 @@ function WOrmReladb(opt = {}) {
1546
1613
 
1547
1614
  //si
1548
1615
  let si = instance
1549
- if (instance === null) {
1550
- si = await initSequelize()
1551
- }
1552
1616
 
1553
1617
  try {
1554
1618
 
1555
1619
  //check, 實例已關閉屬整批性錯誤, 於入口快速失敗
1556
1620
  procClosed(instance)
1557
1621
 
1622
+ //initSequelize, 內部自動初始化須在try內: 其例外(如驅動缺失)與si.err同屬整批性錯誤, 方能於reject前發出error事件, 已建構之sequelize亦由finally關閉
1623
+ if (instance === null) {
1624
+ si = await initSequelize()
1625
+ }
1626
+
1558
1627
  //check
1559
1628
  if (si.err) {
1560
1629
  throw si.err
@@ -1563,9 +1632,15 @@ function WOrmReladb(opt = {}) {
1563
1632
  //md
1564
1633
  let md = si.mds[opt.cl]
1565
1634
 
1635
+ //useFind, 與select共用cvFind, 令刪除之數據即select命中之數據; 條件不合法者於此拋錯而不刪除任何數據
1636
+ let useFind = cvFind(find, getFindCtx(md))
1637
+
1638
+ //chkScopeForDelAll, model之預設scope會使刪除對象與select分歧者拒絕
1639
+ chkScopeForDelAll(md)
1640
+
1566
1641
  //setting
1567
1642
  let setting = {
1568
- where: find,
1643
+ where: useFind,
1569
1644
  }
1570
1645
  if (transaction !== null) {
1571
1646
  setting.transaction = transaction //destroy的說明寫不需transaction但實際需要 (2020/10/07)