@naturalcycles/db-lib 8.46.1 → 8.48.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 +2 -3
- package/dist/adapter/cachedb/cache.db.js +12 -51
- package/dist/adapter/file/file.db.d.ts +0 -2
- package/dist/adapter/file/file.db.js +0 -20
- package/dist/adapter/inmemory/inMemory.db.d.ts +2 -3
- package/dist/adapter/inmemory/inMemory.db.js +32 -25
- package/dist/base.common.db.d.ts +8 -9
- package/dist/base.common.db.js +22 -26
- package/dist/common.db.d.ts +20 -7
- package/dist/commondao/common.dao.d.ts +4 -1
- package/dist/commondao/common.dao.js +32 -13
- package/dist/db.model.d.ts +13 -0
- package/dist/db.model.js +17 -1
- package/dist/query/dbQuery.d.ts +3 -1
- package/dist/query/dbQuery.js +8 -1
- package/dist/testing/daoTest.js +3 -4
- package/dist/testing/dbTest.d.ts +2 -0
- package/dist/testing/dbTest.js +52 -12
- package/dist/transaction/dbTransaction.util.js +5 -1
- package/package.json +1 -1
- package/src/adapter/cachedb/cache.db.ts +21 -82
- package/src/adapter/file/file.db.ts +0 -32
- package/src/adapter/inmemory/inMemory.db.ts +34 -34
- package/src/base.common.db.ts +33 -33
- package/src/common.db.ts +24 -16
- package/src/commondao/common.dao.ts +46 -15
- package/src/db.model.ts +19 -0
- package/src/query/dbQuery.ts +17 -2
- package/src/testing/daoTest.ts +13 -10
- package/src/testing/dbTest.ts +80 -17
- package/src/transaction/dbTransaction.util.ts +5 -1
|
@@ -3,7 +3,7 @@ import { Readable } from 'node:stream';
|
|
|
3
3
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
4
|
import { BaseCommonDB } from '../../base.common.db';
|
|
5
5
|
import { CommonDB } from '../../common.db';
|
|
6
|
-
import { CommonDBOptions, RunQueryResult } from '../../db.model';
|
|
6
|
+
import { CommonDBOptions, DBPatch, RunQueryResult } from '../../db.model';
|
|
7
7
|
import { DBQuery } from '../../query/dbQuery';
|
|
8
8
|
import { DBTransaction } from '../../transaction/dbTransaction';
|
|
9
9
|
import { CacheDBCfg, CacheDBCreateOptions, CacheDBOptions, CacheDBSaveOptions, CacheDBStreamOptions } from './cache.db.model';
|
|
@@ -23,12 +23,11 @@ export declare class CacheDB extends BaseCommonDB implements CommonDB {
|
|
|
23
23
|
getTables(): Promise<string[]>;
|
|
24
24
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
25
25
|
createTable<ROW extends ObjectWithId>(table: string, schema: JsonSchemaObject<ROW>, opt?: CacheDBCreateOptions): Promise<void>;
|
|
26
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: CacheDBSaveOptions<ROW>): Promise<ROW[]>;
|
|
27
|
-
deleteByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: CacheDBOptions): Promise<number>;
|
|
28
26
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CacheDBSaveOptions<ROW>): Promise<void>;
|
|
29
27
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBSaveOptions<ROW>): Promise<RunQueryResult<ROW>>;
|
|
30
28
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
31
29
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBStreamOptions): Readable;
|
|
32
30
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
31
|
+
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
33
32
|
commitTransaction(tx: DBTransaction, opt?: CommonDBOptions): Promise<void>;
|
|
34
33
|
}
|
|
@@ -42,57 +42,6 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
|
42
42
|
await this.cfg.cacheDB.createTable(table, schema, opt);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
async getByIds(table, ids, opt = {}) {
|
|
46
|
-
const resultMap = {};
|
|
47
|
-
const missingIds = [];
|
|
48
|
-
if (!opt.skipCache && !this.cfg.skipCache) {
|
|
49
|
-
const results = await this.cfg.cacheDB.getByIds(table, ids, opt);
|
|
50
|
-
results.forEach(r => (resultMap[r.id] = r));
|
|
51
|
-
missingIds.push(...ids.filter(id => !resultMap[id]));
|
|
52
|
-
if (this.cfg.logCached) {
|
|
53
|
-
this.cfg.logger?.log(`${table}.getByIds ${results.length} rows from cache: [${results
|
|
54
|
-
.map(r => r.id)
|
|
55
|
-
.join(', ')}]`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (missingIds.length && !opt.onlyCache && !this.cfg.onlyCache) {
|
|
59
|
-
const results = await this.cfg.downstreamDB.getByIds(table, missingIds, opt);
|
|
60
|
-
results.forEach(r => (resultMap[r.id] = r));
|
|
61
|
-
if (this.cfg.logDownstream) {
|
|
62
|
-
this.cfg.logger?.log(`${table}.getByIds ${results.length} rows from downstream: [${results
|
|
63
|
-
.map(r => r.id)
|
|
64
|
-
.join(', ')}]`);
|
|
65
|
-
}
|
|
66
|
-
if (!opt.skipCache) {
|
|
67
|
-
const cacheResult = this.cfg.cacheDB.saveBatch(table, results, opt);
|
|
68
|
-
if (this.cfg.awaitCache)
|
|
69
|
-
await cacheResult;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// return in right order
|
|
73
|
-
return ids.map(id => resultMap[id]).filter(Boolean);
|
|
74
|
-
}
|
|
75
|
-
async deleteByIds(table, ids, opt = {}) {
|
|
76
|
-
let deletedIds = 0;
|
|
77
|
-
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
78
|
-
deletedIds = await this.cfg.downstreamDB.deleteByIds(table, ids, opt);
|
|
79
|
-
if (this.cfg.logDownstream) {
|
|
80
|
-
this.cfg.logger?.log(`${table}.deleteByIds ${deletedIds} rows from downstream`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (!opt.skipCache && !this.cfg.skipCache) {
|
|
84
|
-
const cacheResult = this.cfg.cacheDB
|
|
85
|
-
.deleteByIds(table, ids, opt)
|
|
86
|
-
.then(deletedFromCache => {
|
|
87
|
-
if (this.cfg.logCached) {
|
|
88
|
-
this.cfg.logger?.log(`${table}.deleteByIds ${deletedFromCache} rows from cache`);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
if (this.cfg.awaitCache)
|
|
92
|
-
await cacheResult;
|
|
93
|
-
}
|
|
94
|
-
return deletedIds;
|
|
95
|
-
}
|
|
96
45
|
async saveBatch(table, rows, opt = {}) {
|
|
97
46
|
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
98
47
|
await this.cfg.downstreamDB.saveBatch(table, rows, opt);
|
|
@@ -195,6 +144,18 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
|
195
144
|
}
|
|
196
145
|
return deletedIds;
|
|
197
146
|
}
|
|
147
|
+
async updateByQuery(q, patch, opt = {}) {
|
|
148
|
+
let updated;
|
|
149
|
+
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
150
|
+
updated = await this.cfg.downstreamDB.updateByQuery(q, patch, opt);
|
|
151
|
+
}
|
|
152
|
+
if (!opt.skipCache && !this.cfg.skipCache) {
|
|
153
|
+
const cacheResult = this.cfg.cacheDB.updateByQuery(q, patch, opt);
|
|
154
|
+
if (this.cfg.awaitCache)
|
|
155
|
+
updated ??= await cacheResult;
|
|
156
|
+
}
|
|
157
|
+
return updated || 0;
|
|
158
|
+
}
|
|
198
159
|
async commitTransaction(tx, opt) {
|
|
199
160
|
await this.cfg.downstreamDB.commitTransaction(tx, opt);
|
|
200
161
|
await this.cfg.cacheDB.commitTransaction(tx, opt);
|
|
@@ -21,7 +21,6 @@ export declare class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
21
21
|
cfg: FileDBCfg;
|
|
22
22
|
ping(): Promise<void>;
|
|
23
23
|
getTables(): Promise<string[]>;
|
|
24
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<ROW[]>;
|
|
25
24
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
26
25
|
/**
|
|
27
26
|
* Implementation is optimized for loading/saving _whole files_.
|
|
@@ -30,7 +29,6 @@ export declare class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
30
29
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
31
30
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
32
31
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions): ReadableTyped<ROW>;
|
|
33
|
-
deleteByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<number>;
|
|
34
32
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
35
33
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
36
34
|
loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]>;
|
|
@@ -34,10 +34,6 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
34
34
|
this.logFinished(started, `getTables() ${tables.length} tables`);
|
|
35
35
|
return tables;
|
|
36
36
|
}
|
|
37
|
-
async getByIds(table, ids, _opt) {
|
|
38
|
-
const byId = (0, js_lib_1._by)(await this.loadFile(table), r => r.id);
|
|
39
|
-
return ids.map(id => byId[id]).filter(Boolean);
|
|
40
|
-
}
|
|
41
37
|
async saveBatch(table, rows, _opt) {
|
|
42
38
|
if (!rows.length)
|
|
43
39
|
return; // save some api calls
|
|
@@ -130,22 +126,6 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
130
126
|
});
|
|
131
127
|
return readable;
|
|
132
128
|
}
|
|
133
|
-
async deleteByIds(table, ids, _opt) {
|
|
134
|
-
if (!ids.length)
|
|
135
|
-
return 0;
|
|
136
|
-
let deleted = 0;
|
|
137
|
-
const rows = (await this.loadFile(table)).filter(r => {
|
|
138
|
-
if (ids.includes(r.id)) {
|
|
139
|
-
deleted++;
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
return true;
|
|
143
|
-
});
|
|
144
|
-
if (deleted > 0) {
|
|
145
|
-
await this.saveFile(table, rows);
|
|
146
|
-
}
|
|
147
|
-
return deleted;
|
|
148
|
-
}
|
|
149
129
|
async deleteByQuery(q, _opt) {
|
|
150
130
|
const byId = (0, js_lib_1._by)(await this.loadFile(q.table), r => r.id);
|
|
151
131
|
let deleted = 0;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JsonSchemaObject, StringMap, JsonSchemaRootObject, ObjectWithId, CommonLogger } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDB, DBTransaction } from '../..';
|
|
3
|
+
import { CommonDB, DBPatch, DBTransaction } from '../..';
|
|
4
4
|
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, RunQueryResult } from '../../db.model';
|
|
5
5
|
import { DBQuery } from '../../query/dbQuery';
|
|
6
6
|
export interface InMemoryDBCfg {
|
|
@@ -52,10 +52,9 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
52
52
|
getTables(): Promise<string[]>;
|
|
53
53
|
getTableSchema<ROW extends ObjectWithId>(_table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
54
54
|
createTable<ROW extends ObjectWithId>(_table: string, _schema: JsonSchemaObject<ROW>, opt?: CommonDBCreateOptions): Promise<void>;
|
|
55
|
-
getByIds<ROW extends ObjectWithId>(_table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<ROW[]>;
|
|
56
55
|
saveBatch<ROW extends Partial<ObjectWithId>>(_table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
57
|
-
deleteByIds<ROW extends ObjectWithId>(_table: string, ids: ROW['id'][], _opt?: CommonDBOptions): Promise<number>;
|
|
58
56
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
57
|
+
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>): Promise<number>;
|
|
59
58
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
60
59
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
61
60
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): ReadableTyped<ROW>;
|
|
@@ -8,6 +8,7 @@ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
|
8
8
|
const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
|
|
9
9
|
const fs = require("fs-extra");
|
|
10
10
|
const __1 = require("../..");
|
|
11
|
+
const dbQuery_1 = require("../../query/dbQuery");
|
|
11
12
|
class InMemoryDB {
|
|
12
13
|
constructor(cfg) {
|
|
13
14
|
// data[table][id] > {id: 'a', created: ... }
|
|
@@ -66,11 +67,6 @@ class InMemoryDB {
|
|
|
66
67
|
this.data[table] ||= {};
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
async getByIds(_table, ids, _opt) {
|
|
70
|
-
const table = this.cfg.tablesPrefix + _table;
|
|
71
|
-
this.data[table] ||= {};
|
|
72
|
-
return ids.map(id => this.data[table][id]).filter(Boolean);
|
|
73
|
-
}
|
|
74
70
|
async saveBatch(_table, rows, opt = {}) {
|
|
75
71
|
const table = this.cfg.tablesPrefix + _table;
|
|
76
72
|
this.data[table] ||= {};
|
|
@@ -91,23 +87,35 @@ class InMemoryDB {
|
|
|
91
87
|
this.data[table][r.id] = JSON.parse(JSON.stringify(r), nodejs_lib_1.bufferReviver);
|
|
92
88
|
});
|
|
93
89
|
}
|
|
94
|
-
async
|
|
95
|
-
const table = this.cfg.tablesPrefix +
|
|
90
|
+
async deleteByQuery(q, _opt) {
|
|
91
|
+
const table = this.cfg.tablesPrefix + q.table;
|
|
96
92
|
this.data[table] ||= {};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
|
|
93
|
+
let count = 0;
|
|
94
|
+
(0, __1.queryInMemory)(q, Object.values(this.data[table] || {})).forEach(r => {
|
|
95
|
+
if (!this.data[table][r.id])
|
|
96
|
+
return;
|
|
97
|
+
delete this.data[table][r.id];
|
|
98
|
+
count++;
|
|
99
|
+
});
|
|
100
|
+
return count;
|
|
105
101
|
}
|
|
106
|
-
async
|
|
102
|
+
async updateByQuery(q, patch) {
|
|
103
|
+
const patchEntries = Object.entries(patch);
|
|
104
|
+
if (!patchEntries.length)
|
|
105
|
+
return 0;
|
|
107
106
|
const table = this.cfg.tablesPrefix + q.table;
|
|
108
107
|
const rows = (0, __1.queryInMemory)(q, Object.values(this.data[table] || {}));
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
rows.forEach((row) => {
|
|
109
|
+
patchEntries.forEach(([k, v]) => {
|
|
110
|
+
if (v instanceof __1.DBIncrement) {
|
|
111
|
+
row[k] = (row[k] || 0) + v.amount;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
row[k] = v;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
return rows.length;
|
|
111
119
|
}
|
|
112
120
|
async runQuery(q, _opt) {
|
|
113
121
|
const table = this.cfg.tablesPrefix + q.table;
|
|
@@ -129,7 +137,10 @@ class InMemoryDB {
|
|
|
129
137
|
await this.saveBatch(op.table, op.rows, { ...op.opt, ...opt });
|
|
130
138
|
}
|
|
131
139
|
else if (op.type === 'deleteByIds') {
|
|
132
|
-
await this.
|
|
140
|
+
await this.deleteByQuery(dbQuery_1.DBQuery.create(op.table).filter('id', 'in', op.ids), {
|
|
141
|
+
...op.opt,
|
|
142
|
+
...opt,
|
|
143
|
+
});
|
|
133
144
|
}
|
|
134
145
|
else {
|
|
135
146
|
throw new Error(`DBOperation not supported: ${op.type}`);
|
|
@@ -147,9 +158,7 @@ class InMemoryDB {
|
|
|
147
158
|
* Flushes all tables (all namespaces) at once.
|
|
148
159
|
*/
|
|
149
160
|
async flushToDisk() {
|
|
150
|
-
|
|
151
|
-
throw new Error('flushToDisk() called but persistenceEnabled=false');
|
|
152
|
-
}
|
|
161
|
+
(0, js_lib_1._assert)(this.cfg.persistenceEnabled, 'flushToDisk() called but persistenceEnabled=false');
|
|
153
162
|
const { persistentStoragePath, persistZip } = this.cfg;
|
|
154
163
|
const started = Date.now();
|
|
155
164
|
await fs.emptyDir(persistentStoragePath);
|
|
@@ -175,9 +184,7 @@ class InMemoryDB {
|
|
|
175
184
|
* Restores all tables (all namespaces) at once.
|
|
176
185
|
*/
|
|
177
186
|
async restoreFromDisk() {
|
|
178
|
-
|
|
179
|
-
throw new Error('restoreFromDisk() called but persistenceEnabled=false');
|
|
180
|
-
}
|
|
187
|
+
(0, js_lib_1._assert)(this.cfg.persistenceEnabled, 'restoreFromDisk() called but persistenceEnabled=false');
|
|
181
188
|
const { persistentStoragePath } = this.cfg;
|
|
182
189
|
const started = Date.now();
|
|
183
190
|
await fs.ensureDir(persistentStoragePath);
|
package/dist/base.common.db.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDB } from './common.db';
|
|
4
|
-
import { CommonDBOptions, CommonDBSaveOptions, RunQueryResult } from './db.model';
|
|
4
|
+
import { CommonDBOptions, CommonDBSaveOptions, DBPatch, RunQueryResult } from './db.model';
|
|
5
5
|
import { DBQuery } from './query/dbQuery';
|
|
6
6
|
import { DBTransaction } from './transaction/dbTransaction';
|
|
7
7
|
/**
|
|
@@ -12,14 +12,13 @@ export declare class BaseCommonDB implements CommonDB {
|
|
|
12
12
|
ping(): Promise<void>;
|
|
13
13
|
getTables(): Promise<string[]>;
|
|
14
14
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
15
|
-
createTable<ROW extends ObjectWithId>(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): ReadableTyped<ROW>;
|
|
15
|
+
createTable<ROW extends ObjectWithId>(table: string, schema: JsonSchemaObject<ROW>): Promise<void>;
|
|
16
|
+
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number>;
|
|
17
|
+
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
18
|
+
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
|
19
|
+
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number>;
|
|
20
|
+
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
21
|
+
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): ReadableTyped<ROW>;
|
|
23
22
|
/**
|
|
24
23
|
* Naive implementation.
|
|
25
24
|
* Doesn't support rollback on error, hence doesn't pass dbTest.
|
package/dist/base.common.db.js
CHANGED
|
@@ -1,45 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseCommonDB = void 0;
|
|
4
|
-
|
|
5
|
-
const dbTransaction_util_1 = require("./transaction/dbTransaction.util");
|
|
4
|
+
/* eslint-disable unused-imports/no-unused-vars */
|
|
6
5
|
/**
|
|
7
6
|
* No-op implementation of CommonDB interface.
|
|
8
7
|
* To be extended by actual implementations.
|
|
9
8
|
*/
|
|
10
9
|
class BaseCommonDB {
|
|
11
|
-
async ping() {
|
|
10
|
+
async ping() {
|
|
11
|
+
throw new Error('ping is not implemented');
|
|
12
|
+
}
|
|
12
13
|
async getTables() {
|
|
13
|
-
|
|
14
|
+
throw new Error('getTables is not implemented');
|
|
14
15
|
}
|
|
15
16
|
async getTableSchema(table) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
properties: {},
|
|
21
|
-
required: [],
|
|
22
|
-
};
|
|
17
|
+
throw new Error('getTableSchema is not implemented');
|
|
18
|
+
}
|
|
19
|
+
async createTable(table, schema) {
|
|
20
|
+
// no-op
|
|
23
21
|
}
|
|
24
|
-
async
|
|
25
|
-
|
|
26
|
-
return 0;
|
|
22
|
+
async deleteByQuery(q) {
|
|
23
|
+
throw new Error('deleteByQuery is not implemented');
|
|
27
24
|
}
|
|
28
|
-
async
|
|
29
|
-
|
|
25
|
+
async updateByQuery(q, patch, opt) {
|
|
26
|
+
throw new Error('updateByQuery is not implemented');
|
|
30
27
|
}
|
|
31
|
-
async
|
|
32
|
-
|
|
28
|
+
async runQuery(q) {
|
|
29
|
+
throw new Error('runQuery is not implemented');
|
|
33
30
|
}
|
|
34
|
-
async
|
|
35
|
-
|
|
31
|
+
async runQueryCount(q) {
|
|
32
|
+
throw new Error('runQueryCount is not implemented');
|
|
36
33
|
}
|
|
37
|
-
async
|
|
38
|
-
|
|
34
|
+
async saveBatch(table, rows, opt) {
|
|
35
|
+
throw new Error('saveBatch is not implemented');
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return node_stream_1.Readable.from([]);
|
|
37
|
+
streamQuery(q) {
|
|
38
|
+
throw new Error('streamQuery is not implemented');
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
41
|
* Naive implementation.
|
|
@@ -47,7 +43,7 @@ class BaseCommonDB {
|
|
|
47
43
|
* To be extended.
|
|
48
44
|
*/
|
|
49
45
|
async commitTransaction(tx, opt) {
|
|
50
|
-
|
|
46
|
+
throw new Error('commitTransaction is not implemented');
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
exports.BaseCommonDB = BaseCommonDB;
|
package/dist/common.db.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, RunQueryResult } from './db.model';
|
|
3
|
+
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, DBPatch, RunQueryResult } from './db.model';
|
|
4
4
|
import { DBQuery } from './query/dbQuery';
|
|
5
5
|
import { DBTransaction } from './transaction/dbTransaction';
|
|
6
6
|
export interface CommonDB {
|
|
@@ -27,11 +27,6 @@ export interface CommonDB {
|
|
|
27
27
|
* Caution! dropIfExists defaults to false. If set to true - will actually DROP the table!
|
|
28
28
|
*/
|
|
29
29
|
createTable<ROW extends ObjectWithId>(table: string, schema: JsonSchemaObject<ROW>, opt?: CommonDBCreateOptions): Promise<void>;
|
|
30
|
-
/**
|
|
31
|
-
* Order of items returned is not guaranteed to match order of ids.
|
|
32
|
-
* (Such limitation exists because Datastore doesn't support it).
|
|
33
|
-
*/
|
|
34
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: CommonDBOptions): Promise<ROW[]>;
|
|
35
30
|
/**
|
|
36
31
|
* Order by 'id' is not supported by all implementations (for example, Datastore doesn't support it).
|
|
37
32
|
*/
|
|
@@ -46,8 +41,26 @@ export interface CommonDB {
|
|
|
46
41
|
* Returns number of deleted items.
|
|
47
42
|
* Not supported by all implementations (e.g Datastore will always return same number as number of ids).
|
|
48
43
|
*/
|
|
49
|
-
deleteByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: CommonDBOptions): Promise<number>;
|
|
50
44
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Applies patch to the rows returned by the query.
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
*
|
|
50
|
+
* UPDATE table SET A = B where $QUERY_CONDITION
|
|
51
|
+
*
|
|
52
|
+
* patch would be { A: 'B' } for that query.
|
|
53
|
+
*
|
|
54
|
+
* Supports "increment query", example:
|
|
55
|
+
*
|
|
56
|
+
* UPDATE table SET A = A + 1
|
|
57
|
+
*
|
|
58
|
+
* In that case patch would look like:
|
|
59
|
+
* { A: DBIncrement(1) }
|
|
60
|
+
*
|
|
61
|
+
* Returns number of rows affected.
|
|
62
|
+
*/
|
|
63
|
+
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
51
64
|
/**
|
|
52
65
|
* Should be implemented as a Transaction (best effort), which means that
|
|
53
66
|
* either ALL or NONE of the operations should be applied.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyObject, AsyncMapper, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, Saved, Unsaved } from '@naturalcycles/js-lib';
|
|
2
2
|
import { AjvSchema, ObjectSchemaTyped, ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { DBDeleteByIdsOperation, DBModelType, DBOperation, DBSaveBatchOperation, RunQueryResult } from '../db.model';
|
|
3
|
+
import { DBDeleteByIdsOperation, DBModelType, DBOperation, DBPatch, DBSaveBatchOperation, RunQueryResult } from '../db.model';
|
|
4
4
|
import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
|
|
5
5
|
import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions } from './common.dao.model';
|
|
6
6
|
/**
|
|
@@ -120,6 +120,9 @@ export declare class CommonDao<BM extends Partial<ObjectWithId<ID>>, DBM extends
|
|
|
120
120
|
deleteByQuery(q: DBQuery<DBM>, opt?: CommonDaoStreamForEachOptions<DBM> & {
|
|
121
121
|
stream?: boolean;
|
|
122
122
|
}): Promise<number>;
|
|
123
|
+
updateById(id: ID, patch: DBPatch<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
124
|
+
updateByIds(ids: ID[], patch: DBPatch<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
125
|
+
updateByQuery(q: DBQuery<DBM>, patch: DBPatch<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
123
126
|
dbmToBM(_dbm: undefined, opt?: CommonDaoOptions): Promise<undefined>;
|
|
124
127
|
dbmToBM(_dbm?: DBM, opt?: CommonDaoOptions): Promise<Saved<BM>>;
|
|
125
128
|
dbmsToBM(dbms: DBM[], opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
@@ -112,13 +112,15 @@ class CommonDao {
|
|
|
112
112
|
let dbm;
|
|
113
113
|
if (opt.timeout) {
|
|
114
114
|
// todo: possibly remove it after debugging is done
|
|
115
|
-
dbm =
|
|
115
|
+
dbm = await (0, js_lib_1.pTimeout)(async () => {
|
|
116
|
+
return (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterEq('id', id))).rows[0];
|
|
117
|
+
}, {
|
|
116
118
|
timeout: opt.timeout,
|
|
117
119
|
name: `getById(${table})`,
|
|
118
|
-
})
|
|
120
|
+
});
|
|
119
121
|
}
|
|
120
122
|
else {
|
|
121
|
-
dbm = (await this.cfg.db.
|
|
123
|
+
dbm = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterEq('id', id))).rows[0];
|
|
122
124
|
}
|
|
123
125
|
const bm = opt.raw ? dbm : await this.dbmToBM(dbm, opt);
|
|
124
126
|
this.logResult(started, op, bm, table);
|
|
@@ -143,7 +145,7 @@ class CommonDao {
|
|
|
143
145
|
const op = `getByIdAsDBM(${id})`;
|
|
144
146
|
const table = opt.table || this.cfg.table;
|
|
145
147
|
const started = this.logStarted(op, table);
|
|
146
|
-
let [dbm] = await this.cfg.db.
|
|
148
|
+
let [dbm] = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterEq('id', id))).rows;
|
|
147
149
|
if (!opt.raw) {
|
|
148
150
|
dbm = this.anyToDBM(dbm, opt);
|
|
149
151
|
}
|
|
@@ -156,7 +158,7 @@ class CommonDao {
|
|
|
156
158
|
const op = `getByIdAsTM(${id})`;
|
|
157
159
|
const table = opt.table || this.cfg.table;
|
|
158
160
|
const started = this.logStarted(op, table);
|
|
159
|
-
const [dbm] = await this.cfg.db.
|
|
161
|
+
const [dbm] = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterEq('id', id))).rows;
|
|
160
162
|
if (opt.raw) {
|
|
161
163
|
this.logResult(started, op, dbm, table);
|
|
162
164
|
return dbm || null;
|
|
@@ -170,7 +172,7 @@ class CommonDao {
|
|
|
170
172
|
const op = `getByIds ${ids.length} id(s) (${(0, js_lib_1._truncate)(ids.slice(0, 10).join(', '), 50)})`;
|
|
171
173
|
const table = opt.table || this.cfg.table;
|
|
172
174
|
const started = this.logStarted(op, table);
|
|
173
|
-
const dbms = await this.cfg.db.
|
|
175
|
+
const dbms = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterIn('id', ids))).rows;
|
|
174
176
|
const bms = opt.raw ? dbms : await this.dbmsToBM(dbms, opt);
|
|
175
177
|
this.logResult(started, op, bms, table);
|
|
176
178
|
return bms;
|
|
@@ -179,7 +181,7 @@ class CommonDao {
|
|
|
179
181
|
const op = `getByIdsAsDBM ${ids.length} id(s) (${(0, js_lib_1._truncate)(ids.slice(0, 10).join(', '), 50)})`;
|
|
180
182
|
const table = opt.table || this.cfg.table;
|
|
181
183
|
const started = this.logStarted(op, table);
|
|
182
|
-
const dbms = await this.cfg.db.
|
|
184
|
+
const dbms = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterIn('id', ids))).rows;
|
|
183
185
|
this.logResult(started, op, dbms, table);
|
|
184
186
|
return dbms;
|
|
185
187
|
}
|
|
@@ -229,7 +231,8 @@ class CommonDao {
|
|
|
229
231
|
}
|
|
230
232
|
async ensureUniqueId(table, dbm) {
|
|
231
233
|
// todo: retry N times
|
|
232
|
-
const existing = await this.cfg.db.
|
|
234
|
+
const existing = (await this.cfg.db.runQuery(dbQuery_1.DBQuery.create(table).filterEq('id', dbm.id)))
|
|
235
|
+
.rows;
|
|
233
236
|
if (existing.length) {
|
|
234
237
|
throw new js_lib_1.AppError(cnst_1.DBLibError.NON_UNIQUE_ID, {
|
|
235
238
|
table,
|
|
@@ -656,9 +659,9 @@ class CommonDao {
|
|
|
656
659
|
const op = `deleteById(${id})`;
|
|
657
660
|
const table = opt.table || this.cfg.table;
|
|
658
661
|
const started = this.logStarted(op, table);
|
|
659
|
-
const
|
|
662
|
+
const count = await this.cfg.db.deleteByQuery(dbQuery_1.DBQuery.create(table).filterEq('id', id));
|
|
660
663
|
this.logSaveResult(started, op, table);
|
|
661
|
-
return
|
|
664
|
+
return count;
|
|
662
665
|
}
|
|
663
666
|
async deleteByIds(ids, opt = {}) {
|
|
664
667
|
this.requireWriteAccess();
|
|
@@ -666,9 +669,9 @@ class CommonDao {
|
|
|
666
669
|
const op = `deleteByIds(${ids.join(', ')})`;
|
|
667
670
|
const table = opt.table || this.cfg.table;
|
|
668
671
|
const started = this.logStarted(op, table);
|
|
669
|
-
const
|
|
672
|
+
const count = await this.cfg.db.deleteByQuery(dbQuery_1.DBQuery.create(table).filterIn('id', ids));
|
|
670
673
|
this.logSaveResult(started, op, table);
|
|
671
|
-
return
|
|
674
|
+
return count;
|
|
672
675
|
}
|
|
673
676
|
/**
|
|
674
677
|
* Pass `stream: true` option to use Streaming: it will Stream the query, batch by 500, and execute
|
|
@@ -691,7 +694,7 @@ class CommonDao {
|
|
|
691
694
|
}),
|
|
692
695
|
(0, nodejs_lib_1.transformBuffer)({ batchSize }),
|
|
693
696
|
(0, nodejs_lib_1.transformMap)(async (ids) => {
|
|
694
|
-
deleted += await this.cfg.db.
|
|
697
|
+
deleted += await this.cfg.db.deleteByQuery(dbQuery_1.DBQuery.create(q.table).filterIn('id', ids), opt);
|
|
695
698
|
}, {
|
|
696
699
|
predicate: js_lib_1._passthroughPredicate,
|
|
697
700
|
}),
|
|
@@ -711,6 +714,22 @@ class CommonDao {
|
|
|
711
714
|
this.logSaveResult(started, op, q.table);
|
|
712
715
|
return deleted;
|
|
713
716
|
}
|
|
717
|
+
async updateById(id, patch, opt = {}) {
|
|
718
|
+
return await this.updateByQuery(this.query().filterEq('id', id), patch, opt);
|
|
719
|
+
}
|
|
720
|
+
async updateByIds(ids, patch, opt = {}) {
|
|
721
|
+
return await this.updateByQuery(this.query().filterIn('id', ids), patch, opt);
|
|
722
|
+
}
|
|
723
|
+
async updateByQuery(q, patch, opt = {}) {
|
|
724
|
+
this.requireWriteAccess();
|
|
725
|
+
this.requireObjectMutability(opt);
|
|
726
|
+
q.table = opt.table || q.table;
|
|
727
|
+
const op = `updateByQuery(${q.pretty()})`;
|
|
728
|
+
const started = this.logStarted(op, q.table);
|
|
729
|
+
const updated = await this.cfg.db.updateByQuery(q, patch, opt);
|
|
730
|
+
this.logSaveResult(started, op, q.table);
|
|
731
|
+
return updated;
|
|
732
|
+
}
|
|
714
733
|
async dbmToBM(_dbm, opt = {}) {
|
|
715
734
|
if (!_dbm)
|
|
716
735
|
return;
|
package/dist/db.model.d.ts
CHANGED
|
@@ -62,3 +62,16 @@ export declare enum DBModelType {
|
|
|
62
62
|
BM = "BM",
|
|
63
63
|
TM = "TM"
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Allows to construct a query similar to:
|
|
67
|
+
*
|
|
68
|
+
* UPDATE table SET A = A + 1
|
|
69
|
+
*
|
|
70
|
+
* In this case DBIncement.of(1) will be needed.
|
|
71
|
+
*/
|
|
72
|
+
export declare class DBIncrement {
|
|
73
|
+
amount: number;
|
|
74
|
+
private constructor();
|
|
75
|
+
static of(amount: number): DBIncrement;
|
|
76
|
+
}
|
|
77
|
+
export type DBPatch<ROW extends Partial<ObjectWithId>> = Partial<Record<keyof ROW, ROW[keyof ROW] | DBIncrement>>;
|
package/dist/db.model.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DBModelType = exports.DBRelation = void 0;
|
|
3
|
+
exports.DBIncrement = exports.DBModelType = exports.DBRelation = void 0;
|
|
4
4
|
var DBRelation;
|
|
5
5
|
(function (DBRelation) {
|
|
6
6
|
DBRelation["ONE_TO_ONE"] = "ONE_TO_ONE";
|
|
@@ -12,3 +12,19 @@ var DBModelType;
|
|
|
12
12
|
DBModelType["BM"] = "BM";
|
|
13
13
|
DBModelType["TM"] = "TM";
|
|
14
14
|
})(DBModelType = exports.DBModelType || (exports.DBModelType = {}));
|
|
15
|
+
/**
|
|
16
|
+
* Allows to construct a query similar to:
|
|
17
|
+
*
|
|
18
|
+
* UPDATE table SET A = A + 1
|
|
19
|
+
*
|
|
20
|
+
* In this case DBIncement.of(1) will be needed.
|
|
21
|
+
*/
|
|
22
|
+
class DBIncrement {
|
|
23
|
+
constructor(amount) {
|
|
24
|
+
this.amount = amount;
|
|
25
|
+
}
|
|
26
|
+
static of(amount) {
|
|
27
|
+
return new DBIncrement(amount);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.DBIncrement = DBIncrement;
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyObjectWithId, ObjectWithId, AsyncMapper, Saved, AnyObject } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDaoOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions } from '..';
|
|
3
|
+
import { CommonDaoOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, DBPatch } from '..';
|
|
4
4
|
import { CommonDao } from '../commondao/common.dao';
|
|
5
5
|
import { RunQueryResult } from '../db.model';
|
|
6
6
|
/**
|
|
@@ -68,6 +68,7 @@ export declare class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
68
68
|
_distinct: boolean;
|
|
69
69
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this;
|
|
70
70
|
filterEq(name: keyof ROW, val: any): this;
|
|
71
|
+
filterIn(name: keyof ROW, val: any[]): this;
|
|
71
72
|
limit(limit: number): this;
|
|
72
73
|
offset(offset: number): this;
|
|
73
74
|
order(name: keyof ROW, descending?: boolean): this;
|
|
@@ -97,6 +98,7 @@ export declare class RunnableDBQuery<BM extends Partial<ObjectWithId<ID>>, DBM e
|
|
|
97
98
|
runQueryExtendedAsDBM(opt?: CommonDaoOptions): Promise<RunQueryResult<DBM>>;
|
|
98
99
|
runQueryExtendedAsTM(opt?: CommonDaoOptions): Promise<RunQueryResult<TM>>;
|
|
99
100
|
runQueryCount(opt?: CommonDaoOptions): Promise<number>;
|
|
101
|
+
updateByQuery(patch: DBPatch<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
100
102
|
streamQueryForEach(mapper: AsyncMapper<Saved<BM>, void>, opt?: CommonDaoStreamForEachOptions<Saved<BM>>): Promise<void>;
|
|
101
103
|
streamQueryAsDBMForEach(mapper: AsyncMapper<DBM, void>, opt?: CommonDaoStreamForEachOptions<DBM>): Promise<void>;
|
|
102
104
|
streamQuery(opt?: CommonDaoStreamOptions): ReadableTyped<Saved<BM>>;
|