@naturalcycles/db-lib 8.60.1 → 9.1.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 +4 -7
- package/dist/adapter/file/file.db.js +102 -56
- package/dist/adapter/inmemory/inMemory.db.d.ts +32 -3
- package/dist/adapter/inmemory/inMemory.db.js +76 -25
- package/dist/base.common.db.d.ts +7 -10
- package/dist/base.common.db.js +13 -7
- package/dist/common.db.d.ts +60 -4
- package/dist/common.db.js +23 -0
- package/dist/commondao/common.dao.d.ts +28 -9
- package/dist/commondao/common.dao.js +72 -71
- package/dist/commondao/common.dao.model.d.ts +0 -10
- package/dist/db.model.d.ts +29 -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 +41 -50
- package/dist/testing/index.d.ts +2 -2
- package/dist/timeseries/commonTimeSeriesDao.js +9 -10
- package/dist/transaction/dbTransaction.util.d.ts +14 -4
- package/dist/transaction/dbTransaction.util.js +49 -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 +120 -74
- package/src/adapter/inmemory/inMemory.db.ts +101 -24
- package/src/base.common.db.ts +22 -11
- package/src/common.db.ts +84 -3
- package/src/commondao/common.dao.model.ts +0 -11
- package/src/commondao/common.dao.ts +102 -91
- package/src/db.model.ts +34 -2
- package/src/index.ts +0 -1
- package/src/testing/daoTest.ts +32 -52
- package/src/testing/dbTest.ts +43 -120
- package/src/testing/index.ts +2 -12
- package/src/timeseries/commonTimeSeriesDao.ts +9 -12
- package/src/transaction/dbTransaction.util.ts +61 -23
- 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
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateJsonSchemaFromData,
|
|
3
|
-
pMap,
|
|
4
|
-
StringMap,
|
|
5
3
|
_by,
|
|
6
4
|
_deepEquals,
|
|
7
5
|
_since,
|
|
8
6
|
_sortBy,
|
|
9
7
|
_sortObjectDeep,
|
|
10
8
|
_stringMapValues,
|
|
11
|
-
_uniq,
|
|
12
9
|
JsonSchemaRootObject,
|
|
13
10
|
_filterUndefinedValues,
|
|
14
11
|
ObjectWithId,
|
|
15
12
|
_assert,
|
|
16
|
-
_deepCopy,
|
|
17
|
-
_stringMapEntries,
|
|
18
13
|
Saved,
|
|
19
14
|
} from '@naturalcycles/js-lib'
|
|
20
15
|
import { readableCreate, ReadableTyped, dimGrey } from '@naturalcycles/nodejs-lib'
|
|
21
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
BaseCommonDB,
|
|
18
|
+
commonDBFullSupport,
|
|
19
|
+
CommonDBSupport,
|
|
20
|
+
DBSaveBatchOperation,
|
|
21
|
+
queryInMemory,
|
|
22
|
+
} from '../..'
|
|
22
23
|
import { CommonDB } from '../../common.db'
|
|
23
24
|
import {
|
|
24
25
|
CommonDBOptions,
|
|
@@ -27,7 +28,6 @@ import {
|
|
|
27
28
|
RunQueryResult,
|
|
28
29
|
} from '../../db.model'
|
|
29
30
|
import { DBQuery } from '../../query/dbQuery'
|
|
30
|
-
import { DBTransaction } from '../../transaction/dbTransaction'
|
|
31
31
|
import { FileDBCfg } from './file.db.model'
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -41,6 +41,16 @@ import { FileDBCfg } from './file.db.model'
|
|
|
41
41
|
* Each save operation saves *whole* file to the persistence layer.
|
|
42
42
|
*/
|
|
43
43
|
export class FileDB extends BaseCommonDB implements CommonDB {
|
|
44
|
+
override support: CommonDBSupport = {
|
|
45
|
+
...commonDBFullSupport,
|
|
46
|
+
bufferValues: false, // todo: implement
|
|
47
|
+
insertSaveMethod: false,
|
|
48
|
+
updateSaveMethod: false,
|
|
49
|
+
updateByQuery: false,
|
|
50
|
+
createTable: false,
|
|
51
|
+
transactions: false, // todo
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
constructor(cfg: FileDBCfg) {
|
|
45
55
|
super()
|
|
46
56
|
this.cfg = {
|
|
@@ -101,72 +111,6 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
113
|
|
|
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
114
|
override async runQuery<ROW extends ObjectWithId>(
|
|
171
115
|
q: DBQuery<ROW>,
|
|
172
116
|
_opt?: CommonDBOptions,
|
|
@@ -216,6 +160,27 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
216
160
|
return deleted
|
|
217
161
|
}
|
|
218
162
|
|
|
163
|
+
override async deleteByIds(
|
|
164
|
+
table: string,
|
|
165
|
+
ids: string[],
|
|
166
|
+
_opt?: CommonDBOptions,
|
|
167
|
+
): Promise<number> {
|
|
168
|
+
const byId = _by(await this.loadFile(table), r => r.id)
|
|
169
|
+
|
|
170
|
+
let deleted = 0
|
|
171
|
+
ids.forEach(id => {
|
|
172
|
+
if (!byId[id]) return
|
|
173
|
+
delete byId[id]
|
|
174
|
+
deleted++
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
if (deleted > 0) {
|
|
178
|
+
await this.saveFile(table, _stringMapValues(byId))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return deleted
|
|
182
|
+
}
|
|
183
|
+
|
|
219
184
|
override async getTableSchema<ROW extends ObjectWithId>(
|
|
220
185
|
table: string,
|
|
221
186
|
): Promise<JsonSchemaRootObject<ROW>> {
|
|
@@ -256,7 +221,11 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
256
221
|
this.logFinished(started, op)
|
|
257
222
|
}
|
|
258
223
|
|
|
259
|
-
|
|
224
|
+
// override async createTransaction(): Promise<FileDBTransaction> {
|
|
225
|
+
// return new FileDBTransaction(this)
|
|
226
|
+
// }
|
|
227
|
+
|
|
228
|
+
sortRows<ROW extends ObjectWithId>(rows: ROW[]): ROW[] {
|
|
260
229
|
rows = rows.map(r => _filterUndefinedValues(r))
|
|
261
230
|
|
|
262
231
|
if (this.cfg.sortOnSave) {
|
|
@@ -283,3 +252,80 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
283
252
|
this.cfg.logger?.log(`<< ${op} ${dimGrey(`in ${_since(started)}`)}`)
|
|
284
253
|
}
|
|
285
254
|
}
|
|
255
|
+
|
|
256
|
+
// todo: get back and fix it
|
|
257
|
+
// Implementation is optimized for loading/saving _whole files_.
|
|
258
|
+
/*
|
|
259
|
+
export class FileDBTransaction implements DBTransaction {
|
|
260
|
+
constructor(private db: FileDB) {}
|
|
261
|
+
|
|
262
|
+
ops: DBOperation[] = []
|
|
263
|
+
|
|
264
|
+
async commit(): Promise<void> {
|
|
265
|
+
// data[table][id] => row
|
|
266
|
+
const data: StringMap<StringMap<ObjectWithId>> = {}
|
|
267
|
+
|
|
268
|
+
// 1. Load all tables data (concurrently)
|
|
269
|
+
const tables = _uniq(this.ops.map(o => o.table))
|
|
270
|
+
|
|
271
|
+
await pMap(
|
|
272
|
+
tables,
|
|
273
|
+
async table => {
|
|
274
|
+
const rows = await this.db.loadFile(table)
|
|
275
|
+
data[table] = _by(rows, r => r.id)
|
|
276
|
+
},
|
|
277
|
+
{ concurrency: 16 },
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
const backup = _deepCopy(data)
|
|
281
|
+
|
|
282
|
+
// 2. Apply ops one by one (in order)
|
|
283
|
+
this.ops.forEach(op => {
|
|
284
|
+
if (op.type === 'deleteByIds') {
|
|
285
|
+
op.ids.forEach(id => delete data[op.table]![id])
|
|
286
|
+
} else if (op.type === 'saveBatch') {
|
|
287
|
+
op.rows.forEach(r => {
|
|
288
|
+
if (!r.id) {
|
|
289
|
+
throw new Error('FileDB: row has an empty id')
|
|
290
|
+
}
|
|
291
|
+
data[op.table]![r.id] = r
|
|
292
|
+
})
|
|
293
|
+
} else {
|
|
294
|
+
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
295
|
+
}
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
// 3. Sort, turn it into ops
|
|
299
|
+
// Not filtering empty arrays, cause it's already filtered in this.saveFiles()
|
|
300
|
+
const ops: DBSaveBatchOperation[] = _stringMapEntries(data).map(([table, map]) => {
|
|
301
|
+
return {
|
|
302
|
+
type: 'saveBatch',
|
|
303
|
+
table,
|
|
304
|
+
rows: this.db.sortRows(_stringMapValues(map)),
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// 4. Save all files
|
|
309
|
+
try {
|
|
310
|
+
await this.db.saveFiles(ops)
|
|
311
|
+
} catch (err) {
|
|
312
|
+
const ops: DBSaveBatchOperation[] = _stringMapEntries(backup).map(([table, map]) => {
|
|
313
|
+
return {
|
|
314
|
+
type: 'saveBatch',
|
|
315
|
+
table,
|
|
316
|
+
rows: this.db.sortRows(_stringMapValues(map)),
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
// Rollback, ignore rollback error (if any)
|
|
321
|
+
await this.db.saveFiles(ops).catch(_ => {})
|
|
322
|
+
|
|
323
|
+
throw err
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async rollback(): Promise<void> {
|
|
328
|
+
this.ops = []
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
*/
|
|
@@ -29,11 +29,21 @@ import {
|
|
|
29
29
|
yellow,
|
|
30
30
|
fs2,
|
|
31
31
|
} from '@naturalcycles/nodejs-lib'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
CommonDB,
|
|
34
|
+
commonDBFullSupport,
|
|
35
|
+
CommonDBType,
|
|
36
|
+
DBIncrement,
|
|
37
|
+
DBOperation,
|
|
38
|
+
DBPatch,
|
|
39
|
+
DBTransactionFn,
|
|
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
|
|
@@ -192,13 +208,22 @@ export class InMemoryDB implements CommonDB {
|
|
|
192
208
|
_opt?: CommonDBOptions,
|
|
193
209
|
): Promise<number> {
|
|
194
210
|
const table = this.cfg.tablesPrefix + q.table
|
|
195
|
-
this.data[table]
|
|
211
|
+
if (!this.data[table]) return 0
|
|
212
|
+
const ids = queryInMemory(q, Object.values(this.data[table]!) as ROW[]).map(r => r.id)
|
|
213
|
+
return await this.deleteByIds(q.table, ids)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async deleteByIds(_table: string, ids: string[], _opt?: CommonDBOptions): Promise<number> {
|
|
217
|
+
const table = this.cfg.tablesPrefix + _table
|
|
218
|
+
if (!this.data[table]) return 0
|
|
219
|
+
|
|
196
220
|
let count = 0
|
|
197
|
-
|
|
198
|
-
if (!this.data[table]![
|
|
199
|
-
delete this.data[table]![
|
|
221
|
+
ids.forEach(id => {
|
|
222
|
+
if (!this.data[table]![id]) return
|
|
223
|
+
delete this.data[table]![id]
|
|
200
224
|
count++
|
|
201
225
|
})
|
|
226
|
+
|
|
202
227
|
return count
|
|
203
228
|
}
|
|
204
229
|
|
|
@@ -248,27 +273,13 @@ export class InMemoryDB implements CommonDB {
|
|
|
248
273
|
return Readable.from(queryInMemory(q, Object.values(this.data[table] || {}) as ROW[]))
|
|
249
274
|
}
|
|
250
275
|
|
|
251
|
-
async
|
|
252
|
-
const
|
|
253
|
-
|
|
276
|
+
async runInTransaction(fn: DBTransactionFn): Promise<void> {
|
|
277
|
+
const tx = new InMemoryDBTransaction(this)
|
|
254
278
|
try {
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
}
|
|
279
|
+
await fn(tx)
|
|
280
|
+
await tx.commit()
|
|
267
281
|
} catch (err) {
|
|
268
|
-
|
|
269
|
-
this.data = backup
|
|
270
|
-
this.cfg.logger!.log('InMemoryDB transaction rolled back')
|
|
271
|
-
|
|
282
|
+
await tx.rollback()
|
|
272
283
|
throw err
|
|
273
284
|
}
|
|
274
285
|
}
|
|
@@ -348,3 +359,69 @@ export class InMemoryDB implements CommonDB {
|
|
|
348
359
|
)
|
|
349
360
|
}
|
|
350
361
|
}
|
|
362
|
+
|
|
363
|
+
export class InMemoryDBTransaction implements DBTransaction {
|
|
364
|
+
constructor(private db: InMemoryDB) {}
|
|
365
|
+
|
|
366
|
+
ops: DBOperation[] = []
|
|
367
|
+
|
|
368
|
+
async getByIds<ROW extends ObjectWithId>(
|
|
369
|
+
table: string,
|
|
370
|
+
ids: string[],
|
|
371
|
+
opt?: CommonDBOptions,
|
|
372
|
+
): Promise<ROW[]> {
|
|
373
|
+
return await this.db.getByIds(table, ids, opt)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async saveBatch<ROW extends Partial<ObjectWithId>>(
|
|
377
|
+
table: string,
|
|
378
|
+
rows: ROW[],
|
|
379
|
+
opt?: CommonDBSaveOptions<ROW>,
|
|
380
|
+
): Promise<void> {
|
|
381
|
+
this.ops.push({
|
|
382
|
+
type: 'saveBatch',
|
|
383
|
+
table,
|
|
384
|
+
rows,
|
|
385
|
+
opt,
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async deleteByIds(table: string, ids: string[], opt?: CommonDBOptions): Promise<number> {
|
|
390
|
+
this.ops.push({
|
|
391
|
+
type: 'deleteByIds',
|
|
392
|
+
table,
|
|
393
|
+
ids,
|
|
394
|
+
opt,
|
|
395
|
+
})
|
|
396
|
+
return ids.length
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async commit(): Promise<void> {
|
|
400
|
+
const backup = _deepCopy(this.db.data)
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
for (const op of this.ops) {
|
|
404
|
+
if (op.type === 'saveBatch') {
|
|
405
|
+
await this.db.saveBatch(op.table, op.rows, op.opt)
|
|
406
|
+
} else if (op.type === 'deleteByIds') {
|
|
407
|
+
await this.db.deleteByIds(op.table, op.ids, op.opt)
|
|
408
|
+
} else {
|
|
409
|
+
throw new Error(`DBOperation not supported: ${(op as any).type}`)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
this.ops = []
|
|
414
|
+
} catch (err) {
|
|
415
|
+
// rollback
|
|
416
|
+
this.ops = []
|
|
417
|
+
this.db.data = backup
|
|
418
|
+
this.db.cfg.logger!.log('InMemoryDB transaction rolled back')
|
|
419
|
+
|
|
420
|
+
throw err
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async rollback(): Promise<void> {
|
|
425
|
+
this.ops = []
|
|
426
|
+
}
|
|
427
|
+
}
|
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
|
+
DBTransactionFn,
|
|
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,13 @@ 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
|
-
|
|
82
|
+
async deleteByIds(table: string, ids: string[], opt?: CommonDBOptions): Promise<number> {
|
|
83
|
+
throw new Error('deleteByIds is not implemented')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async runInTransaction(fn: DBTransactionFn): Promise<void> {
|
|
87
|
+
const tx = new FakeDBTransaction(this)
|
|
88
|
+
await fn(tx)
|
|
89
|
+
// there's no try/catch and rollback, as there's nothing to rollback
|
|
79
90
|
}
|
|
80
91
|
}
|
package/src/common.db.ts
CHANGED
|
@@ -1,17 +1,49 @@
|
|
|
1
1
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib'
|
|
2
|
-
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
2
|
+
import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
3
3
|
import {
|
|
4
4
|
CommonDBCreateOptions,
|
|
5
5
|
CommonDBOptions,
|
|
6
6
|
CommonDBSaveOptions,
|
|
7
7
|
CommonDBStreamOptions,
|
|
8
8
|
DBPatch,
|
|
9
|
+
DBTransactionFn,
|
|
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).
|
|
@@ -121,6 +159,49 @@ export interface CommonDB {
|
|
|
121
159
|
/**
|
|
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.
|
|
162
|
+
*
|
|
163
|
+
* Transaction is automatically committed if fn resolves normally.
|
|
164
|
+
* Transaction is rolled back if fn throws, the error is re-thrown in that case.
|
|
165
|
+
* Graceful rollback is allowed on tx.rollback()
|
|
124
166
|
*/
|
|
125
|
-
|
|
167
|
+
runInTransaction: (fn: DBTransactionFn) => Promise<void>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Manifest of supported features.
|
|
172
|
+
*/
|
|
173
|
+
export interface CommonDBSupport {
|
|
174
|
+
queries?: boolean
|
|
175
|
+
dbQueryFilter?: boolean
|
|
176
|
+
dbQueryFilterIn?: boolean
|
|
177
|
+
dbQueryOrder?: boolean
|
|
178
|
+
dbQuerySelectFields?: boolean
|
|
179
|
+
insertSaveMethod?: boolean
|
|
180
|
+
updateSaveMethod?: boolean
|
|
181
|
+
updateByQuery?: boolean
|
|
182
|
+
dbIncrement?: boolean
|
|
183
|
+
createTable?: boolean
|
|
184
|
+
tableSchemas?: boolean
|
|
185
|
+
streaming?: boolean
|
|
186
|
+
bufferValues?: boolean
|
|
187
|
+
nullValues?: boolean
|
|
188
|
+
transactions?: boolean
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const commonDBFullSupport: CommonDBSupport = {
|
|
192
|
+
queries: true,
|
|
193
|
+
dbQueryFilter: true,
|
|
194
|
+
dbQueryFilterIn: true,
|
|
195
|
+
dbQueryOrder: true,
|
|
196
|
+
dbQuerySelectFields: true,
|
|
197
|
+
insertSaveMethod: true,
|
|
198
|
+
updateSaveMethod: true,
|
|
199
|
+
updateByQuery: true,
|
|
200
|
+
dbIncrement: true,
|
|
201
|
+
createTable: true,
|
|
202
|
+
tableSchemas: true,
|
|
203
|
+
streaming: true,
|
|
204
|
+
bufferValues: true,
|
|
205
|
+
nullValues: true,
|
|
206
|
+
transactions: true,
|
|
126
207
|
}
|
|
@@ -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>
|