@quatrain/backend-sqlite 1.0.2 → 1.0.3
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/LICENSE.md +15 -0
- package/README.md +26 -0
- package/package.json +40 -43
- package/src/SQLiteAdapter.ts +916 -0
- package/src/__test__/CRUD.test.ts +67 -0
- package/src/__test__/SQLiteAdapter.test.ts +433 -0
- package/src/__test__/Search.test.ts +325 -0
- package/src/__test__/common.ts +61 -0
- package/src/index.ts +3 -0
- package/lib/SQLiteAdapter.d.ts +0 -55
- package/lib/SQLiteAdapter.js +0 -696
- package/lib/index.d.ts +0 -2
- package/lib/index.js +0 -5
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { User } from '@quatrain/backend'
|
|
2
|
+
import { Filter, OperatorKeys } from '@quatrain/backend'
|
|
3
|
+
import { setup, createUser, createEntity, Entity } from './common'
|
|
4
|
+
|
|
5
|
+
describe('SQLite Search Operations', () => {
|
|
6
|
+
let adapter: any
|
|
7
|
+
let user: User
|
|
8
|
+
let entity: Entity
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
adapter = setup()
|
|
12
|
+
|
|
13
|
+
// Create test entity
|
|
14
|
+
entity = await createEntity()
|
|
15
|
+
await adapter.create(entity.dataObject, undefined)
|
|
16
|
+
|
|
17
|
+
// Create multiple test users
|
|
18
|
+
const users = []
|
|
19
|
+
for (let i = 0; i < 10; i++) {
|
|
20
|
+
const testUser = await User.factory()
|
|
21
|
+
testUser._.firstname = `TestUser${i}`
|
|
22
|
+
testUser._.lastname = i % 2 === 0 ? 'Even' : 'Odd'
|
|
23
|
+
testUser._.email = `testuser${i}@example.com`
|
|
24
|
+
testUser._.password = 'password'
|
|
25
|
+
|
|
26
|
+
// Some users belong to the entity
|
|
27
|
+
if (i < 5) {
|
|
28
|
+
testUser._.entity = entity
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await adapter.create(testUser.dataObject, undefined)
|
|
32
|
+
users.push(testUser)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
user = users[0]
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
afterAll(async () => {
|
|
39
|
+
await adapter.deleteCollection('user')
|
|
40
|
+
await adapter.deleteCollection('entities')
|
|
41
|
+
await adapter.close()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('Basic Search Operations', () => {
|
|
45
|
+
test('find all users without filters', async () => {
|
|
46
|
+
const searchUser = await User.factory()
|
|
47
|
+
const result = await adapter.find(searchUser.dataObject)
|
|
48
|
+
|
|
49
|
+
expect(result.items.length).toBe(10)
|
|
50
|
+
expect(result.meta.count).toBe(10)
|
|
51
|
+
expect(result.meta.batch).toBe(20) // Default batch size
|
|
52
|
+
expect(result.meta.offset).toBe(0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('find users with firstname filter', async () => {
|
|
56
|
+
const searchUser = await User.factory()
|
|
57
|
+
const filters = [new Filter('firstname', 'TestUser5', OperatorKeys.equals)]
|
|
58
|
+
|
|
59
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
60
|
+
expect(result.items.length).toBe(1)
|
|
61
|
+
expect(result.items[0].val('firstname')).toBe('TestUser5')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('find users with lastname filter', async () => {
|
|
65
|
+
const searchUser = await User.factory()
|
|
66
|
+
const filters = [new Filter('lastname', 'Even', OperatorKeys.equals)]
|
|
67
|
+
|
|
68
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
69
|
+
expect(result.items.length).toBe(5)
|
|
70
|
+
|
|
71
|
+
result.items.forEach((item: any) => {
|
|
72
|
+
expect(item.val('lastname')).toBe('Even')
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('find users with multiple filters', async () => {
|
|
77
|
+
const searchUser = await User.factory()
|
|
78
|
+
const filters = [
|
|
79
|
+
new Filter('lastname', 'Even', OperatorKeys.equals),
|
|
80
|
+
new Filter('firstname', 'TestUser0', OperatorKeys.equals)
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
84
|
+
expect(result.items.length).toBe(1)
|
|
85
|
+
expect(result.items[0].val('firstname')).toBe('TestUser0')
|
|
86
|
+
expect(result.items[0].val('lastname')).toBe('Even')
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
describe('Comparison Operators', () => {
|
|
91
|
+
test('greater than filter', async () => {
|
|
92
|
+
const searchUser = await User.factory()
|
|
93
|
+
const filters = [new Filter('firstname', 'TestUser5', OperatorKeys.greater)]
|
|
94
|
+
|
|
95
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
96
|
+
expect(result.items.length).toBeGreaterThan(0)
|
|
97
|
+
|
|
98
|
+
result.items.forEach((item: any) => {
|
|
99
|
+
expect(item.val('firstname') > 'TestUser5').toBe(true)
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('less than filter', async () => {
|
|
104
|
+
const searchUser = await User.factory()
|
|
105
|
+
const filters = [new Filter('firstname', 'TestUser5', OperatorKeys.lower)]
|
|
106
|
+
|
|
107
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
108
|
+
expect(result.items.length).toBeGreaterThan(0)
|
|
109
|
+
|
|
110
|
+
result.items.forEach((item: any) => {
|
|
111
|
+
expect(item.val('firstname') < 'TestUser5').toBe(true)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('not equals filter', async () => {
|
|
116
|
+
const searchUser = await User.factory()
|
|
117
|
+
const filters = [new Filter('lastname', 'Even', OperatorKeys.notEquals)]
|
|
118
|
+
|
|
119
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
120
|
+
expect(result.items.length).toBe(5)
|
|
121
|
+
|
|
122
|
+
result.items.forEach((item: any) => {
|
|
123
|
+
expect(item.val('lastname')).not.toBe('Even')
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('greater than or equals filter', async () => {
|
|
128
|
+
const searchUser = await User.factory()
|
|
129
|
+
const filters = [new Filter('firstname', 'TestUser5', OperatorKeys.greaterOrEquals)]
|
|
130
|
+
|
|
131
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
132
|
+
expect(result.items.length).toBeGreaterThan(0)
|
|
133
|
+
|
|
134
|
+
result.items.forEach((item: any) => {
|
|
135
|
+
expect(item.val('firstname') >= 'TestUser5').toBe(true)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('less than or equals filter', async () => {
|
|
140
|
+
const searchUser = await User.factory()
|
|
141
|
+
const filters = [new Filter('firstname', 'TestUser5', OperatorKeys.lowerOrEquals)]
|
|
142
|
+
|
|
143
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
144
|
+
expect(result.items.length).toBeGreaterThan(0)
|
|
145
|
+
|
|
146
|
+
result.items.forEach((item: any) => {
|
|
147
|
+
expect(item.val('firstname') <= 'TestUser5').toBe(true)
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('Text Search Operations', () => {
|
|
153
|
+
test('keywords search across multiple fields', async () => {
|
|
154
|
+
const searchUser = await User.factory()
|
|
155
|
+
const filters = [new Filter('keywords', 'TestUser', OperatorKeys.like)]
|
|
156
|
+
|
|
157
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
158
|
+
expect(result.items.length).toBe(10) // All users have "TestUser" in firstname
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('keywords search with specific term', async () => {
|
|
162
|
+
const searchUser = await User.factory()
|
|
163
|
+
const filters = [new Filter('keywords', 'testuser3@example.com', OperatorKeys.like)]
|
|
164
|
+
|
|
165
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
166
|
+
expect(result.items.length).toBeGreaterThan(0)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test('like filter on specific field', async () => {
|
|
170
|
+
const searchUser = await User.factory()
|
|
171
|
+
const filters = [new Filter('email', '@example.com', OperatorKeys.like)]
|
|
172
|
+
|
|
173
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
174
|
+
expect(result.items.length).toBe(10) // All test users have @example.com
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('Pagination and Sorting', () => {
|
|
179
|
+
test('pagination with limit', async () => {
|
|
180
|
+
const searchUser = await User.factory()
|
|
181
|
+
const pagination = {
|
|
182
|
+
limits: { batch: 3, offset: 0 },
|
|
183
|
+
sortings: [{ prop: 'firstname', order: 'asc' as const }]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const result = await adapter.find(searchUser.dataObject, undefined, pagination)
|
|
187
|
+
expect(result.items.length).toBe(3)
|
|
188
|
+
expect(result.meta.batch).toBe(3)
|
|
189
|
+
expect(result.meta.offset).toBe(0)
|
|
190
|
+
expect(result.meta.count).toBe(10) // Total count should still be 10
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('pagination with offset', async () => {
|
|
194
|
+
const searchUser = await User.factory()
|
|
195
|
+
const pagination = {
|
|
196
|
+
limits: { batch: 3, offset: 3 },
|
|
197
|
+
sortings: [{ prop: 'firstname', order: 'asc' as const }]
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const result = await adapter.find(searchUser.dataObject, undefined, pagination)
|
|
201
|
+
expect(result.items.length).toBe(3)
|
|
202
|
+
expect(result.meta.offset).toBe(3)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('sorting ascending', async () => {
|
|
206
|
+
const searchUser = await User.factory()
|
|
207
|
+
const pagination = {
|
|
208
|
+
limits: { batch: 5, offset: 0 },
|
|
209
|
+
sortings: [{ prop: 'firstname', order: 'asc' as const }]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = await adapter.find(searchUser.dataObject, undefined, pagination)
|
|
213
|
+
|
|
214
|
+
for (let i = 1; i < result.items.length; i++) {
|
|
215
|
+
const prev = result.items[i-1].val('firstname')
|
|
216
|
+
const curr = result.items[i].val('firstname')
|
|
217
|
+
expect(prev <= curr).toBe(true)
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('sorting descending', async () => {
|
|
222
|
+
const searchUser = await User.factory()
|
|
223
|
+
const pagination = {
|
|
224
|
+
limits: { batch: 5, offset: 0 },
|
|
225
|
+
sortings: [{ prop: 'firstname', order: 'desc' as const }]
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const result = await adapter.find(searchUser.dataObject, undefined, pagination)
|
|
229
|
+
|
|
230
|
+
for (let i = 1; i < result.items.length; i++) {
|
|
231
|
+
const prev = result.items[i-1].val('firstname')
|
|
232
|
+
const curr = result.items[i].val('firstname')
|
|
233
|
+
expect(prev >= curr).toBe(true)
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
test('multiple sorting criteria', async () => {
|
|
238
|
+
const searchUser = await User.factory()
|
|
239
|
+
const pagination = {
|
|
240
|
+
limits: { batch: 10, offset: 0 },
|
|
241
|
+
sortings: [
|
|
242
|
+
{ prop: 'lastname', order: 'asc' as const },
|
|
243
|
+
{ prop: 'firstname', order: 'desc' as const }
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const result = await adapter.find(searchUser.dataObject, undefined, pagination)
|
|
248
|
+
expect(result.items.length).toBe(10)
|
|
249
|
+
expect(result.meta.sortField).toContain('lastname ASC')
|
|
250
|
+
expect(result.meta.sortField).toContain('firstname DESC')
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
describe('Object Reference Filters', () => {
|
|
255
|
+
test('filter by entity reference', async () => {
|
|
256
|
+
const searchUser = await User.factory()
|
|
257
|
+
const filters = [new Filter('entity', entity, OperatorKeys.equals)]
|
|
258
|
+
|
|
259
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
260
|
+
expect(result.items.length).toBe(5) // 5 users have this entity
|
|
261
|
+
|
|
262
|
+
result.items.forEach((item: any) => {
|
|
263
|
+
const entityValue = item.val('entity')
|
|
264
|
+
expect(entityValue).toBeDefined()
|
|
265
|
+
})
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
test('filter by null entity', async () => {
|
|
269
|
+
const searchUser = await User.factory()
|
|
270
|
+
const filters = [new Filter('entity', 'null', OperatorKeys.equals)]
|
|
271
|
+
|
|
272
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
273
|
+
expect(result.items.length).toBe(5) // 5 users don't have entity
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
describe('Complex Queries', () => {
|
|
278
|
+
test('combined filters with pagination and sorting', async () => {
|
|
279
|
+
const searchUser = await User.factory()
|
|
280
|
+
const filters = [new Filter('lastname', 'Even', OperatorKeys.equals)]
|
|
281
|
+
const pagination = {
|
|
282
|
+
limits: { batch: 2, offset: 1 },
|
|
283
|
+
sortings: [{ prop: 'firstname', order: 'asc' as const }]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const result = await adapter.find(searchUser.dataObject, filters, pagination)
|
|
287
|
+
expect(result.items.length).toBe(2)
|
|
288
|
+
expect(result.meta.count).toBe(5) // Total matching records
|
|
289
|
+
expect(result.meta.offset).toBe(1)
|
|
290
|
+
|
|
291
|
+
result.items.forEach((item: any) => {
|
|
292
|
+
expect(item.val('lastname')).toBe('Even')
|
|
293
|
+
})
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
test('no results query', async () => {
|
|
297
|
+
const searchUser = await User.factory()
|
|
298
|
+
const filters = [new Filter('firstname', 'NonExistentUser', OperatorKeys.equals)]
|
|
299
|
+
|
|
300
|
+
const result = await adapter.find(searchUser.dataObject, filters)
|
|
301
|
+
expect(result.items.length).toBe(0)
|
|
302
|
+
expect(result.meta.count).toBe(0)
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
describe('Error Cases', () => {
|
|
307
|
+
test('invalid property name in filter', async () => {
|
|
308
|
+
const searchUser = await User.factory()
|
|
309
|
+
const filters = [new Filter('invalidProperty', 'value', OperatorKeys.equals)]
|
|
310
|
+
|
|
311
|
+
await expect(adapter.find(searchUser.dataObject, filters)).rejects.toThrow()
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test('invalid collection for search', async () => {
|
|
315
|
+
const searchUser = await User.factory()
|
|
316
|
+
// Force collection to be undefined
|
|
317
|
+
Object.defineProperty(searchUser.dataObject.uri, 'collection', {
|
|
318
|
+
value: undefined,
|
|
319
|
+
writable: true
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
await expect(adapter.find(searchUser.dataObject)).rejects.toThrow()
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { User, PersistedBaseObject } from '@quatrain/backend'
|
|
2
|
+
import { Entity as CoreEntity } from '@quatrain/core'
|
|
3
|
+
import { SQLiteAdapter } from '../SQLiteAdapter'
|
|
4
|
+
|
|
5
|
+
// Create a simple Entity class that extends PersistedBaseObject for testing
|
|
6
|
+
class Entity extends PersistedBaseObject {
|
|
7
|
+
static COLLECTION = 'entities'
|
|
8
|
+
static PROPS_DEFINITION = CoreEntity.PROPS_DEFINITION
|
|
9
|
+
|
|
10
|
+
static async factory(src: any = undefined): Promise<Entity> {
|
|
11
|
+
return super.factory(src, Entity)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const setup = (dbPath: string = ':memory:') => {
|
|
16
|
+
return new SQLiteAdapter({
|
|
17
|
+
config: {
|
|
18
|
+
database: dbPath
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const createUser = async () => {
|
|
24
|
+
const user = await User.factory()
|
|
25
|
+
user._.firstname = 'John'
|
|
26
|
+
user._.lastname = 'Doe'
|
|
27
|
+
user._.email = 'john@doe.com'
|
|
28
|
+
user._.password = 'password123'
|
|
29
|
+
|
|
30
|
+
return user
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const createEntity = async () => {
|
|
34
|
+
const entity = await Entity.factory()
|
|
35
|
+
entity._.name = 'ACME Inc.'
|
|
36
|
+
|
|
37
|
+
return entity
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const createUsers = async (
|
|
41
|
+
userModel: User,
|
|
42
|
+
qty: number = 5,
|
|
43
|
+
forcedValues: any = {}
|
|
44
|
+
): Promise<User[]> => {
|
|
45
|
+
// Simple data generator since utils.DataGenerator is not available
|
|
46
|
+
const users: User[] = []
|
|
47
|
+
for (let i = 0; i < qty; i++) {
|
|
48
|
+
const user = await User.factory()
|
|
49
|
+
user._.firstname = forcedValues.firstname || `User${i}`
|
|
50
|
+
user._.lastname = forcedValues.lastname || 'Test'
|
|
51
|
+
user._.email = forcedValues.email || `user${i}@test.com`
|
|
52
|
+
user._.password = forcedValues.password || 'password'
|
|
53
|
+
if (forcedValues.entity) {
|
|
54
|
+
user._.entity = forcedValues.entity
|
|
55
|
+
}
|
|
56
|
+
users.push(user)
|
|
57
|
+
}
|
|
58
|
+
return users
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { Entity }
|
package/src/index.ts
ADDED
package/lib/SQLiteAdapter.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { DataObjectClass, AbstractBackendAdapter, BackendParameters, QueryResultType, Filters, Filter, SortAndLimit } from '@quatrain/backend';
|
|
2
|
-
import sqlite3 from 'sqlite3';
|
|
3
|
-
import { Database } from 'sqlite';
|
|
4
|
-
/**
|
|
5
|
-
* SQLite Backend Adapter for Quatrain
|
|
6
|
-
*/
|
|
7
|
-
export declare class SQLiteAdapter extends AbstractBackendAdapter {
|
|
8
|
-
protected _connection: undefined | Database<sqlite3.Database>;
|
|
9
|
-
protected _dbPath: string;
|
|
10
|
-
constructor(params?: BackendParameters);
|
|
11
|
-
protected _buildPath(dataObject: DataObjectClass<any>, uid?: string): string;
|
|
12
|
-
protected _connect(): Promise<Database<sqlite3.Database>>;
|
|
13
|
-
/**
|
|
14
|
-
* Process data for compatibility
|
|
15
|
-
* @param data
|
|
16
|
-
* @param filterNulls
|
|
17
|
-
* @returns
|
|
18
|
-
*/
|
|
19
|
-
protected _prepareData(data: any, filterNulls?: boolean): any;
|
|
20
|
-
/**
|
|
21
|
-
* Ensure the collection table exists in SQLite
|
|
22
|
-
* @param dataObject DataObject to create table for
|
|
23
|
-
*/
|
|
24
|
-
private _ensureTable;
|
|
25
|
-
/**
|
|
26
|
-
* Create record in backend
|
|
27
|
-
* @param dataObject DataObject instance to persist in backend
|
|
28
|
-
* @param desiredUid Desired unique ID for record
|
|
29
|
-
* @returns DataObject
|
|
30
|
-
*/
|
|
31
|
-
create(dataObject: DataObjectClass<any>, desiredUid: string | undefined): Promise<DataObjectClass<any>>;
|
|
32
|
-
read(dataObject: DataObjectClass<any>): Promise<DataObjectClass<any>>;
|
|
33
|
-
update(dataObject: DataObjectClass<any>): Promise<DataObjectClass<any>>;
|
|
34
|
-
delete(dataObject: DataObjectClass<any>, hardDelete?: boolean): Promise<DataObjectClass<any>>;
|
|
35
|
-
deleteCollection(collection: string, batchSize?: number): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* Convert array into SQL expression
|
|
38
|
-
* @param from Array of strings or numbers
|
|
39
|
-
* @returns string
|
|
40
|
-
*/
|
|
41
|
-
protected _array2String(from: (string | number)[]): string;
|
|
42
|
-
/**
|
|
43
|
-
* Execute a query on a collection
|
|
44
|
-
* @param dataObject
|
|
45
|
-
* @param filters
|
|
46
|
-
* @param pagination
|
|
47
|
-
* @params parent
|
|
48
|
-
* @returns
|
|
49
|
-
*/
|
|
50
|
-
find(dataObject: DataObjectClass<any>, filters?: Filters | Filter[] | undefined, pagination?: SortAndLimit | undefined, parent?: DataObjectClass<any> | undefined): Promise<QueryResultType<DataObjectClass<any>>>;
|
|
51
|
-
/**
|
|
52
|
-
* Close the SQLite connection
|
|
53
|
-
*/
|
|
54
|
-
close(): Promise<void>;
|
|
55
|
-
}
|