w-serv-orm 1.1.8 → 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 +1 -6
- package/dist/w-serv-orm.umd.js +2 -2
- package/dist/w-serv-orm.umd.js.map +1 -1
- package/docs/WServOrm.html +10 -158
- package/docs/WServOrm.mjs.html +35 -17
- package/docs/index.html +1 -1
- package/g-mOrm.mjs +1 -6
- package/package.json +1 -1
- package/src/WServOrm.mjs +33 -15
- package/src/getProc.mjs +104 -189
- package/test/unit-WServOrm.test.mjs +62 -49
- package/test/unit-mapOrm.test.mjs +1 -1
package/src/getProc.mjs
CHANGED
|
@@ -1,189 +1,104 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return Promise.reject(`invalid return of pre-processing, need an object with input`)
|
|
106
|
-
}
|
|
107
|
-
input = paramsOut.input
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
//output
|
|
111
|
-
let output = await st.mapOrm(userId, woName, mode, input)
|
|
112
|
-
|
|
113
|
-
//useExcludeWhenNotAdmin, 非管理者則要過濾掉已刪除之數據
|
|
114
|
-
if (st.useExcludeWhenNotAdmin && isAdmin === 'n') {
|
|
115
|
-
if (mode === 'select' && isarr(output)) { //有可能為錯誤物件
|
|
116
|
-
output = filter(output, (v) => {
|
|
117
|
-
if (haskey(v, 'isActive')) { //針對有isActive屬性
|
|
118
|
-
return !(v.isActive === 'n') //過濾isActive='n'
|
|
119
|
-
}
|
|
120
|
-
return true
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
//funPostProcessing, 擴充後處理output, 提供給各 mOrm[OOO].mjs 後處理
|
|
126
|
-
//逐一呼叫, 各後處理皆收新建之參數物件, output為前一個之回傳值, 回傳值成為新output; 迭代前先取快照
|
|
127
|
-
for (let f of [...st.funPostProcessing]) {
|
|
128
|
-
output = await f({ woName, userId, isAdmin, mode, input, output })
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return output
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
function getProc(mapOrm, opt = {}) {
|
|
136
|
-
|
|
137
|
-
//check
|
|
138
|
-
if (!isfun(mapOrm)) {
|
|
139
|
-
return Promise.reject(`invalid mapOrm`)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
//useCheckUser
|
|
143
|
-
let useCheckUser = get(opt, 'useCheckUser')
|
|
144
|
-
if (!isbol(useCheckUser)) {
|
|
145
|
-
useCheckUser = true
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
//getUserById, 不事先檢查, 因若useCheckUser=false可允許不給
|
|
149
|
-
let getUserById = get(opt, 'getUserById')
|
|
150
|
-
|
|
151
|
-
//useExcludeWhenNotAdmin
|
|
152
|
-
let useExcludeWhenNotAdmin = get(opt, 'useExcludeWhenNotAdmin')
|
|
153
|
-
if (!isbol(useExcludeWhenNotAdmin)) {
|
|
154
|
-
useExcludeWhenNotAdmin = true
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
//st, 各實例之狀態, 每次呼叫各自建立, 令同一行程內之多個實例互不干擾
|
|
158
|
-
let st = {
|
|
159
|
-
funChecks: [],
|
|
160
|
-
funPreProcessing: [],
|
|
161
|
-
funPostProcessing: [],
|
|
162
|
-
mapOrm,
|
|
163
|
-
getUserById,
|
|
164
|
-
useCheckUser,
|
|
165
|
-
useExcludeWhenNotAdmin,
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
//回傳函數綁定st而不依賴this, 使用端可解構取用並當裸函數傳遞
|
|
169
|
-
return {
|
|
170
|
-
addFunCheck: (f) => {
|
|
171
|
-
//由外部添加擴充檢查函數
|
|
172
|
-
addFun(st.funChecks, f, 'addFunCheck', true)
|
|
173
|
-
},
|
|
174
|
-
addFunPreProcessing: (f) => {
|
|
175
|
-
//由外部添加擴充前處理函數
|
|
176
|
-
addFun(st.funPreProcessing, f, 'addFunPreProcessing')
|
|
177
|
-
},
|
|
178
|
-
addFunPostProcessing: (f) => {
|
|
179
|
-
//由外部添加擴充後置處理函數
|
|
180
|
-
addFun(st.funPostProcessing, f, 'addFunPostProcessing')
|
|
181
|
-
},
|
|
182
|
-
procOrm: async (userId, woName, mode, input) => {
|
|
183
|
-
return procOrm(st, userId, woName, mode, input)
|
|
184
|
-
},
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
export default getProc
|
|
1
|
+
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
2
|
+
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
3
|
+
import isfun from 'wsemi/src/isfun.mjs'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function addFun(fs, f, name, useGuard = false) {
|
|
7
|
+
//由外部添加擴充函數至該實例之陣列
|
|
8
|
+
//延後1ms生效係沿用既有之生效時序: 原為避開模組層陣列於循環引用時之「Cannot access before initialization」,
|
|
9
|
+
//改為各實例狀態後該原因已不成立, 惟使用端之啟動流程可能依賴此時序, 故保留
|
|
10
|
+
|
|
11
|
+
//check, 非函數於註冊時即拋錯; useGuard(check用)另推入恆reject之守門函數, 令拋錯被呼叫端攔下時該實例仍維持fail-closed
|
|
12
|
+
//註冊時拋錯屬建構期錯誤故為Error; 守門函數於procOrm內reject, 與procOrm其餘拒絕一致為字串
|
|
13
|
+
if (!isfun(f)) {
|
|
14
|
+
let msg = `${name} needs a function, but got ${typeof f}`
|
|
15
|
+
if (useGuard) {
|
|
16
|
+
fs.push(() => {
|
|
17
|
+
return Promise.reject(msg)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
throw new Error(msg)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
fs.push(f)
|
|
25
|
+
}, 1)
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async function procOrm(st, userId, woName, mode, input) {
|
|
31
|
+
//封裝mapOrm, 依序執行擴充檢查、前處理、ORM操作與後處理, st為該實例之狀態
|
|
32
|
+
//不做授權: 不檢查使用者亦不依使用者過濾數據, userId只供寫入稽核欄位與交給擴充函數; 開放給前端時須由開放處負責授權
|
|
33
|
+
|
|
34
|
+
//check
|
|
35
|
+
if (!isfun(st.mapOrm)) {
|
|
36
|
+
return Promise.reject(`invalid mapOrm`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//funChecks, 擴充檢查, 提供給各 mOrm[OOO].mjs 檢查
|
|
40
|
+
await pmSeries(st.funChecks, (v) => {
|
|
41
|
+
return v({ woName, userId, mode, input })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
//funPreProcessing, 擴充前處理input, 提供給各 mOrm[OOO].mjs 前處理
|
|
45
|
+
//逐一呼叫, 各前處理皆收新建之參數物件, input為前一個回傳之input; 回傳須為含input之物件, 否則reject, 避免input成為undefined而令select回全表
|
|
46
|
+
//迭代前先取快照, 呼叫進行中註冊者不套用於本次呼叫
|
|
47
|
+
for (let f of [...st.funPreProcessing]) {
|
|
48
|
+
let paramsOut = await f({ woName, userId, mode, input })
|
|
49
|
+
if (!iseobj(paramsOut) || paramsOut.input === undefined) {
|
|
50
|
+
return Promise.reject(`invalid return of pre-processing, need an object with input`)
|
|
51
|
+
}
|
|
52
|
+
input = paramsOut.input
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//output
|
|
56
|
+
let output = await st.mapOrm(userId, woName, mode, input)
|
|
57
|
+
|
|
58
|
+
//funPostProcessing, 擴充後處理output, 提供給各 mOrm[OOO].mjs 後處理
|
|
59
|
+
//逐一呼叫, 各後處理皆收新建之參數物件, output為前一個之回傳值, 回傳值成為新output; 迭代前先取快照
|
|
60
|
+
for (let f of [...st.funPostProcessing]) {
|
|
61
|
+
output = await f({ woName, userId, mode, input, output })
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return output
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
function getProc(mapOrm) {
|
|
69
|
+
|
|
70
|
+
//check
|
|
71
|
+
if (!isfun(mapOrm)) {
|
|
72
|
+
return Promise.reject(`invalid mapOrm`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//st, 各實例之狀態, 每次呼叫各自建立, 令同一行程內之多個實例互不干擾
|
|
76
|
+
let st = {
|
|
77
|
+
funChecks: [],
|
|
78
|
+
funPreProcessing: [],
|
|
79
|
+
funPostProcessing: [],
|
|
80
|
+
mapOrm,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//回傳函數綁定st而不依賴this, 使用端可解構取用並當裸函數傳遞
|
|
84
|
+
return {
|
|
85
|
+
addFunCheck: (f) => {
|
|
86
|
+
//由外部添加擴充檢查函數
|
|
87
|
+
addFun(st.funChecks, f, 'addFunCheck', true)
|
|
88
|
+
},
|
|
89
|
+
addFunPreProcessing: (f) => {
|
|
90
|
+
//由外部添加擴充前處理函數
|
|
91
|
+
addFun(st.funPreProcessing, f, 'addFunPreProcessing')
|
|
92
|
+
},
|
|
93
|
+
addFunPostProcessing: (f) => {
|
|
94
|
+
//由外部添加擴充後置處理函數
|
|
95
|
+
addFun(st.funPostProcessing, f, 'addFunPostProcessing')
|
|
96
|
+
},
|
|
97
|
+
procOrm: async (userId, woName, mode, input) => {
|
|
98
|
+
return procOrm(st, userId, woName, mode, input)
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
export default getProc
|
|
@@ -86,37 +86,44 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
86
86
|
assert.ok(!('timeUpdate' in log[1].data[0]))
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
it('I03
|
|
90
|
-
//
|
|
89
|
+
it('I03 已移除之設定給予非預設值即建構拋錯且不建立ORM', async function() {
|
|
90
|
+
//R3: useCheckUser、getUserById、useExcludeWhenNotAdmin已移除; 給予未給、null、false以外之值即拋錯, 避免使用端以為仍有檢查而無聲失去
|
|
91
|
+
//拋錯於建立各資料表ORM之前, 否則已開啟之ORM(如lmdb之檔案)無從關閉; 亦不影響既有實例
|
|
91
92
|
let log = []
|
|
92
|
-
let callsGet = []
|
|
93
93
|
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a', optOff)
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
let created = 0
|
|
95
|
+
let WOrmCount = function() {
|
|
96
|
+
created++
|
|
97
|
+
return {}
|
|
98
|
+
}
|
|
99
|
+
let bads = [
|
|
100
|
+
['useCheckUser', true],
|
|
101
|
+
['useCheckUser', 'true'],
|
|
102
|
+
['useCheckUser', 1],
|
|
103
|
+
['getUserById', async () => ({ isActive: 'y' })],
|
|
104
|
+
['getUserById', 'x'],
|
|
105
|
+
['useExcludeWhenNotAdmin', true],
|
|
106
|
+
['useExcludeWhenNotAdmin', 'n'],
|
|
107
|
+
]
|
|
108
|
+
for (let [k, v] of bads) {
|
|
109
|
+
assert.throws(() => WServOrm(dsAll, WOrmCount, 'url-x', 'db-x', { [k]: v }), (e) => e instanceof Error && e.message.startsWith(`opt.${k} has been removed, `), `${k}: ${String(v)}`)
|
|
110
|
+
}
|
|
111
|
+
assert.strict.equal(created, 0)
|
|
112
|
+
let r = await A.procOrm('u1', 'tests', 'select', {})
|
|
113
|
+
assert.strict.deepEqual(r.map((v) => v.id), ['A-r1', 'A-r2'])
|
|
109
114
|
})
|
|
110
115
|
|
|
111
|
-
it('I04
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
let
|
|
115
|
-
let
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
it('I04 已移除之設定未給、null或false照常建構, 不檢查使用者亦不過濾', async function() {
|
|
117
|
+
//R3: 四個使用端現行之設定({useCheckUser:false, getUserById:null, useExcludeWhenNotAdmin:false})升版照常可用
|
|
118
|
+
//procOrm不做授權: userId不檢查(含空字串、null、undefined), select不依使用者濾除isActive為n者
|
|
119
|
+
let opts = [undefined, null, {}, { useCheckUser: null }, { useCheckUser: false, getUserById: null, useExcludeWhenNotAdmin: false }]
|
|
120
|
+
for (let opt of opts) {
|
|
121
|
+
let X = WServOrm(dsAll, mkWOrm('X', []), 'url-x', 'db-x', opt)
|
|
122
|
+
for (let userId of ['u1', '', null, undefined]) {
|
|
123
|
+
let r = await X.procOrm(userId, 'tests', 'select', {})
|
|
124
|
+
assert.strict.deepEqual(r.map((v) => v.id), ['X-r1', 'X-r2'], `opt ${JSON.stringify(opt)}, userId ${String(userId)}`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
120
127
|
})
|
|
121
128
|
|
|
122
129
|
it('I05 三種hook各自屬於所註冊之實例', async function() {
|
|
@@ -178,39 +185,45 @@ describe('WServOrm實例互不干擾', function() {
|
|
|
178
185
|
assert.strict.deepEqual(log, ['W1', 'W2'])
|
|
179
186
|
})
|
|
180
187
|
|
|
181
|
-
it('I08
|
|
182
|
-
//R3: useCheckUser
|
|
183
|
-
let
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
188
|
+
it('I08 擴充函數之參數不含isAdmin', async function() {
|
|
189
|
+
//R3: 隨useCheckUser移除, 參數物件只含woName、userId、mode、input, 後處理另含output
|
|
190
|
+
let A = WServOrm(dsAll, mkWOrm('A', []), 'url-a', 'db-a', optOff)
|
|
191
|
+
let ks = {}
|
|
192
|
+
A.addFunCheck((p) => {
|
|
193
|
+
ks.check = Object.keys(p)
|
|
194
|
+
})
|
|
195
|
+
A.addFunPreProcessing((p) => {
|
|
196
|
+
ks.pre = Object.keys(p)
|
|
197
|
+
return p
|
|
198
|
+
})
|
|
199
|
+
A.addFunPostProcessing((p) => {
|
|
200
|
+
ks.post = Object.keys(p)
|
|
201
|
+
return p.output
|
|
202
|
+
})
|
|
203
|
+
await wait(20)
|
|
204
|
+
await A.procOrm('u1', 'tests', 'select', {})
|
|
205
|
+
assert.strict.deepEqual(ks, {
|
|
206
|
+
check: ['woName', 'userId', 'mode', 'input'],
|
|
207
|
+
pre: ['woName', 'userId', 'mode', 'input'],
|
|
208
|
+
post: ['woName', 'userId', 'mode', 'input', 'output'],
|
|
209
|
+
})
|
|
194
210
|
})
|
|
195
211
|
|
|
196
212
|
it('I09 呼叫進行中建立另一實例不影響該次呼叫', async function() {
|
|
197
|
-
//R1a: A
|
|
213
|
+
//R1a: A之check等待中建立B, A之呼叫仍打A之ORM
|
|
198
214
|
let log = []
|
|
199
215
|
let release = null
|
|
200
216
|
let gate = new Promise((resolve) => {
|
|
201
217
|
release = resolve
|
|
202
218
|
})
|
|
203
|
-
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a',
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
getUserById: async () => {
|
|
207
|
-
await gate
|
|
208
|
-
return { isAdmin: 'n', isActive: 'y' }
|
|
209
|
-
},
|
|
219
|
+
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a', optOff)
|
|
220
|
+
A.addFunCheck(async () => {
|
|
221
|
+
await gate
|
|
210
222
|
})
|
|
223
|
+
await wait(20)
|
|
211
224
|
let pA = A.procOrm('u1', 'tests', 'select', {})
|
|
212
225
|
await wait(5)
|
|
213
|
-
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b',
|
|
226
|
+
WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b', optOff)
|
|
214
227
|
release()
|
|
215
228
|
let rA = await pA
|
|
216
229
|
assert.strict.deepEqual(log.map((v) => v.name), ['A'])
|
|
@@ -4,7 +4,7 @@ import genTestData from '../src/genTestData.mjs'
|
|
|
4
4
|
import dsSchema from '../schema/index.mjs'
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
//替身ORM, 回傳形狀依w-orm系列規格(
|
|
7
|
+
//替身ORM, 回傳形狀依w-orm系列規格(w-orm系列套件統一規格.md T2、T4):
|
|
8
8
|
//save與del回傳與輸入等長保序之逐筆陣列, 單筆失敗時整批仍resolve, 該筆以ok為0並附err回報; 整批性錯誤則reject
|
|
9
9
|
let plan = {}
|
|
10
10
|
let calls = []
|