w-serv-orm 1.1.7 → 1.1.9
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 +2 -6
- package/dist/w-serv-orm.umd.js +2 -2
- package/dist/w-serv-orm.umd.js.map +1 -1
- package/docs/WServOrm.html +21 -158
- package/docs/WServOrm.mjs.html +48 -16
- package/docs/index.html +1 -1
- package/g-mOrm.mjs +2 -6
- package/package.json +3 -3
- package/schema/tables/tests.mjs +1 -1
- package/src/WServOrm.mjs +46 -14
- package/src/genTestData.mjs +2 -2
- package/src/getDb.mjs +27 -6
- package/src/getDbBackupAndRecover.mjs +27 -2
- package/src/getItemsFail.mjs +2 -34
- package/src/getMapOrm.mjs +128 -46
- package/src/getProc.mjs +104 -180
- package/src/getSettings.mjs +1 -1
- package/test/api-procOrm.test.mjs +27 -2
- package/test/unit-WServOrm.test.mjs +567 -0
- package/test/unit-getDb.test.mjs +188 -0
- package/test/unit-mapOrm.test.mjs +119 -14
package/docs/WServOrm.html
CHANGED
|
@@ -75,15 +75,28 @@
|
|
|
75
75
|
|
|
76
76
|
<dt class="tag-description">Description:</dt>
|
|
77
77
|
<dd class="tag-description"><ul class="dummy"><li><p>產生伺服器ORM的支援物件</p>
|
|
78
|
-
<p
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
<p>每次呼叫各自建立資料表ORM、設定與擴充函數,同一行程內之多個實例互不干擾;同一url與db之資料庫資源能否並存,依所用ORM而定。</p>
|
|
79
|
+
<p>procOrm之save、del與mix,於ORM回傳之逐筆結果有任一筆ok為0(單筆失敗)時reject,訊息列出失敗筆之主鍵,如'failed to save data: id[b]'(超過100字元者截斷顯示;無有效主鍵者以data[k]列其於輸入內之位置,k自0起;超過10筆者只列前10筆並附總筆數),錯誤原文另由console.log輸出。
|
|
80
|
+
單筆失敗不中斷整批,故reject時其餘筆數已寫入。
|
|
81
|
+
mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後一併reject;遇整批性錯誤則立即reject,後續步驟不執行。</p>
|
|
82
|
+
<p>insert、save與mix之新增、修改,數據未帶有效主鍵(非空字串或數字)者,若資料表之主鍵欄為id且為字串型(或型別未知),由本套件產生主鍵(同各ORM之genIDSeq)並於resolve時回傳;無欄位之數據不補。
|
|
83
|
+
reject時不回傳補出之主鍵,故重送未帶主鍵之數據會再產生新主鍵而重複寫入,需冪等重送者請自帶主鍵;save帶主鍵者重送以主鍵覆寫,del重送時已刪除者為主鍵未命中。
|
|
84
|
+
insert(含mix之新增)為主鍵已存在即略過之冪等新增,回傳之id含被略過者;recover亦以insert還原,故資料表須先清空。
|
|
85
|
+
insert、save與mix之新增、修改,寫入前各欄位之字串皆經wsemi之clearXSS清除(白名單外之標籤轉義,白名單內之標籤刪除白名單外之屬性與危險網址,標籤外之文字只轉義會開始標籤之<,故'a < b'等數學式不改寫);select與del不經清除。
|
|
86
|
+
字串主鍵若會被清除改寫(含HTML標記,如<後緊接英文字母),整批reject且不寫入任何一筆(mix於任何步驟之前檢查新增與修改),訊息列其位置而不回顯主鍵,如'failed to save data, id contains HTML markup: data[1]';否則改寫後之主鍵與呼叫端所持者不同,以原主鍵查詢與刪除皆找不到。</p>
|
|
87
|
+
<p>擴充函數(addFunCheck、addFunPreProcessing、addFunPostProcessing)屬於各實例,重建實例後須重新註冊;註冊時須傳入函數,否則立即拋錯(addFunCheck另令該實例之procOrm一律reject);註冊後約1毫秒(以計時器)才生效,在此之前之procOrm呼叫不會套用。
|
|
88
|
+
呼叫契約:check以reject或拋錯阻擋,回傳值不影響結果,且早於前處理執行;前處理逐一呼叫,各收新建之參數物件{woName,userId,mode,input},input為前一個回傳之input,回傳須為含input之物件否則reject;後處理逐一呼叫,各收新建之參數物件且其output為前一個之回傳值,最後之回傳值即為procOrm之回傳值。
|
|
89
|
+
後處理只在check、前處理與ORM操作皆成功後執行,逐筆失敗(含del)或mix部分寫入後reject者皆不執行;後處理自身亦可reject。後處理之input為呼叫端傳入之數據,不含本套件補出之主鍵,主鍵見output。
|
|
90
|
+
如需觀察ORM實際寫入,可另監聽woItems內各ORM之change與error事件;惟事件由ORM發出,不含userId,mix會依步驟分次發出,經woItems直接寫入者亦會發出,insert之結果為聚合計數而非逐筆。
|
|
91
|
+
錯誤型別:procOrm由本套件產生之reject一律為英文訊息字串(供前端顯示或對應多語系;ORM之錯誤原文另由console.log輸出而不轉出),擴充函數自身之reject或拋錯則原樣轉出;建構(設定或ORM無效)、擴充函數註冊、backup與recover由本套件產生之錯誤一律為Error,ORM之錯誤則原樣轉出。</p>
|
|
92
|
+
<p>授權:procOrm不做授權,不檢查使用者,亦不依使用者過濾數據;userId只供寫入稽核欄位(userId、userIdUpdate)與交給擴充函數。procOrm開放給前端時(如讓前端經資料通道直接操作資料表),須由開放處負責授權;addFunCheck可掛額外檢查,惟伺服端程式之呼叫亦會經過。
|
|
93
|
+
已移除之設定:useCheckUser、getUserById、useExcludeWhenNotAdmin,未給、null或false者照常建構,給予其他值即於建構時拋錯。</p></li></ul></dd>
|
|
81
94
|
|
|
82
95
|
|
|
83
96
|
|
|
84
97
|
<dt class="tag-source">Source:</dt>
|
|
85
98
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
86
|
-
<a href="WServOrm.mjs.html">WServOrm.mjs</a>, <a href="WServOrm.mjs.html#
|
|
99
|
+
<a href="WServOrm.mjs.html">WServOrm.mjs</a>, <a href="WServOrm.mjs.html#line115">line 115</a>
|
|
87
100
|
</li></ul></dd>
|
|
88
101
|
|
|
89
102
|
|
|
@@ -130,7 +143,7 @@ mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後
|
|
|
130
143
|
|
|
131
144
|
<h5 class="h5-examples">Example</h5>
|
|
132
145
|
|
|
133
|
-
<pre class="prettyprint"><code>// import WOrm from 'w-orm-mongodb/src/WOrmMongodb.mjs' //自行選擇引用ORM
|
|
134
146
|
getUserById: null,
|
|
135
147
|
useCheckUser: false,
|
|
136
148
|
useExcludeWhenNotAdmin: false,
|
|
149
|
+
<pre class="prettyprint"><code>// import WOrm from 'w-orm-mongodb/src/WOrmMongodb.mjs' //自行選擇引用ORM
|
|
137
150
|
|
|
138
151
|
|
|
139
152
|
|
|
@@ -341,157 +354,7 @@ mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後
|
|
|
341
354
|
</td>
|
|
342
355
|
|
|
343
356
|
|
|
344
|
-
<td class="description last"><p>輸入設定物件,預設{}
|
|
345
|
-
<h6>Properties</h6>
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
<table class="params">
|
|
349
|
-
<thead>
|
|
350
|
-
<tr>
|
|
351
|
-
|
|
352
|
-
<th>Name</th>
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
<th>Type</th>
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
<th>Attributes</th>
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<th>Default</th>
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
<th class="last">Description</th>
|
|
366
|
-
</tr>
|
|
367
|
-
</thead>
|
|
368
|
-
|
|
369
|
-
<tbody>
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
<tr>
|
|
373
|
-
|
|
374
|
-
<td class="name"><code>useCheckUser</code></td>
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
<td class="type">
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
<span class="param-type">Boolean</span>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
</td>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
<td class="attributes">
|
|
389
|
-
|
|
390
|
-
<optional><br>
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
</td>
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
<td class="default">
|
|
401
|
-
|
|
402
|
-
<code>true</code>
|
|
403
|
-
|
|
404
|
-
</td>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
<td class="description last"><p>輸入是否檢查使用者資訊布林值,預設true</p></td>
|
|
408
|
-
</tr>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
<tr>
|
|
413
|
-
|
|
414
|
-
<td class="name"><code>getUserById</code></td>
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
<td class="type">
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
<span class="param-type">function</span>
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
</td>
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
<td class="attributes">
|
|
429
|
-
|
|
430
|
-
<optional><br>
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
</td>
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
<td class="default">
|
|
441
|
-
|
|
442
|
-
<code>null</code>
|
|
443
|
-
|
|
444
|
-
</td>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
<td class="description last"><p>輸入當useCheckUser=true時依照使用者ID取得使用者資訊物件函數,預設null</p></td>
|
|
448
|
-
</tr>
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
<tr>
|
|
453
|
-
|
|
454
|
-
<td class="name"><code>useExcludeWhenNotAdmin</code></td>
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
<td class="type">
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
<span class="param-type">Boolean</span>
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
</td>
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
<td class="attributes">
|
|
469
|
-
|
|
470
|
-
<optional><br>
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
</td>
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
<td class="default">
|
|
481
|
-
|
|
482
|
-
<code>true</code>
|
|
483
|
-
|
|
484
|
-
</td>
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<td class="description last"><p>輸入使用ORM的select方法時是否自動刪除數據內isActive欄位之布林值,預設true</p></td>
|
|
488
|
-
</tr>
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
</tbody>
|
|
492
|
-
</table>
|
|
493
|
-
|
|
494
|
-
</td>
|
|
357
|
+
<td class="description last"><p>輸入設定物件,預設{};目前無設定鍵,保留供日後擴充,已移除之設定見上述</p></td>
|
|
495
358
|
</tr>
|
|
496
359
|
|
|
497
360
|
|
|
@@ -517,7 +380,7 @@ mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後
|
|
|
517
380
|
|
|
518
381
|
|
|
519
382
|
<div class="param-desc">
|
|
520
|
-
<p
|
|
383
|
+
<p>回傳伺服器ORM支援物件,含woItems(各資料表ORM實例)、procOrm(資料操作函數,輸入為userId、woName、mode、input)、addFunCheck、addFunPreProcessing、addFunPostProcessing、closeAll(逐一關閉各資料表ORM之連線),以及backup(woItems)與recover(fp, woItems, genModels, needCreateStorage);後兩者不綁定本實例,須自行傳入woItems(須為非空物件,否則reject),其參數順序與getDb之recover(woItems, fp, opt)不同;recover於寫入前驗證備份內容(須為非空陣列且各筆之name為woItems內之資料表),失敗時reject,逐表寫入時中途失敗則先前之表已寫入</p>
|
|
521
384
|
</div>
|
|
522
385
|
|
|
523
386
|
|
|
@@ -576,7 +439,7 @@ mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後
|
|
|
576
439
|
<br class="clear">
|
|
577
440
|
|
|
578
441
|
<footer>
|
|
579
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
442
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Oct 13 2026 00:02:33 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
580
443
|
</footer>
|
|
581
444
|
|
|
582
445
|
<script>prettyPrint();</script>
|
package/docs/WServOrm.mjs.html
CHANGED
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
|
|
46
46
|
<section>
|
|
47
47
|
<article>
|
|
48
|
-
<pre class="prettyprint source linenums"><code>import
|
|
48
|
+
<pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
|
|
49
|
+
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
49
50
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
50
51
|
import getDbBackupAndRecover from './getDbBackupAndRecover.mjs'
|
|
51
52
|
import getWoItems from './getWoItems.mjs'
|
|
@@ -53,23 +54,56 @@ import getMapOrm from './getMapOrm.mjs'
|
|
|
53
54
|
import getProc from './getProc.mjs'
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
function checkOptRemoved(opt) {
|
|
58
|
+
//已移除之設定: 未給、null或false者接受(使用端現行之設定), 其餘值拋錯, 避免使用端以為仍有檢查而無聲失去
|
|
59
|
+
//useCheckUser只查使用者存在且有效, 屬認證而非授權, 卻曾被當成授權; procOrm不做授權, 須由procOrm開放給前端之處負責
|
|
60
|
+
//useExcludeWhenNotAdmin依賴只有useCheckUser才產生之isAdmin, 未開useCheckUser時會把所有人當非管理者過濾, 一併移除
|
|
61
|
+
let msgAuth = 'procOrm does not authorize users, authorize where procOrm is exposed to clients'
|
|
62
|
+
let ks = [
|
|
63
|
+
['useCheckUser', msgAuth],
|
|
64
|
+
['getUserById', msgAuth],
|
|
65
|
+
['useExcludeWhenNotAdmin', 'procOrm does not filter select results by user, use addFunPostProcessing if needed'],
|
|
66
|
+
]
|
|
67
|
+
for (let [k, hint] of ks) {
|
|
68
|
+
let v = get(opt, k)
|
|
69
|
+
if (v !== undefined && v !== null && v !== false) {
|
|
70
|
+
throw new Error(`opt.${k} has been removed, ${hint}`)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
56
76
|
/**
|
|
57
77
|
* 產生伺服器ORM的支援物件
|
|
58
78
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
79
|
+
* 每次呼叫各自建立資料表ORM、設定與擴充函數,同一行程內之多個實例互不干擾;同一url與db之資料庫資源能否並存,依所用ORM而定。
|
|
80
|
+
*
|
|
81
|
+
* procOrm之save、del與mix,於ORM回傳之逐筆結果有任一筆ok為0(單筆失敗)時reject,訊息列出失敗筆之主鍵,如'failed to save data: id[b]'(超過100字元者截斷顯示;無有效主鍵者以data[k]列其於輸入內之位置,k自0起;超過10筆者只列前10筆並附總筆數),錯誤原文另由console.log輸出。
|
|
82
|
+
* 單筆失敗不中斷整批,故reject時其餘筆數已寫入。
|
|
61
83
|
* mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後一併reject;遇整批性錯誤則立即reject,後續步驟不執行。
|
|
62
84
|
*
|
|
85
|
+
* insert、save與mix之新增、修改,數據未帶有效主鍵(非空字串或數字)者,若資料表之主鍵欄為id且為字串型(或型別未知),由本套件產生主鍵(同各ORM之genIDSeq)並於resolve時回傳;無欄位之數據不補。
|
|
86
|
+
* reject時不回傳補出之主鍵,故重送未帶主鍵之數據會再產生新主鍵而重複寫入,需冪等重送者請自帶主鍵;save帶主鍵者重送以主鍵覆寫,del重送時已刪除者為主鍵未命中。
|
|
87
|
+
* insert(含mix之新增)為主鍵已存在即略過之冪等新增,回傳之id含被略過者;recover亦以insert還原,故資料表須先清空。
|
|
88
|
+
* insert、save與mix之新增、修改,寫入前各欄位之字串皆經wsemi之clearXSS清除(白名單外之標籤轉義,白名單內之標籤刪除白名單外之屬性與危險網址,標籤外之文字只轉義會開始標籤之<,故'a < b'等數學式不改寫);select與del不經清除。
|
|
89
|
+
* 字串主鍵若會被清除改寫(含HTML標記,如<後緊接英文字母),整批reject且不寫入任何一筆(mix於任何步驟之前檢查新增與修改),訊息列其位置而不回顯主鍵,如'failed to save data, id contains HTML markup: data[1]';否則改寫後之主鍵與呼叫端所持者不同,以原主鍵查詢與刪除皆找不到。
|
|
90
|
+
*
|
|
91
|
+
* 擴充函數(addFunCheck、addFunPreProcessing、addFunPostProcessing)屬於各實例,重建實例後須重新註冊;註冊時須傳入函數,否則立即拋錯(addFunCheck另令該實例之procOrm一律reject);註冊後約1毫秒(以計時器)才生效,在此之前之procOrm呼叫不會套用。
|
|
92
|
+
* 呼叫契約:check以reject或拋錯阻擋,回傳值不影響結果,且早於前處理執行;前處理逐一呼叫,各收新建之參數物件{woName,userId,mode,input},input為前一個回傳之input,回傳須為含input之物件否則reject;後處理逐一呼叫,各收新建之參數物件且其output為前一個之回傳值,最後之回傳值即為procOrm之回傳值。
|
|
93
|
+
* 後處理只在check、前處理與ORM操作皆成功後執行,逐筆失敗(含del)或mix部分寫入後reject者皆不執行;後處理自身亦可reject。後處理之input為呼叫端傳入之數據,不含本套件補出之主鍵,主鍵見output。
|
|
94
|
+
* 如需觀察ORM實際寫入,可另監聽woItems內各ORM之change與error事件;惟事件由ORM發出,不含userId,mix會依步驟分次發出,經woItems直接寫入者亦會發出,insert之結果為聚合計數而非逐筆。
|
|
95
|
+
* 錯誤型別:procOrm由本套件產生之reject一律為英文訊息字串(供前端顯示或對應多語系;ORM之錯誤原文另由console.log輸出而不轉出),擴充函數自身之reject或拋錯則原樣轉出;建構(設定或ORM無效)、擴充函數註冊、backup與recover由本套件產生之錯誤一律為Error,ORM之錯誤則原樣轉出。
|
|
96
|
+
*
|
|
97
|
+
* 授權:procOrm不做授權,不檢查使用者,亦不依使用者過濾數據;userId只供寫入稽核欄位(userId、userIdUpdate)與交給擴充函數。procOrm開放給前端時(如讓前端經資料通道直接操作資料表),須由開放處負責授權;addFunCheck可掛額外檢查,惟伺服端程式之呼叫亦會經過。
|
|
98
|
+
* 已移除之設定:useCheckUser、getUserById、useExcludeWhenNotAdmin,未給、null或false者照常建構,給予其他值即於建構時拋錯。
|
|
99
|
+
*
|
|
63
100
|
* @class
|
|
64
101
|
* @param {Object} ds 輸入資料表設定物件
|
|
65
102
|
* @param {Object} WOrm 輸入資料庫ORM物件
|
|
66
103
|
* @param {String} url 輸入資料庫連線位址字串
|
|
67
104
|
* @param {String} db 輸入資料庫名稱字串
|
|
68
|
-
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
69
|
-
* @
|
|
70
|
-
* @param {Function} [opt.getUserById=null] 輸入當useCheckUser=true時依照使用者ID取得使用者資訊物件函數,預設null
|
|
71
|
-
* @param {Boolean} [opt.useExcludeWhenNotAdmin=true] 輸入使用ORM的select方法時是否自動刪除數據內isActive欄位之布林值,預設true
|
|
72
|
-
* @returns {Object} 回傳通訊物件,可監聽事件open、error、clientChange、execute、broadcast、deliver,可使用函數broadcast
|
|
105
|
+
* @param {Object} [opt={}] 輸入設定物件,預設{};目前無設定鍵,保留供日後擴充,已移除之設定見上述
|
|
106
|
+
* @returns {Object} 回傳伺服器ORM支援物件,含woItems(各資料表ORM實例)、procOrm(資料操作函數,輸入為userId、woName、mode、input)、addFunCheck、addFunPreProcessing、addFunPostProcessing、closeAll(逐一關閉各資料表ORM之連線),以及backup(woItems)與recover(fp, woItems, genModels, needCreateStorage);後兩者不綁定本實例,須自行傳入woItems(須為非空物件,否則reject),其參數順序與getDb之recover(woItems, fp, opt)不同;recover於寫入前驗證備份內容(須為非空陣列且各筆之name為woItems內之資料表),失敗時reject,逐表寫入時中途失敗則先前之表已寫入
|
|
73
107
|
* @example
|
|
74
108
|
*
|
|
75
109
|
* // import WOrm from 'w-orm-mongodb/src/WOrmMongodb.mjs' //自行選擇引用ORM
|
|
@@ -93,12 +127,7 @@ import getProc from './getProc.mjs'
|
|
|
93
127
|
* let db = 'worm'
|
|
94
128
|
*
|
|
95
129
|
* //WServOrm
|
|
96
|
-
* let
|
|
97
|
-
* getUserById: null,
|
|
98
|
-
* useCheckUser: false,
|
|
99
|
-
* useExcludeWhenNotAdmin: false,
|
|
100
|
-
* }
|
|
101
|
-
* let r = WServOrm(ds, WOrm, url, db, opt)
|
|
130
|
+
* let r = WServOrm(ds, WOrm, url, db)
|
|
102
131
|
* console.log(r) //回傳server用orm相關函數
|
|
103
132
|
* // => {
|
|
104
133
|
* // backup: [AsyncFunction: backup],
|
|
@@ -132,6 +161,9 @@ import getProc from './getProc.mjs'
|
|
|
132
161
|
*/
|
|
133
162
|
function WServOrm(ds, WOrm, url, db, opt = {}) {
|
|
134
163
|
|
|
164
|
+
//checkOptRemoved, 須於建立各資料表ORM之前, 否則拋錯時已開啟之ORM(如lmdb之檔案)無從關閉
|
|
165
|
+
checkOptRemoved(opt)
|
|
166
|
+
|
|
135
167
|
//getWoItems
|
|
136
168
|
let woItems = getWoItems(ds, WOrm, url, db)
|
|
137
169
|
// console.log('woItems', woItems)
|
|
@@ -141,7 +173,7 @@ function WServOrm(ds, WOrm, url, db, opt = {}) {
|
|
|
141
173
|
// console.log('mapOrm', mapOrm)
|
|
142
174
|
|
|
143
175
|
//getProc
|
|
144
|
-
let proc = getProc(mapOrm
|
|
176
|
+
let proc = getProc(mapOrm)
|
|
145
177
|
// console.log('proc', proc)
|
|
146
178
|
|
|
147
179
|
//closeAll, 逐一關閉woItems內各資料表ORM實例之連線(env), 釋放檔案鎖, 供測試隔離或優雅關機使用
|
|
@@ -178,7 +210,7 @@ export default WServOrm
|
|
|
178
210
|
<br class="clear">
|
|
179
211
|
|
|
180
212
|
<footer>
|
|
181
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
213
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Oct 13 2026 00:02:33 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
182
214
|
</footer>
|
|
183
215
|
|
|
184
216
|
<script>prettyPrint();</script>
|
package/docs/index.html
CHANGED
|
@@ -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
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Oct 13 2026 00:02:33 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-mOrm.mjs
CHANGED
|
@@ -20,12 +20,7 @@ let url = './db.json'
|
|
|
20
20
|
let db = 'worm'
|
|
21
21
|
|
|
22
22
|
//WServOrm
|
|
23
|
-
let
|
|
24
|
-
getUserById: null,
|
|
25
|
-
useCheckUser: false,
|
|
26
|
-
useExcludeWhenNotAdmin: false,
|
|
27
|
-
}
|
|
28
|
-
let r = WServOrm(ds, WOrm, url, db, opt)
|
|
23
|
+
let r = WServOrm(ds, WOrm, url, db)
|
|
29
24
|
console.log(r) //回傳server用orm相關函數
|
|
30
25
|
// => {
|
|
31
26
|
// backup: [AsyncFunction: backup],
|
|
@@ -47,6 +42,7 @@ console.log(r) //回傳server用orm相關函數
|
|
|
47
42
|
// [Symbol(kCapture)]: false
|
|
48
43
|
// }
|
|
49
44
|
// },
|
|
45
|
+
// closeAll: [AsyncFunction: closeAll],
|
|
50
46
|
// addFunCheck: [Function: addFunCheck],
|
|
51
47
|
// addFunPreProcessing: [Function: addFunPreProcessing],
|
|
52
48
|
// addFunPostProcessing: [Function: addFunPostProcessing],
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w-serv-orm",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"main": "dist/w-serv-orm.umd.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"json5": "^2.2.3",
|
|
7
|
-
"
|
|
7
|
+
"w-data-collector": "^1.0.46",
|
|
8
|
+
"wsemi": "^1.9.13"
|
|
8
9
|
},
|
|
9
10
|
"devDependencies": {
|
|
10
|
-
"w-data-collector": "^1.0.43",
|
|
11
11
|
"w-orm-lowdb": "^1.0.31",
|
|
12
12
|
"w-package-tools": "^1.1.16"
|
|
13
13
|
},
|
package/schema/tables/tests.mjs
CHANGED
package/src/WServOrm.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import get from 'lodash-es/get.js'
|
|
1
2
|
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
2
3
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
3
4
|
import getDbBackupAndRecover from './getDbBackupAndRecover.mjs'
|
|
@@ -6,23 +7,56 @@ import getMapOrm from './getMapOrm.mjs'
|
|
|
6
7
|
import getProc from './getProc.mjs'
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
function checkOptRemoved(opt) {
|
|
11
|
+
//已移除之設定: 未給、null或false者接受(使用端現行之設定), 其餘值拋錯, 避免使用端以為仍有檢查而無聲失去
|
|
12
|
+
//useCheckUser只查使用者存在且有效, 屬認證而非授權, 卻曾被當成授權; procOrm不做授權, 須由procOrm開放給前端之處負責
|
|
13
|
+
//useExcludeWhenNotAdmin依賴只有useCheckUser才產生之isAdmin, 未開useCheckUser時會把所有人當非管理者過濾, 一併移除
|
|
14
|
+
let msgAuth = 'procOrm does not authorize users, authorize where procOrm is exposed to clients'
|
|
15
|
+
let ks = [
|
|
16
|
+
['useCheckUser', msgAuth],
|
|
17
|
+
['getUserById', msgAuth],
|
|
18
|
+
['useExcludeWhenNotAdmin', 'procOrm does not filter select results by user, use addFunPostProcessing if needed'],
|
|
19
|
+
]
|
|
20
|
+
for (let [k, hint] of ks) {
|
|
21
|
+
let v = get(opt, k)
|
|
22
|
+
if (v !== undefined && v !== null && v !== false) {
|
|
23
|
+
throw new Error(`opt.${k} has been removed, ${hint}`)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
9
29
|
/**
|
|
10
30
|
* 產生伺服器ORM的支援物件
|
|
11
31
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
32
|
+
* 每次呼叫各自建立資料表ORM、設定與擴充函數,同一行程內之多個實例互不干擾;同一url與db之資料庫資源能否並存,依所用ORM而定。
|
|
33
|
+
*
|
|
34
|
+
* procOrm之save、del與mix,於ORM回傳之逐筆結果有任一筆ok為0(單筆失敗)時reject,訊息列出失敗筆之主鍵,如'failed to save data: id[b]'(超過100字元者截斷顯示;無有效主鍵者以data[k]列其於輸入內之位置,k自0起;超過10筆者只列前10筆並附總筆數),錯誤原文另由console.log輸出。
|
|
35
|
+
* 單筆失敗不中斷整批,故reject時其餘筆數已寫入。
|
|
14
36
|
* mix之各步驟遇單筆失敗不中斷後續步驟,待全部步驟完成後一併reject;遇整批性錯誤則立即reject,後續步驟不執行。
|
|
15
37
|
*
|
|
38
|
+
* insert、save與mix之新增、修改,數據未帶有效主鍵(非空字串或數字)者,若資料表之主鍵欄為id且為字串型(或型別未知),由本套件產生主鍵(同各ORM之genIDSeq)並於resolve時回傳;無欄位之數據不補。
|
|
39
|
+
* reject時不回傳補出之主鍵,故重送未帶主鍵之數據會再產生新主鍵而重複寫入,需冪等重送者請自帶主鍵;save帶主鍵者重送以主鍵覆寫,del重送時已刪除者為主鍵未命中。
|
|
40
|
+
* insert(含mix之新增)為主鍵已存在即略過之冪等新增,回傳之id含被略過者;recover亦以insert還原,故資料表須先清空。
|
|
41
|
+
* insert、save與mix之新增、修改,寫入前各欄位之字串皆經wsemi之clearXSS清除(白名單外之標籤轉義,白名單內之標籤刪除白名單外之屬性與危險網址,標籤外之文字只轉義會開始標籤之<,故'a < b'等數學式不改寫);select與del不經清除。
|
|
42
|
+
* 字串主鍵若會被清除改寫(含HTML標記,如<後緊接英文字母),整批reject且不寫入任何一筆(mix於任何步驟之前檢查新增與修改),訊息列其位置而不回顯主鍵,如'failed to save data, id contains HTML markup: data[1]';否則改寫後之主鍵與呼叫端所持者不同,以原主鍵查詢與刪除皆找不到。
|
|
43
|
+
*
|
|
44
|
+
* 擴充函數(addFunCheck、addFunPreProcessing、addFunPostProcessing)屬於各實例,重建實例後須重新註冊;註冊時須傳入函數,否則立即拋錯(addFunCheck另令該實例之procOrm一律reject);註冊後約1毫秒(以計時器)才生效,在此之前之procOrm呼叫不會套用。
|
|
45
|
+
* 呼叫契約:check以reject或拋錯阻擋,回傳值不影響結果,且早於前處理執行;前處理逐一呼叫,各收新建之參數物件{woName,userId,mode,input},input為前一個回傳之input,回傳須為含input之物件否則reject;後處理逐一呼叫,各收新建之參數物件且其output為前一個之回傳值,最後之回傳值即為procOrm之回傳值。
|
|
46
|
+
* 後處理只在check、前處理與ORM操作皆成功後執行,逐筆失敗(含del)或mix部分寫入後reject者皆不執行;後處理自身亦可reject。後處理之input為呼叫端傳入之數據,不含本套件補出之主鍵,主鍵見output。
|
|
47
|
+
* 如需觀察ORM實際寫入,可另監聽woItems內各ORM之change與error事件;惟事件由ORM發出,不含userId,mix會依步驟分次發出,經woItems直接寫入者亦會發出,insert之結果為聚合計數而非逐筆。
|
|
48
|
+
* 錯誤型別:procOrm由本套件產生之reject一律為英文訊息字串(供前端顯示或對應多語系;ORM之錯誤原文另由console.log輸出而不轉出),擴充函數自身之reject或拋錯則原樣轉出;建構(設定或ORM無效)、擴充函數註冊、backup與recover由本套件產生之錯誤一律為Error,ORM之錯誤則原樣轉出。
|
|
49
|
+
*
|
|
50
|
+
* 授權:procOrm不做授權,不檢查使用者,亦不依使用者過濾數據;userId只供寫入稽核欄位(userId、userIdUpdate)與交給擴充函數。procOrm開放給前端時(如讓前端經資料通道直接操作資料表),須由開放處負責授權;addFunCheck可掛額外檢查,惟伺服端程式之呼叫亦會經過。
|
|
51
|
+
* 已移除之設定:useCheckUser、getUserById、useExcludeWhenNotAdmin,未給、null或false者照常建構,給予其他值即於建構時拋錯。
|
|
52
|
+
*
|
|
16
53
|
* @class
|
|
17
54
|
* @param {Object} ds 輸入資料表設定物件
|
|
18
55
|
* @param {Object} WOrm 輸入資料庫ORM物件
|
|
19
56
|
* @param {String} url 輸入資料庫連線位址字串
|
|
20
57
|
* @param {String} db 輸入資料庫名稱字串
|
|
21
|
-
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
22
|
-
* @
|
|
23
|
-
* @param {Function} [opt.getUserById=null] 輸入當useCheckUser=true時依照使用者ID取得使用者資訊物件函數,預設null
|
|
24
|
-
* @param {Boolean} [opt.useExcludeWhenNotAdmin=true] 輸入使用ORM的select方法時是否自動刪除數據內isActive欄位之布林值,預設true
|
|
25
|
-
* @returns {Object} 回傳通訊物件,可監聽事件open、error、clientChange、execute、broadcast、deliver,可使用函數broadcast
|
|
58
|
+
* @param {Object} [opt={}] 輸入設定物件,預設{};目前無設定鍵,保留供日後擴充,已移除之設定見上述
|
|
59
|
+
* @returns {Object} 回傳伺服器ORM支援物件,含woItems(各資料表ORM實例)、procOrm(資料操作函數,輸入為userId、woName、mode、input)、addFunCheck、addFunPreProcessing、addFunPostProcessing、closeAll(逐一關閉各資料表ORM之連線),以及backup(woItems)與recover(fp, woItems, genModels, needCreateStorage);後兩者不綁定本實例,須自行傳入woItems(須為非空物件,否則reject),其參數順序與getDb之recover(woItems, fp, opt)不同;recover於寫入前驗證備份內容(須為非空陣列且各筆之name為woItems內之資料表),失敗時reject,逐表寫入時中途失敗則先前之表已寫入
|
|
26
60
|
* @example
|
|
27
61
|
*
|
|
28
62
|
* // import WOrm from 'w-orm-mongodb/src/WOrmMongodb.mjs' //自行選擇引用ORM
|
|
@@ -46,12 +80,7 @@ import getProc from './getProc.mjs'
|
|
|
46
80
|
* let db = 'worm'
|
|
47
81
|
*
|
|
48
82
|
* //WServOrm
|
|
49
|
-
* let
|
|
50
|
-
* getUserById: null,
|
|
51
|
-
* useCheckUser: false,
|
|
52
|
-
* useExcludeWhenNotAdmin: false,
|
|
53
|
-
* }
|
|
54
|
-
* let r = WServOrm(ds, WOrm, url, db, opt)
|
|
83
|
+
* let r = WServOrm(ds, WOrm, url, db)
|
|
55
84
|
* console.log(r) //回傳server用orm相關函數
|
|
56
85
|
* // => {
|
|
57
86
|
* // backup: [AsyncFunction: backup],
|
|
@@ -85,6 +114,9 @@ import getProc from './getProc.mjs'
|
|
|
85
114
|
*/
|
|
86
115
|
function WServOrm(ds, WOrm, url, db, opt = {}) {
|
|
87
116
|
|
|
117
|
+
//checkOptRemoved, 須於建立各資料表ORM之前, 否則拋錯時已開啟之ORM(如lmdb之檔案)無從關閉
|
|
118
|
+
checkOptRemoved(opt)
|
|
119
|
+
|
|
88
120
|
//getWoItems
|
|
89
121
|
let woItems = getWoItems(ds, WOrm, url, db)
|
|
90
122
|
// console.log('woItems', woItems)
|
|
@@ -94,7 +126,7 @@ function WServOrm(ds, WOrm, url, db, opt = {}) {
|
|
|
94
126
|
// console.log('mapOrm', mapOrm)
|
|
95
127
|
|
|
96
128
|
//getProc
|
|
97
|
-
let proc = getProc(mapOrm
|
|
129
|
+
let proc = getProc(mapOrm)
|
|
98
130
|
// console.log('proc', proc)
|
|
99
131
|
|
|
100
132
|
//closeAll, 逐一關閉woItems內各資料表ORM實例之連線(env), 釋放檔案鎖, 供測試隔離或優雅關機使用
|
package/src/genTestData.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import size from 'lodash-es/size.js'
|
|
|
3
3
|
import isbol from 'wsemi/src/isbol.mjs'
|
|
4
4
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
5
5
|
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
6
|
-
import getItemsFail from '
|
|
6
|
+
import getItemsFail from 'w-data-collector/src/getItemsFail.mjs'
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
async function genTestData(ds, woItems, opt = {}) {
|
|
@@ -51,7 +51,7 @@ async function genTestData(ds, woItems, opt = {}) {
|
|
|
51
51
|
//check, 單筆失敗時整批仍resolve並以該筆ok為0回報, 須逐筆檢查
|
|
52
52
|
let fails = getItemsFail(rss, rs)
|
|
53
53
|
if (size(fails) > 0) {
|
|
54
|
-
throw new Error(
|
|
54
|
+
throw new Error(`failed to write test data into table[${k}]: ${JSON.stringify(fails)}`)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
if (bLog) {
|
package/src/getDb.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs'
|
|
3
|
-
import get from 'lodash-es/get.js'
|
|
4
|
-
import each from 'lodash-es/each.js'
|
|
5
|
-
import keys from 'lodash-es/keys.js'
|
|
3
|
+
import get from 'lodash-es/get.js'
|
|
4
|
+
import each from 'lodash-es/each.js'
|
|
5
|
+
import keys from 'lodash-es/keys.js'
|
|
6
6
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
7
7
|
import isbol from 'wsemi/src/isbol.mjs'
|
|
8
8
|
import isestr from 'wsemi/src/isestr.mjs'
|
|
9
|
+
import isfun from 'wsemi/src/isfun.mjs'
|
|
9
10
|
import o2j from 'wsemi/src/o2j.mjs'
|
|
10
11
|
import now2strp from 'wsemi/src/now2strp.mjs'
|
|
11
12
|
import haskey from 'wsemi/src/haskey.mjs'
|
|
@@ -38,13 +39,13 @@ function genModels(ds, genModelsByTabs, opt = {}) {
|
|
|
38
39
|
|
|
39
40
|
//check
|
|
40
41
|
if (!haskey(ds[name], 'settings')) {
|
|
41
|
-
console.log(
|
|
42
|
+
console.log(`table[${name}] has no settings`)
|
|
42
43
|
return true //跳出換下一個
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
//check
|
|
46
47
|
if (!iseobj(ds[name].settings)) {
|
|
47
|
-
console.log(`ds[${name}].settings
|
|
48
|
+
console.log(`invalid ds[${name}].settings`)
|
|
48
49
|
return true //跳出換下一個
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -66,6 +67,7 @@ function genModels(ds, genModelsByTabs, opt = {}) {
|
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
async function backup(woItems, opt = {}) {
|
|
70
|
+
//備份各資料表至cwd(模組載入時之工作目錄)下之backup-時間.json; 失敗時印log後reject原錯誤, 令呼叫端(含未await之頂層腳本)可偵測
|
|
69
71
|
|
|
70
72
|
//bLog
|
|
71
73
|
let bLog = get(opt, 'bLog')
|
|
@@ -80,6 +82,11 @@ async function backup(woItems, opt = {}) {
|
|
|
80
82
|
//o2j
|
|
81
83
|
let j = o2j(res)
|
|
82
84
|
|
|
85
|
+
//check, o2j無法序列化時回空字串, 不得寫出空備份而回報成功
|
|
86
|
+
if (!isestr(j)) {
|
|
87
|
+
throw new Error('backup data can not be serialized')
|
|
88
|
+
}
|
|
89
|
+
|
|
83
90
|
//fn
|
|
84
91
|
let fn = `backup-${now2strp()}.json`
|
|
85
92
|
|
|
@@ -95,12 +102,15 @@ async function backup(woItems, opt = {}) {
|
|
|
95
102
|
})
|
|
96
103
|
.catch((err) => {
|
|
97
104
|
console.log(err)
|
|
105
|
+
throw err
|
|
98
106
|
})
|
|
99
107
|
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
|
|
103
111
|
async function recover(woItems, fp, opt = {}) {
|
|
112
|
+
//由備份檔以insert還原各資料表; 主鍵已存在者略過, 故資料表須先清空; 逐表寫入, 中途失敗時先前之表已寫入
|
|
113
|
+
//失敗時印log後reject原錯誤; bRela為true時須提供opt.ds與opt.genModelsByTabs以產生model
|
|
104
114
|
|
|
105
115
|
//bRela, 是否為關聯資料庫
|
|
106
116
|
let bRela = get(opt, 'bRela')
|
|
@@ -115,10 +125,20 @@ async function recover(woItems, fp, opt = {}) {
|
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
//funGenModels and bNeedCreateStorage, 若為關聯資料庫則需使用genModels與needCreateStorage=true
|
|
128
|
+
//genModels須以ds與genModelsByTabs產生model, 低階recover則以無參數呼叫, 故以閉包帶入; 缺則於任何寫入之前reject
|
|
118
129
|
let funGenModels = null
|
|
119
130
|
let bNeedCreateStorage = false
|
|
120
131
|
if (bRela) {
|
|
121
|
-
|
|
132
|
+
let ds = get(opt, 'ds')
|
|
133
|
+
let genModelsByTabs = get(opt, 'genModelsByTabs')
|
|
134
|
+
if (!iseobj(ds) || !isfun(genModelsByTabs)) {
|
|
135
|
+
let err = new Error('bRela needs opt.ds and opt.genModelsByTabs')
|
|
136
|
+
console.log(err)
|
|
137
|
+
return Promise.reject(err)
|
|
138
|
+
}
|
|
139
|
+
funGenModels = () => {
|
|
140
|
+
genModels(ds, genModelsByTabs, opt)
|
|
141
|
+
}
|
|
122
142
|
bNeedCreateStorage = true
|
|
123
143
|
}
|
|
124
144
|
|
|
@@ -131,6 +151,7 @@ async function recover(woItems, fp, opt = {}) {
|
|
|
131
151
|
})
|
|
132
152
|
.catch((err) => {
|
|
133
153
|
console.log(err)
|
|
154
|
+
throw err
|
|
134
155
|
})
|
|
135
156
|
|
|
136
157
|
}
|