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/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
- return Promise.reject(`invalid mapOrm`)
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', { useCheckUser: false, useExcludeWhenNotAdmin: false })
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並列出失敗主鍵; R10: 單筆失敗不中斷整批, 有效筆已刪除
48
- let err = await getReject(proc('del', [{ id: 'a1' }, { id: 123 }]))
49
- assert.strict.equal(err, 'failed to delete data: id[123]')
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: 456 }], diff: [{ id: 'a2', isActive: 'y' }] }))
57
- assert.strict.equal(err, 'failed to delete data: id[456]')
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 getItemsFailWdc from 'w-data-collector/src/getItemsFail.mjs'
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', optOff)
67
- let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b', optOff)
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', optOff)
81
- let B = WServOrm(dsNoTime, mkWOrm('B', log), 'url-b', 'db-b', optOff)
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', optOff)
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', optOff)
134
- let B = WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
237
- WServOrm(dsAll, mkWOrm('B', log), 'url-b', 'db-b', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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
- //D1: null、空字串、物件補值; 數字與非空字串保留(reladb、mdb視數字為有效主鍵)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', optOff)
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', { useCheckUser: false, useExcludeWhenNotAdmin: false })
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: 0, nDeleted: 0, ok: 0, err: 'can not delete by invalid id[123]' }]
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', { useCheckUser: false, useExcludeWhenNotAdmin: false })
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
- //數字與不被改寫之主鍵照寫, mix之修改未帶主鍵者補值, mix之刪除不經clearXSS而原樣交ORM
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' }])