w-serv-orm 1.1.10 → 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 +9 -5
- package/docs/index.html +1 -1
- package/package.json +3 -3
- package/src/WServOrm.mjs +8 -4
- package/src/getMapOrm.mjs +233 -14
- package/test/api-pkcast.test.mjs +113 -0
- package/test/api-procOrm.test.mjs +7 -6
- package/test/unit-WServOrm.test.mjs +2 -2
- package/test/unit-mapOrm.test.mjs +7 -7
- package/test/unit-pkcast.test.mjs +325 -0
|
@@ -395,14 +395,14 @@ describe('procOrm補主鍵', function() {
|
|
|
395
395
|
})
|
|
396
396
|
|
|
397
397
|
it('P02 依主鍵值決定是否補值', async function() {
|
|
398
|
-
//
|
|
398
|
+
//R-ID-01 規則1: null、空字串、物件補值, 非空字串保留; R-ID-02 規則2: 字串型(或型別未知)主鍵欄之有限數字轉為其字串形式
|
|
399
399
|
let log = []
|
|
400
400
|
let A = WServOrm(dsAll, mkWOrm('A', log), 'url-a', 'db-a')
|
|
401
401
|
let input = [{ id: null }, { id: '' }, { id: { x: 1 } }, { id: 123 }, { id: 'keep' }]
|
|
402
402
|
let r = await A.procOrm('u1', 'tests', 'save', input)
|
|
403
403
|
let got = log[0].data.map((v) => v.id)
|
|
404
404
|
assert.ok(isId(got[0]) && isId(got[1]) && isId(got[2]))
|
|
405
|
-
assert.strict.equal(got[3], 123)
|
|
405
|
+
assert.strict.equal(got[3], '123')
|
|
406
406
|
assert.strict.equal(got[4], 'keep')
|
|
407
407
|
assert.strict.deepEqual(r.map((v) => v.id), got)
|
|
408
408
|
})
|
|
@@ -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
|
})
|
|
@@ -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' }])
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import WServOrm from '../src/WServOrm.mjs'
|
|
3
|
+
import getMapOrm from '../src/getMapOrm.mjs'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
//替身ORM: 記錄收到之數據, 回傳形狀依w-orm系列規格(save、del回逐筆陣列, insert與delAll回聚合物件); plan可覆寫各函數之回傳
|
|
7
|
+
let calls = []
|
|
8
|
+
let plan = {}
|
|
9
|
+
function WOrmStub() {
|
|
10
|
+
let ev = {}
|
|
11
|
+
for (let fn of ['select', 'insert', 'save', 'del', 'delAll']) {
|
|
12
|
+
ev[fn] = async (data) => {
|
|
13
|
+
calls.push({ fn, data })
|
|
14
|
+
if (plan[fn]) {
|
|
15
|
+
return plan[fn](data)
|
|
16
|
+
}
|
|
17
|
+
if (fn === 'select') {
|
|
18
|
+
return []
|
|
19
|
+
}
|
|
20
|
+
if (fn === 'save') {
|
|
21
|
+
return (Array.isArray(data) ? data : [data]).map(() => ({ n: 1, nInserted: 0, nModified: 1, ok: 1 }))
|
|
22
|
+
}
|
|
23
|
+
if (fn === 'del') {
|
|
24
|
+
return (Array.isArray(data) ? data : [data]).map(() => ({ n: 1, nDeleted: 1, ok: 1 }))
|
|
25
|
+
}
|
|
26
|
+
if (fn === 'delAll') {
|
|
27
|
+
return { n: 0, nDeleted: 0, ok: 1 }
|
|
28
|
+
}
|
|
29
|
+
return { n: 1, nInserted: 1, ok: 1 }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return ev
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let dsStr = { tests: { keys: ['id', 'name'], settings: { id: { pk: true, type: 'STRING' }, name: { type: 'STRING' } } } }
|
|
36
|
+
let dsUnknown = { tests: { keys: ['id', 'name'] } }
|
|
37
|
+
let dsInt = { tests: { keys: ['id', 'name'], settings: { id: { pk: true, type: 'INTEGER' }, name: { type: 'STRING' } } } }
|
|
38
|
+
let dsAudit = { tests: { keys: ['id', 'name', 'userId', 'timeCreate', 'userIdUpdate', 'timeUpdate'] } }
|
|
39
|
+
let isGen = (v) => typeof v === 'string' && v.length > 30
|
|
40
|
+
let idOf = (d) => (Array.isArray(d) ? d[0].id : d.id)
|
|
41
|
+
let wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
42
|
+
|
|
43
|
+
async function getReject(pm) {
|
|
44
|
+
try {
|
|
45
|
+
await pm
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return err
|
|
49
|
+
}
|
|
50
|
+
throw new Error('預期reject但resolve')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function quiet(fn) {
|
|
54
|
+
let logOrig = console.log
|
|
55
|
+
console.log = () => {}
|
|
56
|
+
try {
|
|
57
|
+
return await fn()
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
console.log = logOrig
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
describe('R-ID-02 字串型主鍵欄之數字主鍵以字串處置', function() {
|
|
66
|
+
|
|
67
|
+
beforeEach(function() {
|
|
68
|
+
calls = []
|
|
69
|
+
plan = {}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('N01 寫入六入口之有限數字主鍵轉為字串並回報之, 呼叫端物件不變', async function() {
|
|
73
|
+
//R-ID-02 規則1(字串型或型別未知)、規則2(寫入)、規則4(複本)
|
|
74
|
+
for (let ds of [dsStr, dsUnknown]) {
|
|
75
|
+
let so = WServOrm(ds, WOrmStub, 'u', 'd')
|
|
76
|
+
for (let n of [123, 0, -5, 1.5]) {
|
|
77
|
+
calls = []
|
|
78
|
+
let a = { id: n, name: 'a' }
|
|
79
|
+
let rs = [
|
|
80
|
+
await so.procOrm('u1', 'tests', 'insert', [a]),
|
|
81
|
+
await so.procOrm('u1', 'tests', 'insert', a),
|
|
82
|
+
await so.procOrm('u1', 'tests', 'save', [a]),
|
|
83
|
+
await so.procOrm('u1', 'tests', 'save', a),
|
|
84
|
+
await so.procOrm('u1', 'tests', 'mix', { add: [a] }),
|
|
85
|
+
await so.procOrm('u1', 'tests', 'mix', { diff: [a] }),
|
|
86
|
+
]
|
|
87
|
+
let s = String(n)
|
|
88
|
+
assert.deepStrictEqual(calls.map((c) => idOf(c.data)), [s, s, s, s, s, s], JSON.stringify(ds))
|
|
89
|
+
assert.deepStrictEqual(rs.map((r) => idOf(r)), [s, s, s, s, s, s])
|
|
90
|
+
assert.strictEqual(a.id, n)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('N02 刪除三入口之數字主鍵轉為字串, 逐筆失敗之訊息照列', async function() {
|
|
96
|
+
//R-ID-02 規則2(刪除; mix回報之del列為轉型後之值); R-MSG-01 規則3
|
|
97
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
98
|
+
await so.procOrm('u1', 'tests', 'del', [{ id: 123 }, { id: 'x' }])
|
|
99
|
+
await so.procOrm('u1', 'tests', 'del', { id: 7 })
|
|
100
|
+
let r = await so.procOrm('u1', 'tests', 'mix', { del: [{ id: 8 }] })
|
|
101
|
+
assert.deepStrictEqual(calls.map((c) => c.data), [[{ id: '123' }, { id: 'x' }], { id: '7' }, [{ id: '8' }]])
|
|
102
|
+
assert.deepStrictEqual(r, [{ id: '8' }])
|
|
103
|
+
plan.del = (data) => data.map((v, k) => (k === 0 ? { n: 1, nDeleted: 0, ok: 0, err: 'E-del' } : { n: 1, nDeleted: 1, ok: 1 }))
|
|
104
|
+
let err = await quiet(() => getReject(so.procOrm('u1', 'tests', 'del', [{ id: 123 }, { id: 'y' }])))
|
|
105
|
+
assert.strictEqual(err, 'failed to delete data: id[123]')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('N03 查詢條件之比較運算子(含$not與巢狀)轉型, 他欄與其餘運算子不變, 呼叫端條件不變', async function() {
|
|
109
|
+
//R-ID-02 規則2(查詢條件)、規則4
|
|
110
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
111
|
+
let finds = [
|
|
112
|
+
{ id: 123 },
|
|
113
|
+
{ id: { $eq: 1, $ne: 2, $gt: 3, $gte: 4, $lt: 5, $lte: 6 } },
|
|
114
|
+
{ id: { $in: [7, 'a'], $nin: [8], $all: [9] } },
|
|
115
|
+
{ id: { $not: { $eq: 10 } } },
|
|
116
|
+
{ id: { $not: { $in: [11, 12] } } },
|
|
117
|
+
{ $or: [{ id: 13 }, { name: 'x' }], $and: [{ id: { $in: [14] } }], $nor: [{ id: 15 }] },
|
|
118
|
+
{ $and: [{ $or: [{ id: 16 }] }] },
|
|
119
|
+
{ name: 17, id: { $regex: '^a', $exists: true } },
|
|
120
|
+
]
|
|
121
|
+
let findsCopy = JSON.parse(JSON.stringify(finds))
|
|
122
|
+
for (let f of finds) {
|
|
123
|
+
await so.procOrm('u1', 'tests', 'select', f)
|
|
124
|
+
}
|
|
125
|
+
await so.procOrm('u1', 'tests', 'delAll', { id: 18 })
|
|
126
|
+
await so.procOrm('u1', 'tests', 'delAll', { id: { $in: [19] } })
|
|
127
|
+
assert.deepStrictEqual(calls.map((c) => c.data), [
|
|
128
|
+
{ id: '123' },
|
|
129
|
+
{ id: { $eq: '1', $ne: '2', $gt: '3', $gte: '4', $lt: '5', $lte: '6' } },
|
|
130
|
+
{ id: { $in: ['7', 'a'], $nin: ['8'], $all: ['9'] } },
|
|
131
|
+
{ id: { $not: { $eq: '10' } } },
|
|
132
|
+
{ id: { $not: { $in: ['11', '12'] } } },
|
|
133
|
+
{ $or: [{ id: '13' }, { name: 'x' }], $and: [{ id: { $in: ['14'] } }], $nor: [{ id: '15' }] },
|
|
134
|
+
{ $and: [{ $or: [{ id: '16' }] }] },
|
|
135
|
+
{ name: 17, id: { $regex: '^a', $exists: true } },
|
|
136
|
+
{ id: '18' },
|
|
137
|
+
{ id: { $in: ['19'] } },
|
|
138
|
+
])
|
|
139
|
+
assert.deepStrictEqual(finds, findsCopy)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('N04 主鍵欄為整數型者各入口皆不轉型亦不補值', async function() {
|
|
143
|
+
//R-ID-02 規則1; R-ID-01 規則1(整數型不補值)
|
|
144
|
+
let so = WServOrm(dsInt, WOrmStub, 'u', 'd')
|
|
145
|
+
let r = await so.procOrm('u1', 'tests', 'insert', [{ id: 123 }, { name: 'a' }])
|
|
146
|
+
await so.procOrm('u1', 'tests', 'del', [{ id: 5 }])
|
|
147
|
+
await so.procOrm('u1', 'tests', 'select', { id: 5 })
|
|
148
|
+
await so.procOrm('u1', 'tests', 'delAll', { id: { $in: [6] } })
|
|
149
|
+
await so.procOrm('u1', 'tests', 'mix', { diff: [{ id: 7, name: 'b' }] })
|
|
150
|
+
assert.deepStrictEqual(calls[0].data.map((v) => v.id), [123, undefined])
|
|
151
|
+
assert.deepStrictEqual(r.map((v) => v.id), [123, undefined])
|
|
152
|
+
assert.deepStrictEqual(calls.slice(1).map((c) => c.data), [[{ id: 5 }], { id: 5 }, { id: { $in: [6] } }, [{ id: 7, name: 'b' }]])
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('N05 NaN與正負Infinity視為未提供: 寫入補值且回報一致, 刪除與查詢原樣', async function() {
|
|
156
|
+
//R-ID-02 規則3; R-ID-01 規則1
|
|
157
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
158
|
+
let r = await so.procOrm('u1', 'tests', 'insert', [{ id: NaN }, { id: Infinity }, { id: -Infinity }])
|
|
159
|
+
let got = calls[0].data.map((v) => v.id)
|
|
160
|
+
assert.ok(got.every(isGen), JSON.stringify(got))
|
|
161
|
+
assert.deepStrictEqual(r.map((v) => v.id), got)
|
|
162
|
+
await so.procOrm('u1', 'tests', 'del', [{ id: Infinity }])
|
|
163
|
+
await so.procOrm('u1', 'tests', 'select', { id: NaN })
|
|
164
|
+
assert.deepStrictEqual(calls[1].data, [{ id: Infinity }])
|
|
165
|
+
assert.deepStrictEqual(calls[2].data, { id: NaN })
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('N06 同批之數字與其字串形式為同一字串主鍵', async function() {
|
|
169
|
+
//R-ID-02 規則2: 後端依同批重複處置, 本套件回報兩筆同鍵(insert回傳之id含被略過者)
|
|
170
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
171
|
+
let r = await so.procOrm('u1', 'tests', 'insert', [{ id: 1 }, { id: '1' }])
|
|
172
|
+
assert.deepStrictEqual(calls[0].data.map((v) => v.id), ['1', '1'])
|
|
173
|
+
assert.deepStrictEqual(r, [{ id: '1' }, { id: '1' }])
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('N07 ds無該表者select與del不拋錯且原樣交ORM', async function() {
|
|
177
|
+
//R-ID-02 規則1: 直接呼叫getMapOrm而ds與woItems不一致者不轉型
|
|
178
|
+
let procOrm = getMapOrm({ others: dsStr.tests }, { tests: WOrmStub() })
|
|
179
|
+
await procOrm('u1', 'tests', 'select', { id: 123 })
|
|
180
|
+
await procOrm('u1', 'tests', 'del', [{ id: 123 }])
|
|
181
|
+
await procOrm('u1', 'tests', 'delAll', { id: 123 })
|
|
182
|
+
assert.deepStrictEqual(calls.map((c) => c.data), [{ id: 123 }, [{ id: 123 }], { id: 123 }])
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('N08 型別字串去參數後比對: STRING(36)視為字串型而補值與轉型', async function() {
|
|
186
|
+
//R-ID-01 規則1(取「(」之前之字並轉大寫); R-ID-02 規則1
|
|
187
|
+
let cases = [
|
|
188
|
+
['STRING(36)', true],
|
|
189
|
+
['string(36)', true],
|
|
190
|
+
['TEXT', true],
|
|
191
|
+
['INTEGER', false],
|
|
192
|
+
['INTEGER(11)', false],
|
|
193
|
+
]
|
|
194
|
+
for (let [type, expect] of cases) {
|
|
195
|
+
calls = []
|
|
196
|
+
let ds = { tests: { keys: ['id', 'name'], settings: { id: { pk: true, type }, name: { type: 'STRING' } } } }
|
|
197
|
+
let so = WServOrm(ds, WOrmStub, 'u', 'd')
|
|
198
|
+
await so.procOrm('u1', 'tests', 'insert', [{ name: 'a' }, { id: 5 }])
|
|
199
|
+
let got = calls[0].data.map((v) => v.id)
|
|
200
|
+
assert.strictEqual(isGen(got[0]), expect, type)
|
|
201
|
+
assert.strictEqual(got[1], expect ? '5' : 5, type)
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('N09 後處理之input為前處理後之input(主鍵不轉型), output為轉型後之回報', async function() {
|
|
206
|
+
//R-ID-02 規則5; R-HOOK-01 規則5
|
|
207
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
208
|
+
let seen = []
|
|
209
|
+
so.addFunPreProcessing(({ input }) => ({ input: [...input, { id: 2, name: 'pre' }] }))
|
|
210
|
+
so.addFunPostProcessing(({ input, output }) => {
|
|
211
|
+
seen.push({ input, output })
|
|
212
|
+
return output
|
|
213
|
+
})
|
|
214
|
+
await wait(20)
|
|
215
|
+
let r = await so.procOrm('u1', 'tests', 'insert', [{ id: 1, name: 'a' }])
|
|
216
|
+
assert.deepStrictEqual(seen[0].input, [{ id: 1, name: 'a' }, { id: 2, name: 'pre' }])
|
|
217
|
+
assert.deepStrictEqual(seen[0].output, [{ id: '1' }, { id: '2' }])
|
|
218
|
+
assert.deepStrictEqual(r, [{ id: '1' }, { id: '2' }])
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
describe('R-MIX-01 mix之跨段同鍵整批拒絕', function() {
|
|
225
|
+
|
|
226
|
+
beforeEach(function() {
|
|
227
|
+
calls = []
|
|
228
|
+
plan = {}
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('M01 add與del、del與diff正規化後同鍵者整批reject且ORM未被呼叫, add與diff同鍵照常', async function() {
|
|
232
|
+
//R-MIX-01 規則1-4
|
|
233
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
234
|
+
let mix = (input) => quiet(() => getReject(so.procOrm('u1', 'tests', 'mix', input)))
|
|
235
|
+
assert.strictEqual(await mix({ add: [{ id: 123 }], del: [{ id: '123' }] }), 'invalid input of mix, same id in add and del: add[0], del[0]')
|
|
236
|
+
assert.strictEqual(await mix({ add: [{ id: 'a' }, { id: 'x' }], del: [{ id: 'b' }, { id: 'a' }] }), 'invalid input of mix, same id in add and del: add[0], del[1]')
|
|
237
|
+
assert.strictEqual(await mix({ del: [{ id: 'b' }], diff: [{ id: 'c' }, { id: 'b' }] }), 'invalid input of mix, same id in del and diff: del[0], diff[1]')
|
|
238
|
+
assert.strictEqual(await mix({ add: [{ id: 'a' }], del: [{ id: 'a' }, { id: 'b' }], diff: [{ id: 'b' }] }), 'invalid input of mix, same id in add and del: add[0], del[0]; invalid input of mix, same id in del and diff: del[1], diff[0]')
|
|
239
|
+
assert.deepStrictEqual(calls, [])
|
|
240
|
+
|
|
241
|
+
//未提供主鍵者不參與比對; add與diff同鍵照常(insert略過、save更新, 不遺失)
|
|
242
|
+
await so.procOrm('u1', 'tests', 'mix', { add: [{ name: 'x' }], del: [{ name: 'y' }], diff: [{ name: 'z' }] })
|
|
243
|
+
await so.procOrm('u1', 'tests', 'mix', { add: [{ id: 'c' }], diff: [{ id: 'c' }] })
|
|
244
|
+
assert.deepStrictEqual(calls.map((v) => v.fn), ['insert', 'del', 'save', 'insert', 'save'])
|
|
245
|
+
|
|
246
|
+
//整數主鍵欄之5與'5'亦視為同鍵
|
|
247
|
+
calls = []
|
|
248
|
+
let si = WServOrm(dsInt, WOrmStub, 'u', 'd')
|
|
249
|
+
let err = await quiet(() => getReject(si.procOrm('u1', 'tests', 'mix', { add: [{ id: 5 }], del: [{ id: '5' }] })))
|
|
250
|
+
assert.strictEqual(err, 'invalid input of mix, same id in add and del: add[0], del[0]')
|
|
251
|
+
assert.deepStrictEqual(calls, [])
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
describe('R-INPUT-01 寫入與delAll之輸入形狀', function() {
|
|
258
|
+
|
|
259
|
+
beforeEach(function() {
|
|
260
|
+
calls = []
|
|
261
|
+
plan = {}
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('E01 insert、save、mix之新增與修改之元素非一般物件即整批reject且ORM未被呼叫', async function() {
|
|
265
|
+
//R-INPUT-01 規則1、2; 有稽核欄位者原為failed to adjust data, 無者原寫入垃圾紀錄
|
|
266
|
+
for (let ds of [dsUnknown, dsAudit]) {
|
|
267
|
+
let so = WServOrm(ds, WOrmStub, 'u', 'd')
|
|
268
|
+
let rj = (mode, input) => quiet(() => getReject(so.procOrm('u1', 'tests', mode, input)))
|
|
269
|
+
for (let bad of ['abc', ['a', 'b'], 5, null, true, new Date('2026-01-01T00:00:00Z')]) {
|
|
270
|
+
assert.strictEqual(await rj('insert', [bad]), 'failed to insert data, not an object: data[0]', String(bad))
|
|
271
|
+
assert.strictEqual(await rj('save', [{ id: 'a' }, bad]), 'failed to save data, not an object: data[1]', String(bad))
|
|
272
|
+
assert.strictEqual(await rj('mix', { add: [bad] }), 'failed to insert data, not an object: data[0]', String(bad))
|
|
273
|
+
assert.strictEqual(await rj('mix', { diff: [{ id: 'b' }, bad] }), 'failed to update data, not an object: data[1]', String(bad))
|
|
274
|
+
}
|
|
275
|
+
assert.strictEqual(await rj('insert', 'abc'), 'failed to insert data, not an object: data[0]')
|
|
276
|
+
assert.strictEqual(await rj('save', 5), 'failed to save data, not an object: data[0]')
|
|
277
|
+
assert.strictEqual(await rj('insert', null), 'failed to insert data, not an object: data[0]')
|
|
278
|
+
assert.strictEqual(await rj('insert', undefined), 'failed to insert data, not an object: data[0]')
|
|
279
|
+
assert.strictEqual(await rj('insert', [{ id: 'a' }, 'x', 5]), 'failed to insert data, not an object: data[1], data[2]')
|
|
280
|
+
assert.strictEqual(await rj('mix', { add: ['x'], diff: [5] }), 'failed to insert data, not an object: data[0]; failed to update data, not an object: data[0]')
|
|
281
|
+
assert.deepStrictEqual(calls, [])
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('E02 mix之add、del、diff給予而非陣列即reject且ORM未被呼叫', async function() {
|
|
286
|
+
//R-INPUT-01 規則2
|
|
287
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
288
|
+
let msg = 'invalid input of mix, need the result object of ltdtDiffByKey'
|
|
289
|
+
for (let input of [{ add: { id: 'a' } }, { del: { id: 'a' } }, { diff: { id: 'a' } }, { add: null }, { del: 'a' }, { add: [], diff: 5 }]) {
|
|
290
|
+
assert.strictEqual(await quiet(() => getReject(so.procOrm('u1', 'tests', 'mix', input))), msg, JSON.stringify(input))
|
|
291
|
+
}
|
|
292
|
+
assert.deepStrictEqual(calls, [])
|
|
293
|
+
let r = await so.procOrm('u1', 'tests', 'mix', { add: [], del: [], diff: [] })
|
|
294
|
+
assert.deepStrictEqual(r, [])
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('E03 delAll之find非物件即reject且ORM未被呼叫, undefined與物件照常', async function() {
|
|
298
|
+
//R-INPUT-01 規則3
|
|
299
|
+
let so = WServOrm(dsStr, WOrmStub, 'u', 'd')
|
|
300
|
+
for (let find of [[], ['a'], 'a', null, 5, true]) {
|
|
301
|
+
assert.strictEqual(await quiet(() => getReject(so.procOrm('u1', 'tests', 'delAll', find))), 'invalid find of delAll, need an object', JSON.stringify(find))
|
|
302
|
+
}
|
|
303
|
+
assert.deepStrictEqual(calls, [])
|
|
304
|
+
await so.procOrm('u1', 'tests', 'delAll', undefined)
|
|
305
|
+
await so.procOrm('u1', 'tests', 'delAll', {})
|
|
306
|
+
await so.procOrm('u1', 'tests', 'delAll', { name: 'x' })
|
|
307
|
+
assert.deepStrictEqual(calls.map((c) => c.data), [undefined, {}, { name: 'x' }])
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('E04 多筆批次之空物件列補值且回報與ORM收到者一致, 單筆空物件維持原樣', async function() {
|
|
311
|
+
//R-ID-01 規則3(裁示D5)
|
|
312
|
+
let so = WServOrm(dsUnknown, WOrmStub, 'u', 'd')
|
|
313
|
+
let r1 = await so.procOrm('u1', 'tests', 'insert', [{}, { name: 'x' }])
|
|
314
|
+
let r2 = await so.procOrm('u1', 'tests', 'save', [{}, {}])
|
|
315
|
+
let r3 = await so.procOrm('u1', 'tests', 'insert', [{}])
|
|
316
|
+
let r4 = await so.procOrm('u1', 'tests', 'insert', {})
|
|
317
|
+
assert.ok(calls[0].data.every((v) => isGen(v.id)) && calls[1].data.every((v) => isGen(v.id)))
|
|
318
|
+
assert.deepStrictEqual(r1.map((v) => v.id), calls[0].data.map((v) => v.id))
|
|
319
|
+
assert.deepStrictEqual(r2.map((v) => v.id), calls[1].data.map((v) => v.id))
|
|
320
|
+
assert.deepStrictEqual(calls[2].data, [{}])
|
|
321
|
+
assert.deepStrictEqual(calls[3].data, {})
|
|
322
|
+
assert.deepStrictEqual([r3, r4], [[{ id: undefined }], { id: undefined }])
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
})
|