@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
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
3
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
4
|
import { BaseCommonDB } from '../../base.common.db';
|
|
5
|
-
import { CommonDB } from '../../common.db';
|
|
6
|
-
import {
|
|
5
|
+
import { CommonDB, CommonDBSupport } from '../../common.db';
|
|
6
|
+
import { DBPatch, RunQueryResult } from '../../db.model';
|
|
7
7
|
import { DBQuery } from '../../query/dbQuery';
|
|
8
|
-
import { DBTransaction } from '../../transaction/dbTransaction';
|
|
9
8
|
import { CacheDBCfg, CacheDBCreateOptions, CacheDBOptions, CacheDBSaveOptions, CacheDBStreamOptions } from './cache.db.model';
|
|
10
9
|
/**
|
|
11
10
|
* CommonDB implementation that proxies requests to downstream CommonDB
|
|
@@ -14,6 +13,7 @@ import { CacheDBCfg, CacheDBCreateOptions, CacheDBOptions, CacheDBSaveOptions, C
|
|
|
14
13
|
* Queries always hit downstream (unless `onlyCache` is passed)
|
|
15
14
|
*/
|
|
16
15
|
export declare class CacheDB extends BaseCommonDB implements CommonDB {
|
|
16
|
+
support: CommonDBSupport;
|
|
17
17
|
constructor(cfg: CacheDBCfg);
|
|
18
18
|
cfg: CacheDBCfg;
|
|
19
19
|
ping(): Promise<void>;
|
|
@@ -30,5 +30,4 @@ export declare class CacheDB extends BaseCommonDB implements CommonDB {
|
|
|
30
30
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBStreamOptions): Readable;
|
|
31
31
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
32
32
|
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
33
|
-
commitTransaction(tx: DBTransaction, opt?: CommonDBOptions): Promise<void>;
|
|
34
33
|
}
|
|
@@ -4,6 +4,7 @@ exports.CacheDB = void 0;
|
|
|
4
4
|
const node_stream_1 = require("node:stream");
|
|
5
5
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
6
|
const base_common_db_1 = require("../../base.common.db");
|
|
7
|
+
const common_db_1 = require("../../common.db");
|
|
7
8
|
/**
|
|
8
9
|
* CommonDB implementation that proxies requests to downstream CommonDB
|
|
9
10
|
* and does in-memory caching.
|
|
@@ -13,6 +14,10 @@ const base_common_db_1 = require("../../base.common.db");
|
|
|
13
14
|
class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
14
15
|
constructor(cfg) {
|
|
15
16
|
super();
|
|
17
|
+
this.support = {
|
|
18
|
+
...common_db_1.commonDBFullSupport,
|
|
19
|
+
transactions: false,
|
|
20
|
+
};
|
|
16
21
|
this.cfg = {
|
|
17
22
|
logger: console,
|
|
18
23
|
...cfg,
|
|
@@ -187,9 +192,5 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
|
187
192
|
}
|
|
188
193
|
return updated || 0;
|
|
189
194
|
}
|
|
190
|
-
async commitTransaction(tx, opt) {
|
|
191
|
-
await this.cfg.downstreamDB.commitTransaction(tx, opt);
|
|
192
|
-
await this.cfg.cacheDB.commitTransaction(tx, opt);
|
|
193
|
-
}
|
|
194
195
|
}
|
|
195
196
|
exports.CacheDB = CacheDB;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommonLogger, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import { CommonDB } from '../../common.db';
|
|
3
|
-
import { CommonDBCreateOptions, CommonDBSaveOptions, CommonDBStreamOptions } from '../../db.model';
|
|
3
|
+
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions } from '../../db.model';
|
|
4
4
|
export interface CacheDBCfg {
|
|
5
5
|
name: string;
|
|
6
6
|
cacheDB: CommonDB;
|
|
@@ -37,7 +37,7 @@ export interface CacheDBCfg {
|
|
|
37
37
|
*/
|
|
38
38
|
logger?: CommonLogger;
|
|
39
39
|
}
|
|
40
|
-
export interface CacheDBOptions {
|
|
40
|
+
export interface CacheDBOptions extends CommonDBOptions {
|
|
41
41
|
/**
|
|
42
42
|
* @default false
|
|
43
43
|
*/
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { BaseCommonDB, DBSaveBatchOperation } from '../..';
|
|
3
|
+
import { BaseCommonDB, CommonDBSupport, DBOperation, DBSaveBatchOperation, DBTransaction } from '../..';
|
|
4
4
|
import { CommonDB } from '../../common.db';
|
|
5
5
|
import { CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, RunQueryResult } from '../../db.model';
|
|
6
6
|
import { DBQuery } from '../../query/dbQuery';
|
|
7
|
-
import { DBTransaction } from '../../transaction/dbTransaction';
|
|
8
7
|
import { FileDBCfg } from './file.db.model';
|
|
9
8
|
/**
|
|
10
9
|
* Provides barebone implementation for "whole file" based CommonDB.
|
|
@@ -17,25 +16,34 @@ import { FileDBCfg } from './file.db.model';
|
|
|
17
16
|
* Each save operation saves *whole* file to the persistence layer.
|
|
18
17
|
*/
|
|
19
18
|
export declare class FileDB extends BaseCommonDB implements CommonDB {
|
|
19
|
+
support: CommonDBSupport;
|
|
20
20
|
constructor(cfg: FileDBCfg);
|
|
21
21
|
cfg: FileDBCfg;
|
|
22
22
|
ping(): Promise<void>;
|
|
23
23
|
getTables(): Promise<string[]>;
|
|
24
24
|
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<ROW[]>;
|
|
25
25
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Implementation is optimized for loading/saving _whole files_.
|
|
28
|
-
*/
|
|
29
|
-
commitTransaction(tx: DBTransaction, _opt?: CommonDBOptions): Promise<void>;
|
|
30
26
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
31
27
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
32
28
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions): ReadableTyped<ROW>;
|
|
33
29
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
30
|
+
deleteByIds(table: string, ids: string[], _opt?: CommonDBOptions): Promise<number>;
|
|
34
31
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
35
32
|
loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]>;
|
|
36
33
|
saveFile<ROW extends ObjectWithId>(table: string, _rows: ROW[]): Promise<void>;
|
|
37
34
|
saveFiles<ROW extends ObjectWithId>(ops: DBSaveBatchOperation<ROW>[]): Promise<void>;
|
|
38
|
-
|
|
35
|
+
createTransaction(): Promise<FileDBTransaction>;
|
|
36
|
+
sortRows<ROW extends ObjectWithId>(rows: ROW[]): ROW[];
|
|
39
37
|
private logStarted;
|
|
40
38
|
private logFinished;
|
|
41
39
|
}
|
|
40
|
+
export declare class FileDBTransaction implements DBTransaction {
|
|
41
|
+
private db;
|
|
42
|
+
constructor(db: FileDB);
|
|
43
|
+
ops: DBOperation[];
|
|
44
|
+
/**
|
|
45
|
+
* Implementation is optimized for loading/saving _whole files_.
|
|
46
|
+
*/
|
|
47
|
+
commit(): Promise<void>;
|
|
48
|
+
rollback(): Promise<void>;
|
|
49
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FileDB = void 0;
|
|
3
|
+
exports.FileDBTransaction = exports.FileDB = void 0;
|
|
4
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
5
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
6
6
|
const __1 = require("../..");
|
|
@@ -17,6 +17,15 @@ const __1 = require("../..");
|
|
|
17
17
|
class FileDB extends __1.BaseCommonDB {
|
|
18
18
|
constructor(cfg) {
|
|
19
19
|
super();
|
|
20
|
+
this.support = {
|
|
21
|
+
...__1.commonDBFullSupport,
|
|
22
|
+
bufferValues: false, // todo: implement
|
|
23
|
+
insertSaveMethod: false,
|
|
24
|
+
updateSaveMethod: false,
|
|
25
|
+
updateByQuery: false,
|
|
26
|
+
createTable: false,
|
|
27
|
+
transactions: false,
|
|
28
|
+
};
|
|
20
29
|
this.cfg = {
|
|
21
30
|
sortObjects: true,
|
|
22
31
|
logFinished: true,
|
|
@@ -57,62 +66,6 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
57
66
|
await this.saveFile(table, (0, js_lib_1._stringMapValues)(byId));
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Implementation is optimized for loading/saving _whole files_.
|
|
62
|
-
*/
|
|
63
|
-
async commitTransaction(tx, _opt) {
|
|
64
|
-
// data[table][id] => row
|
|
65
|
-
const data = {};
|
|
66
|
-
// 1. Load all tables data (concurrently)
|
|
67
|
-
const tables = (0, js_lib_1._uniq)(tx.ops.map(o => o.table));
|
|
68
|
-
await (0, js_lib_1.pMap)(tables, async (table) => {
|
|
69
|
-
const rows = await this.loadFile(table);
|
|
70
|
-
data[table] = (0, js_lib_1._by)(rows, r => r.id);
|
|
71
|
-
}, { concurrency: 16 });
|
|
72
|
-
const backup = (0, js_lib_1._deepCopy)(data);
|
|
73
|
-
// 2. Apply ops one by one (in order)
|
|
74
|
-
tx.ops.forEach(op => {
|
|
75
|
-
if (op.type === 'deleteByIds') {
|
|
76
|
-
op.ids.forEach(id => delete data[op.table][id]);
|
|
77
|
-
}
|
|
78
|
-
else if (op.type === 'saveBatch') {
|
|
79
|
-
op.rows.forEach(r => {
|
|
80
|
-
if (!r.id) {
|
|
81
|
-
throw new Error('FileDB: row has an empty id');
|
|
82
|
-
}
|
|
83
|
-
data[op.table][r.id] = r;
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
// 3. Sort, turn it into ops
|
|
91
|
-
// Not filtering empty arrays, cause it's already filtered in this.saveFiles()
|
|
92
|
-
const ops = (0, js_lib_1._stringMapEntries)(data).map(([table, map]) => {
|
|
93
|
-
return {
|
|
94
|
-
type: 'saveBatch',
|
|
95
|
-
table,
|
|
96
|
-
rows: this.sortRows((0, js_lib_1._stringMapValues)(map)),
|
|
97
|
-
};
|
|
98
|
-
});
|
|
99
|
-
// 4. Save all files
|
|
100
|
-
try {
|
|
101
|
-
await this.saveFiles(ops);
|
|
102
|
-
}
|
|
103
|
-
catch (err) {
|
|
104
|
-
const ops = (0, js_lib_1._stringMapEntries)(backup).map(([table, map]) => {
|
|
105
|
-
return {
|
|
106
|
-
type: 'saveBatch',
|
|
107
|
-
table,
|
|
108
|
-
rows: this.sortRows((0, js_lib_1._stringMapValues)(map)),
|
|
109
|
-
};
|
|
110
|
-
});
|
|
111
|
-
// Rollback, ignore rollback error (if any)
|
|
112
|
-
await this.saveFiles(ops).catch(_ => { });
|
|
113
|
-
throw err;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
69
|
async runQuery(q, _opt) {
|
|
117
70
|
return {
|
|
118
71
|
rows: (0, __1.queryInMemory)(q, await this.loadFile(q.table)),
|
|
@@ -141,6 +94,20 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
141
94
|
}
|
|
142
95
|
return deleted;
|
|
143
96
|
}
|
|
97
|
+
async deleteByIds(table, ids, _opt) {
|
|
98
|
+
const byId = (0, js_lib_1._by)(await this.loadFile(table), r => r.id);
|
|
99
|
+
let deleted = 0;
|
|
100
|
+
ids.forEach(id => {
|
|
101
|
+
if (!byId[id])
|
|
102
|
+
return;
|
|
103
|
+
delete byId[id];
|
|
104
|
+
deleted++;
|
|
105
|
+
});
|
|
106
|
+
if (deleted > 0) {
|
|
107
|
+
await this.saveFile(table, (0, js_lib_1._stringMapValues)(byId));
|
|
108
|
+
}
|
|
109
|
+
return deleted;
|
|
110
|
+
}
|
|
144
111
|
async getTableSchema(table) {
|
|
145
112
|
const rows = await this.loadFile(table);
|
|
146
113
|
return {
|
|
@@ -173,6 +140,9 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
173
140
|
await this.cfg.plugin.saveFiles(ops);
|
|
174
141
|
this.logFinished(started, op);
|
|
175
142
|
}
|
|
143
|
+
async createTransaction() {
|
|
144
|
+
return new FileDBTransaction(this);
|
|
145
|
+
}
|
|
176
146
|
sortRows(rows) {
|
|
177
147
|
rows = rows.map(r => (0, js_lib_1._filterUndefinedValues)(r));
|
|
178
148
|
if (this.cfg.sortOnSave) {
|
|
@@ -198,3 +168,69 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
198
168
|
}
|
|
199
169
|
}
|
|
200
170
|
exports.FileDB = FileDB;
|
|
171
|
+
class FileDBTransaction {
|
|
172
|
+
constructor(db) {
|
|
173
|
+
this.db = db;
|
|
174
|
+
this.ops = [];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Implementation is optimized for loading/saving _whole files_.
|
|
178
|
+
*/
|
|
179
|
+
async commit() {
|
|
180
|
+
// data[table][id] => row
|
|
181
|
+
const data = {};
|
|
182
|
+
// 1. Load all tables data (concurrently)
|
|
183
|
+
const tables = (0, js_lib_1._uniq)(this.ops.map(o => o.table));
|
|
184
|
+
await (0, js_lib_1.pMap)(tables, async (table) => {
|
|
185
|
+
const rows = await this.db.loadFile(table);
|
|
186
|
+
data[table] = (0, js_lib_1._by)(rows, r => r.id);
|
|
187
|
+
}, { concurrency: 16 });
|
|
188
|
+
const backup = (0, js_lib_1._deepCopy)(data);
|
|
189
|
+
// 2. Apply ops one by one (in order)
|
|
190
|
+
this.ops.forEach(op => {
|
|
191
|
+
if (op.type === 'deleteByIds') {
|
|
192
|
+
op.ids.forEach(id => delete data[op.table][id]);
|
|
193
|
+
}
|
|
194
|
+
else if (op.type === 'saveBatch') {
|
|
195
|
+
op.rows.forEach(r => {
|
|
196
|
+
if (!r.id) {
|
|
197
|
+
throw new Error('FileDB: row has an empty id');
|
|
198
|
+
}
|
|
199
|
+
data[op.table][r.id] = r;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
// 3. Sort, turn it into ops
|
|
207
|
+
// Not filtering empty arrays, cause it's already filtered in this.saveFiles()
|
|
208
|
+
const ops = (0, js_lib_1._stringMapEntries)(data).map(([table, map]) => {
|
|
209
|
+
return {
|
|
210
|
+
type: 'saveBatch',
|
|
211
|
+
table,
|
|
212
|
+
rows: this.db.sortRows((0, js_lib_1._stringMapValues)(map)),
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
// 4. Save all files
|
|
216
|
+
try {
|
|
217
|
+
await this.db.saveFiles(ops);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
const ops = (0, js_lib_1._stringMapEntries)(backup).map(([table, map]) => {
|
|
221
|
+
return {
|
|
222
|
+
type: 'saveBatch',
|
|
223
|
+
table,
|
|
224
|
+
rows: this.db.sortRows((0, js_lib_1._stringMapValues)(map)),
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
// Rollback, ignore rollback error (if any)
|
|
228
|
+
await this.db.saveFiles(ops).catch(_ => { });
|
|
229
|
+
throw err;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async rollback() {
|
|
233
|
+
this.ops = [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
exports.FileDBTransaction = FileDBTransaction;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JsonSchemaObject, StringMap, JsonSchemaRootObject, ObjectWithId, CommonLogger } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDB,
|
|
4
|
-
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, RunQueryResult } from '../../db.model';
|
|
3
|
+
import { CommonDB, CommonDBType, DBOperation, DBPatch } from '../..';
|
|
4
|
+
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, DBTransaction, RunQueryResult } from '../../db.model';
|
|
5
5
|
import { DBQuery } from '../../query/dbQuery';
|
|
6
6
|
export interface InMemoryDBCfg {
|
|
7
7
|
/**
|
|
@@ -36,6 +36,24 @@ export interface InMemoryDBCfg {
|
|
|
36
36
|
logger?: CommonLogger;
|
|
37
37
|
}
|
|
38
38
|
export declare class InMemoryDB implements CommonDB {
|
|
39
|
+
dbType: CommonDBType;
|
|
40
|
+
support: {
|
|
41
|
+
queries?: boolean | undefined;
|
|
42
|
+
dbQueryFilter?: boolean | undefined;
|
|
43
|
+
dbQueryFilterIn?: boolean | undefined;
|
|
44
|
+
dbQueryOrder?: boolean | undefined;
|
|
45
|
+
dbQuerySelectFields?: boolean | undefined;
|
|
46
|
+
insertSaveMethod?: boolean | undefined;
|
|
47
|
+
updateSaveMethod?: boolean | undefined;
|
|
48
|
+
updateByQuery?: boolean | undefined;
|
|
49
|
+
dbIncrement?: boolean | undefined;
|
|
50
|
+
createTable?: boolean | undefined;
|
|
51
|
+
tableSchemas?: boolean | undefined;
|
|
52
|
+
streaming?: boolean | undefined;
|
|
53
|
+
bufferValues?: boolean | undefined;
|
|
54
|
+
nullValues?: boolean | undefined;
|
|
55
|
+
transactions?: boolean | undefined;
|
|
56
|
+
};
|
|
39
57
|
constructor(cfg?: Partial<InMemoryDBCfg>);
|
|
40
58
|
cfg: InMemoryDBCfg;
|
|
41
59
|
data: StringMap<StringMap<ObjectWithId>>;
|
|
@@ -54,12 +72,13 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
54
72
|
createTable<ROW extends ObjectWithId>(_table: string, _schema: JsonSchemaObject<ROW>, opt?: CommonDBCreateOptions): Promise<void>;
|
|
55
73
|
getByIds<ROW extends ObjectWithId>(_table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<ROW[]>;
|
|
56
74
|
saveBatch<ROW extends Partial<ObjectWithId>>(_table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
57
|
-
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>,
|
|
75
|
+
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
76
|
+
deleteByIds(_table: string, ids: string[], opt?: CommonDBOptions): Promise<number>;
|
|
58
77
|
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>): Promise<number>;
|
|
59
78
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
60
79
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
61
80
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): ReadableTyped<ROW>;
|
|
62
|
-
|
|
81
|
+
createTransaction(): Promise<DBTransaction>;
|
|
63
82
|
/**
|
|
64
83
|
* Flushes all tables (all namespaces) at once.
|
|
65
84
|
*/
|
|
@@ -69,3 +88,10 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
69
88
|
*/
|
|
70
89
|
restoreFromDisk(): Promise<void>;
|
|
71
90
|
}
|
|
91
|
+
export declare class InMemoryDBTransaction implements DBTransaction {
|
|
92
|
+
private db;
|
|
93
|
+
constructor(db: InMemoryDB);
|
|
94
|
+
ops: DBOperation[];
|
|
95
|
+
commit(): Promise<void>;
|
|
96
|
+
rollback(): Promise<void>;
|
|
97
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InMemoryDB = void 0;
|
|
3
|
+
exports.InMemoryDBTransaction = exports.InMemoryDB = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
6
|
const promises_1 = tslib_1.__importDefault(require("node:fs/promises"));
|
|
@@ -9,9 +9,12 @@ const node_zlib_1 = require("node:zlib");
|
|
|
9
9
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
10
10
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
11
11
|
const __1 = require("../..");
|
|
12
|
-
const dbQuery_1 = require("../../query/dbQuery");
|
|
13
12
|
class InMemoryDB {
|
|
14
13
|
constructor(cfg) {
|
|
14
|
+
this.dbType = __1.CommonDBType.document;
|
|
15
|
+
this.support = {
|
|
16
|
+
...__1.commonDBFullSupport,
|
|
17
|
+
};
|
|
15
18
|
// data[table][id] > {id: 'a', created: ... }
|
|
16
19
|
this.data = {};
|
|
17
20
|
this.cfg = {
|
|
@@ -74,6 +77,17 @@ class InMemoryDB {
|
|
|
74
77
|
return ids.map(id => this.data[table][id]).filter(Boolean);
|
|
75
78
|
}
|
|
76
79
|
async saveBatch(_table, rows, opt = {}) {
|
|
80
|
+
const { tx } = opt;
|
|
81
|
+
if (tx) {
|
|
82
|
+
;
|
|
83
|
+
tx.ops.push({
|
|
84
|
+
type: 'saveBatch',
|
|
85
|
+
table: _table,
|
|
86
|
+
rows,
|
|
87
|
+
opt: (0, js_lib_1._omit)(opt, ['tx']),
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
77
91
|
const table = this.cfg.tablesPrefix + _table;
|
|
78
92
|
this.data[table] ||= {};
|
|
79
93
|
rows.forEach(r => {
|
|
@@ -93,14 +107,44 @@ class InMemoryDB {
|
|
|
93
107
|
this.data[table][r.id] = JSON.parse(JSON.stringify(r), nodejs_lib_1.bufferReviver);
|
|
94
108
|
});
|
|
95
109
|
}
|
|
96
|
-
async deleteByQuery(q,
|
|
110
|
+
async deleteByQuery(q, opt = {}) {
|
|
97
111
|
const table = this.cfg.tablesPrefix + q.table;
|
|
98
|
-
this.data[table]
|
|
112
|
+
if (!this.data[table])
|
|
113
|
+
return 0;
|
|
114
|
+
const ids = (0, __1.queryInMemory)(q, Object.values(this.data[table])).map(r => r.id);
|
|
115
|
+
const { tx } = opt;
|
|
116
|
+
if (tx) {
|
|
117
|
+
;
|
|
118
|
+
tx.ops.push({
|
|
119
|
+
type: 'deleteByIds',
|
|
120
|
+
table: q.table,
|
|
121
|
+
ids,
|
|
122
|
+
opt: (0, js_lib_1._omit)(opt, ['tx']),
|
|
123
|
+
});
|
|
124
|
+
return ids.length;
|
|
125
|
+
}
|
|
126
|
+
return await this.deleteByIds(q.table, ids);
|
|
127
|
+
}
|
|
128
|
+
async deleteByIds(_table, ids, opt = {}) {
|
|
129
|
+
const table = this.cfg.tablesPrefix + _table;
|
|
130
|
+
if (!this.data[table])
|
|
131
|
+
return 0;
|
|
132
|
+
const { tx } = opt;
|
|
133
|
+
if (tx) {
|
|
134
|
+
;
|
|
135
|
+
tx.ops.push({
|
|
136
|
+
type: 'deleteByIds',
|
|
137
|
+
table: _table,
|
|
138
|
+
ids,
|
|
139
|
+
opt: (0, js_lib_1._omit)(opt, ['tx']),
|
|
140
|
+
});
|
|
141
|
+
return ids.length;
|
|
142
|
+
}
|
|
99
143
|
let count = 0;
|
|
100
|
-
|
|
101
|
-
if (!this.data[table][
|
|
144
|
+
ids.forEach(id => {
|
|
145
|
+
if (!this.data[table][id])
|
|
102
146
|
return;
|
|
103
|
-
delete this.data[table][
|
|
147
|
+
delete this.data[table][id];
|
|
104
148
|
count++;
|
|
105
149
|
});
|
|
106
150
|
return count;
|
|
@@ -109,6 +153,7 @@ class InMemoryDB {
|
|
|
109
153
|
const patchEntries = Object.entries(patch);
|
|
110
154
|
if (!patchEntries.length)
|
|
111
155
|
return 0;
|
|
156
|
+
// todo: can we support tx here? :thinking:
|
|
112
157
|
const table = this.cfg.tablesPrefix + q.table;
|
|
113
158
|
const rows = (0, __1.queryInMemory)(q, Object.values(this.data[table] || {}));
|
|
114
159
|
rows.forEach((row) => {
|
|
@@ -135,30 +180,8 @@ class InMemoryDB {
|
|
|
135
180
|
const table = this.cfg.tablesPrefix + q.table;
|
|
136
181
|
return node_stream_1.Readable.from((0, __1.queryInMemory)(q, Object.values(this.data[table] || {})));
|
|
137
182
|
}
|
|
138
|
-
async
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
for await (const op of tx.ops) {
|
|
142
|
-
if (op.type === 'saveBatch') {
|
|
143
|
-
await this.saveBatch(op.table, op.rows, { ...op.opt, ...opt });
|
|
144
|
-
}
|
|
145
|
-
else if (op.type === 'deleteByIds') {
|
|
146
|
-
await this.deleteByQuery(dbQuery_1.DBQuery.create(op.table).filter('id', 'in', op.ids), {
|
|
147
|
-
...op.opt,
|
|
148
|
-
...opt,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
// rollback
|
|
158
|
-
this.data = backup;
|
|
159
|
-
this.cfg.logger.log('InMemoryDB transaction rolled back');
|
|
160
|
-
throw err;
|
|
161
|
-
}
|
|
183
|
+
async createTransaction() {
|
|
184
|
+
return new InMemoryDBTransaction(this);
|
|
162
185
|
}
|
|
163
186
|
/**
|
|
164
187
|
* Flushes all tables (all namespaces) at once.
|
|
@@ -215,3 +238,36 @@ class InMemoryDB {
|
|
|
215
238
|
}
|
|
216
239
|
}
|
|
217
240
|
exports.InMemoryDB = InMemoryDB;
|
|
241
|
+
class InMemoryDBTransaction {
|
|
242
|
+
constructor(db) {
|
|
243
|
+
this.db = db;
|
|
244
|
+
this.ops = [];
|
|
245
|
+
}
|
|
246
|
+
async commit() {
|
|
247
|
+
const backup = (0, js_lib_1._deepCopy)(this.db.data);
|
|
248
|
+
try {
|
|
249
|
+
for (const op of this.ops) {
|
|
250
|
+
if (op.type === 'saveBatch') {
|
|
251
|
+
await this.db.saveBatch(op.table, op.rows, op.opt);
|
|
252
|
+
}
|
|
253
|
+
else if (op.type === 'deleteByIds') {
|
|
254
|
+
await this.db.deleteByIds(op.table, op.ids, op.opt);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
this.ops = [];
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
// rollback
|
|
264
|
+
this.db.data = backup;
|
|
265
|
+
this.db.cfg.logger.log('InMemoryDB transaction rolled back');
|
|
266
|
+
throw err;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async rollback() {
|
|
270
|
+
this.ops = [];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.InMemoryDBTransaction = InMemoryDBTransaction;
|
package/dist/base.common.db.d.ts
CHANGED
|
@@ -1,29 +1,26 @@
|
|
|
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 { CommonDBOptions, CommonDBSaveOptions, DBPatch, RunQueryResult } from './db.model';
|
|
3
|
+
import { CommonDB, CommonDBSupport, CommonDBType } from './common.db';
|
|
4
|
+
import { CommonDBOptions, CommonDBSaveOptions, DBPatch, DBTransaction, RunQueryResult } from './db.model';
|
|
5
5
|
import { DBQuery } from './query/dbQuery';
|
|
6
|
-
import { DBTransaction } from './transaction/dbTransaction';
|
|
7
6
|
/**
|
|
8
7
|
* No-op implementation of CommonDB interface.
|
|
9
8
|
* To be extended by actual implementations.
|
|
10
9
|
*/
|
|
11
10
|
export declare class BaseCommonDB implements CommonDB {
|
|
11
|
+
dbType: CommonDBType;
|
|
12
|
+
support: CommonDBSupport;
|
|
12
13
|
ping(): Promise<void>;
|
|
13
14
|
getTables(): Promise<string[]>;
|
|
14
15
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
15
16
|
createTable<ROW extends ObjectWithId>(table: string, schema: JsonSchemaObject<ROW>): Promise<void>;
|
|
16
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids:
|
|
17
|
+
getByIds<ROW extends ObjectWithId>(table: string, ids: string[]): Promise<ROW[]>;
|
|
17
18
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number>;
|
|
18
19
|
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
19
20
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
|
20
21
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number>;
|
|
21
22
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
22
23
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): ReadableTyped<ROW>;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* Doesn't support rollback on error, hence doesn't pass dbTest.
|
|
26
|
-
* To be extended.
|
|
27
|
-
*/
|
|
28
|
-
commitTransaction(tx: DBTransaction, opt?: CommonDBOptions): Promise<void>;
|
|
24
|
+
deleteByIds(table: string, ids: string[], opt?: CommonDBOptions): Promise<number>;
|
|
25
|
+
createTransaction(): Promise<DBTransaction>;
|
|
29
26
|
}
|
package/dist/base.common.db.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseCommonDB = void 0;
|
|
4
|
+
const common_db_1 = require("./common.db");
|
|
5
|
+
const dbTransaction_util_1 = require("./transaction/dbTransaction.util");
|
|
4
6
|
/* eslint-disable unused-imports/no-unused-vars */
|
|
5
7
|
/**
|
|
6
8
|
* No-op implementation of CommonDB interface.
|
|
7
9
|
* To be extended by actual implementations.
|
|
8
10
|
*/
|
|
9
11
|
class BaseCommonDB {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.dbType = common_db_1.CommonDBType.document;
|
|
14
|
+
this.support = {};
|
|
15
|
+
}
|
|
10
16
|
async ping() {
|
|
11
17
|
throw new Error('ping is not implemented');
|
|
12
18
|
}
|
|
@@ -40,13 +46,11 @@ class BaseCommonDB {
|
|
|
40
46
|
streamQuery(q) {
|
|
41
47
|
throw new Error('streamQuery is not implemented');
|
|
42
48
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
async commitTransaction(tx, opt) {
|
|
49
|
-
throw new Error('commitTransaction is not implemented');
|
|
49
|
+
async deleteByIds(table, ids, opt) {
|
|
50
|
+
throw new Error('deleteByIds is not implemented');
|
|
51
|
+
}
|
|
52
|
+
async createTransaction() {
|
|
53
|
+
return new dbTransaction_util_1.FakeDBTransaction(this);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
exports.BaseCommonDB = BaseCommonDB;
|