w-orm-lowdb 1.0.32 → 1.0.34
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 +20 -3
- package/dist/w-orm-lowdb.umd.js +2 -2
- package/dist/w-orm-lowdb.umd.js.map +1 -1
- package/docs/WOrmLowdb.html +30 -17
- package/docs/WOrmLowdb.mjs.html +126 -6
- package/docs/index.html +1 -1
- package/package.json +3 -3
- package/src/WOrmLowdb.mjs +125 -5
- package/test/lib/leaves.mjs +46 -0
- package/test/lib/mkObserver.mjs +52 -0
- package/test/unit-date-write.test.mjs +711 -0
- package/test/unit-find-whitelist.test.mjs +433 -43
package/docs/WOrmLowdb.html
CHANGED
|
@@ -91,13 +91,14 @@ err為錯誤訊息字串,內容與正規管道所送出者一致。
|
|
|
91
91
|
註: 逐筆失敗時整批仍resolve,故收到本事件不表示該次呼叫失敗;正常結果(如查無數據、主鍵未命中、全數已存在)不發出本事件。</p>
|
|
92
92
|
<p>註: 本套件之主鍵欄位固定為id,尚未支援指定其他欄位為主鍵。
|
|
93
93
|
註: 本套件之寫入為[整檔讀出、記憶體修改、整檔寫回],其原子性由行程內之序列化佇列提供,
|
|
94
|
-
故僅單一行程內併發成立,跨行程併發不成立,詳見README
|
|
94
|
+
故僅單一行程內併發成立,跨行程併發不成立,詳見README之併發保證宣告。
|
|
95
|
+
註: 數據以JSON存檔,Date存入後為ISO字串;insert、insertBulk與save寫入之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject,詳見各函數與README。</p></li></ul></dd>
|
|
95
96
|
|
|
96
97
|
|
|
97
98
|
|
|
98
99
|
<dt class="tag-source">Source:</dt>
|
|
99
100
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
100
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
101
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line63">line 63</a>
|
|
101
102
|
</li></ul></dd>
|
|
102
103
|
|
|
103
104
|
|
|
@@ -528,7 +529,7 @@ err為錯誤訊息字串,內容與正規管道所送出者一致。
|
|
|
528
529
|
<li>傳了值卻不是條件物件(null、陣列含[]與[{...}]、字串、數值、布林、函數、Date、RegExp、Map、Set、類別實例等)
|
|
529
530
|
一律整批reject,不視為{},不刪除任何數據。</li>
|
|
530
531
|
<li>條件僅支援系列白名單: 欄位等值{欄:純量}(多欄為AND)、欄位運算子$eq $ne $gt $gte $lt $lte(值為純量)與
|
|
531
|
-
$in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date;
|
|
532
|
+
$in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date(年份須介於0000-9999,範圍外整批reject,見第6點);
|
|
532
533
|
null僅可用於欄位等值、$eq、$ne。白名單外之運算子($not $nor $regex $options $exists $where $expr $like $ilike等)、
|
|
533
534
|
欄位層$and/$or、子查詢、函數值、Symbol鍵、undefined值、空的$nin/$and/$or等一律整批reject,
|
|
534
535
|
訊息為invalid find: 原因 at [路徑],且不刪除任何數據。</li>
|
|
@@ -538,7 +539,11 @@ null僅可用於欄位等值、$eq、$ne。白名單外之運算子($not $nor $r
|
|
|
538
539
|
空的$nin會reject,$in:[]則為恆假(刪除0筆)。</li>
|
|
539
540
|
<li>語意差異(依後端,見README): MongoDB式: $ne(比較值非null時)與$nin會命中欄位為null或缺欄之數據,$ne:null則排除之;
|
|
540
541
|
欄名同於Object.prototype成員(constructor、toString等)者,數據無此自有欄位時視為缺欄;
|
|
541
|
-
Date條件於本後端轉為ISO
|
|
542
|
+
Date條件於本後端轉為ISO字串後以字典序比較(與字串型欄位亦會比較):條件內任何位置之Date其年份須介於0000-9999,
|
|
543
|
+
範圍外(年份小於0或大於9999,如new Date(8.64e15)、new Date(-8.64e15))整批reject,訊息為invalid find: Date year is out of range 0000-9999 at [路徑],
|
|
544
|
+
不回顯值,不讀檔、不刪除任何數據;數據側自1.0.34起insert、insertBulk與save寫入時已拒收範圍外Date,
|
|
545
|
+
但資料庫檔內既有之範圍外Date字串(舊版以new Date(8.64e15)作永不過期哨兵存入者)仍無法以Date條件正確比較
|
|
546
|
+
(例如{t:{$lt:現在}}會命中哨兵並將其刪除),請自行清理或改寫,見README。
|
|
542
547
|
需明確表達時可用可攜寫法: 排除NULL為{$and:[{f:{$ne:null}},{f:{$ne:x}}]},含NULL為{$or:[{f:null},{f:{$ne:x}}]}。</li>
|
|
543
548
|
</ol>
|
|
544
549
|
<p>n與nDeleted皆為實際刪除筆數,不取全表筆數。條件無命中時回{n:0,nDeleted:0,ok:1},不視為錯誤。</p></li></ul></dd>
|
|
@@ -547,7 +552,7 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
547
552
|
|
|
548
553
|
<dt class="tag-source">Source:</dt>
|
|
549
554
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
550
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
555
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line1178">line 1178</a>
|
|
551
556
|
</li></ul></dd>
|
|
552
557
|
|
|
553
558
|
|
|
@@ -725,7 +730,7 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
725
730
|
|
|
726
731
|
<dt class="tag-source">Source:</dt>
|
|
727
732
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
728
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
733
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line995">line 995</a>
|
|
729
734
|
</li></ul></dd>
|
|
730
735
|
|
|
731
736
|
|
|
@@ -884,13 +889,14 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
884
889
|
註: 本函數非insert之加速版,兩者衝突政策不同。insert於主鍵已存在時跳過該筆而整批ok為1,
|
|
885
890
|
本函數則整批reject且不寫入任何一筆;同批含重複主鍵者亦視為衝突。確無衝突時兩者結果相同
|
|
886
891
|
註: 於本套件不會較insert快,因兩者皆為一次讀檔與一次寫檔,
|
|
887
|
-
提供本函數係為與其他w-orm
|
|
892
|
+
提供本函數係為與其他w-orm系列套件維持同一組函數,令呼叫端得於各套件間替換而不須改寫呼叫
|
|
893
|
+
註: 數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆,規則同insert,詳見insert與README</p></li></ul></dd>
|
|
888
894
|
|
|
889
895
|
|
|
890
896
|
|
|
891
897
|
<dt class="tag-source">Source:</dt>
|
|
892
898
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
893
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
899
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line689">line 689</a>
|
|
894
900
|
</li></ul></dd>
|
|
895
901
|
|
|
896
902
|
|
|
@@ -1045,13 +1051,17 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
1045
1051
|
<dl class="details">
|
|
1046
1052
|
|
|
1047
1053
|
<dt class="tag-description">Description:</dt>
|
|
1048
|
-
<dd class="tag-description"><ul class="dummy"><li><p>插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫</p
|
|
1054
|
+
<dd class="tag-description"><ul class="dummy"><li><p>插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫</p>
|
|
1055
|
+
<p>數據內任何深度(頂層欄位、巢狀物件、陣列內)之Date年份須介於0000-9999(序列化為固定24字元之ISO字串,字典序即時間序),
|
|
1056
|
+
範圍外(年份小於0或大於9999,如以new Date(8.64e15)作永不過期哨兵)整批reject且不寫入任何一筆,訊息為invalid data: Date year is out of range 0000-9999 at [路徑],
|
|
1057
|
+
不回顯值,於reject之前發出一次error事件、不發出change事件;無效Date維持序列化為null存入;永不過期請改用null或new Date('9999-12-31T23:59:59.999Z');
|
|
1058
|
+
資料庫檔內既有之範圍外Date字串不遷移,仍無法以Date條件正確比較,詳見README</p></li></ul></dd>
|
|
1049
1059
|
|
|
1050
1060
|
|
|
1051
1061
|
|
|
1052
1062
|
<dt class="tag-source">Source:</dt>
|
|
1053
1063
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1054
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
1064
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line551">line 551</a>
|
|
1055
1065
|
</li></ul></dd>
|
|
1056
1066
|
|
|
1057
1067
|
|
|
@@ -1332,13 +1342,15 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
1332
1342
|
<dl class="details">
|
|
1333
1343
|
|
|
1334
1344
|
<dt class="tag-description">Description:</dt>
|
|
1335
|
-
<dd class="tag-description"><ul class="dummy"><li><p>儲存數據,以主鍵為準更新既有數據,未給之欄位保留;主鍵不存在且autoInsert為true時改為插入</p
|
|
1345
|
+
<dd class="tag-description"><ul class="dummy"><li><p>儲存數據,以主鍵為準更新既有數據,未給之欄位保留;主鍵不存在且autoInsert為true時改為插入</p>
|
|
1346
|
+
<p>數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆(逐筆失敗之ok為0機制不適用),規則同insert,詳見insert與README;
|
|
1347
|
+
autoInsert為false而主鍵不存在(不會寫入)者亦先經同一檢核;合併與覆寫路徑寫入之Date皆來自已檢核之數據,已存在於資料庫之字串不檢核</p></li></ul></dd>
|
|
1336
1348
|
|
|
1337
1349
|
|
|
1338
1350
|
|
|
1339
1351
|
<dt class="tag-source">Source:</dt>
|
|
1340
1352
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1341
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
1353
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line796">line 796</a>
|
|
1342
1354
|
</li></ul></dd>
|
|
1343
1355
|
|
|
1344
1356
|
|
|
@@ -1628,7 +1640,7 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
1628
1640
|
|
|
1629
1641
|
<dt class="tag-source">Source:</dt>
|
|
1630
1642
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1631
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
1643
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line487">line 487</a>
|
|
1632
1644
|
</li></ul></dd>
|
|
1633
1645
|
|
|
1634
1646
|
|
|
@@ -1781,13 +1793,14 @@ Date條件於本後端轉為ISO字串後比較(與字串型欄位亦會比較,
|
|
|
1781
1793
|
|
|
1782
1794
|
<dt class="tag-description">Description:</dt>
|
|
1783
1795
|
<dd class="tag-description"><ul class="dummy"><li><p>查詢數據</p>
|
|
1784
|
-
<p>條件find僅支援系列白名單(規則同delAll之第1-3點,見delAll),與delAll共用同一檢核,select(find)命中之數據即delAll(find)
|
|
1796
|
+
<p>條件find僅支援系列白名單(規則同delAll之第1-3點,見delAll),與delAll共用同一檢核,select(find)命中之數據即delAll(find)刪除之數據
|
|
1797
|
+
條件內之Date年份須介於0000-9999,範圍外整批reject;資料庫檔內既有之範圍外Date字串(1.0.34起寫入已拒收範圍外Date)無法以Date條件正確比較(規則同delAll之第6點,見README)</p></li></ul></dd>
|
|
1785
1798
|
|
|
1786
1799
|
|
|
1787
1800
|
|
|
1788
1801
|
<dt class="tag-source">Source:</dt>
|
|
1789
1802
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1790
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
1803
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line419">line 419</a>
|
|
1791
1804
|
</li></ul></dd>
|
|
1792
1805
|
|
|
1793
1806
|
|
|
@@ -1972,7 +1985,7 @@ select亦納入序列化,令其不致與寫入之整檔替換交錯。</p>
|
|
|
1972
1985
|
|
|
1973
1986
|
<dt class="tag-source">Source:</dt>
|
|
1974
1987
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1975
|
-
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#
|
|
1988
|
+
<a href="WOrmLowdb.mjs.html">WOrmLowdb.mjs</a>, <a href="WOrmLowdb.mjs.html#line131">line 131</a>
|
|
1976
1989
|
</li></ul></dd>
|
|
1977
1990
|
|
|
1978
1991
|
|
|
@@ -2056,7 +2069,7 @@ select亦納入序列化,令其不致與寫入之整檔替換交錯。</p>
|
|
|
2056
2069
|
<br class="clear">
|
|
2057
2070
|
|
|
2058
2071
|
<footer>
|
|
2059
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
2072
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Oct 19 2026 21:48:29 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
2060
2073
|
</footer>
|
|
2061
2074
|
|
|
2062
2075
|
<script>prettyPrint();</script>
|
package/docs/WOrmLowdb.mjs.html
CHANGED
|
@@ -96,6 +96,7 @@ let kpGqueue = {}
|
|
|
96
96
|
* 註: 本套件之主鍵欄位固定為id,尚未支援指定其他欄位為主鍵。
|
|
97
97
|
* 註: 本套件之寫入為[整檔讀出、記憶體修改、整檔寫回],其原子性由行程內之序列化佇列提供,
|
|
98
98
|
* 故僅單一行程內併發成立,跨行程併發不成立,詳見README之併發保證宣告。
|
|
99
|
+
* 註: 數據以JSON存檔,Date存入後為ISO字串;insert、insertBulk與save寫入之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject,詳見各函數與README。
|
|
99
100
|
*
|
|
100
101
|
* @class
|
|
101
102
|
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
@@ -190,17 +191,113 @@ function WOrmLowdb(opt = {}) {
|
|
|
190
191
|
return pm
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
//reIsoDate, 西元0000-9999年之toISOString()恆為24字元YYYY-MM-DDTHH:mm:ss.sssZ, 字典序即時間序;
|
|
195
|
+
//年份<0或>9999者帶-yyyyyy-/+yyyyyy-前綴(27字元), 且'+'<'-'<數字, 字典序與時間序顛倒, 故不符此形者視為範圍外
|
|
196
|
+
let reIsoDate = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
|
|
197
|
+
|
|
198
|
+
//pathKey, 路徑段(欄名或運算子名,皆已通過cvOrmFind之文法): 過長者截短, 規則同cvOrmFind之訊息(單鍵>30字元取前30加...,
|
|
199
|
+
//截斷處切開代理對而成孤立之高代理碼元者, cvOrmFind以?取代)
|
|
200
|
+
let pathKey = (k) => {
|
|
201
|
+
if (k.length <= 30) {
|
|
202
|
+
return k
|
|
203
|
+
}
|
|
204
|
+
let t = k.slice(0, 30)
|
|
205
|
+
let c = t.charCodeAt(29)
|
|
206
|
+
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
207
|
+
t = `${t.slice(0, 29)}?`
|
|
208
|
+
}
|
|
209
|
+
return `${t}...`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
//pathStr, 路徑字串化: 全路徑>120字元取...加末100字元, 規則同cvOrmFind之訊息
|
|
213
|
+
let pathStr = (s) => {
|
|
214
|
+
return s.length > 120 ? `...${s.slice(-100)}` : s
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
//reIdent, 數據之鍵為一般識別字者於路徑以.鍵表示, 其餘以括號法表示
|
|
218
|
+
let reIdent = /^[\p{L}_$][\p{L}\p{M}\p{N}_$]*$/u
|
|
219
|
+
|
|
220
|
+
//pathSeg, 數據之鍵於路徑之表示: 數據之鍵不受條件白名單之欄名文法約束(可含空白,點,括號,引號,換行,孤立代理碼元),
|
|
221
|
+
//故非一般識別字者以JSON字串括號法表示, 過長者依pathKey截短
|
|
222
|
+
let pathSeg = (k) => {
|
|
223
|
+
let t = pathKey(k)
|
|
224
|
+
return reIdent.test(k) ? `.${t}` : `[${JSON.stringify(t)}]`
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
//isDateNode, 是否為JSON序列化時會經toJSON轉為日期字串之Date: 須有可呼叫之toJSON(此判斷同時避免對每個物件節點都以拋錯探測內部槽),
|
|
228
|
+
//且以Date.prototype.getTime證明內部槽為Date(不受Symbol.toStringTag、instanceof、被覆寫之getTime影響, 跨realm之Date亦可)
|
|
229
|
+
let isDateNode = (v) => {
|
|
230
|
+
if (typeof v.toJSON !== 'function') {
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
Date.prototype.getTime.call(v)
|
|
235
|
+
return true
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
return false
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
//chkDataDate, 寫入前之Date範圍檢核(帳本R-DATE-01), 供insert、insertBulk與save於cloneDeep之後(即檢核實際寫入之複本)、readData之前呼叫:
|
|
243
|
+
//走訪數據複本任何深度之Date, 以JSON.stringify(即寫檔時之序列化, 檢查之值即使用之值)判定, 序列化為字串者須為reIsoDate之形(年份0000-9999),
|
|
244
|
+
//範圍外(年份<0或>9999)者fail-closed: 拋出invalid data(由呼叫端既有catch走emitError後reject, 整批不寫檔), 不回顯值;
|
|
245
|
+
//無效Date序列化為null故不檢(既有處置不變); 已是字串者、非Date之toJSON物件(含Buffer)與Map/Set內之Date不檢, 其餘ArrayBuffer視圖(無toJSON者, 序列化時其自有屬性照常輸出)依一般物件走訪;
|
|
246
|
+
//ks為由根起之鍵序列(陣列索引記number, 物件之鍵記string, 僅於拋出時才組成路徑), seen為已走訪物件集合(進入時加入、不移除):
|
|
247
|
+
//循環參照遇回邊即略過(仍由寫檔時之JSON序列化報錯), 共用參照(菱形圖)亦只走訪一次, 時間為O(節點+邊)
|
|
248
|
+
let chkDataDate = (v, ks = [], seen = new WeakSet()) => {
|
|
249
|
+
if (v === null || typeof v !== 'object' || seen.has(v)) {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
if (ArrayBuffer.isView(v) && typeof v.toJSON === 'function') {
|
|
253
|
+
|
|
254
|
+
//Buffer: JSON序列化取其toJSON之輸出({type,data}), 不含自有屬性, 不走訪(避免逐位元組走訪)
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
if (isDateNode(v)) {
|
|
258
|
+
let s = JSON.stringify(v)
|
|
259
|
+
if (typeof s === 'string' && s.charAt(0) === '"' && !reIsoDate.test(s.slice(1, -1))) {
|
|
260
|
+
let p = `data${ks.map((k) => (typeof k === 'number' ? `[${k}]` : pathSeg(k))).join('')}`
|
|
261
|
+
throw new Error(`invalid data: Date year is out of range 0000-9999 at [${pathStr(p)}]`)
|
|
262
|
+
}
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
seen.add(v)
|
|
266
|
+
if (Array.isArray(v)) {
|
|
267
|
+
|
|
268
|
+
//陣列以索引走訪(JSON序列化亦逐索引, 空洞為null)
|
|
269
|
+
for (let i = 0; i < v.length; i++) {
|
|
270
|
+
ks.push(i)
|
|
271
|
+
chkDataDate(v[i], ks, seen)
|
|
272
|
+
ks.pop()
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
for (let k of Object.keys(v)) {
|
|
277
|
+
ks.push(k)
|
|
278
|
+
chkDataDate(v[k], ks, seen)
|
|
279
|
+
ks.pop()
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
193
284
|
//isoFind, 把cvOrmFind所回傳複本內之Date就地轉為ISO字串(轉譯層): 數據以JSON存檔, Date於寫入時已成toISOString()之字串,
|
|
194
285
|
//條件內之Date不轉則恆不命中; 複本僅含null原型物件、密集陣列、純量與有效Date(無共享參照、無環), 就地轉換不影響呼叫端之find
|
|
195
|
-
|
|
286
|
+
//轉換所得之字串須為reIsoDate之形(檢查之值即使用之值), 範圍外(年份<0或>9999)者fail-closed: 拋出invalid find(帳本R-FIND-02), 不回顯值, p為路徑
|
|
287
|
+
let isoFind = (v, p = 'find') => {
|
|
196
288
|
if (v instanceof Date) {
|
|
197
|
-
|
|
289
|
+
let s = v.toISOString()
|
|
290
|
+
if (!reIsoDate.test(s)) {
|
|
291
|
+
throw new Error(`invalid find: Date year is out of range 0000-9999 at [${pathStr(p)}]`)
|
|
292
|
+
}
|
|
293
|
+
return s
|
|
198
294
|
}
|
|
199
295
|
if (v !== null && typeof v === 'object') {
|
|
200
296
|
|
|
201
297
|
//物件與陣列皆以Object.keys走訪(陣列為密集, 鍵即索引)
|
|
298
|
+
let isArr = Array.isArray(v)
|
|
202
299
|
for (let k of Object.keys(v)) {
|
|
203
|
-
v[k] = isoFind(v[k])
|
|
300
|
+
v[k] = isoFind(v[k], isArr ? `${p}[${k}]` : `${p}.${pathKey(k)}`)
|
|
204
301
|
}
|
|
205
302
|
}
|
|
206
303
|
return v
|
|
@@ -360,6 +457,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
360
457
|
* 查詢數據
|
|
361
458
|
*
|
|
362
459
|
* 條件find僅支援系列白名單(規則同delAll之第1-3點,見delAll),與delAll共用同一檢核,select(find)命中之數據即delAll(find)刪除之數據
|
|
460
|
+
* 條件內之Date年份須介於0000-9999,範圍外整批reject;資料庫檔內既有之範圍外Date字串(1.0.34起寫入已拒收範圍外Date)無法以Date條件正確比較(規則同delAll之第6點,見README)
|
|
363
461
|
*
|
|
364
462
|
* @memberOf WOrmLowdb
|
|
365
463
|
* @param {Object} [find={}] 輸入查詢條件物件(系列白名單,規則同delAll之第1-3點); 未給、undefined或{}回傳全部數據; 非條件物件或白名單外運算子整批reject
|
|
@@ -486,6 +584,11 @@ function WOrmLowdb(opt = {}) {
|
|
|
486
584
|
/**
|
|
487
585
|
* 插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫
|
|
488
586
|
*
|
|
587
|
+
* 數據內任何深度(頂層欄位、巢狀物件、陣列內)之Date年份須介於0000-9999(序列化為固定24字元之ISO字串,字典序即時間序),
|
|
588
|
+
* 範圍外(年份小於0或大於9999,如以new Date(8.64e15)作永不過期哨兵)整批reject且不寫入任何一筆,訊息為invalid data: Date year is out of range 0000-9999 at [路徑],
|
|
589
|
+
* 不回顯值,於reject之前發出一次error事件、不發出change事件;無效Date維持序列化為null存入;永不過期請改用null或new Date('9999-12-31T23:59:59.999Z');
|
|
590
|
+
* 資料庫檔內既有之範圍外Date字串不遷移,仍無法以Date條件正確比較,詳見README
|
|
591
|
+
*
|
|
489
592
|
* @memberOf WOrmLowdb
|
|
490
593
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
491
594
|
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
@@ -529,6 +632,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
529
632
|
//check id
|
|
530
633
|
data = procPk(data, 'insert')
|
|
531
634
|
|
|
635
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01)
|
|
636
|
+
chkDataDate(data)
|
|
637
|
+
|
|
532
638
|
//read
|
|
533
639
|
let arrOld = await readData()
|
|
534
640
|
|
|
@@ -621,6 +727,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
621
727
|
* 本函數則整批reject且不寫入任何一筆;同批含重複主鍵者亦視為衝突。確無衝突時兩者結果相同
|
|
622
728
|
* 註: 於本套件不會較insert快,因兩者皆為一次讀檔與一次寫檔,
|
|
623
729
|
* 提供本函數係為與其他w-orm系列套件維持同一組函數,令呼叫端得於各套件間替換而不須改寫呼叫
|
|
730
|
+
* 註: 數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆,規則同insert,詳見insert與README
|
|
624
731
|
*
|
|
625
732
|
* @memberOf WOrmLowdb
|
|
626
733
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
@@ -653,6 +760,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
653
760
|
//check id
|
|
654
761
|
data = procPk(data, 'insertBulk')
|
|
655
762
|
|
|
763
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01)
|
|
764
|
+
chkDataDate(data)
|
|
765
|
+
|
|
656
766
|
//read
|
|
657
767
|
let arrOld = await readData()
|
|
658
768
|
|
|
@@ -721,6 +831,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
721
831
|
/**
|
|
722
832
|
* 儲存數據,以主鍵為準更新既有數據,未給之欄位保留;主鍵不存在且autoInsert為true時改為插入
|
|
723
833
|
*
|
|
834
|
+
* 數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆(逐筆失敗之ok為0機制不適用),規則同insert,詳見insert與README;
|
|
835
|
+
* autoInsert為false而主鍵不存在(不會寫入)者亦先經同一檢核;合併與覆寫路徑寫入之Date皆來自已檢核之數據,已存在於資料庫之字串不檢核
|
|
836
|
+
*
|
|
724
837
|
* @memberOf WOrmLowdb
|
|
725
838
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
726
839
|
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
@@ -753,6 +866,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
753
866
|
//check id
|
|
754
867
|
data = procPk(data, 'save')
|
|
755
868
|
|
|
869
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01); 合併與覆寫路徑之Date皆來自此複本
|
|
870
|
+
chkDataDate(data)
|
|
871
|
+
|
|
756
872
|
//read
|
|
757
873
|
let arrOld = await readData()
|
|
758
874
|
|
|
@@ -1083,7 +1199,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
1083
1199
|
* 2. 傳了值卻不是條件物件(null、陣列含[]與[{...}]、字串、數值、布林、函數、Date、RegExp、Map、Set、類別實例等)
|
|
1084
1200
|
* 一律整批reject,不視為{},不刪除任何數據。
|
|
1085
1201
|
* 3. 條件僅支援系列白名單: 欄位等值{欄:純量}(多欄為AND)、欄位運算子$eq $ne $gt $gte $lt $lte(值為純量)與
|
|
1086
|
-
* $in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date;
|
|
1202
|
+
* $in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date(年份須介於0000-9999,範圍外整批reject,見第6點);
|
|
1087
1203
|
* null僅可用於欄位等值、$eq、$ne。白名單外之運算子($not $nor $regex $options $exists $where $expr $like $ilike等)、
|
|
1088
1204
|
* 欄位層$and/$or、子查詢、函數值、Symbol鍵、undefined值、空的$nin/$and/$or等一律整批reject,
|
|
1089
1205
|
* 訊息為invalid find: 原因 at [路徑],且不刪除任何數據。
|
|
@@ -1093,7 +1209,11 @@ function WOrmLowdb(opt = {}) {
|
|
|
1093
1209
|
* 空的$nin會reject,$in:[]則為恆假(刪除0筆)。
|
|
1094
1210
|
* 6. 語意差異(依後端,見README): MongoDB式: $ne(比較值非null時)與$nin會命中欄位為null或缺欄之數據,$ne:null則排除之;
|
|
1095
1211
|
* 欄名同於Object.prototype成員(constructor、toString等)者,數據無此自有欄位時視為缺欄;
|
|
1096
|
-
* Date條件於本後端轉為ISO
|
|
1212
|
+
* Date條件於本後端轉為ISO字串後以字典序比較(與字串型欄位亦會比較):條件內任何位置之Date其年份須介於0000-9999,
|
|
1213
|
+
* 範圍外(年份小於0或大於9999,如new Date(8.64e15)、new Date(-8.64e15))整批reject,訊息為invalid find: Date year is out of range 0000-9999 at [路徑],
|
|
1214
|
+
* 不回顯值,不讀檔、不刪除任何數據;數據側自1.0.34起insert、insertBulk與save寫入時已拒收範圍外Date,
|
|
1215
|
+
* 但資料庫檔內既有之範圍外Date字串(舊版以new Date(8.64e15)作永不過期哨兵存入者)仍無法以Date條件正確比較
|
|
1216
|
+
* (例如{t:{$lt:現在}}會命中哨兵並將其刪除),請自行清理或改寫,見README。
|
|
1097
1217
|
* 需明確表達時可用可攜寫法: 排除NULL為{$and:[{f:{$ne:null}},{f:{$ne:x}}]},含NULL為{$or:[{f:null},{f:{$ne:x}}]}。
|
|
1098
1218
|
*
|
|
1099
1219
|
* n與nDeleted皆為實際刪除筆數,不取全表筆數。條件無命中時回{n:0,nDeleted:0,ok:1},不視為錯誤。
|
|
@@ -1220,7 +1340,7 @@ export default WOrmLowdb
|
|
|
1220
1340
|
<br class="clear">
|
|
1221
1341
|
|
|
1222
1342
|
<footer>
|
|
1223
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
1343
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Oct 19 2026 21:48:29 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1224
1344
|
</footer>
|
|
1225
1345
|
|
|
1226
1346
|
<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 Mon Oct 19 2026 21:48:29 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/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w-orm-lowdb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"main": "dist/w-orm-lowdb.umd.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"lowdb": "^7.0.1",
|
|
7
7
|
"mingo": "^7.2.4",
|
|
8
|
-
"wsemi": "^1.9.
|
|
8
|
+
"wsemi": "^1.9.20"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"w-package-tools": "^1.1.
|
|
11
|
+
"w-package-tools": "^1.1.21"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test": "mocha --parallel \"test/*.test.mjs\" --timeout 180000",
|
package/src/WOrmLowdb.mjs
CHANGED
|
@@ -49,6 +49,7 @@ let kpGqueue = {}
|
|
|
49
49
|
* 註: 本套件之主鍵欄位固定為id,尚未支援指定其他欄位為主鍵。
|
|
50
50
|
* 註: 本套件之寫入為[整檔讀出、記憶體修改、整檔寫回],其原子性由行程內之序列化佇列提供,
|
|
51
51
|
* 故僅單一行程內併發成立,跨行程併發不成立,詳見README之併發保證宣告。
|
|
52
|
+
* 註: 數據以JSON存檔,Date存入後為ISO字串;insert、insertBulk與save寫入之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject,詳見各函數與README。
|
|
52
53
|
*
|
|
53
54
|
* @class
|
|
54
55
|
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
@@ -143,17 +144,113 @@ function WOrmLowdb(opt = {}) {
|
|
|
143
144
|
return pm
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
//reIsoDate, 西元0000-9999年之toISOString()恆為24字元YYYY-MM-DDTHH:mm:ss.sssZ, 字典序即時間序;
|
|
148
|
+
//年份<0或>9999者帶-yyyyyy-/+yyyyyy-前綴(27字元), 且'+'<'-'<數字, 字典序與時間序顛倒, 故不符此形者視為範圍外
|
|
149
|
+
let reIsoDate = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
|
|
150
|
+
|
|
151
|
+
//pathKey, 路徑段(欄名或運算子名,皆已通過cvOrmFind之文法): 過長者截短, 規則同cvOrmFind之訊息(單鍵>30字元取前30加...,
|
|
152
|
+
//截斷處切開代理對而成孤立之高代理碼元者, cvOrmFind以?取代)
|
|
153
|
+
let pathKey = (k) => {
|
|
154
|
+
if (k.length <= 30) {
|
|
155
|
+
return k
|
|
156
|
+
}
|
|
157
|
+
let t = k.slice(0, 30)
|
|
158
|
+
let c = t.charCodeAt(29)
|
|
159
|
+
if (c >= 0xD800 && c <= 0xDBFF) {
|
|
160
|
+
t = `${t.slice(0, 29)}?`
|
|
161
|
+
}
|
|
162
|
+
return `${t}...`
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
//pathStr, 路徑字串化: 全路徑>120字元取...加末100字元, 規則同cvOrmFind之訊息
|
|
166
|
+
let pathStr = (s) => {
|
|
167
|
+
return s.length > 120 ? `...${s.slice(-100)}` : s
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
//reIdent, 數據之鍵為一般識別字者於路徑以.鍵表示, 其餘以括號法表示
|
|
171
|
+
let reIdent = /^[\p{L}_$][\p{L}\p{M}\p{N}_$]*$/u
|
|
172
|
+
|
|
173
|
+
//pathSeg, 數據之鍵於路徑之表示: 數據之鍵不受條件白名單之欄名文法約束(可含空白,點,括號,引號,換行,孤立代理碼元),
|
|
174
|
+
//故非一般識別字者以JSON字串括號法表示, 過長者依pathKey截短
|
|
175
|
+
let pathSeg = (k) => {
|
|
176
|
+
let t = pathKey(k)
|
|
177
|
+
return reIdent.test(k) ? `.${t}` : `[${JSON.stringify(t)}]`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
//isDateNode, 是否為JSON序列化時會經toJSON轉為日期字串之Date: 須有可呼叫之toJSON(此判斷同時避免對每個物件節點都以拋錯探測內部槽),
|
|
181
|
+
//且以Date.prototype.getTime證明內部槽為Date(不受Symbol.toStringTag、instanceof、被覆寫之getTime影響, 跨realm之Date亦可)
|
|
182
|
+
let isDateNode = (v) => {
|
|
183
|
+
if (typeof v.toJSON !== 'function') {
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
Date.prototype.getTime.call(v)
|
|
188
|
+
return true
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
return false
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//chkDataDate, 寫入前之Date範圍檢核(帳本R-DATE-01), 供insert、insertBulk與save於cloneDeep之後(即檢核實際寫入之複本)、readData之前呼叫:
|
|
196
|
+
//走訪數據複本任何深度之Date, 以JSON.stringify(即寫檔時之序列化, 檢查之值即使用之值)判定, 序列化為字串者須為reIsoDate之形(年份0000-9999),
|
|
197
|
+
//範圍外(年份<0或>9999)者fail-closed: 拋出invalid data(由呼叫端既有catch走emitError後reject, 整批不寫檔), 不回顯值;
|
|
198
|
+
//無效Date序列化為null故不檢(既有處置不變); 已是字串者、非Date之toJSON物件(含Buffer)與Map/Set內之Date不檢, 其餘ArrayBuffer視圖(無toJSON者, 序列化時其自有屬性照常輸出)依一般物件走訪;
|
|
199
|
+
//ks為由根起之鍵序列(陣列索引記number, 物件之鍵記string, 僅於拋出時才組成路徑), seen為已走訪物件集合(進入時加入、不移除):
|
|
200
|
+
//循環參照遇回邊即略過(仍由寫檔時之JSON序列化報錯), 共用參照(菱形圖)亦只走訪一次, 時間為O(節點+邊)
|
|
201
|
+
let chkDataDate = (v, ks = [], seen = new WeakSet()) => {
|
|
202
|
+
if (v === null || typeof v !== 'object' || seen.has(v)) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
if (ArrayBuffer.isView(v) && typeof v.toJSON === 'function') {
|
|
206
|
+
|
|
207
|
+
//Buffer: JSON序列化取其toJSON之輸出({type,data}), 不含自有屬性, 不走訪(避免逐位元組走訪)
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
if (isDateNode(v)) {
|
|
211
|
+
let s = JSON.stringify(v)
|
|
212
|
+
if (typeof s === 'string' && s.charAt(0) === '"' && !reIsoDate.test(s.slice(1, -1))) {
|
|
213
|
+
let p = `data${ks.map((k) => (typeof k === 'number' ? `[${k}]` : pathSeg(k))).join('')}`
|
|
214
|
+
throw new Error(`invalid data: Date year is out of range 0000-9999 at [${pathStr(p)}]`)
|
|
215
|
+
}
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
seen.add(v)
|
|
219
|
+
if (Array.isArray(v)) {
|
|
220
|
+
|
|
221
|
+
//陣列以索引走訪(JSON序列化亦逐索引, 空洞為null)
|
|
222
|
+
for (let i = 0; i < v.length; i++) {
|
|
223
|
+
ks.push(i)
|
|
224
|
+
chkDataDate(v[i], ks, seen)
|
|
225
|
+
ks.pop()
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
for (let k of Object.keys(v)) {
|
|
230
|
+
ks.push(k)
|
|
231
|
+
chkDataDate(v[k], ks, seen)
|
|
232
|
+
ks.pop()
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
146
237
|
//isoFind, 把cvOrmFind所回傳複本內之Date就地轉為ISO字串(轉譯層): 數據以JSON存檔, Date於寫入時已成toISOString()之字串,
|
|
147
238
|
//條件內之Date不轉則恆不命中; 複本僅含null原型物件、密集陣列、純量與有效Date(無共享參照、無環), 就地轉換不影響呼叫端之find
|
|
148
|
-
|
|
239
|
+
//轉換所得之字串須為reIsoDate之形(檢查之值即使用之值), 範圍外(年份<0或>9999)者fail-closed: 拋出invalid find(帳本R-FIND-02), 不回顯值, p為路徑
|
|
240
|
+
let isoFind = (v, p = 'find') => {
|
|
149
241
|
if (v instanceof Date) {
|
|
150
|
-
|
|
242
|
+
let s = v.toISOString()
|
|
243
|
+
if (!reIsoDate.test(s)) {
|
|
244
|
+
throw new Error(`invalid find: Date year is out of range 0000-9999 at [${pathStr(p)}]`)
|
|
245
|
+
}
|
|
246
|
+
return s
|
|
151
247
|
}
|
|
152
248
|
if (v !== null && typeof v === 'object') {
|
|
153
249
|
|
|
154
250
|
//物件與陣列皆以Object.keys走訪(陣列為密集, 鍵即索引)
|
|
251
|
+
let isArr = Array.isArray(v)
|
|
155
252
|
for (let k of Object.keys(v)) {
|
|
156
|
-
v[k] = isoFind(v[k])
|
|
253
|
+
v[k] = isoFind(v[k], isArr ? `${p}[${k}]` : `${p}.${pathKey(k)}`)
|
|
157
254
|
}
|
|
158
255
|
}
|
|
159
256
|
return v
|
|
@@ -313,6 +410,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
313
410
|
* 查詢數據
|
|
314
411
|
*
|
|
315
412
|
* 條件find僅支援系列白名單(規則同delAll之第1-3點,見delAll),與delAll共用同一檢核,select(find)命中之數據即delAll(find)刪除之數據
|
|
413
|
+
* 條件內之Date年份須介於0000-9999,範圍外整批reject;資料庫檔內既有之範圍外Date字串(1.0.34起寫入已拒收範圍外Date)無法以Date條件正確比較(規則同delAll之第6點,見README)
|
|
316
414
|
*
|
|
317
415
|
* @memberOf WOrmLowdb
|
|
318
416
|
* @param {Object} [find={}] 輸入查詢條件物件(系列白名單,規則同delAll之第1-3點); 未給、undefined或{}回傳全部數據; 非條件物件或白名單外運算子整批reject
|
|
@@ -439,6 +537,11 @@ function WOrmLowdb(opt = {}) {
|
|
|
439
537
|
/**
|
|
440
538
|
* 插入數據,僅於主鍵不存在時寫入,已存在者跳過且不覆寫
|
|
441
539
|
*
|
|
540
|
+
* 數據內任何深度(頂層欄位、巢狀物件、陣列內)之Date年份須介於0000-9999(序列化為固定24字元之ISO字串,字典序即時間序),
|
|
541
|
+
* 範圍外(年份小於0或大於9999,如以new Date(8.64e15)作永不過期哨兵)整批reject且不寫入任何一筆,訊息為invalid data: Date year is out of range 0000-9999 at [路徑],
|
|
542
|
+
* 不回顯值,於reject之前發出一次error事件、不發出change事件;無效Date維持序列化為null存入;永不過期請改用null或new Date('9999-12-31T23:59:59.999Z');
|
|
543
|
+
* 資料庫檔內既有之範圍外Date字串不遷移,仍無法以Date條件正確比較,詳見README
|
|
544
|
+
*
|
|
442
545
|
* @memberOf WOrmLowdb
|
|
443
546
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
444
547
|
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
@@ -482,6 +585,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
482
585
|
//check id
|
|
483
586
|
data = procPk(data, 'insert')
|
|
484
587
|
|
|
588
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01)
|
|
589
|
+
chkDataDate(data)
|
|
590
|
+
|
|
485
591
|
//read
|
|
486
592
|
let arrOld = await readData()
|
|
487
593
|
|
|
@@ -574,6 +680,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
574
680
|
* 本函數則整批reject且不寫入任何一筆;同批含重複主鍵者亦視為衝突。確無衝突時兩者結果相同
|
|
575
681
|
* 註: 於本套件不會較insert快,因兩者皆為一次讀檔與一次寫檔,
|
|
576
682
|
* 提供本函數係為與其他w-orm系列套件維持同一組函數,令呼叫端得於各套件間替換而不須改寫呼叫
|
|
683
|
+
* 註: 數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆,規則同insert,詳見insert與README
|
|
577
684
|
*
|
|
578
685
|
* @memberOf WOrmLowdb
|
|
579
686
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
@@ -606,6 +713,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
606
713
|
//check id
|
|
607
714
|
data = procPk(data, 'insertBulk')
|
|
608
715
|
|
|
716
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01)
|
|
717
|
+
chkDataDate(data)
|
|
718
|
+
|
|
609
719
|
//read
|
|
610
720
|
let arrOld = await readData()
|
|
611
721
|
|
|
@@ -674,6 +784,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
674
784
|
/**
|
|
675
785
|
* 儲存數據,以主鍵為準更新既有數據,未給之欄位保留;主鍵不存在且autoInsert為true時改為插入
|
|
676
786
|
*
|
|
787
|
+
* 數據內任何深度之Date年份須介於0000-9999,範圍外(如new Date(8.64e15))整批reject且不寫入任何一筆(逐筆失敗之ok為0機制不適用),規則同insert,詳見insert與README;
|
|
788
|
+
* autoInsert為false而主鍵不存在(不會寫入)者亦先經同一檢核;合併與覆寫路徑寫入之Date皆來自已檢核之數據,已存在於資料庫之字串不檢核
|
|
789
|
+
*
|
|
677
790
|
* @memberOf WOrmLowdb
|
|
678
791
|
* @param {Object|Array} data 輸入數據物件或陣列
|
|
679
792
|
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
@@ -706,6 +819,9 @@ function WOrmLowdb(opt = {}) {
|
|
|
706
819
|
//check id
|
|
707
820
|
data = procPk(data, 'save')
|
|
708
821
|
|
|
822
|
+
//check Date, 複本內任何深度之Date年份須介於0000-9999, 範圍外整批reject(帳本R-DATE-01); 合併與覆寫路徑之Date皆來自此複本
|
|
823
|
+
chkDataDate(data)
|
|
824
|
+
|
|
709
825
|
//read
|
|
710
826
|
let arrOld = await readData()
|
|
711
827
|
|
|
@@ -1036,7 +1152,7 @@ function WOrmLowdb(opt = {}) {
|
|
|
1036
1152
|
* 2. 傳了值卻不是條件物件(null、陣列含[]與[{...}]、字串、數值、布林、函數、Date、RegExp、Map、Set、類別實例等)
|
|
1037
1153
|
* 一律整批reject,不視為{},不刪除任何數據。
|
|
1038
1154
|
* 3. 條件僅支援系列白名單: 欄位等值{欄:純量}(多欄為AND)、欄位運算子$eq $ne $gt $gte $lt $lte(值為純量)與
|
|
1039
|
-
* $in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date;
|
|
1155
|
+
* $in $nin(值為純量陣列)、文件層$and $or(值為條件物件之非空陣列)。純量為字串(不含NUL字元與孤立代理字元)、有限數字、布林、有效Date(年份須介於0000-9999,範圍外整批reject,見第6點);
|
|
1040
1156
|
* null僅可用於欄位等值、$eq、$ne。白名單外之運算子($not $nor $regex $options $exists $where $expr $like $ilike等)、
|
|
1041
1157
|
* 欄位層$and/$or、子查詢、函數值、Symbol鍵、undefined值、空的$nin/$and/$or等一律整批reject,
|
|
1042
1158
|
* 訊息為invalid find: 原因 at [路徑],且不刪除任何數據。
|
|
@@ -1046,7 +1162,11 @@ function WOrmLowdb(opt = {}) {
|
|
|
1046
1162
|
* 空的$nin會reject,$in:[]則為恆假(刪除0筆)。
|
|
1047
1163
|
* 6. 語意差異(依後端,見README): MongoDB式: $ne(比較值非null時)與$nin會命中欄位為null或缺欄之數據,$ne:null則排除之;
|
|
1048
1164
|
* 欄名同於Object.prototype成員(constructor、toString等)者,數據無此自有欄位時視為缺欄;
|
|
1049
|
-
* Date條件於本後端轉為ISO
|
|
1165
|
+
* Date條件於本後端轉為ISO字串後以字典序比較(與字串型欄位亦會比較):條件內任何位置之Date其年份須介於0000-9999,
|
|
1166
|
+
* 範圍外(年份小於0或大於9999,如new Date(8.64e15)、new Date(-8.64e15))整批reject,訊息為invalid find: Date year is out of range 0000-9999 at [路徑],
|
|
1167
|
+
* 不回顯值,不讀檔、不刪除任何數據;數據側自1.0.34起insert、insertBulk與save寫入時已拒收範圍外Date,
|
|
1168
|
+
* 但資料庫檔內既有之範圍外Date字串(舊版以new Date(8.64e15)作永不過期哨兵存入者)仍無法以Date條件正確比較
|
|
1169
|
+
* (例如{t:{$lt:現在}}會命中哨兵並將其刪除),請自行清理或改寫,見README。
|
|
1050
1170
|
* 需明確表達時可用可攜寫法: 排除NULL為{$and:[{f:{$ne:null}},{f:{$ne:x}}]},含NULL為{$or:[{f:null},{f:{$ne:x}}]}。
|
|
1051
1171
|
*
|
|
1052
1172
|
* n與nDeleted皆為實際刪除筆數,不取全表筆數。條件無命中時回{n:0,nDeleted:0,ok:1},不視為錯誤。
|