@naturalcycles/db-lib 8.60.1 → 9.0.0
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/adapter/cachedb/cache.db.d.ts +3 -4
- package/dist/adapter/cachedb/cache.db.js +5 -4
- package/dist/adapter/cachedb/cache.db.model.d.ts +2 -2
- package/dist/adapter/file/file.db.d.ts +15 -7
- package/dist/adapter/file/file.db.js +93 -57
- package/dist/adapter/inmemory/inMemory.db.d.ts +30 -4
- package/dist/adapter/inmemory/inMemory.db.js +87 -31
- package/dist/base.common.db.d.ts +7 -10
- package/dist/base.common.db.js +11 -7
- package/dist/common.db.d.ts +55 -3
- package/dist/common.db.js +23 -0
- package/dist/commondao/common.dao.d.ts +17 -9
- package/dist/commondao/common.dao.js +82 -69
- package/dist/commondao/common.dao.model.d.ts +0 -10
- package/dist/db.model.d.ts +12 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/testing/daoTest.d.ts +2 -2
- package/dist/testing/daoTest.js +29 -39
- package/dist/testing/dbTest.d.ts +1 -39
- package/dist/testing/dbTest.js +40 -49
- package/dist/testing/index.d.ts +2 -2
- package/dist/timeseries/commonTimeSeriesDao.js +5 -6
- package/dist/transaction/dbTransaction.util.d.ts +17 -4
- package/dist/transaction/dbTransaction.util.js +46 -22
- package/dist/validation/index.js +2 -2
- package/package.json +1 -1
- package/src/adapter/cachedb/cache.db.model.ts +7 -2
- package/src/adapter/cachedb/cache.db.ts +7 -8
- package/src/adapter/file/file.db.ts +121 -69
- package/src/adapter/inmemory/inMemory.db.ts +103 -29
- package/src/base.common.db.ts +20 -11
- package/src/common.db.ts +79 -2
- package/src/commondao/common.dao.model.ts +0 -11
- package/src/commondao/common.dao.ts +103 -89
- package/src/db.model.ts +15 -2
- package/src/index.ts +0 -1
- package/src/testing/daoTest.ts +32 -52
- package/src/testing/dbTest.ts +42 -119
- package/src/testing/index.ts +2 -12
- package/src/timeseries/commonTimeSeriesDao.ts +5 -6
- package/src/transaction/dbTransaction.util.ts +61 -22
- package/src/validation/index.ts +2 -2
- package/dist/transaction/dbTransaction.d.ts +0 -27
- package/dist/transaction/dbTransaction.js +0 -64
- package/src/transaction/dbTransaction.ts +0 -67
|
@@ -18,7 +18,15 @@ import {
|
|
|
18
18
|
Saved,
|
|
19
19
|
} from '@naturalcycles/js-lib'
|
|
20
20
|
import { readableCreate, ReadableTyped, dimGrey } from '@naturalcycles/nodejs-lib'
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
BaseCommonDB,
|
|
23
|
+
commonDBFullSupport,
|
|
24
|
+
CommonDBSupport,
|
|
25
|
+
DBOperation,
|
|
26
|
+
DBSaveBatchOperation,
|
|
27
|
+
DBTransaction,
|
|
28
|
+
queryInMemory,
|
|
29
|
+
} from '../..'
|
|
22
30
|
import { CommonDB } from '../../common.db'
|
|
23
31
|
import {
|
|
24
32
|
CommonDBOptions,
|
|
@@ -27,7 +35,6 @@ import {
|
|
|
27
35
|
RunQueryResult,
|
|
28
36
|
} from '../../db.model'
|
|
29
37
|
import { DBQuery } from '../../query/dbQuery'
|
|
30
|
-
import { DBTransaction } from '../../transaction/dbTransaction'
|
|
31
38
|
import { FileDBCfg } from './file.db.model'
|
|
32
39
|
|
|
33
40
|
/**
|
|
@@ -41,6 +48,16 @@ import { FileDBCfg } from './file.db.model'
|
|
|
41
48
|
* Each save operation saves *whole* file to the persistence layer.
|
|
42
49
|
*/
|
|
43
50
|
export class FileDB extends BaseCommonDB implements CommonDB {
|
|
51
|
+
override support: CommonDBSupport = {
|
|
52
|
+
...commonDBFullSupport,
|
|
53
|
+
bufferValues: false, // todo: implement
|
|
54
|
+
insertSaveMethod: false,
|
|
55
|
+
updateSaveMethod: false,
|
|
56
|
+
updateByQuery: false,
|
|
57
|
+
createTable: false,
|
|
58
|
+
transactions: false,
|
|
59
|
+
}
|
|
60
|
+
|
|
44
61
|
constructor(cfg: FileDBCfg) {
|
|
45
62
|
super()
|
|
46
63
|
this.cfg = {
|
|
@@ -101,72 +118,6 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
101
118
|
}
|
|
102
119
|
}
|
|
103
120
|
|
|
104
|
-
/**
|
|
105
|
-
* Implementation is optimized for loading/saving _whole files_.
|
|
106
|
-
*/
|
|
107
|
-
override async commitTransaction(tx: DBTransaction, _opt?: CommonDBOptions): Promise<void> {
|
|
108
|
-
// data[table][id] => row
|
|
109
|
-
const data: StringMap<StringMap<ObjectWithId>> = {}
|
|
110
|
-
|
|
111
|
-
// 1. Load all tables data (concurrently)
|
|
112
|
-
const tables = _uniq(tx.ops.map(o => o.table))
|
|
113
|
-
|
|
114
|
-
await pMap(
|
|
115
|
-
tables,
|
|
116
|
-
async table => {
|
|
117
|
-
const rows = await this.loadFile(table)
|
|
118
|
-
data[table] = _by(rows, r => r.id)
|
|
119
|
-
},
|
|
120
|
-
{ concurrency: 16 },
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
const backup = _deepCopy(data)
|
|
124
|
-
|
|
125
|
-
// 2. Apply ops one by one (in order)
|
|
126
|
-
tx.ops.forEach(op => {
|
|
127
|
-
if (op.type === 'deleteByIds') {
|
|
128
|
-
op.ids.forEach(id => delete data[op.table]![id])
|
|
129
|
-
} else if (op.type === 'saveBatch') {
|
|
130
|
-
op.rows.forEach(r => {
|
|
131
|
-
if (!r.id) {
|
|
132
|
-
throw new Error('FileDB: row has an empty id')
|
|
133
|
-
}
|
|
134
|
-
data[op.table]![r.id] = r
|
|
135
|
-
})
|
|
136
|
-
} else {
|
|
137
|
-
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
// 3. Sort, turn it into ops
|
|
142
|
-
// Not filtering empty arrays, cause it's already filtered in this.saveFiles()
|
|
143
|
-
const ops: DBSaveBatchOperation[] = _stringMapEntries(data).map(([table, map]) => {
|
|
144
|
-
return {
|
|
145
|
-
type: 'saveBatch',
|
|
146
|
-
table,
|
|
147
|
-
rows: this.sortRows(_stringMapValues(map)),
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
// 4. Save all files
|
|
152
|
-
try {
|
|
153
|
-
await this.saveFiles(ops)
|
|
154
|
-
} catch (err) {
|
|
155
|
-
const ops: DBSaveBatchOperation[] = _stringMapEntries(backup).map(([table, map]) => {
|
|
156
|
-
return {
|
|
157
|
-
type: 'saveBatch',
|
|
158
|
-
table,
|
|
159
|
-
rows: this.sortRows(_stringMapValues(map)),
|
|
160
|
-
}
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
// Rollback, ignore rollback error (if any)
|
|
164
|
-
await this.saveFiles(ops).catch(_ => {})
|
|
165
|
-
|
|
166
|
-
throw err
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
121
|
override async runQuery<ROW extends ObjectWithId>(
|
|
171
122
|
q: DBQuery<ROW>,
|
|
172
123
|
_opt?: CommonDBOptions,
|
|
@@ -216,6 +167,27 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
216
167
|
return deleted
|
|
217
168
|
}
|
|
218
169
|
|
|
170
|
+
override async deleteByIds(
|
|
171
|
+
table: string,
|
|
172
|
+
ids: string[],
|
|
173
|
+
_opt?: CommonDBOptions,
|
|
174
|
+
): Promise<number> {
|
|
175
|
+
const byId = _by(await this.loadFile(table), r => r.id)
|
|
176
|
+
|
|
177
|
+
let deleted = 0
|
|
178
|
+
ids.forEach(id => {
|
|
179
|
+
if (!byId[id]) return
|
|
180
|
+
delete byId[id]
|
|
181
|
+
deleted++
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
if (deleted > 0) {
|
|
185
|
+
await this.saveFile(table, _stringMapValues(byId))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return deleted
|
|
189
|
+
}
|
|
190
|
+
|
|
219
191
|
override async getTableSchema<ROW extends ObjectWithId>(
|
|
220
192
|
table: string,
|
|
221
193
|
): Promise<JsonSchemaRootObject<ROW>> {
|
|
@@ -256,7 +228,11 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
256
228
|
this.logFinished(started, op)
|
|
257
229
|
}
|
|
258
230
|
|
|
259
|
-
|
|
231
|
+
override async createTransaction(): Promise<FileDBTransaction> {
|
|
232
|
+
return new FileDBTransaction(this)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
sortRows<ROW extends ObjectWithId>(rows: ROW[]): ROW[] {
|
|
260
236
|
rows = rows.map(r => _filterUndefinedValues(r))
|
|
261
237
|
|
|
262
238
|
if (this.cfg.sortOnSave) {
|
|
@@ -283,3 +259,79 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
283
259
|
this.cfg.logger?.log(`<< ${op} ${dimGrey(`in ${_since(started)}`)}`)
|
|
284
260
|
}
|
|
285
261
|
}
|
|
262
|
+
|
|
263
|
+
export class FileDBTransaction implements DBTransaction {
|
|
264
|
+
constructor(private db: FileDB) {}
|
|
265
|
+
|
|
266
|
+
ops: DBOperation[] = []
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Implementation is optimized for loading/saving _whole files_.
|
|
270
|
+
*/
|
|
271
|
+
async commit(): Promise<void> {
|
|
272
|
+
// data[table][id] => row
|
|
273
|
+
const data: StringMap<StringMap<ObjectWithId>> = {}
|
|
274
|
+
|
|
275
|
+
// 1. Load all tables data (concurrently)
|
|
276
|
+
const tables = _uniq(this.ops.map(o => o.table))
|
|
277
|
+
|
|
278
|
+
await pMap(
|
|
279
|
+
tables,
|
|
280
|
+
async table => {
|
|
281
|
+
const rows = await this.db.loadFile(table)
|
|
282
|
+
data[table] = _by(rows, r => r.id)
|
|
283
|
+
},
|
|
284
|
+
{ concurrency: 16 },
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
const backup = _deepCopy(data)
|
|
288
|
+
|
|
289
|
+
// 2. Apply ops one by one (in order)
|
|
290
|
+
this.ops.forEach(op => {
|
|
291
|
+
if (op.type === 'deleteByIds') {
|
|
292
|
+
op.ids.forEach(id => delete data[op.table]![id])
|
|
293
|
+
} else if (op.type === 'saveBatch') {
|
|
294
|
+
op.rows.forEach(r => {
|
|
295
|
+
if (!r.id) {
|
|
296
|
+
throw new Error('FileDB: row has an empty id')
|
|
297
|
+
}
|
|
298
|
+
data[op.table]![r.id] = r
|
|
299
|
+
})
|
|
300
|
+
} else {
|
|
301
|
+
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
// 3. Sort, turn it into ops
|
|
306
|
+
// Not filtering empty arrays, cause it's already filtered in this.saveFiles()
|
|
307
|
+
const ops: DBSaveBatchOperation[] = _stringMapEntries(data).map(([table, map]) => {
|
|
308
|
+
return {
|
|
309
|
+
type: 'saveBatch',
|
|
310
|
+
table,
|
|
311
|
+
rows: this.db.sortRows(_stringMapValues(map)),
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
// 4. Save all files
|
|
316
|
+
try {
|
|
317
|
+
await this.db.saveFiles(ops)
|
|
318
|
+
} catch (err) {
|
|
319
|
+
const ops: DBSaveBatchOperation[] = _stringMapEntries(backup).map(([table, map]) => {
|
|
320
|
+
return {
|
|
321
|
+
type: 'saveBatch',
|
|
322
|
+
table,
|
|
323
|
+
rows: this.db.sortRows(_stringMapValues(map)),
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
// Rollback, ignore rollback error (if any)
|
|
328
|
+
await this.db.saveFiles(ops).catch(_ => {})
|
|
329
|
+
|
|
330
|
+
throw err
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async rollback(): Promise<void> {
|
|
335
|
+
this.ops = []
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
CommonLogger,
|
|
17
17
|
_deepCopy,
|
|
18
18
|
_assert,
|
|
19
|
+
_omit,
|
|
19
20
|
} from '@naturalcycles/js-lib'
|
|
20
21
|
import {
|
|
21
22
|
bufferReviver,
|
|
@@ -29,11 +30,20 @@ import {
|
|
|
29
30
|
yellow,
|
|
30
31
|
fs2,
|
|
31
32
|
} from '@naturalcycles/nodejs-lib'
|
|
32
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
CommonDB,
|
|
35
|
+
commonDBFullSupport,
|
|
36
|
+
CommonDBType,
|
|
37
|
+
DBIncrement,
|
|
38
|
+
DBOperation,
|
|
39
|
+
DBPatch,
|
|
40
|
+
queryInMemory,
|
|
41
|
+
} from '../..'
|
|
33
42
|
import {
|
|
34
43
|
CommonDBCreateOptions,
|
|
35
44
|
CommonDBOptions,
|
|
36
45
|
CommonDBSaveOptions,
|
|
46
|
+
DBTransaction,
|
|
37
47
|
RunQueryResult,
|
|
38
48
|
} from '../../db.model'
|
|
39
49
|
import { DBQuery } from '../../query/dbQuery'
|
|
@@ -76,6 +86,12 @@ export interface InMemoryDBCfg {
|
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
export class InMemoryDB implements CommonDB {
|
|
89
|
+
dbType = CommonDBType.document
|
|
90
|
+
|
|
91
|
+
support = {
|
|
92
|
+
...commonDBFullSupport,
|
|
93
|
+
}
|
|
94
|
+
|
|
79
95
|
constructor(cfg?: Partial<InMemoryDBCfg>) {
|
|
80
96
|
this.cfg = {
|
|
81
97
|
// defaults
|
|
@@ -161,6 +177,17 @@ export class InMemoryDB implements CommonDB {
|
|
|
161
177
|
rows: ROW[],
|
|
162
178
|
opt: CommonDBSaveOptions<ROW> = {},
|
|
163
179
|
): Promise<void> {
|
|
180
|
+
const { tx } = opt
|
|
181
|
+
if (tx) {
|
|
182
|
+
;(tx as InMemoryDBTransaction).ops.push({
|
|
183
|
+
type: 'saveBatch',
|
|
184
|
+
table: _table,
|
|
185
|
+
rows,
|
|
186
|
+
opt: _omit(opt, ['tx']),
|
|
187
|
+
})
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
|
|
164
191
|
const table = this.cfg.tablesPrefix + _table
|
|
165
192
|
this.data[table] ||= {}
|
|
166
193
|
|
|
@@ -189,16 +216,48 @@ export class InMemoryDB implements CommonDB {
|
|
|
189
216
|
|
|
190
217
|
async deleteByQuery<ROW extends ObjectWithId>(
|
|
191
218
|
q: DBQuery<ROW>,
|
|
192
|
-
|
|
219
|
+
opt: CommonDBOptions = {},
|
|
193
220
|
): Promise<number> {
|
|
194
221
|
const table = this.cfg.tablesPrefix + q.table
|
|
195
|
-
this.data[table]
|
|
222
|
+
if (!this.data[table]) return 0
|
|
223
|
+
const ids = queryInMemory(q, Object.values(this.data[table]!) as ROW[]).map(r => r.id)
|
|
224
|
+
|
|
225
|
+
const { tx } = opt
|
|
226
|
+
if (tx) {
|
|
227
|
+
;(tx as InMemoryDBTransaction).ops.push({
|
|
228
|
+
type: 'deleteByIds',
|
|
229
|
+
table: q.table,
|
|
230
|
+
ids,
|
|
231
|
+
opt: _omit(opt, ['tx']),
|
|
232
|
+
})
|
|
233
|
+
return ids.length
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return await this.deleteByIds(q.table, ids)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async deleteByIds(_table: string, ids: string[], opt: CommonDBOptions = {}): Promise<number> {
|
|
240
|
+
const table = this.cfg.tablesPrefix + _table
|
|
241
|
+
if (!this.data[table]) return 0
|
|
242
|
+
|
|
243
|
+
const { tx } = opt
|
|
244
|
+
if (tx) {
|
|
245
|
+
;(tx as InMemoryDBTransaction).ops.push({
|
|
246
|
+
type: 'deleteByIds',
|
|
247
|
+
table: _table,
|
|
248
|
+
ids,
|
|
249
|
+
opt: _omit(opt, ['tx']),
|
|
250
|
+
})
|
|
251
|
+
return ids.length
|
|
252
|
+
}
|
|
253
|
+
|
|
196
254
|
let count = 0
|
|
197
|
-
|
|
198
|
-
if (!this.data[table]![
|
|
199
|
-
delete this.data[table]![
|
|
255
|
+
ids.forEach(id => {
|
|
256
|
+
if (!this.data[table]![id]) return
|
|
257
|
+
delete this.data[table]![id]
|
|
200
258
|
count++
|
|
201
259
|
})
|
|
260
|
+
|
|
202
261
|
return count
|
|
203
262
|
}
|
|
204
263
|
|
|
@@ -209,6 +268,8 @@ export class InMemoryDB implements CommonDB {
|
|
|
209
268
|
const patchEntries = Object.entries(patch)
|
|
210
269
|
if (!patchEntries.length) return 0
|
|
211
270
|
|
|
271
|
+
// todo: can we support tx here? :thinking:
|
|
272
|
+
|
|
212
273
|
const table = this.cfg.tablesPrefix + q.table
|
|
213
274
|
const rows = queryInMemory(q, Object.values(this.data[table] || {}) as ROW[])
|
|
214
275
|
rows.forEach((row: any) => {
|
|
@@ -248,29 +309,8 @@ export class InMemoryDB implements CommonDB {
|
|
|
248
309
|
return Readable.from(queryInMemory(q, Object.values(this.data[table] || {}) as ROW[]))
|
|
249
310
|
}
|
|
250
311
|
|
|
251
|
-
async
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
for await (const op of tx.ops) {
|
|
256
|
-
if (op.type === 'saveBatch') {
|
|
257
|
-
await this.saveBatch(op.table, op.rows, { ...op.opt, ...opt })
|
|
258
|
-
} else if (op.type === 'deleteByIds') {
|
|
259
|
-
await this.deleteByQuery(DBQuery.create(op.table).filter('id', 'in', op.ids), {
|
|
260
|
-
...op.opt,
|
|
261
|
-
...opt,
|
|
262
|
-
})
|
|
263
|
-
} else {
|
|
264
|
-
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
} catch (err) {
|
|
268
|
-
// rollback
|
|
269
|
-
this.data = backup
|
|
270
|
-
this.cfg.logger!.log('InMemoryDB transaction rolled back')
|
|
271
|
-
|
|
272
|
-
throw err
|
|
273
|
-
}
|
|
312
|
+
async createTransaction(): Promise<DBTransaction> {
|
|
313
|
+
return new InMemoryDBTransaction(this)
|
|
274
314
|
}
|
|
275
315
|
|
|
276
316
|
/**
|
|
@@ -348,3 +388,37 @@ export class InMemoryDB implements CommonDB {
|
|
|
348
388
|
)
|
|
349
389
|
}
|
|
350
390
|
}
|
|
391
|
+
|
|
392
|
+
export class InMemoryDBTransaction implements DBTransaction {
|
|
393
|
+
constructor(private db: InMemoryDB) {}
|
|
394
|
+
|
|
395
|
+
ops: DBOperation[] = []
|
|
396
|
+
|
|
397
|
+
async commit(): Promise<void> {
|
|
398
|
+
const backup = _deepCopy(this.db.data)
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
for (const op of this.ops) {
|
|
402
|
+
if (op.type === 'saveBatch') {
|
|
403
|
+
await this.db.saveBatch(op.table, op.rows, op.opt)
|
|
404
|
+
} else if (op.type === 'deleteByIds') {
|
|
405
|
+
await this.db.deleteByIds(op.table, op.ids, op.opt)
|
|
406
|
+
} else {
|
|
407
|
+
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.ops = []
|
|
412
|
+
} catch (err) {
|
|
413
|
+
// rollback
|
|
414
|
+
this.db.data = backup
|
|
415
|
+
this.db.cfg.logger!.log('InMemoryDB transaction rolled back')
|
|
416
|
+
|
|
417
|
+
throw err
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async rollback(): Promise<void> {
|
|
422
|
+
this.ops = []
|
|
423
|
+
}
|
|
424
|
+
}
|
package/src/base.common.db.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib'
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
3
|
-
import { CommonDB } from './common.db'
|
|
4
|
-
import {
|
|
3
|
+
import { CommonDB, CommonDBSupport, CommonDBType } from './common.db'
|
|
4
|
+
import {
|
|
5
|
+
CommonDBOptions,
|
|
6
|
+
CommonDBSaveOptions,
|
|
7
|
+
DBPatch,
|
|
8
|
+
DBTransaction,
|
|
9
|
+
RunQueryResult,
|
|
10
|
+
} from './db.model'
|
|
5
11
|
import { DBQuery } from './query/dbQuery'
|
|
6
|
-
import {
|
|
12
|
+
import { FakeDBTransaction } from './transaction/dbTransaction.util'
|
|
7
13
|
|
|
8
14
|
/* eslint-disable unused-imports/no-unused-vars */
|
|
9
15
|
|
|
@@ -12,6 +18,10 @@ import { DBTransaction } from './transaction/dbTransaction'
|
|
|
12
18
|
* To be extended by actual implementations.
|
|
13
19
|
*/
|
|
14
20
|
export class BaseCommonDB implements CommonDB {
|
|
21
|
+
dbType = CommonDBType.document
|
|
22
|
+
|
|
23
|
+
support: CommonDBSupport = {}
|
|
24
|
+
|
|
15
25
|
async ping(): Promise<void> {
|
|
16
26
|
throw new Error('ping is not implemented')
|
|
17
27
|
}
|
|
@@ -33,7 +43,7 @@ export class BaseCommonDB implements CommonDB {
|
|
|
33
43
|
// no-op
|
|
34
44
|
}
|
|
35
45
|
|
|
36
|
-
async getByIds<ROW extends ObjectWithId>(table: string, ids:
|
|
46
|
+
async getByIds<ROW extends ObjectWithId>(table: string, ids: string[]): Promise<ROW[]> {
|
|
37
47
|
throw new Error('getByIds is not implemented')
|
|
38
48
|
}
|
|
39
49
|
|
|
@@ -69,12 +79,11 @@ export class BaseCommonDB implements CommonDB {
|
|
|
69
79
|
throw new Error('streamQuery is not implemented')
|
|
70
80
|
}
|
|
71
81
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
throw new Error('commitTransaction is not implemented')
|
|
82
|
+
async deleteByIds(table: string, ids: string[], opt?: CommonDBOptions): Promise<number> {
|
|
83
|
+
throw new Error('deleteByIds is not implemented')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async createTransaction(): Promise<DBTransaction> {
|
|
87
|
+
return new FakeDBTransaction(this)
|
|
79
88
|
}
|
|
80
89
|
}
|
package/src/common.db.ts
CHANGED
|
@@ -6,12 +6,44 @@ import {
|
|
|
6
6
|
CommonDBSaveOptions,
|
|
7
7
|
CommonDBStreamOptions,
|
|
8
8
|
DBPatch,
|
|
9
|
+
DBTransaction,
|
|
9
10
|
RunQueryResult,
|
|
10
11
|
} from './db.model'
|
|
11
12
|
import { DBQuery } from './query/dbQuery'
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
export enum CommonDBType {
|
|
15
|
+
'document' = 'document',
|
|
16
|
+
'relational' = 'relational',
|
|
17
|
+
}
|
|
13
18
|
|
|
14
19
|
export interface CommonDB {
|
|
20
|
+
/**
|
|
21
|
+
* Relational databases are expected to return `null` for all missing properties.
|
|
22
|
+
*/
|
|
23
|
+
dbType: CommonDBType
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Manifest of supported features.
|
|
27
|
+
*/
|
|
28
|
+
support: CommonDBSupport
|
|
29
|
+
|
|
30
|
+
// Support flags indicate which of the CommonDB features are supported by this implementation.
|
|
31
|
+
supportsQueries?: boolean
|
|
32
|
+
supportsDBQueryFilter?: boolean
|
|
33
|
+
supportsDBQueryFilterIn?: boolean
|
|
34
|
+
supportsDBQueryOrder?: boolean
|
|
35
|
+
supportsDBQuerySelectFields?: boolean
|
|
36
|
+
supportsInsertSaveMethod?: boolean
|
|
37
|
+
supportsUpdateSaveMethod?: boolean
|
|
38
|
+
supportsUpdateByQuery?: boolean
|
|
39
|
+
supportsDBIncrement?: boolean
|
|
40
|
+
supportsCreateTable?: boolean
|
|
41
|
+
supportsTableSchemas?: boolean
|
|
42
|
+
supportsStreaming?: boolean
|
|
43
|
+
supportsBufferValues?: boolean
|
|
44
|
+
supportsNullValues?: boolean
|
|
45
|
+
supportsTransactions?: boolean
|
|
46
|
+
|
|
15
47
|
/**
|
|
16
48
|
* Checks that connection/credentials/etc is ok.
|
|
17
49
|
* Also acts as a "warmup request" for a DB.
|
|
@@ -84,6 +116,12 @@ export interface CommonDB {
|
|
|
84
116
|
) => Promise<void>
|
|
85
117
|
|
|
86
118
|
// DELETE
|
|
119
|
+
/**
|
|
120
|
+
* Returns number of deleted items.
|
|
121
|
+
* Not supported by all implementations (e.g Datastore will always return same number as number of ids).
|
|
122
|
+
*/
|
|
123
|
+
deleteByIds: (table: string, ids: string[], opt?: CommonDBOptions) => Promise<number>
|
|
124
|
+
|
|
87
125
|
/**
|
|
88
126
|
* Returns number of deleted items.
|
|
89
127
|
* Not supported by all implementations (e.g Datastore will always return same number as number of ids).
|
|
@@ -122,5 +160,44 @@ export interface CommonDB {
|
|
|
122
160
|
* Should be implemented as a Transaction (best effort), which means that
|
|
123
161
|
* either ALL or NONE of the operations should be applied.
|
|
124
162
|
*/
|
|
125
|
-
|
|
163
|
+
createTransaction: () => Promise<DBTransaction>
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Manifest of supported features.
|
|
168
|
+
*/
|
|
169
|
+
export interface CommonDBSupport {
|
|
170
|
+
queries?: boolean
|
|
171
|
+
dbQueryFilter?: boolean
|
|
172
|
+
dbQueryFilterIn?: boolean
|
|
173
|
+
dbQueryOrder?: boolean
|
|
174
|
+
dbQuerySelectFields?: boolean
|
|
175
|
+
insertSaveMethod?: boolean
|
|
176
|
+
updateSaveMethod?: boolean
|
|
177
|
+
updateByQuery?: boolean
|
|
178
|
+
dbIncrement?: boolean
|
|
179
|
+
createTable?: boolean
|
|
180
|
+
tableSchemas?: boolean
|
|
181
|
+
streaming?: boolean
|
|
182
|
+
bufferValues?: boolean
|
|
183
|
+
nullValues?: boolean
|
|
184
|
+
transactions?: boolean
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export const commonDBFullSupport: CommonDBSupport = {
|
|
188
|
+
queries: true,
|
|
189
|
+
dbQueryFilter: true,
|
|
190
|
+
dbQueryFilterIn: true,
|
|
191
|
+
dbQueryOrder: true,
|
|
192
|
+
dbQuerySelectFields: true,
|
|
193
|
+
insertSaveMethod: true,
|
|
194
|
+
updateSaveMethod: true,
|
|
195
|
+
updateByQuery: true,
|
|
196
|
+
dbIncrement: true,
|
|
197
|
+
createTable: true,
|
|
198
|
+
tableSchemas: true,
|
|
199
|
+
streaming: true,
|
|
200
|
+
bufferValues: true,
|
|
201
|
+
nullValues: true,
|
|
202
|
+
transactions: true,
|
|
126
203
|
}
|
|
@@ -274,17 +274,6 @@ export interface CommonDaoOptions extends CommonDBOptions {
|
|
|
274
274
|
* Useful e.g in AirtableDB where you can have one Dao to control multiple tables.
|
|
275
275
|
*/
|
|
276
276
|
table?: string
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* If passed - operation will not be performed immediately, but instead "added" to the transaction.
|
|
280
|
-
* In the end - transaction needs to be committed (by calling `commit`).
|
|
281
|
-
* This API is inspired by Datastore API.
|
|
282
|
-
*
|
|
283
|
-
* Only applicable to save* and delete* operations
|
|
284
|
-
*
|
|
285
|
-
* @experimental
|
|
286
|
-
*/
|
|
287
|
-
tx?: boolean
|
|
288
277
|
}
|
|
289
278
|
|
|
290
279
|
export interface CommonDaoSaveOptions<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId>
|