w-orm-reladb 1.0.43 → 1.0.44
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/.github/workflows/ci-test.yml +3 -3
- package/.github/workflows/ci.yml +52 -0
- package/README.md +1 -0
- package/babel.config.js +4 -3
- package/dist/w-orm-reladb.umd.js +2 -2
- package/dist/w-orm-reladb.umd.js.map +1 -1
- package/docs/WOrmReladb.html +1 -1
- package/docs/WOrmReladb.mjs.html +1 -1
- package/docs/index.html +1 -1
- package/package.json +7 -7
- package/test/api-fixtures.mjs +48 -0
- package/test/api-mssql.test.mjs +212 -0
- package/test/api-sqlite.test.mjs +236 -0
- package/worm.sqlite +0 -0
- package/test/all.test.mjs +0 -10
package/docs/WOrmReladb.html
CHANGED
|
@@ -3763,7 +3763,7 @@
|
|
|
3763
3763
|
<br class="clear">
|
|
3764
3764
|
|
|
3765
3765
|
<footer>
|
|
3766
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.
|
|
3766
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Jul 23 2026 10:27:23 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
3767
3767
|
</footer>
|
|
3768
3768
|
|
|
3769
3769
|
<script>prettyPrint();</script>
|
package/docs/WOrmReladb.mjs.html
CHANGED
|
@@ -1132,7 +1132,7 @@ export default WOrmReladb
|
|
|
1132
1132
|
<br class="clear">
|
|
1133
1133
|
|
|
1134
1134
|
<footer>
|
|
1135
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.
|
|
1135
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Jul 23 2026 10:27:23 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1136
1136
|
</footer>
|
|
1137
1137
|
|
|
1138
1138
|
<script>prettyPrint();</script>
|
package/docs/index.html
CHANGED
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
<br class="clear">
|
|
72
72
|
|
|
73
73
|
<footer>
|
|
74
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Jul 23 2026 10:27:23 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
75
75
|
</footer>
|
|
76
76
|
|
|
77
77
|
<script>prettyPrint();</script>
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w-orm-reladb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.44",
|
|
4
4
|
"main": "dist/w-orm-reladb.umd.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"json5": "^2.2.3",
|
|
7
|
-
"lodash-es": "^4.
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"w-auto-sequelize": "^1.0.
|
|
11
|
-
"wsemi": "^1.
|
|
7
|
+
"lodash-es": "^4.18.1",
|
|
8
|
+
"sqlite3": "^6.0.1",
|
|
9
|
+
"tedious": "^19.2.2",
|
|
10
|
+
"w-auto-sequelize": "^1.0.28",
|
|
11
|
+
"wsemi": "^1.8.66"
|
|
12
12
|
},
|
|
13
13
|
"dependenciesTemp": {
|
|
14
14
|
"@journeyapps/sqlcipher": "^5.3.1",
|
|
15
15
|
"msg": "install sqlcipher fo the protection when db=sqlite"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"w-package-tools": "^1.
|
|
18
|
+
"w-package-tools": "^1.1.11"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"test": "mocha --parallel --timeout 60000",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//共用測試數據, 對應g-mssql.mjs與g-sqlite.mjs之rs與rsm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
//genRs, 初始插入數據, 第3筆id為空字串會自動產生主鍵
|
|
5
|
+
export let genRs = () => {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
id: 'id-peter',
|
|
9
|
+
name: 'peter',
|
|
10
|
+
value: 123,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'id-rosemary',
|
|
14
|
+
name: 'rosemary',
|
|
15
|
+
value: 123.456,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: '',
|
|
19
|
+
name: 'kettle',
|
|
20
|
+
value: 456,
|
|
21
|
+
},
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
//genRsm, 儲存(修改)數據, 第3筆id為空字串需視autoInsert決定是否插入
|
|
27
|
+
export let genRsm = () => {
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
id: 'id-peter',
|
|
31
|
+
name: 'peter(modify)',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'id-rosemary',
|
|
35
|
+
name: 'rosemary(modify)',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: '',
|
|
39
|
+
name: 'kettle(modify)',
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
//sortByName, select結果排序供穩定比對
|
|
46
|
+
export let sortByName = (rows) => {
|
|
47
|
+
return [...rows].sort((a, b) => (a.name < b.name ? -1 : 1))
|
|
48
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import wo from '../src/WOrmReladb.mjs'
|
|
3
|
+
import { genRs, genRsm, sortByName } from './api-fixtures.mjs'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
//測試前需先啟動本機MSSQL服務(如docker容器: docker start mssql-worm), 並具有資料庫worm與帳號username/password(db_owner)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
let genOpt = () => {
|
|
10
|
+
return {
|
|
11
|
+
url: 'mssql://username:password@localhost:1433',
|
|
12
|
+
db: 'worm',
|
|
13
|
+
cl: 'users',
|
|
14
|
+
fdModels: './models',
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
describe('mssql crud', function() {
|
|
20
|
+
|
|
21
|
+
let w = wo(genOpt())
|
|
22
|
+
|
|
23
|
+
before(async function() {
|
|
24
|
+
await w.createStorage()
|
|
25
|
+
await w.delAll().catch(() => {})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('insert 3筆, 空id自動產生主鍵', async function() {
|
|
29
|
+
let msg = await w.insert(genRs())
|
|
30
|
+
assert.deepStrictEqual(msg, { n: 3, nInserted: 3, ok: 1 })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('save({autoInsert:true}) 修改2筆並插入1筆', async function() {
|
|
34
|
+
let msg = await w.save(genRsm(), { autoInsert: true })
|
|
35
|
+
assert.deepStrictEqual(msg, [
|
|
36
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
37
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
38
|
+
{ n: 1, nInserted: 1, ok: 1 },
|
|
39
|
+
])
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('select() 查全部得4筆', async function() {
|
|
43
|
+
let ss = sortByName(await w.select())
|
|
44
|
+
assert.strictEqual(ss.length, 4)
|
|
45
|
+
let [kettle, kettleM, peter, rosemary] = ss
|
|
46
|
+
assert.ok(typeof kettle.id === 'string' && kettle.id.length > 0)
|
|
47
|
+
assert.strictEqual(kettle.name, 'kettle')
|
|
48
|
+
assert.strictEqual(kettle.value, 456)
|
|
49
|
+
assert.ok(typeof kettleM.id === 'string' && kettleM.id.length > 0)
|
|
50
|
+
assert.strictEqual(kettleM.name, 'kettle(modify)')
|
|
51
|
+
assert.strictEqual(kettleM.value, null)
|
|
52
|
+
assert.deepStrictEqual(peter, { id: 'id-peter', name: 'peter(modify)', value: 123 })
|
|
53
|
+
assert.deepStrictEqual(rosemary, { id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 })
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('select({id}) 依主鍵查詢', async function() {
|
|
57
|
+
let so = await w.select({ id: 'id-rosemary' })
|
|
58
|
+
assert.deepStrictEqual(so, [{ id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 }])
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('select $and+$gt+$lt', async function() {
|
|
62
|
+
let sp = await w.select({ '$and': [{ value: { '$gt': 123 } }, { value: { '$lt': 200 } }] })
|
|
63
|
+
assert.deepStrictEqual(sp, [{ id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 }])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('select $or+$gte+$lte', async function() {
|
|
67
|
+
let sp = await w.select({ '$or': [{ value: { '$lte': -1 } }, { value: { '$gte': 200 } }] })
|
|
68
|
+
assert.strictEqual(sp.length, 1)
|
|
69
|
+
assert.strictEqual(sp[0].name, 'kettle')
|
|
70
|
+
assert.strictEqual(sp[0].value, 456)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('select 巢狀$or+$and+$ne+$in+$nin', async function() {
|
|
74
|
+
let sp = sortByName(await w.select({ '$or': [{ '$and': [{ value: { '$ne': 123 } }, { value: { '$in': [123, 321, 123.456, 456] } }, { value: { '$nin': [456, 654] } }] }, { '$or': [{ value: { '$lte': -1 } }, { value: { '$gte': 400 } }] }] }))
|
|
75
|
+
assert.strictEqual(sp.length, 2)
|
|
76
|
+
assert.strictEqual(sp[0].name, 'kettle')
|
|
77
|
+
assert.strictEqual(sp[0].value, 456)
|
|
78
|
+
assert.deepStrictEqual(sp[1], { id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 })
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('select $regex不分大小寫', async function() {
|
|
82
|
+
let sr = await w.select({ name: { $regex: 'PeT', $options: '$i' } })
|
|
83
|
+
assert.deepStrictEqual(sr, [{ id: 'id-peter', name: 'peter(modify)', value: 123 }])
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('del 刪除3筆並保留kettle', async function() {
|
|
87
|
+
let ss = await w.select()
|
|
88
|
+
let d = ss.filter((v) => v.name !== 'kettle')
|
|
89
|
+
let msg = await w.del(d)
|
|
90
|
+
assert.deepStrictEqual(msg, [
|
|
91
|
+
{ n: 1, nDeleted: 1, ok: 1 },
|
|
92
|
+
{ n: 1, nDeleted: 1, ok: 1 },
|
|
93
|
+
{ n: 1, nDeleted: 1, ok: 1 },
|
|
94
|
+
])
|
|
95
|
+
let left = await w.select()
|
|
96
|
+
assert.strictEqual(left.length, 1)
|
|
97
|
+
assert.strictEqual(left[0].name, 'kettle')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('delAll 清空後select回傳空陣列', async function() {
|
|
101
|
+
let msg = await w.delAll()
|
|
102
|
+
assert.deepStrictEqual(msg, { n: 1, nDeleted: 1, ok: 1 })
|
|
103
|
+
let ss = await w.select()
|
|
104
|
+
assert.deepStrictEqual(ss, [])
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
describe('mssql transaction commit', function() {
|
|
111
|
+
|
|
112
|
+
let w = wo(genOpt())
|
|
113
|
+
let instance = null
|
|
114
|
+
|
|
115
|
+
before(async function() {
|
|
116
|
+
await w.createStorage()
|
|
117
|
+
await w.delAll().catch(() => {})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
after(async function() {
|
|
121
|
+
if (instance) {
|
|
122
|
+
await instance.close().catch(() => {})
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('交易內insert+save+del, commit後數據持久化', async function() {
|
|
127
|
+
instance = await w.init()
|
|
128
|
+
let transaction = await w.genTransaction()
|
|
129
|
+
let connState = { instance, transaction }
|
|
130
|
+
|
|
131
|
+
let mi = await w.insert(genRs(), connState)
|
|
132
|
+
assert.deepStrictEqual(mi, { n: 3, nInserted: 3, ok: 1 })
|
|
133
|
+
|
|
134
|
+
let msv = await w.save(genRsm(), { ...connState, autoInsert: false })
|
|
135
|
+
assert.deepStrictEqual(msv, [
|
|
136
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
137
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
138
|
+
{ n: 0, nModified: 0, ok: 1 },
|
|
139
|
+
])
|
|
140
|
+
|
|
141
|
+
let md = await w.del({ id: 'id-rosemary' }, connState)
|
|
142
|
+
assert.deepStrictEqual(md, [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
143
|
+
|
|
144
|
+
//交易內select可查到暫時有效的數據
|
|
145
|
+
let ssIn = sortByName(await w.select(null, connState))
|
|
146
|
+
assert.strictEqual(ssIn.length, 2)
|
|
147
|
+
assert.strictEqual(ssIn[0].name, 'kettle')
|
|
148
|
+
assert.strictEqual(ssIn[1].name, 'peter(modify)')
|
|
149
|
+
|
|
150
|
+
await transaction.commit()
|
|
151
|
+
await instance.close()
|
|
152
|
+
instance = null
|
|
153
|
+
|
|
154
|
+
let ssFinal = sortByName(await w.select())
|
|
155
|
+
assert.strictEqual(ssFinal.length, 2)
|
|
156
|
+
assert.strictEqual(ssFinal[0].name, 'kettle')
|
|
157
|
+
assert.strictEqual(ssFinal[0].value, 456)
|
|
158
|
+
assert.deepStrictEqual(ssFinal[1], { id: 'id-peter', name: 'peter(modify)', value: 123 })
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
describe('mssql transaction rollback', function() {
|
|
165
|
+
|
|
166
|
+
let w = wo(genOpt())
|
|
167
|
+
let instance = null
|
|
168
|
+
|
|
169
|
+
before(async function() {
|
|
170
|
+
await w.createStorage()
|
|
171
|
+
await w.delAll().catch(() => {})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
after(async function() {
|
|
175
|
+
if (instance) {
|
|
176
|
+
await instance.close().catch(() => {})
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('交易內insert+save+del, rollback後數據全數還原', async function() {
|
|
181
|
+
instance = await w.init()
|
|
182
|
+
let transaction = await w.genTransaction()
|
|
183
|
+
let connState = { instance, transaction }
|
|
184
|
+
|
|
185
|
+
let mi = await w.insert(genRs(), connState)
|
|
186
|
+
assert.deepStrictEqual(mi, { n: 3, nInserted: 3, ok: 1 })
|
|
187
|
+
|
|
188
|
+
let msv = await w.save(genRsm(), { ...connState, autoInsert: false })
|
|
189
|
+
assert.deepStrictEqual(msv, [
|
|
190
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
191
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
192
|
+
{ n: 0, nModified: 0, ok: 1 },
|
|
193
|
+
])
|
|
194
|
+
|
|
195
|
+
let md = await w.del({ id: 'id-rosemary' }, connState)
|
|
196
|
+
assert.deepStrictEqual(md, [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
197
|
+
|
|
198
|
+
//交易內select可查到暫時有效的數據
|
|
199
|
+
let ssIn = sortByName(await w.select(null, connState))
|
|
200
|
+
assert.strictEqual(ssIn.length, 2)
|
|
201
|
+
assert.strictEqual(ssIn[0].name, 'kettle')
|
|
202
|
+
assert.strictEqual(ssIn[1].name, 'peter(modify)')
|
|
203
|
+
|
|
204
|
+
await transaction.rollback()
|
|
205
|
+
await instance.close()
|
|
206
|
+
instance = null
|
|
207
|
+
|
|
208
|
+
let ssFinal = await w.select()
|
|
209
|
+
assert.deepStrictEqual(ssFinal, [])
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
})
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import assert from 'assert'
|
|
3
|
+
import wo from '../src/WOrmReladb.mjs'
|
|
4
|
+
import { genRs, genRsm, sortByName } from './api-fixtures.mjs'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
//sqlite使用獨立暫存storage檔測試, 不使用專案根目錄之worm.sqlite
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
let genOpt = (storage) => {
|
|
11
|
+
return {
|
|
12
|
+
url: 'sqlite://:',
|
|
13
|
+
db: 'worm',
|
|
14
|
+
cl: 'users',
|
|
15
|
+
fdModels: './models',
|
|
16
|
+
storage,
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let prepStorage = (storage) => {
|
|
21
|
+
fs.mkdirSync('./tmp', { recursive: true })
|
|
22
|
+
if (fs.existsSync(storage)) {
|
|
23
|
+
fs.unlinkSync(storage)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let cleanStorage = (storage) => {
|
|
28
|
+
if (fs.existsSync(storage)) {
|
|
29
|
+
fs.unlinkSync(storage)
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
fs.rmdirSync('./tmp') //僅在空資料夾時移除
|
|
33
|
+
}
|
|
34
|
+
catch (err) {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
describe('sqlite crud', function() {
|
|
39
|
+
|
|
40
|
+
let storage = './tmp/api-sqlite-crud.sqlite'
|
|
41
|
+
let w = wo(genOpt(storage))
|
|
42
|
+
|
|
43
|
+
before(async function() {
|
|
44
|
+
prepStorage(storage)
|
|
45
|
+
await w.createStorage()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
after(function() {
|
|
49
|
+
cleanStorage(storage)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('insert 3筆, 空id自動產生主鍵', async function() {
|
|
53
|
+
let msg = await w.insert(genRs())
|
|
54
|
+
assert.deepStrictEqual(msg, { n: 3, nInserted: 3, ok: 1 })
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('save({autoInsert:false}) 修改2筆且不插入空id項', async function() {
|
|
58
|
+
let msg = await w.save(genRsm(), { autoInsert: false })
|
|
59
|
+
assert.deepStrictEqual(msg, [
|
|
60
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
61
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
62
|
+
{ n: 0, nModified: 0, ok: 1 },
|
|
63
|
+
])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('select() 查全部得3筆', async function() {
|
|
67
|
+
let ss = sortByName(await w.select())
|
|
68
|
+
assert.strictEqual(ss.length, 3)
|
|
69
|
+
let [kettle, peter, rosemary] = ss
|
|
70
|
+
assert.ok(typeof kettle.id === 'string' && kettle.id.length > 0)
|
|
71
|
+
assert.strictEqual(kettle.name, 'kettle')
|
|
72
|
+
assert.strictEqual(kettle.value, 456)
|
|
73
|
+
assert.deepStrictEqual(peter, { id: 'id-peter', name: 'peter(modify)', value: 123 })
|
|
74
|
+
assert.deepStrictEqual(rosemary, { id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 })
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('select({id}) 依主鍵查詢', async function() {
|
|
78
|
+
let so = await w.select({ id: 'id-rosemary' })
|
|
79
|
+
assert.deepStrictEqual(so, [{ id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 }])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('select $and+$gt+$lt', async function() {
|
|
83
|
+
let sp = await w.select({ '$and': [{ value: { '$gt': 123 } }, { value: { '$lt': 200 } }] })
|
|
84
|
+
assert.deepStrictEqual(sp, [{ id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 }])
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('select $or+$gte+$lte', async function() {
|
|
88
|
+
let sp = await w.select({ '$or': [{ value: { '$lte': -1 } }, { value: { '$gte': 200 } }] })
|
|
89
|
+
assert.strictEqual(sp.length, 1)
|
|
90
|
+
assert.strictEqual(sp[0].name, 'kettle')
|
|
91
|
+
assert.strictEqual(sp[0].value, 456)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('select 巢狀$or+$and+$ne+$in+$nin', async function() {
|
|
95
|
+
let sp = sortByName(await w.select({ '$or': [{ '$and': [{ value: { '$ne': 123 } }, { value: { '$in': [123, 321, 123.456, 456] } }, { value: { '$nin': [456, 654] } }] }, { '$or': [{ value: { '$lte': -1 } }, { value: { '$gte': 400 } }] }] }))
|
|
96
|
+
assert.strictEqual(sp.length, 2)
|
|
97
|
+
assert.strictEqual(sp[0].name, 'kettle')
|
|
98
|
+
assert.strictEqual(sp[0].value, 456)
|
|
99
|
+
assert.deepStrictEqual(sp[1], { id: 'id-rosemary', name: 'rosemary(modify)', value: 123.456 })
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('select $regex不分大小寫', async function() {
|
|
103
|
+
let sr = await w.select({ name: { $regex: 'PeT', $options: '$i' } })
|
|
104
|
+
assert.deepStrictEqual(sr, [{ id: 'id-peter', name: 'peter(modify)', value: 123 }])
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('del 刪除2筆並保留kettle', async function() {
|
|
108
|
+
let ss = await w.select()
|
|
109
|
+
let d = ss.filter((v) => v.name !== 'kettle')
|
|
110
|
+
let msg = await w.del(d)
|
|
111
|
+
assert.deepStrictEqual(msg, [
|
|
112
|
+
{ n: 1, nDeleted: 1, ok: 1 },
|
|
113
|
+
{ n: 1, nDeleted: 1, ok: 1 },
|
|
114
|
+
])
|
|
115
|
+
let left = await w.select()
|
|
116
|
+
assert.strictEqual(left.length, 1)
|
|
117
|
+
assert.strictEqual(left[0].name, 'kettle')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('delAll 清空後select回傳空陣列', async function() {
|
|
121
|
+
let msg = await w.delAll()
|
|
122
|
+
assert.deepStrictEqual(msg, { n: 1, nDeleted: 1, ok: 1 })
|
|
123
|
+
let ss = await w.select()
|
|
124
|
+
assert.deepStrictEqual(ss, [])
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
describe('sqlite transaction commit', function() {
|
|
131
|
+
|
|
132
|
+
let storage = './tmp/api-sqlite-commit.sqlite'
|
|
133
|
+
let w = wo(genOpt(storage))
|
|
134
|
+
let instance = null
|
|
135
|
+
|
|
136
|
+
before(async function() {
|
|
137
|
+
prepStorage(storage)
|
|
138
|
+
await w.createStorage()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
after(async function() {
|
|
142
|
+
if (instance) {
|
|
143
|
+
await instance.close().catch(() => {})
|
|
144
|
+
}
|
|
145
|
+
cleanStorage(storage)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('交易內insert+save+del, commit後數據持久化', async function() {
|
|
149
|
+
instance = await w.init()
|
|
150
|
+
let transaction = await w.genTransaction()
|
|
151
|
+
let connState = { instance, transaction }
|
|
152
|
+
|
|
153
|
+
let mi = await w.insert(genRs(), connState)
|
|
154
|
+
assert.deepStrictEqual(mi, { n: 3, nInserted: 3, ok: 1 })
|
|
155
|
+
|
|
156
|
+
let msv = await w.save(genRsm(), { ...connState, autoInsert: false })
|
|
157
|
+
assert.deepStrictEqual(msv, [
|
|
158
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
159
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
160
|
+
{ n: 0, nModified: 0, ok: 1 },
|
|
161
|
+
])
|
|
162
|
+
|
|
163
|
+
let md = await w.del({ id: 'id-rosemary' }, connState)
|
|
164
|
+
assert.deepStrictEqual(md, [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
165
|
+
|
|
166
|
+
//交易內select可查到暫時有效的數據
|
|
167
|
+
let ssIn = sortByName(await w.select(null, connState))
|
|
168
|
+
assert.strictEqual(ssIn.length, 2)
|
|
169
|
+
assert.strictEqual(ssIn[0].name, 'kettle')
|
|
170
|
+
assert.strictEqual(ssIn[1].name, 'peter(modify)')
|
|
171
|
+
|
|
172
|
+
await transaction.commit()
|
|
173
|
+
await instance.close()
|
|
174
|
+
instance = null
|
|
175
|
+
|
|
176
|
+
let ssFinal = sortByName(await w.select())
|
|
177
|
+
assert.strictEqual(ssFinal.length, 2)
|
|
178
|
+
assert.strictEqual(ssFinal[0].name, 'kettle')
|
|
179
|
+
assert.strictEqual(ssFinal[0].value, 456)
|
|
180
|
+
assert.deepStrictEqual(ssFinal[1], { id: 'id-peter', name: 'peter(modify)', value: 123 })
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
describe('sqlite transaction rollback', function() {
|
|
187
|
+
|
|
188
|
+
let storage = './tmp/api-sqlite-rollback.sqlite'
|
|
189
|
+
let w = wo(genOpt(storage))
|
|
190
|
+
let instance = null
|
|
191
|
+
|
|
192
|
+
before(async function() {
|
|
193
|
+
prepStorage(storage)
|
|
194
|
+
await w.createStorage()
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
after(async function() {
|
|
198
|
+
if (instance) {
|
|
199
|
+
await instance.close().catch(() => {})
|
|
200
|
+
}
|
|
201
|
+
cleanStorage(storage)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('交易內insert+save+del, rollback後數據全數還原', async function() {
|
|
205
|
+
instance = await w.init()
|
|
206
|
+
let transaction = await w.genTransaction()
|
|
207
|
+
let connState = { instance, transaction }
|
|
208
|
+
|
|
209
|
+
let mi = await w.insert(genRs(), connState)
|
|
210
|
+
assert.deepStrictEqual(mi, { n: 3, nInserted: 3, ok: 1 })
|
|
211
|
+
|
|
212
|
+
let msv = await w.save(genRsm(), { ...connState, autoInsert: false })
|
|
213
|
+
assert.deepStrictEqual(msv, [
|
|
214
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
215
|
+
{ n: 1, nModified: 1, ok: 1 },
|
|
216
|
+
{ n: 0, nModified: 0, ok: 1 },
|
|
217
|
+
])
|
|
218
|
+
|
|
219
|
+
let md = await w.del({ id: 'id-rosemary' }, connState)
|
|
220
|
+
assert.deepStrictEqual(md, [{ n: 1, nDeleted: 1, ok: 1 }])
|
|
221
|
+
|
|
222
|
+
//交易內select可查到暫時有效的數據
|
|
223
|
+
let ssIn = sortByName(await w.select(null, connState))
|
|
224
|
+
assert.strictEqual(ssIn.length, 2)
|
|
225
|
+
assert.strictEqual(ssIn[0].name, 'kettle')
|
|
226
|
+
assert.strictEqual(ssIn[1].name, 'peter(modify)')
|
|
227
|
+
|
|
228
|
+
await transaction.rollback()
|
|
229
|
+
await instance.close()
|
|
230
|
+
instance = null
|
|
231
|
+
|
|
232
|
+
let ssFinal = await w.select()
|
|
233
|
+
assert.deepStrictEqual(ssFinal, [])
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
})
|
package/worm.sqlite
CHANGED
|
Binary file
|