w-serv-orm 1.1.9 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/w-serv-orm.umd.js +2 -2
- package/dist/w-serv-orm.umd.js.map +1 -1
- package/docs/WServOrm.html +10 -6
- package/docs/WServOrm.mjs.html +13 -28
- package/docs/index.html +1 -1
- package/package.json +3 -3
- package/src/WServOrm.mjs +11 -26
- package/src/checkOptRemoved.mjs +25 -0
- package/src/getMapOrm.mjs +233 -14
- package/src/getProc.mjs +9 -7
- package/test/api-pkcast.test.mjs +113 -0
- package/test/api-procOrm.test.mjs +8 -7
- package/test/unit-WServOrm.test.mjs +88 -45
- package/test/unit-mapOrm.test.mjs +9 -9
- package/test/unit-pkcast.test.mjs +325 -0
- package/src/getItemsFail.mjs +0 -5
package/src/getProc.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
2
2
|
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
3
3
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
4
|
+
import checkOptRemoved from './checkOptRemoved.mjs'
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
function addFun(fs, f, name, useGuard = false) {
|
|
@@ -30,11 +31,7 @@ function addFun(fs, f, name, useGuard = false) {
|
|
|
30
31
|
async function procOrm(st, userId, woName, mode, input) {
|
|
31
32
|
//封裝mapOrm, 依序執行擴充檢查、前處理、ORM操作與後處理, st為該實例之狀態
|
|
32
33
|
//不做授權: 不檢查使用者亦不依使用者過濾數據, userId只供寫入稽核欄位與交給擴充函數; 開放給前端時須由開放處負責授權
|
|
33
|
-
|
|
34
|
-
//check
|
|
35
|
-
if (!isfun(st.mapOrm)) {
|
|
36
|
-
return Promise.reject(`invalid mapOrm`)
|
|
37
|
-
}
|
|
34
|
+
//st.mapOrm已於getProc建立st時驗證為函數, 且st不外露, 故此處不再檢查
|
|
38
35
|
|
|
39
36
|
//funChecks, 擴充檢查, 提供給各 mOrm[OOO].mjs 檢查
|
|
40
37
|
await pmSeries(st.funChecks, (v) => {
|
|
@@ -65,11 +62,16 @@ async function procOrm(st, userId, woName, mode, input) {
|
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
|
|
68
|
-
function getProc(mapOrm) {
|
|
65
|
+
function getProc(mapOrm, opt = {}) {
|
|
66
|
+
//mapOrm為getMapOrm之回傳函數, opt目前無設定鍵, 只檢查已移除之設定; 使用端有直接呼叫者(如測試以getMapOrm與getProc組出procOrm), 故檢查與WServOrm一致
|
|
67
|
+
//建構期之錯誤一律為Error, 與procOrm之字串reject區隔
|
|
68
|
+
|
|
69
|
+
//checkOptRemoved
|
|
70
|
+
checkOptRemoved(opt)
|
|
69
71
|
|
|
70
72
|
//check
|
|
71
73
|
if (!isfun(mapOrm)) {
|
|
72
|
-
|
|
74
|
+
throw new Error(`invalid mapOrm`)
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
//st, 各實例之狀態, 每次呼叫各自建立, 令同一行程內之多個實例互不干擾
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import assert from 'assert'
|
|
3
|
+
import WOrm from 'w-orm-lowdb/src/WOrmLowdb.mjs'
|
|
4
|
+
import ltdtDiffByKey from 'wsemi/src/ltdtDiffByKey.mjs'
|
|
5
|
+
import ds from '../schema/index.mjs'
|
|
6
|
+
import WServOrm from '../src/WServOrm.mjs'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
//以真ORM(w-orm-lowdb, 主鍵固定為字串id, 數字主鍵原會被其以genIDSeq取代)經procOrm驗證R-ID-02、R-MIX-01; schema之tests表之id為STRING pk
|
|
10
|
+
let fd = './test/_tmp/api-pkcast'
|
|
11
|
+
|
|
12
|
+
async function getReject(pm) {
|
|
13
|
+
try {
|
|
14
|
+
await pm
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
return err
|
|
18
|
+
}
|
|
19
|
+
throw new Error('預期reject但resolve')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
describe('數字主鍵接w-orm-lowdb', function() {
|
|
24
|
+
|
|
25
|
+
let so = null
|
|
26
|
+
let proc = (mode, input) => so.procOrm('u1', 'tests', mode, input)
|
|
27
|
+
let rows = async () => (await so.woItems.tests.select()).map((v) => [v.id, v.isActive])
|
|
28
|
+
let quiet = async (fn) => {
|
|
29
|
+
let logOrig = console.log
|
|
30
|
+
console.log = () => {}
|
|
31
|
+
try {
|
|
32
|
+
return await fn()
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
console.log = logOrig
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
before(function() {
|
|
40
|
+
fs.rmSync(fd, { recursive: true, force: true })
|
|
41
|
+
fs.mkdirSync(fd, { recursive: true })
|
|
42
|
+
so = WServOrm(ds, WOrm, `${fd}/db.json`, 'worm')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
beforeEach(async function() {
|
|
46
|
+
await so.woItems.tests.delAll()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
after(async function() {
|
|
50
|
+
await so.closeAll()
|
|
51
|
+
fs.rmSync(fd, { recursive: true, force: true })
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('A08 數字主鍵存為其字串形式, 重送與修改命中同一筆, 以數字或字串皆可查可刪', async function() {
|
|
55
|
+
//R-ID-02 規則2: 回報 = 實際; 重送不增筆(原每次另增genIDSeq之列); 寫入、查詢、刪除同一規則
|
|
56
|
+
let r = await proc('insert', [{ id: 123, isActive: 'y' }])
|
|
57
|
+
assert.deepStrictEqual(r, [{ id: '123' }])
|
|
58
|
+
await proc('insert', [{ id: 123, isActive: 'y' }])
|
|
59
|
+
await proc('save', [{ id: 123, isActive: 'n' }])
|
|
60
|
+
await proc('mix', { diff: [{ id: 123, isActive: 'm' }] })
|
|
61
|
+
assert.deepStrictEqual(await rows(), [['123', 'm']])
|
|
62
|
+
assert.strictEqual((await proc('select', { id: 123 })).length, 1)
|
|
63
|
+
assert.strictEqual((await proc('select', { id: '123' })).length, 1)
|
|
64
|
+
let rd = await proc('del', [{ id: 123 }])
|
|
65
|
+
assert.deepStrictEqual(rd, [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
66
|
+
assert.deepStrictEqual(await rows(), [])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('A09 表內已有他方以字串寫入之同值主鍵: 以數字save覆寫該列, insert略過而回報字串主鍵', async function() {
|
|
70
|
+
//R-ID-02 規則2: 123與'123'為同一筆(對外行為變更, 原另增genIDSeq之列)
|
|
71
|
+
await so.woItems.tests.insert([{ id: '777', isActive: 'A' }])
|
|
72
|
+
let rs = await proc('save', [{ id: 777, isActive: 'B' }])
|
|
73
|
+
assert.deepStrictEqual(rs, [{ id: '777' }])
|
|
74
|
+
let ri = await proc('insert', [{ id: 777, isActive: 'C' }])
|
|
75
|
+
assert.deepStrictEqual(ri, [{ id: '777' }])
|
|
76
|
+
assert.deepStrictEqual(await rows(), [['777', 'B']])
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('A10 以ltdtDiffByKey嚴格比對產生之add 888、del 888字串, 整批reject且表內不變', async function() {
|
|
80
|
+
//R-MIX-01 規則1、2: 原為insert略過、del刪除而resolve遺失資料
|
|
81
|
+
await so.woItems.tests.insert([{ id: '888', isActive: 'y' }])
|
|
82
|
+
let old = await so.woItems.tests.select()
|
|
83
|
+
let input = ltdtDiffByKey(old, [{ ...old[0], id: 888 }], 'id', { withInfor: false })
|
|
84
|
+
assert.deepStrictEqual([input.add.length, input.del.length], [1, 1])
|
|
85
|
+
let err = await quiet(() => getReject(proc('mix', input)))
|
|
86
|
+
assert.strictEqual(err, 'invalid input of mix, same id in add and del: add[0], del[0]')
|
|
87
|
+
assert.deepStrictEqual(await rows(), [['888', 'y']])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('A11 同批之數字與其字串形式: 表內一筆(首筆內容), 回報兩筆同鍵', async function() {
|
|
91
|
+
//R-ID-02 規則2; insert回傳之id含被略過者
|
|
92
|
+
let r = await proc('insert', [{ id: 999, isActive: 'p' }, { id: '999', isActive: 'q' }])
|
|
93
|
+
assert.deepStrictEqual(r, [{ id: '999' }, { id: '999' }])
|
|
94
|
+
assert.deepStrictEqual(await rows(), [['999', 'p']])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('A12 查詢與delAll之條件以數字給予: 等值、$in、$ne、$not命中字串主鍵, 範圍依字典序', async function() {
|
|
98
|
+
//R-ID-02 規則2(查詢條件)與已知限制(範圍依字典序: '40' < '5')
|
|
99
|
+
await proc('insert', [{ id: 5, isActive: 'y' }, { id: 40, isActive: 'y' }, { id: 'abc', isActive: 'y' }])
|
|
100
|
+
let ids = async (find) => (await proc('select', find)).map((v) => v.id).sort()
|
|
101
|
+
assert.deepStrictEqual(await ids({ id: 5 }), ['5'])
|
|
102
|
+
assert.deepStrictEqual(await ids({ id: { $in: [5, 40] } }), ['40', '5'])
|
|
103
|
+
assert.deepStrictEqual(await ids({ id: { $ne: 5 } }), ['40', 'abc'])
|
|
104
|
+
assert.deepStrictEqual(await ids({ id: { $not: { $eq: 5 } } }), ['40', 'abc'])
|
|
105
|
+
assert.deepStrictEqual(await ids({ id: { $lt: 5 } }), ['40'])
|
|
106
|
+
let r1 = await proc('delAll', { id: { $in: [40] } })
|
|
107
|
+
assert.deepStrictEqual(r1, { n: 1, nDeleted: 1, ok: 1 })
|
|
108
|
+
let r2 = await proc('delAll', { id: 5 })
|
|
109
|
+
assert.deepStrictEqual(r2, { n: 1, nDeleted: 1, ok: 1 })
|
|
110
|
+
assert.deepStrictEqual(await rows(), [['abc', 'y']])
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
})
|
|
@@ -27,7 +27,7 @@ describe('procOrm接w-orm-lowdb', function() {
|
|
|
27
27
|
before(function() {
|
|
28
28
|
fs.rmSync(fd, { recursive: true, force: true })
|
|
29
29
|
fs.mkdirSync(fd, { recursive: true })
|
|
30
|
-
so = WServOrm(ds, WOrm, `${fd}/db.json`, 'worm'
|
|
30
|
+
so = WServOrm(ds, WOrm, `${fd}/db.json`, 'worm')
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
after(async function() {
|
|
@@ -44,17 +44,18 @@ describe('procOrm接w-orm-lowdb', function() {
|
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
it('A02 del含無效主鍵', async function() {
|
|
47
|
-
//R02: 逐筆ok為0即reject
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
//R02: 逐筆ok為0即reject並列出失敗筆(無有效主鍵者列位置); R10: 單筆失敗不中斷整批, 有效筆已刪除
|
|
48
|
+
//無效主鍵取非字串非數字之值: 數字依R-ID-02轉為字串後為有效主鍵(未命中), 不再觸發逐筆失敗
|
|
49
|
+
let err = await getReject(proc('del', [{ id: 'a1' }, { id: true }]))
|
|
50
|
+
assert.strict.equal(err, 'failed to delete data: data[1]')
|
|
50
51
|
let rs = await proc('select', { id: 'a1' })
|
|
51
52
|
assert.strict.equal(rs.length, 0)
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
it('A03 mix之del含無效主鍵', async function() {
|
|
55
|
-
//R03: del之逐筆失敗不中斷diff, diff已寫入, 最後reject列出del之失敗
|
|
56
|
-
let err = await getReject(proc('mix', { del: [{ id:
|
|
57
|
-
assert.strict.equal(err, 'failed to delete data:
|
|
56
|
+
//R03: del之逐筆失敗不中斷diff, diff已寫入, 最後reject列出del之失敗(未帶主鍵之列以位置列出)
|
|
57
|
+
let err = await getReject(proc('mix', { del: [{ id: null }], diff: [{ id: 'a2', isActive: 'y' }] }))
|
|
58
|
+
assert.strict.equal(err, 'failed to delete data: data[0]')
|
|
58
59
|
let rs = await proc('select', { id: 'a2' })
|
|
59
60
|
assert.strict.equal(rs.length, 1)
|
|
60
61
|
})
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import assert from 'assert'
|
|
2
2
|
import WServOrm from '../src/WServOrm.mjs'
|
|
3
3
|
import getMapOrm from '../src/getMapOrm.mjs'
|
|
4
|
-
import
|
|
4
|
+
import getProc from '../src/getProc.mjs'
|
|
5
|
+
import checkOptRemoved from '../src/checkOptRemoved.mjs'
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
//替身ORM工廠: 以name辨識所屬實例, 呼叫紀錄寫入log; 回傳形狀依w-orm系列規格(save、del回逐筆陣列, insert回聚合物件)
|
|
@@ -29,7 +30,6 @@ function mkWOrm(name, log, behavior = {}) {
|
|
|
29
30
|
|
|
30
31
|
let dsAll = { tests: { keys: ['id', 'name', 'isActive', 'timeUpdate'] } }
|
|
31
32
|
let dsNoTime = { tests: { keys: ['id', 'name', 'isActive'] } }
|
|
32
|
-
let optOff = { useCheckUser: false, useExcludeWhenNotAdmin: false }
|
|
33
33
|
let wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
34
34
|
|
|
35
35
|
async function getReject(pm) {
|
|
@@ -63,8 +63,8 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
63
63
|
it('I01 兩實例之procOrm各自路由至自己的ORM', async function() {
|
|
64
64
|
//R1: 雙向皆打自己的ORM, 解構後呼叫亦然
|
|
65
65
|
let log = []
|
|
66
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
67
|
-
let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b'
|
|
66
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
67
|
+
let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b')
|
|
68
68
|
let { procOrm: pA } = A
|
|
69
69
|
let { procOrm: pB } = B
|
|
70
70
|
await pA('u1', 'tests', 'select', {})
|
|
@@ -77,8 +77,8 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
77
77
|
it('I02 各實例依自己之ds調整數據', async function() {
|
|
78
78
|
//R1: A之ds含timeUpdate而補值, B之ds不含而不補
|
|
79
79
|
let log = []
|
|
80
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
81
|
-
let B = WServOrm(dsNoTime, mkWOrm('B', log), 'url-b', 'db-b'
|
|
80
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
81
|
+
let B = WServOrm(dsNoTime, mkWOrm('B', log), 'url-b', 'db-b')
|
|
82
82
|
await A.procOrm('u1', 'tests', 'save', [{ id: 'x' }])
|
|
83
83
|
await B.procOrm('u1', 'tests', 'save', [{ id: 'y' }])
|
|
84
84
|
assert.strict.deepEqual(log.map((v) => v.name), ['A', 'B'])
|
|
@@ -90,7 +90,7 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
90
90
|
//R3: useCheckUser、getUserById、useExcludeWhenNotAdmin已移除; 給予未給、null、false以外之值即拋錯, 避免使用端以為仍有檢查而無聲失去
|
|
91
91
|
//拋錯於建立各資料表ORM之前, 否則已開啟之ORM(如lmdb之檔案)無從關閉; 亦不影響既有實例
|
|
92
92
|
let log = []
|
|
93
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
93
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
94
94
|
let created = 0
|
|
95
95
|
let WOrmCount = function() {
|
|
96
96
|
created++
|
|
@@ -130,8 +130,8 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
130
130
|
//R1、R4: 雙向隔離; 註冊並等待超過1ms後生效
|
|
131
131
|
let log = []
|
|
132
132
|
let calls = []
|
|
133
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
134
|
-
let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b'
|
|
133
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
134
|
+
let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b')
|
|
135
135
|
for (let [name, ins] of [['A', A], ['B', B]]) {
|
|
136
136
|
ins.addFunCheck(() => {
|
|
137
137
|
calls.push(`${name}-check`)
|
|
@@ -157,12 +157,12 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
157
157
|
//R1d: A註冊後再建C, C之procOrm不呼叫A之hook
|
|
158
158
|
let log = []
|
|
159
159
|
let calls = []
|
|
160
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
160
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
161
161
|
A.addFunCheck(() => {
|
|
162
162
|
calls.push('A-check')
|
|
163
163
|
})
|
|
164
164
|
await wait(20)
|
|
165
|
-
let C = WServOrm(dsAll, mkWOrm('C', log), 'url-c', 'db-c'
|
|
165
|
+
let C = WServOrm(dsAll, mkWOrm('C', log), 'url-c', 'db-c')
|
|
166
166
|
await C.procOrm('u1', 'tests', 'select', {})
|
|
167
167
|
assert.strict.deepEqual(calls, [])
|
|
168
168
|
})
|
|
@@ -187,7 +187,7 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
187
187
|
|
|
188
188
|
it('I08 擴充函數之參數不含isAdmin', async function() {
|
|
189
189
|
//R3: 隨useCheckUser移除, 參數物件只含woName、userId、mode、input, 後處理另含output
|
|
190
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
190
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
191
191
|
let ks = {}
|
|
192
192
|
A.addFunCheck((p) => {
|
|
193
193
|
ks.check = Object.keys(p)
|
|
@@ -216,14 +216,14 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
216
216
|
let gate = new Promise((resolve) => {
|
|
217
217
|
release = resolve
|
|
218
218
|
})
|
|
219
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
219
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
220
220
|
A.addFunCheck(async () => {
|
|
221
221
|
await gate
|
|
222
222
|
})
|
|
223
223
|
await wait(20)
|
|
224
224
|
let pA = A.procOrm('u1', 'tests', 'select', {})
|
|
225
225
|
await wait(5)
|
|
226
|
-
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b'
|
|
226
|
+
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b')
|
|
227
227
|
release()
|
|
228
228
|
let rA = await pA
|
|
229
229
|
assert.strict.deepEqual(log.map((v) => v.name), ['A'])
|
|
@@ -233,8 +233,8 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
233
233
|
it('I10 同一實例之woItems直寫與procOrm寫入打同一個ORM', async function() {
|
|
234
234
|
//R1b: 使用端先以woItems直接寫入再經procOrm寫入之用法
|
|
235
235
|
let log = []
|
|
236
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
237
|
-
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b'
|
|
236
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
237
|
+
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b')
|
|
238
238
|
await A.woItems.tests.save([{ id: 'x' }])
|
|
239
239
|
await A.procOrm('u1', 'tests', 'save', [{ id: 'y' }])
|
|
240
240
|
assert.strict.deepEqual(log.map((v) => v.name), ['A', 'A'])
|
|
@@ -242,7 +242,7 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
242
242
|
|
|
243
243
|
it('I11 回傳函數之名稱與型別不變', async function() {
|
|
244
244
|
//R2: 使用端以解構取用並當裸函數傳遞; addFun*回傳undefined; procOrm為async函數
|
|
245
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
245
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
246
246
|
assert.strict.equal(A.procOrm.name, 'procOrm')
|
|
247
247
|
assert.strict.equal(Object.prototype.toString.call(A.procOrm), '[object AsyncFunction]')
|
|
248
248
|
for (let k of ['addFunCheck', 'addFunPreProcessing', 'addFunPostProcessing']) {
|
|
@@ -251,6 +251,55 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
251
251
|
}
|
|
252
252
|
})
|
|
253
253
|
|
|
254
|
+
it('I12 直接呼叫getProc: 已移除之設定與無效之mapOrm皆拋Error, 未給、null或false照常', async function() {
|
|
255
|
+
//R3: 使用端有以getMapOrm與getProc直接組出procOrm者(如w-web-sso之測試), 已移除之設定不得被靜默忽略, 訊息同WServOrm
|
|
256
|
+
//建構期錯誤為Error, 不回rejected Promise(原回之Promise被解構時得undefined)
|
|
257
|
+
let getThrow = (fn) => {
|
|
258
|
+
try {
|
|
259
|
+
fn()
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
return e
|
|
263
|
+
}
|
|
264
|
+
throw new Error('預期拋錯但未拋')
|
|
265
|
+
}
|
|
266
|
+
let mapOrm = getMapOrm(dsAll, { tests: { select: async () => [{ id: 'r1' }] } })
|
|
267
|
+
let bads = [
|
|
268
|
+
['useCheckUser', true],
|
|
269
|
+
['getUserById', async () => ({ isActive: 'y' })],
|
|
270
|
+
['useExcludeWhenNotAdmin', true],
|
|
271
|
+
]
|
|
272
|
+
for (let [k, v] of bads) {
|
|
273
|
+
let e1 = getThrow(() => getProc(mapOrm, { [k]: v }))
|
|
274
|
+
let e2 = getThrow(() => WServOrm(dsAll, mkWOrm('X', []), 'url-x', 'db-x', { [k]: v }))
|
|
275
|
+
assert.ok(e1 instanceof Error && e1.message.startsWith(`opt.${k} has been removed, `), `${k}: ${String(v)}`)
|
|
276
|
+
assert.strict.equal(e1.message, e2.message)
|
|
277
|
+
}
|
|
278
|
+
for (let bad of [undefined, null, {}, 'x']) {
|
|
279
|
+
let e = getThrow(() => getProc(bad))
|
|
280
|
+
assert.ok(e instanceof Error, String(bad))
|
|
281
|
+
assert.strict.equal(e.message, 'invalid mapOrm')
|
|
282
|
+
}
|
|
283
|
+
for (let args of [[], [undefined], [null], [{}], [{ useCheckUser: false, getUserById: null, useExcludeWhenNotAdmin: false }]]) {
|
|
284
|
+
let { procOrm } = getProc(mapOrm, ...args)
|
|
285
|
+
let r = await procOrm('u1', 'tests', 'select', {})
|
|
286
|
+
assert.strict.deepEqual(r, [{ id: 'r1' }], JSON.stringify(args))
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it('I13 checkOptRemoved可由使用端單獨呼叫: 只看已移除之三鍵, 其他鍵不受影響', async function() {
|
|
291
|
+
//R3: 使用端包裝層(如WWebApi)以自身之opt呼叫, opt含serverPort等其他鍵; 通過時回undefined且不改動opt
|
|
292
|
+
let optWrap = { serverPort: 11005, webName: { eng: 'x' }, useCheckUser: false, getUserById: null }
|
|
293
|
+
assert.strict.equal(checkOptRemoved(optWrap), undefined)
|
|
294
|
+
assert.strict.deepEqual(optWrap, { serverPort: 11005, webName: { eng: 'x' }, useCheckUser: false, getUserById: null })
|
|
295
|
+
for (let opt of [undefined, null, {}, 'x', 1]) {
|
|
296
|
+
assert.strict.equal(checkOptRemoved(opt), undefined, String(opt))
|
|
297
|
+
}
|
|
298
|
+
for (let k of ['useCheckUser', 'getUserById', 'useExcludeWhenNotAdmin']) {
|
|
299
|
+
assert.throws(() => checkOptRemoved({ serverPort: 11005, [k]: true }), (e) => e instanceof Error && e.message.startsWith(`opt.${k} has been removed, `), k)
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
|
|
254
303
|
})
|
|
255
304
|
|
|
256
305
|
|
|
@@ -261,7 +310,7 @@ describe('procOrm後處理', function() {
|
|
|
261
310
|
let log = []
|
|
262
311
|
let calls = []
|
|
263
312
|
let save = (d) => d.map((v, k) => (k === 1 ? { n: 1, ok: 0, err: 'E' } : { n: 1, ok: 1 }))
|
|
264
|
-
let A = WServOrm(dsAll, mkWOrm('A', log, { save }), 'url-a', 'db-a'
|
|
313
|
+
let A = WServOrm(dsAll, mkWOrm('A', log, { save }), 'url-a', 'db-a')
|
|
265
314
|
A.addFunPostProcessing((p) => {
|
|
266
315
|
calls.push(p.mode)
|
|
267
316
|
return p.output
|
|
@@ -283,7 +332,7 @@ describe('mapOrm之log標籤與訊息', function() {
|
|
|
283
332
|
//R6: 標籤依實際操作, reject訊息為該操作之整批失敗訊息
|
|
284
333
|
let log = []
|
|
285
334
|
let fail = () => Promise.reject(new Error('E-batch'))
|
|
286
|
-
let A = WServOrm(dsAll, mkWOrm('A', log, { insert: fail, del: fail }), 'url-a', 'db-a'
|
|
335
|
+
let A = WServOrm(dsAll, mkWOrm('A', log, { insert: fail, del: fail }), 'url-a', 'db-a')
|
|
287
336
|
let errs = []
|
|
288
337
|
let logs = await captureLog(async () => {
|
|
289
338
|
errs.push(await getReject(A.procOrm('u1', 'tests', 'insert', [{ id: 'a' }])))
|
|
@@ -297,7 +346,7 @@ describe('mapOrm之log標籤與訊息', function() {
|
|
|
297
346
|
it('L02 adjustData失敗之標籤含表名', async function() {
|
|
298
347
|
//R6: save、mix之add與diff三處adjustData失敗皆記表名, reject訊息為整批失敗訊息
|
|
299
348
|
let log = []
|
|
300
|
-
let A = WServOrm({ tests: {} }, mkWOrm('A', log), 'url-a', 'db-a'
|
|
349
|
+
let A = WServOrm({ tests: {} }, mkWOrm('A', log), 'url-a', 'db-a')
|
|
301
350
|
let errs = []
|
|
302
351
|
let logs = await captureLog(async () => {
|
|
303
352
|
errs.push(await getReject(A.procOrm('u1', 'tests', 'save', [{ id: 'a' }])))
|
|
@@ -313,7 +362,7 @@ describe('mapOrm之log標籤與訊息', function() {
|
|
|
313
362
|
let id150 = 'k'.repeat(150)
|
|
314
363
|
let id100 = 'm'.repeat(100)
|
|
315
364
|
let save = (d) => d.map(() => ({ n: 1, ok: 0, err: 'E' }))
|
|
316
|
-
let A = WServOrm(dsAll, mkWOrm('A', [], { save }), 'url-a', 'db-a'
|
|
365
|
+
let A = WServOrm(dsAll, mkWOrm('A', [], { save }), 'url-a', 'db-a')
|
|
317
366
|
let err1 = null
|
|
318
367
|
let err2 = null
|
|
319
368
|
let logs = await captureLog(async () => {
|
|
@@ -335,7 +384,7 @@ describe('procOrm補主鍵', function() {
|
|
|
335
384
|
it('P01 insert、save、mix之新增未帶主鍵時補值並回傳', async function() {
|
|
336
385
|
//D1: 本套件以genIDSeq補值, 回傳之id即ORM收到之id; 物件輸入回傳單一{id}
|
|
337
386
|
let log = []
|
|
338
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
387
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
339
388
|
let r1 = await A.procOrm('u1', 'tests', 'insert', [{ name: 'a' }])
|
|
340
389
|
let r2 = await A.procOrm('u1', 'tests', 'save', { name: 'b' })
|
|
341
390
|
let r3 = await A.procOrm('u1', 'tests', 'mix', { add: [{ name: 'c' }] })
|
|
@@ -346,14 +395,14 @@ describe('procOrm補主鍵', function() {
|
|
|
346
395
|
})
|
|
347
396
|
|
|
348
397
|
it('P02 依主鍵值決定是否補值', async function() {
|
|
349
|
-
//
|
|
398
|
+
//R-ID-01 規則1: null、空字串、物件補值, 非空字串保留; R-ID-02 規則2: 字串型(或型別未知)主鍵欄之有限數字轉為其字串形式
|
|
350
399
|
let log = []
|
|
351
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
400
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
352
401
|
let input = [{ id: null }, { id: '' }, { id: { x: 1 } }, { id: 123 }, { id: 'keep' }]
|
|
353
402
|
let r = await A.procOrm('u1', 'tests', 'save', input)
|
|
354
403
|
let got = log[0].data.map((v) => v.id)
|
|
355
404
|
assert.ok(isId(got[0]) && isId(got[1]) && isId(got[2]))
|
|
356
|
-
assert.strict.equal(got[3], 123)
|
|
405
|
+
assert.strict.equal(got[3], '123')
|
|
357
406
|
assert.strict.equal(got[4], 'keep')
|
|
358
407
|
assert.strict.deepEqual(r.map((v) => v.id), got)
|
|
359
408
|
})
|
|
@@ -370,7 +419,7 @@ describe('procOrm補主鍵', function() {
|
|
|
370
419
|
]
|
|
371
420
|
for (let [ds, expectGen] of dsCases) {
|
|
372
421
|
log.length = 0
|
|
373
|
-
let A = WServOrm(ds, mkWOrm('A', log), 'url-a', 'db-a'
|
|
422
|
+
let A = WServOrm(ds, mkWOrm('A', log), 'url-a', 'db-a')
|
|
374
423
|
await A.procOrm('u1', 'tests', 'insert', [{ name: 'a' }])
|
|
375
424
|
assert.strict.equal(isId(log[0].data[0].id), expectGen, JSON.stringify(ds))
|
|
376
425
|
}
|
|
@@ -379,7 +428,7 @@ describe('procOrm補主鍵', function() {
|
|
|
379
428
|
it('P04 單一空物件維持原樣交ORM', async function() {
|
|
380
429
|
//D1: 調整後無欄位之列不補, 保留ORM視空物件為無效輸入之既有行為
|
|
381
430
|
let log = []
|
|
382
|
-
let A = WServOrm({ tests: { keys: ['id', 'name'] } }, mkWOrm('A', log), 'url-a', 'db-a'
|
|
431
|
+
let A = WServOrm({ tests: { keys: ['id', 'name'] } }, mkWOrm('A', log), 'url-a', 'db-a')
|
|
383
432
|
await A.procOrm('u1', 'tests', 'save', {})
|
|
384
433
|
assert.strict.deepEqual(log[0].data, {})
|
|
385
434
|
})
|
|
@@ -387,7 +436,7 @@ describe('procOrm補主鍵', function() {
|
|
|
387
436
|
it('P05 同批多筆各自補值且呼叫端原物件不被加上主鍵', async function() {
|
|
388
437
|
//D1、D1a: 各自唯一; 補值寫在複本, 呼叫端原物件不含補出之主鍵
|
|
389
438
|
let log = []
|
|
390
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
439
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
391
440
|
let input = [{ name: 'a' }, { name: 'b' }, { name: 'c' }]
|
|
392
441
|
let r = await A.procOrm('u1', 'tests', 'insert', input)
|
|
393
442
|
let ids = r.map((v) => v.id)
|
|
@@ -399,7 +448,7 @@ describe('procOrm補主鍵', function() {
|
|
|
399
448
|
//X2: 呼叫端未帶主鍵者仍列第N筆, log保留補出之主鍵
|
|
400
449
|
let log = []
|
|
401
450
|
let save = (d) => d.map((v, k) => (k === 1 ? { n: 1, ok: 0, err: 'E' } : { n: 1, ok: 1 }))
|
|
402
|
-
let A = WServOrm(dsAll, mkWOrm('A', log, { save }), 'url-a', 'db-a'
|
|
451
|
+
let A = WServOrm(dsAll, mkWOrm('A', log, { save }), 'url-a', 'db-a')
|
|
403
452
|
let err = null
|
|
404
453
|
let logs = await captureLog(async () => {
|
|
405
454
|
err = await getReject(A.procOrm('u1', 'tests', 'save', [{ id: 's1' }, { name: 'no-id' }]))
|
|
@@ -418,7 +467,7 @@ describe('hook串接與註冊', function() {
|
|
|
418
467
|
it('K01 多個模組各註冊一個後處理皆正確', async function() {
|
|
419
468
|
//D3: 每個後處理皆收參數物件, output為前一個之回傳值
|
|
420
469
|
let log = []
|
|
421
|
-
let A = WServOrm(dsTwo, mkWOrm('A', log), 'url-a', 'db-a'
|
|
470
|
+
let A = WServOrm(dsTwo, mkWOrm('A', log), 'url-a', 'db-a')
|
|
422
471
|
A.addFunPostProcessing(({ woName, output }) => (woName !== 'users' ? output : output.map((v) => ({ ...v, tagA: 1 }))))
|
|
423
472
|
A.addFunPostProcessing(({ woName, output }) => (woName !== 'items' ? output : output.map((v) => ({ ...v, tagB: 1 }))))
|
|
424
473
|
await wait(20)
|
|
@@ -431,7 +480,7 @@ describe('hook串接與註冊', function() {
|
|
|
431
480
|
it('K02 後處理回傳undefined往下傳且拋錯即中止', async function() {
|
|
432
481
|
//D3: 不加特例; 某個拋錯則procOrm reject且後續不執行
|
|
433
482
|
let calls = []
|
|
434
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
483
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
435
484
|
A.addFunPostProcessing(() => undefined)
|
|
436
485
|
A.addFunPostProcessing((p) => {
|
|
437
486
|
calls.push(p.output)
|
|
@@ -441,7 +490,7 @@ describe('hook串接與註冊', function() {
|
|
|
441
490
|
let r = await A.procOrm('u1', 'tests', 'select', {})
|
|
442
491
|
assert.strict.equal(r, undefined)
|
|
443
492
|
assert.strict.deepEqual(calls, [undefined])
|
|
444
|
-
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b'
|
|
493
|
+
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b')
|
|
445
494
|
let after = []
|
|
446
495
|
B.addFunPostProcessing(() => {
|
|
447
496
|
throw new Error('E-post')
|
|
@@ -460,7 +509,7 @@ describe('hook串接與註冊', function() {
|
|
|
460
509
|
//P3-3: 前一個只回{input}時, 下一個仍收得到woName
|
|
461
510
|
let log = []
|
|
462
511
|
let seen = []
|
|
463
|
-
let A = WServOrm(dsTwo, mkWOrm('A', log), 'url-a', 'db-a'
|
|
512
|
+
let A = WServOrm(dsTwo, mkWOrm('A', log), 'url-a', 'db-a')
|
|
464
513
|
A.addFunPreProcessing((p) => ({ input: p.input.map((v) => ({ ...v, preA: 1 })) }))
|
|
465
514
|
A.addFunPreProcessing((p) => {
|
|
466
515
|
seen.push(p.woName)
|
|
@@ -477,7 +526,7 @@ describe('hook串接與註冊', function() {
|
|
|
477
526
|
//P3-3: 防止input成為undefined而令select回全表
|
|
478
527
|
for (let bad of [undefined, [1], { woName: 'tests' }]) {
|
|
479
528
|
let log = []
|
|
480
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a'
|
|
529
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
481
530
|
A.addFunPreProcessing(() => bad)
|
|
482
531
|
await wait(20)
|
|
483
532
|
let err = await getReject(A.procOrm('u1', 'tests', 'select', {}))
|
|
@@ -493,7 +542,7 @@ describe('hook串接與註冊', function() {
|
|
|
493
542
|
release = resolve
|
|
494
543
|
})
|
|
495
544
|
let calls = []
|
|
496
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
545
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
497
546
|
A.addFunPostProcessing(async (p) => {
|
|
498
547
|
calls.push('h1')
|
|
499
548
|
await gate
|
|
@@ -516,13 +565,13 @@ describe('hook串接與註冊', function() {
|
|
|
516
565
|
|
|
517
566
|
it('K06 註冊非函數即同步拋錯, 函數與async函數可註冊', async function() {
|
|
518
567
|
//D4: 訊息含hook名稱; 合法註冊之實例另建(A之check已因非函數註冊而被守門, 見K07)
|
|
519
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
568
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
520
569
|
for (let k of ['addFunCheck', 'addFunPreProcessing', 'addFunPostProcessing']) {
|
|
521
570
|
for (let bad of [undefined, null, 'x', {}]) {
|
|
522
571
|
assert.throws(() => A[k](bad), (e) => e instanceof Error && e.message.includes(k))
|
|
523
572
|
}
|
|
524
573
|
}
|
|
525
|
-
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b'
|
|
574
|
+
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b')
|
|
526
575
|
for (let k of ['addFunCheck', 'addFunPreProcessing', 'addFunPostProcessing']) {
|
|
527
576
|
B[k](function(p) {
|
|
528
577
|
return k === 'addFunCheck' ? undefined : (k === 'addFunPreProcessing' ? p : p.output)
|
|
@@ -536,7 +585,7 @@ describe('hook串接與註冊', function() {
|
|
|
536
585
|
|
|
537
586
|
it('K07 check註冊失敗被吞掉仍擋下呼叫, 前後處理則不影響', async function() {
|
|
538
587
|
//P3-4: check維持fail-closed; 前後處理註冊失敗時陣列不變
|
|
539
|
-
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a'
|
|
588
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a')
|
|
540
589
|
try {
|
|
541
590
|
A.addFunCheck(null)
|
|
542
591
|
}
|
|
@@ -546,7 +595,7 @@ describe('hook串接與註冊', function() {
|
|
|
546
595
|
assert.ok(String(err).includes('addFunCheck'))
|
|
547
596
|
//錯誤型別: 守門於procOrm內reject, 與procOrm其餘拒絕一致為字串
|
|
548
597
|
assert.strict.equal(typeof err, 'string')
|
|
549
|
-
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b'
|
|
598
|
+
let B = WServOrm(dsAll, mkWOrm('B', []), 'url-b', 'db-b')
|
|
550
599
|
for (let k of ['addFunPreProcessing', 'addFunPostProcessing']) {
|
|
551
600
|
try {
|
|
552
601
|
B[k](null)
|
|
@@ -558,10 +607,4 @@ describe('hook串接與註冊', function() {
|
|
|
558
607
|
assert.strict.equal(r.length, 2)
|
|
559
608
|
})
|
|
560
609
|
|
|
561
|
-
it('K08 src/getItemsFail.mjs相容檔轉出w-data-collector之版本', async function() {
|
|
562
|
-
//X1: 使用端以深層路徑引用(如w-web-sso server/ormWrite.mjs)
|
|
563
|
-
let m = await import('../src/getItemsFail.mjs')
|
|
564
|
-
assert.strict.equal(m.default, getItemsFailWdc)
|
|
565
|
-
})
|
|
566
|
-
|
|
567
610
|
})
|
|
@@ -41,7 +41,7 @@ async function getReject(pm) {
|
|
|
41
41
|
|
|
42
42
|
describe('mapOrm逐筆失敗', function() {
|
|
43
43
|
|
|
44
|
-
let so = WServOrm(ds, WOrmStub, 'stub-url', 'stub-db'
|
|
44
|
+
let so = WServOrm(ds, WOrmStub, 'stub-url', 'stub-db')
|
|
45
45
|
let proc = (mode, input) => so.procOrm('u1', 'tests', mode, input)
|
|
46
46
|
|
|
47
47
|
beforeEach(function() {
|
|
@@ -119,8 +119,8 @@ describe('mapOrm逐筆失敗', function() {
|
|
|
119
119
|
})
|
|
120
120
|
|
|
121
121
|
it('U10 del數字主鍵ok為0', async function() {
|
|
122
|
-
//R02: del逐筆ok為0即reject;
|
|
123
|
-
plan.del = () => [okDel, { n:
|
|
122
|
+
//R02: del逐筆ok為0即reject; 數字主鍵依R-ID-02轉為字串後交ORM, 訊息照列
|
|
123
|
+
plan.del = () => [okDel, { n: 1, nDeleted: 0, ok: 0, err: 'E-del' }]
|
|
124
124
|
let err = await getReject(proc('del', [{ id: 'd1' }, { id: 123 }]))
|
|
125
125
|
assert.strict.equal(err, 'failed to delete data: id[123]')
|
|
126
126
|
})
|
|
@@ -232,7 +232,7 @@ describe('mapOrm逐筆失敗', function() {
|
|
|
232
232
|
|
|
233
233
|
describe('mapOrm主鍵與clearXSS', function() {
|
|
234
234
|
|
|
235
|
-
let so = WServOrm(ds, WOrmStub, 'stub-url', 'stub-db'
|
|
235
|
+
let so = WServOrm(ds, WOrmStub, 'stub-url', 'stub-db')
|
|
236
236
|
let proc = (mode, input) => so.procOrm('u1', 'tests', mode, input)
|
|
237
237
|
|
|
238
238
|
beforeEach(function() {
|
|
@@ -277,10 +277,10 @@ describe('mapOrm主鍵與clearXSS', function() {
|
|
|
277
277
|
})
|
|
278
278
|
|
|
279
279
|
it('X05 數字主鍵、未帶主鍵與不被改寫之主鍵照常寫入', async function() {
|
|
280
|
-
//判準為是否被改寫:
|
|
280
|
+
//判準為是否被改寫: 數字依R-ID-02轉為字串(不含標記), 未帶主鍵者由本套件補值, 白名單標籤之規範寫法不被改寫
|
|
281
281
|
plan.save = (data) => data.map(() => okSave)
|
|
282
282
|
let r = await proc('save', [{ id: 5 }, { id: '<b>粗體</b>' }, { name: 'no-id' }])
|
|
283
|
-
assert.strict.equal(r[0].id, 5)
|
|
283
|
+
assert.strict.equal(r[0].id, '5')
|
|
284
284
|
assert.strict.equal(r[1].id, '<b>粗體</b>')
|
|
285
285
|
assert.ok(typeof r[2].id === 'string' && r[2].id.length > 0)
|
|
286
286
|
})
|
|
@@ -295,14 +295,14 @@ describe('mapOrm主鍵與clearXSS', function() {
|
|
|
295
295
|
})
|
|
296
296
|
|
|
297
297
|
it('X07 insert與mix各入口之其餘主鍵狀態', async function() {
|
|
298
|
-
|
|
298
|
+
//數字依R-ID-02轉為字串, 不被改寫之主鍵照寫, mix之修改未帶主鍵者補值, mix之刪除不經clearXSS而原樣交ORM
|
|
299
299
|
plan.insert = (data) => ({ n: data.length, nInserted: data.length, ok: 1 })
|
|
300
300
|
plan.del = (data) => data.map(() => okDel)
|
|
301
301
|
plan.save = (data) => data.map(() => okSave)
|
|
302
302
|
let r1 = await proc('insert', [{ id: 7 }, { id: 'a < b' }])
|
|
303
|
-
assert.strict.deepEqual(r1, [{ id: 7 }, { id: 'a < b' }])
|
|
303
|
+
assert.strict.deepEqual(r1, [{ id: '7' }, { id: 'a < b' }])
|
|
304
304
|
let r2 = await proc('mix', { add: [{ id: 8 }, { id: '1 > 0' }], del: [{ id: 'a<b' }], diff: [{ id: 9 }, { id: 'x <= 5' }, { name: 'no-id' }] })
|
|
305
|
-
assert.strict.deepEqual(r2.slice(0, 5), [{ id: 8 }, { id: '1 > 0' }, { id: 'a<b' }, { id: 9 }, { id: 'x <= 5' }])
|
|
305
|
+
assert.strict.deepEqual(r2.slice(0, 5), [{ id: '8' }, { id: '1 > 0' }, { id: 'a<b' }, { id: '9' }, { id: 'x <= 5' }])
|
|
306
306
|
assert.ok(typeof r2[5].id === 'string' && r2[5].id.length > 0)
|
|
307
307
|
assert.strict.deepEqual(calls.map((v) => v.fn), ['insert', 'insert', 'del', 'save'])
|
|
308
308
|
assert.strict.deepEqual(calls[2].data, [{ id: 'a<b' }])
|