@naturalcycles/db-lib 9.21.0 → 9.22.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 -2
- package/dist/adapter/cachedb/cache.db.js +4 -3
- package/dist/adapter/file/file.db.js +2 -1
- package/dist/adapter/inmemory/inMemory.db.d.ts +7 -6
- package/dist/adapter/inmemory/inMemory.db.js +15 -13
- package/dist/adapter/inmemory/inMemoryKeyValueDB.d.ts +1 -0
- package/dist/adapter/inmemory/inMemoryKeyValueDB.js +13 -0
- package/dist/base.common.db.d.ts +4 -3
- package/dist/base.common.db.js +5 -2
- package/dist/common.db.d.ts +23 -14
- package/dist/common.db.js +2 -2
- package/dist/commondao/common.dao.d.ts +16 -5
- package/dist/commondao/common.dao.js +37 -8
- package/dist/db.model.d.ts +0 -13
- package/dist/db.model.js +1 -17
- package/dist/kv/commonKeyValueDB.d.ts +16 -2
- package/dist/query/dbQuery.d.ts +2 -2
- package/dist/query/dbQuery.js +2 -2
- package/dist/testing/daoTest.js +26 -0
- package/dist/testing/dbTest.js +21 -23
- package/dist/testing/keyValueDBTest.js +15 -3
- package/package.json +1 -1
- package/src/adapter/cachedb/cache.db.ts +6 -5
- package/src/adapter/file/file.db.ts +2 -1
- package/src/adapter/inmemory/inMemory.db.ts +29 -18
- package/src/adapter/inmemory/inMemoryKeyValueDB.ts +17 -1
- package/src/base.common.db.ts +18 -5
- package/src/common.db.ts +36 -17
- package/src/commondao/common.dao.ts +46 -11
- package/src/db.model.ts +0 -19
- package/src/kv/commonKeyValueDB.ts +17 -2
- package/src/query/dbQuery.ts +2 -3
- package/src/testing/daoTest.ts +28 -0
- package/src/testing/dbTest.ts +22 -28
- package/src/testing/keyValueDBTest.ts +17 -3
|
@@ -2,7 +2,7 @@ import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcy
|
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { BaseCommonDB } from '../../base.common.db';
|
|
4
4
|
import { CommonDB, CommonDBSupport } from '../../common.db';
|
|
5
|
-
import {
|
|
5
|
+
import { RunQueryResult } from '../../db.model';
|
|
6
6
|
import { DBQuery } from '../../query/dbQuery';
|
|
7
7
|
import { CacheDBCfg, CacheDBCreateOptions, CacheDBOptions, CacheDBSaveOptions, CacheDBStreamOptions } from './cache.db.model';
|
|
8
8
|
/**
|
|
@@ -28,5 +28,5 @@ export declare class CacheDB extends BaseCommonDB implements CommonDB {
|
|
|
28
28
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
29
29
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBStreamOptions): ReadableTyped<ROW>;
|
|
30
30
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
31
|
-
|
|
31
|
+
patchByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: Partial<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
32
32
|
}
|
|
@@ -17,6 +17,7 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
|
17
17
|
this.support = {
|
|
18
18
|
...common_db_1.commonDBFullSupport,
|
|
19
19
|
transactions: false,
|
|
20
|
+
increment: false,
|
|
20
21
|
};
|
|
21
22
|
this.cfg = {
|
|
22
23
|
logger: console,
|
|
@@ -180,13 +181,13 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
|
|
|
180
181
|
}
|
|
181
182
|
return deletedIds;
|
|
182
183
|
}
|
|
183
|
-
async
|
|
184
|
+
async patchByQuery(q, patch, opt = {}) {
|
|
184
185
|
let updated;
|
|
185
186
|
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
186
|
-
updated = await this.cfg.downstreamDB.
|
|
187
|
+
updated = await this.cfg.downstreamDB.patchByQuery(q, patch, opt);
|
|
187
188
|
}
|
|
188
189
|
if (!opt.skipCache && !this.cfg.skipCache) {
|
|
189
|
-
const cacheResult = this.cfg.cacheDB.
|
|
190
|
+
const cacheResult = this.cfg.cacheDB.patchByQuery(q, patch, opt);
|
|
190
191
|
if (this.cfg.awaitCache)
|
|
191
192
|
updated ??= await cacheResult;
|
|
192
193
|
}
|
|
@@ -22,9 +22,10 @@ class FileDB extends __1.BaseCommonDB {
|
|
|
22
22
|
bufferValues: false, // todo: implement
|
|
23
23
|
insertSaveMethod: false,
|
|
24
24
|
updateSaveMethod: false,
|
|
25
|
-
|
|
25
|
+
patchByQuery: false,
|
|
26
26
|
createTable: false,
|
|
27
27
|
transactions: false, // todo
|
|
28
|
+
increment: false,
|
|
28
29
|
};
|
|
29
30
|
this.cfg = {
|
|
30
31
|
sortObjects: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, StringMap } from '@naturalcycles/js-lib';
|
|
1
|
+
import { AnyObjectWithId, CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, StringMap } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDB, CommonDBTransactionOptions, CommonDBType, DBOperation,
|
|
3
|
+
import { CommonDB, CommonDBTransactionOptions, CommonDBType, DBOperation, DBTransactionFn } from '../..';
|
|
4
4
|
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, DBTransaction, RunQueryResult } from '../../db.model';
|
|
5
5
|
import { DBQuery } from '../../query/dbQuery';
|
|
6
6
|
export interface InMemoryDBCfg {
|
|
@@ -55,8 +55,8 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
55
55
|
dbQuerySelectFields?: boolean;
|
|
56
56
|
insertSaveMethod?: boolean;
|
|
57
57
|
updateSaveMethod?: boolean;
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
patchByQuery?: boolean;
|
|
59
|
+
increment?: boolean;
|
|
60
60
|
createTable?: boolean;
|
|
61
61
|
tableSchemas?: boolean;
|
|
62
62
|
streaming?: boolean;
|
|
@@ -66,7 +66,7 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
66
66
|
};
|
|
67
67
|
constructor(cfg?: Partial<InMemoryDBCfg>);
|
|
68
68
|
cfg: InMemoryDBCfg;
|
|
69
|
-
data: StringMap<StringMap<
|
|
69
|
+
data: StringMap<StringMap<AnyObjectWithId>>;
|
|
70
70
|
/**
|
|
71
71
|
* Returns internal "Data snapshot".
|
|
72
72
|
* Deterministic - jsonSorted.
|
|
@@ -84,11 +84,12 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
84
84
|
saveBatch<ROW extends ObjectWithId>(_table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
85
85
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
86
86
|
deleteByIds(_table: string, ids: string[], _opt?: CommonDBOptions): Promise<number>;
|
|
87
|
-
|
|
87
|
+
patchByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: Partial<ROW>): Promise<number>;
|
|
88
88
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
89
89
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
90
90
|
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): ReadableTyped<ROW>;
|
|
91
91
|
runInTransaction(fn: DBTransactionFn, opt?: CommonDBTransactionOptions): Promise<void>;
|
|
92
|
+
incrementBatch(table: string, prop: string, incrementMap: StringMap<number>, _opt?: CommonDBOptions): Promise<StringMap<number>>;
|
|
92
93
|
/**
|
|
93
94
|
* Flushes all tables (all namespaces) at once.
|
|
94
95
|
*/
|
|
@@ -113,22 +113,12 @@ class InMemoryDB {
|
|
|
113
113
|
});
|
|
114
114
|
return count;
|
|
115
115
|
}
|
|
116
|
-
async
|
|
117
|
-
|
|
118
|
-
if (!patchEntries.length)
|
|
116
|
+
async patchByQuery(q, patch) {
|
|
117
|
+
if ((0, js_lib_1._isEmptyObject)(patch))
|
|
119
118
|
return 0;
|
|
120
119
|
const table = this.cfg.tablesPrefix + q.table;
|
|
121
120
|
const rows = (0, __1.queryInMemory)(q, Object.values(this.data[table] || {}));
|
|
122
|
-
rows.forEach(
|
|
123
|
-
patchEntries.forEach(([k, v]) => {
|
|
124
|
-
if (v instanceof __1.DBIncrement) {
|
|
125
|
-
row[k] = (row[k] || 0) + v.amount;
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
row[k] = v;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
});
|
|
121
|
+
rows.forEach(row => Object.assign(row, patch));
|
|
132
122
|
return rows.length;
|
|
133
123
|
}
|
|
134
124
|
async runQuery(q, _opt) {
|
|
@@ -157,6 +147,18 @@ class InMemoryDB {
|
|
|
157
147
|
throw err;
|
|
158
148
|
}
|
|
159
149
|
}
|
|
150
|
+
async incrementBatch(table, prop, incrementMap, _opt) {
|
|
151
|
+
const tbl = this.cfg.tablesPrefix + table;
|
|
152
|
+
this.data[tbl] ||= {};
|
|
153
|
+
const result = {};
|
|
154
|
+
for (const [id, by] of (0, js_lib_1._stringMapEntries)(incrementMap)) {
|
|
155
|
+
this.data[tbl][id] ||= { id };
|
|
156
|
+
const newValue = (this.data[tbl][id][prop] || 0) + by;
|
|
157
|
+
this.data[tbl][id][prop] = newValue;
|
|
158
|
+
result[id] = newValue;
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
160
162
|
/**
|
|
161
163
|
* Flushes all tables (all namespaces) at once.
|
|
162
164
|
*/
|
|
@@ -22,4 +22,5 @@ export declare class InMemoryKeyValueDB implements CommonKeyValueDB {
|
|
|
22
22
|
streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
|
|
23
23
|
count(table: string): Promise<number>;
|
|
24
24
|
increment(table: string, id: string, by?: number): Promise<number>;
|
|
25
|
+
incrementBatch(table: string, incrementMap: StringMap<number>): Promise<StringMap<number>>;
|
|
25
26
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InMemoryKeyValueDB = void 0;
|
|
4
4
|
const node_stream_1 = require("node:stream");
|
|
5
|
+
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
6
|
const commonKeyValueDB_1 = require("../../kv/commonKeyValueDB");
|
|
6
7
|
class InMemoryKeyValueDB {
|
|
7
8
|
constructor(cfg = {}) {
|
|
@@ -18,6 +19,7 @@ class InMemoryKeyValueDB {
|
|
|
18
19
|
this.data[table] ||= {};
|
|
19
20
|
ids.forEach(id => delete this.data[table][id]);
|
|
20
21
|
}
|
|
22
|
+
// todo: but should we work with Tuples or Objects?
|
|
21
23
|
async getByIds(table, ids) {
|
|
22
24
|
this.data[table] ||= {};
|
|
23
25
|
return ids.map(id => [id, this.data[table][id]]).filter(e => e[1]);
|
|
@@ -46,5 +48,16 @@ class InMemoryKeyValueDB {
|
|
|
46
48
|
this.data[table][id] = Buffer.from(String(newValue));
|
|
47
49
|
return newValue;
|
|
48
50
|
}
|
|
51
|
+
async incrementBatch(table, incrementMap) {
|
|
52
|
+
this.data[table] ||= {};
|
|
53
|
+
const result = {};
|
|
54
|
+
for (const [id, by] of (0, js_lib_1._stringMapEntries)(incrementMap)) {
|
|
55
|
+
const newValue = parseInt(this.data[table][id]?.toString() || '0') + by;
|
|
56
|
+
// todo: but should this.data store Buffer or number for incremented values?
|
|
57
|
+
this.data[table][id] = Buffer.from(String(newValue));
|
|
58
|
+
result[id] = newValue;
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
49
62
|
}
|
|
50
63
|
exports.InMemoryKeyValueDB = InMemoryKeyValueDB;
|
package/dist/base.common.db.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
1
|
+
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, StringMap } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDB, CommonDBSupport, CommonDBType } from './common.db';
|
|
4
|
-
import { CommonDBOptions, CommonDBSaveOptions, CommonDBTransactionOptions,
|
|
4
|
+
import { CommonDBOptions, CommonDBSaveOptions, CommonDBTransactionOptions, DBTransactionFn, RunQueryResult } from './db.model';
|
|
5
5
|
import { DBQuery } from './query/dbQuery';
|
|
6
6
|
/**
|
|
7
7
|
* No-op implementation of CommonDB interface.
|
|
@@ -16,11 +16,12 @@ export declare class BaseCommonDB implements CommonDB {
|
|
|
16
16
|
createTable<ROW extends ObjectWithId>(_table: string, _schema: JsonSchemaObject<ROW>): Promise<void>;
|
|
17
17
|
getByIds<ROW extends ObjectWithId>(_table: string, _ids: string[]): Promise<ROW[]>;
|
|
18
18
|
deleteByQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<number>;
|
|
19
|
-
|
|
19
|
+
patchByQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>, _patch: Partial<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
20
20
|
runQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
|
21
21
|
runQueryCount<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<number>;
|
|
22
22
|
saveBatch<ROW extends ObjectWithId>(_table: string, _rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
23
23
|
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): ReadableTyped<ROW>;
|
|
24
24
|
deleteByIds(_table: string, _ids: string[], _opt?: CommonDBOptions): Promise<number>;
|
|
25
25
|
runInTransaction(fn: DBTransactionFn, _opt?: CommonDBTransactionOptions): Promise<void>;
|
|
26
|
+
incrementBatch(_table: string, _prop: string, _incrementMap: StringMap<number>, _opt?: CommonDBOptions): Promise<StringMap<number>>;
|
|
26
27
|
}
|
package/dist/base.common.db.js
CHANGED
|
@@ -30,8 +30,8 @@ class BaseCommonDB {
|
|
|
30
30
|
async deleteByQuery(_q) {
|
|
31
31
|
throw new Error('deleteByQuery is not implemented');
|
|
32
32
|
}
|
|
33
|
-
async
|
|
34
|
-
throw new Error('
|
|
33
|
+
async patchByQuery(_q, _patch, _opt) {
|
|
34
|
+
throw new Error('patchByQuery is not implemented');
|
|
35
35
|
}
|
|
36
36
|
async runQuery(_q) {
|
|
37
37
|
throw new Error('runQuery is not implemented');
|
|
@@ -53,5 +53,8 @@ class BaseCommonDB {
|
|
|
53
53
|
await fn(tx);
|
|
54
54
|
// there's no try/catch and rollback, as there's nothing to rollback
|
|
55
55
|
}
|
|
56
|
+
async incrementBatch(_table, _prop, _incrementMap, _opt) {
|
|
57
|
+
throw new Error('incrementBatch is not implemented');
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
exports.BaseCommonDB = BaseCommonDB;
|
package/dist/common.db.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
1
|
+
import { JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, StringMap } from '@naturalcycles/js-lib';
|
|
2
2
|
import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBTransactionOptions,
|
|
3
|
+
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBTransactionOptions, DBTransactionFn, RunQueryResult } from './db.model';
|
|
4
4
|
import { DBQuery } from './query/dbQuery';
|
|
5
5
|
export declare enum CommonDBType {
|
|
6
6
|
'document' = "document",
|
|
@@ -64,7 +64,7 @@ export interface CommonDB {
|
|
|
64
64
|
*/
|
|
65
65
|
deleteByQuery: <ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBOptions) => Promise<number>;
|
|
66
66
|
/**
|
|
67
|
-
* Applies patch to the rows
|
|
67
|
+
* Applies patch to all the rows that are matched by the query.
|
|
68
68
|
*
|
|
69
69
|
* Example:
|
|
70
70
|
*
|
|
@@ -72,16 +72,9 @@ export interface CommonDB {
|
|
|
72
72
|
*
|
|
73
73
|
* patch would be { A: 'B' } for that query.
|
|
74
74
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* UPDATE table SET A = A + 1
|
|
78
|
-
*
|
|
79
|
-
* In that case patch would look like:
|
|
80
|
-
* { A: DBIncrement(1) }
|
|
81
|
-
*
|
|
82
|
-
* Returns number of rows affected.
|
|
75
|
+
* Returns the number of rows affected.
|
|
83
76
|
*/
|
|
84
|
-
|
|
77
|
+
patchByQuery: <ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: Partial<ROW>, opt?: CommonDBOptions) => Promise<number>;
|
|
85
78
|
/**
|
|
86
79
|
* Should be implemented as a Transaction (best effort), which means that
|
|
87
80
|
* either ALL or NONE of the operations should be applied.
|
|
@@ -94,6 +87,22 @@ export interface CommonDB {
|
|
|
94
87
|
* unless specified as readOnly in CommonDBTransactionOptions.
|
|
95
88
|
*/
|
|
96
89
|
runInTransaction: (fn: DBTransactionFn, opt?: CommonDBTransactionOptions) => Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Increments a value of a property by a given amount.
|
|
92
|
+
* This is a batch operation, so it allows to increment multiple rows at once.
|
|
93
|
+
*
|
|
94
|
+
* - table - the table to apply operations on
|
|
95
|
+
* - prop - name of the property to increment (in each of the rows passed)
|
|
96
|
+
* - incrementMap - map from id to increment value
|
|
97
|
+
*
|
|
98
|
+
* Example of incrementMap:
|
|
99
|
+
* { rowId1: 2, rowId2: 3 }
|
|
100
|
+
*
|
|
101
|
+
* Returns the incrementMap with the same keys and updated values.
|
|
102
|
+
*
|
|
103
|
+
* @experimental
|
|
104
|
+
*/
|
|
105
|
+
incrementBatch: (table: string, prop: string, incrementMap: StringMap<number>, opt?: CommonDBOptions) => Promise<StringMap<number>>;
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
108
|
* Manifest of supported features.
|
|
@@ -106,8 +115,8 @@ export interface CommonDBSupport {
|
|
|
106
115
|
dbQuerySelectFields?: boolean;
|
|
107
116
|
insertSaveMethod?: boolean;
|
|
108
117
|
updateSaveMethod?: boolean;
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
patchByQuery?: boolean;
|
|
119
|
+
increment?: boolean;
|
|
111
120
|
createTable?: boolean;
|
|
112
121
|
tableSchemas?: boolean;
|
|
113
122
|
streaming?: boolean;
|
package/dist/common.db.js
CHANGED
|
@@ -14,8 +14,8 @@ exports.commonDBFullSupport = {
|
|
|
14
14
|
dbQuerySelectFields: true,
|
|
15
15
|
insertSaveMethod: true,
|
|
16
16
|
updateSaveMethod: true,
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
patchByQuery: true,
|
|
18
|
+
increment: true,
|
|
19
19
|
createTable: true,
|
|
20
20
|
tableSchemas: true,
|
|
21
21
|
streaming: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Transform } from 'node:stream';
|
|
2
|
-
import { AsyncMapper, BaseDBEntity, CommonLogger, JsonSchemaObject, JsonSchemaRootObject, UnixTimestampMillisNumber, Unsaved, ZodSchema } from '@naturalcycles/js-lib';
|
|
2
|
+
import { AsyncMapper, BaseDBEntity, CommonLogger, JsonSchemaObject, JsonSchemaRootObject, StringMap, UnixTimestampMillisNumber, Unsaved, ZodSchema } from '@naturalcycles/js-lib';
|
|
3
3
|
import { AjvSchema, ObjectSchema, ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
4
|
-
import { CommonDBTransactionOptions,
|
|
4
|
+
import { CommonDBTransactionOptions, DBTransaction, RunQueryResult } from '../db.model';
|
|
5
5
|
import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
|
|
6
6
|
import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoPatchByIdOptions, CommonDaoPatchOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, CommonDaoStreamSaveOptions } from './common.dao.model';
|
|
7
7
|
/**
|
|
@@ -125,9 +125,20 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
125
125
|
* This is expected to be more memory-efficient way of deleting large number of rows.
|
|
126
126
|
*/
|
|
127
127
|
deleteByQuery(q: DBQuery<DBM>, opt?: CommonDaoStreamDeleteOptions<DBM>): Promise<number>;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
patchByIds(ids: ID[], patch: Partial<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
129
|
+
patchByQuery(q: DBQuery<DBM>, patch: Partial<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
130
|
+
/**
|
|
131
|
+
* Caveat: it doesn't update created/updated props.
|
|
132
|
+
*
|
|
133
|
+
* @experimental
|
|
134
|
+
*/
|
|
135
|
+
increment(prop: keyof DBM, id: ID, by?: number, opt?: CommonDaoOptions): Promise<number>;
|
|
136
|
+
/**
|
|
137
|
+
* Caveat: it doesn't update created/updated props.
|
|
138
|
+
*
|
|
139
|
+
* @experimental
|
|
140
|
+
*/
|
|
141
|
+
incrementBatch(prop: keyof DBM, incrementMap: StringMap<number>, opt?: CommonDaoOptions): Promise<StringMap<number>>;
|
|
131
142
|
dbmToBM(_dbm: undefined, opt?: CommonDaoOptions): Promise<undefined>;
|
|
132
143
|
dbmToBM(_dbm?: DBM, opt?: CommonDaoOptions): Promise<BM>;
|
|
133
144
|
dbmsToBM(dbms: DBM[], opt?: CommonDaoOptions): Promise<BM[]>;
|
|
@@ -829,25 +829,54 @@ class CommonDao {
|
|
|
829
829
|
this.logSaveResult(started, op, q.table);
|
|
830
830
|
return deleted;
|
|
831
831
|
}
|
|
832
|
-
async
|
|
833
|
-
return await this.updateByQuery(this.query().filterEq('id', id), patch, opt);
|
|
834
|
-
}
|
|
835
|
-
async updateByIds(ids, patch, opt = {}) {
|
|
832
|
+
async patchByIds(ids, patch, opt = {}) {
|
|
836
833
|
if (!ids.length)
|
|
837
834
|
return 0;
|
|
838
|
-
return await this.
|
|
835
|
+
return await this.patchByQuery(this.query().filterIn('id', ids), patch, opt);
|
|
839
836
|
}
|
|
840
|
-
async
|
|
837
|
+
async patchByQuery(q, patch, opt = {}) {
|
|
841
838
|
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
842
839
|
this.requireWriteAccess();
|
|
843
840
|
this.requireObjectMutability(opt);
|
|
844
841
|
q.table = opt.table || q.table;
|
|
845
|
-
const op = `
|
|
842
|
+
const op = `patchByQuery(${q.pretty()})`;
|
|
846
843
|
const started = this.logStarted(op, q.table);
|
|
847
|
-
const updated = await this.cfg.db.
|
|
844
|
+
const updated = await this.cfg.db.patchByQuery(q, patch, opt);
|
|
848
845
|
this.logSaveResult(started, op, q.table);
|
|
849
846
|
return updated;
|
|
850
847
|
}
|
|
848
|
+
/**
|
|
849
|
+
* Caveat: it doesn't update created/updated props.
|
|
850
|
+
*
|
|
851
|
+
* @experimental
|
|
852
|
+
*/
|
|
853
|
+
async increment(prop, id, by = 1, opt = {}) {
|
|
854
|
+
this.requireWriteAccess();
|
|
855
|
+
this.requireObjectMutability(opt);
|
|
856
|
+
const { table } = this.cfg;
|
|
857
|
+
const op = `increment`;
|
|
858
|
+
const started = this.logStarted(op, table);
|
|
859
|
+
const result = await this.cfg.db.incrementBatch(table, prop, {
|
|
860
|
+
[id]: by,
|
|
861
|
+
});
|
|
862
|
+
this.logSaveResult(started, op, table);
|
|
863
|
+
return result[id];
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Caveat: it doesn't update created/updated props.
|
|
867
|
+
*
|
|
868
|
+
* @experimental
|
|
869
|
+
*/
|
|
870
|
+
async incrementBatch(prop, incrementMap, opt = {}) {
|
|
871
|
+
this.requireWriteAccess();
|
|
872
|
+
this.requireObjectMutability(opt);
|
|
873
|
+
const { table } = this.cfg;
|
|
874
|
+
const op = `incrementBatch`;
|
|
875
|
+
const started = this.logStarted(op, table);
|
|
876
|
+
const result = await this.cfg.db.incrementBatch(table, prop, incrementMap);
|
|
877
|
+
this.logSaveResult(started, op, table);
|
|
878
|
+
return result;
|
|
879
|
+
}
|
|
851
880
|
async dbmToBM(_dbm, opt = {}) {
|
|
852
881
|
if (!_dbm)
|
|
853
882
|
return;
|
package/dist/db.model.d.ts
CHANGED
|
@@ -96,16 +96,3 @@ export declare enum DBModelType {
|
|
|
96
96
|
DBM = "DBM",
|
|
97
97
|
BM = "BM"
|
|
98
98
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Allows to construct a query similar to:
|
|
101
|
-
*
|
|
102
|
-
* UPDATE table SET A = A + 1
|
|
103
|
-
*
|
|
104
|
-
* In this case DBIncement.of(1) will be needed.
|
|
105
|
-
*/
|
|
106
|
-
export declare class DBIncrement {
|
|
107
|
-
amount: number;
|
|
108
|
-
private constructor();
|
|
109
|
-
static of(amount: number): DBIncrement;
|
|
110
|
-
}
|
|
111
|
-
export type DBPatch<ROW extends 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.
|
|
3
|
+
exports.DBModelType = exports.DBRelation = void 0;
|
|
4
4
|
var DBRelation;
|
|
5
5
|
(function (DBRelation) {
|
|
6
6
|
DBRelation["ONE_TO_ONE"] = "ONE_TO_ONE";
|
|
@@ -11,19 +11,3 @@ var DBModelType;
|
|
|
11
11
|
DBModelType["DBM"] = "DBM";
|
|
12
12
|
DBModelType["BM"] = "BM";
|
|
13
13
|
})(DBModelType || (exports.DBModelType = DBModelType = {}));
|
|
14
|
-
/**
|
|
15
|
-
* Allows to construct a query similar to:
|
|
16
|
-
*
|
|
17
|
-
* UPDATE table SET A = A + 1
|
|
18
|
-
*
|
|
19
|
-
* In this case DBIncement.of(1) will be needed.
|
|
20
|
-
*/
|
|
21
|
-
class DBIncrement {
|
|
22
|
-
constructor(amount) {
|
|
23
|
-
this.amount = amount;
|
|
24
|
-
}
|
|
25
|
-
static of(amount) {
|
|
26
|
-
return new DBIncrement(amount);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.DBIncrement = DBIncrement;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UnixTimestampNumber } from '@naturalcycles/js-lib';
|
|
1
|
+
import { StringMap, UnixTimestampNumber } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
3
|
import { CommonDBCreateOptions } from '../db.model';
|
|
4
4
|
/**
|
|
@@ -33,13 +33,27 @@ export interface CommonKeyValueDB {
|
|
|
33
33
|
streamEntries: (table: string, limit?: number) => ReadableTyped<KeyValueDBTuple>;
|
|
34
34
|
count: (table: string) => Promise<number>;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
36
|
* Increments the value of a key in a table by a given amount.
|
|
38
37
|
* Default increment is 1 when `by` is not provided.
|
|
39
38
|
*
|
|
40
39
|
* Returns the new value.
|
|
40
|
+
*
|
|
41
|
+
* @experimental
|
|
41
42
|
*/
|
|
42
43
|
increment: (table: string, id: string, by?: number) => Promise<number>;
|
|
44
|
+
/**
|
|
45
|
+
* Perform a batch of Increment operations.
|
|
46
|
+
* Given incrementMap, increment each key of it by the given amount (value of the map).
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
* { key1: 2, key2: 3 }
|
|
50
|
+
* would increment `key1` by 2, and `key2` by 3.
|
|
51
|
+
*
|
|
52
|
+
* Returns the incrementMap with the same keys and updated values.
|
|
53
|
+
*
|
|
54
|
+
* @experimental
|
|
55
|
+
*/
|
|
56
|
+
incrementBatch: (table: string, incrementMap: StringMap<number>) => Promise<StringMap<number>>;
|
|
43
57
|
}
|
|
44
58
|
export type KeyValueDBTuple = [key: string, value: Buffer];
|
|
45
59
|
export interface CommonKeyValueDBSaveBatchOptions {
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncMapper, BaseDBEntity, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
2
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
3
|
-
import { CommonDaoOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions
|
|
3
|
+
import { CommonDaoOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions } from '..';
|
|
4
4
|
import { CommonDao } from '../commondao/common.dao';
|
|
5
5
|
import { RunQueryResult } from '../db.model';
|
|
6
6
|
/**
|
|
@@ -99,7 +99,7 @@ export declare class RunnableDBQuery<BM extends BaseDBEntity, DBM extends BaseDB
|
|
|
99
99
|
runQueryExtended(opt?: CommonDaoOptions): Promise<RunQueryResult<BM>>;
|
|
100
100
|
runQueryExtendedAsDBM(opt?: CommonDaoOptions): Promise<RunQueryResult<DBM>>;
|
|
101
101
|
runQueryCount(opt?: CommonDaoOptions): Promise<number>;
|
|
102
|
-
|
|
102
|
+
patchByQuery(patch: Partial<DBM>, opt?: CommonDaoOptions): Promise<number>;
|
|
103
103
|
streamQueryForEach(mapper: AsyncMapper<BM, void>, opt?: CommonDaoStreamForEachOptions<BM>): Promise<void>;
|
|
104
104
|
streamQueryAsDBMForEach(mapper: AsyncMapper<DBM, void>, opt?: CommonDaoStreamForEachOptions<DBM>): Promise<void>;
|
|
105
105
|
streamQuery(opt?: CommonDaoStreamOptions<BM>): ReadableTyped<BM>;
|
package/dist/query/dbQuery.js
CHANGED
|
@@ -165,8 +165,8 @@ class RunnableDBQuery extends DBQuery {
|
|
|
165
165
|
async runQueryCount(opt) {
|
|
166
166
|
return await this.dao.runQueryCount(this, opt);
|
|
167
167
|
}
|
|
168
|
-
async
|
|
169
|
-
return await this.dao.
|
|
168
|
+
async patchByQuery(patch, opt) {
|
|
169
|
+
return await this.dao.patchByQuery(this, patch, opt);
|
|
170
170
|
}
|
|
171
171
|
async streamQueryForEach(mapper, opt) {
|
|
172
172
|
await this.dao.streamQueryForEach(this, mapper, opt);
|
package/dist/testing/daoTest.js
CHANGED
|
@@ -99,6 +99,32 @@ function runCommonDaoTest(db, quirks = {}) {
|
|
|
99
99
|
expect(items[0]).toMatchObject(clone);
|
|
100
100
|
(0, dbTest_1.expectMatch)(expectedItems, itemsSaved, quirks);
|
|
101
101
|
});
|
|
102
|
+
if (support.increment) {
|
|
103
|
+
test('increment', async () => {
|
|
104
|
+
await dao.incrementBatch('k3', { id1: 1, id2: 2 });
|
|
105
|
+
let rows = await dao.query().runQuery();
|
|
106
|
+
rows = (0, js_lib_1._sortBy)(rows, r => r.id);
|
|
107
|
+
const expected = expectedItems.map(r => {
|
|
108
|
+
if (r.id === 'id1') {
|
|
109
|
+
return {
|
|
110
|
+
...r,
|
|
111
|
+
k3: r.k3 + 1,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (r.id === 'id2') {
|
|
115
|
+
return {
|
|
116
|
+
...r,
|
|
117
|
+
k3: r.k3 + 2,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return r;
|
|
121
|
+
});
|
|
122
|
+
(0, dbTest_1.expectMatch)(expected, rows, quirks);
|
|
123
|
+
// reset the changes
|
|
124
|
+
await dao.increment('k3', 'id1', -1);
|
|
125
|
+
await dao.increment('k3', 'id2', -2);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
102
128
|
// GET not empty
|
|
103
129
|
test('getByIds all items', async () => {
|
|
104
130
|
const rows = await dao.getByIds(items.map(i => i.id).concat('abcd'));
|
package/dist/testing/dbTest.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.runCommonDBTest = runCommonDBTest;
|
|
|
4
4
|
exports.expectMatch = expectMatch;
|
|
5
5
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
6
|
const common_db_1 = require("../common.db");
|
|
7
|
-
const db_model_1 = require("../db.model");
|
|
8
7
|
const dbQuery_1 = require("../query/dbQuery");
|
|
9
8
|
const test_model_1 = require("./test.model");
|
|
10
9
|
function runCommonDBTest(db, quirks = {}) {
|
|
@@ -236,8 +235,8 @@ function runCommonDBTest(db, quirks = {}) {
|
|
|
236
235
|
expectMatch(expected, rows, quirks);
|
|
237
236
|
});
|
|
238
237
|
}
|
|
239
|
-
if (support.
|
|
240
|
-
test('
|
|
238
|
+
if (support.patchByQuery) {
|
|
239
|
+
test('patchByQuery', async () => {
|
|
241
240
|
// cleanup, reset initial data
|
|
242
241
|
await db.deleteByQuery(queryAll());
|
|
243
242
|
await db.saveBatch(test_model_1.TEST_TABLE, items);
|
|
@@ -245,7 +244,7 @@ function runCommonDBTest(db, quirks = {}) {
|
|
|
245
244
|
k3: 5,
|
|
246
245
|
k2: 'abc',
|
|
247
246
|
};
|
|
248
|
-
await db.
|
|
247
|
+
await db.patchByQuery(dbQuery_1.DBQuery.create(test_model_1.TEST_TABLE).filterEq('even', true), patch);
|
|
249
248
|
const { rows } = await db.runQuery(queryAll());
|
|
250
249
|
const expected = items.map(r => {
|
|
251
250
|
if (r.even) {
|
|
@@ -255,26 +254,25 @@ function runCommonDBTest(db, quirks = {}) {
|
|
|
255
254
|
});
|
|
256
255
|
expectMatch(expected, rows, quirks);
|
|
257
256
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
});
|
|
275
|
-
expectMatch(expected, rows, quirks);
|
|
257
|
+
}
|
|
258
|
+
if (support.increment) {
|
|
259
|
+
test('incrementBatch', async () => {
|
|
260
|
+
// cleanup, reset initial data
|
|
261
|
+
await db.deleteByQuery(queryAll());
|
|
262
|
+
await db.saveBatch(test_model_1.TEST_TABLE, items);
|
|
263
|
+
await db.incrementBatch(test_model_1.TEST_TABLE, 'k3', { id1: 1, id2: 2 });
|
|
264
|
+
const { rows } = await db.runQuery(queryAll());
|
|
265
|
+
const expected = items.map(r => {
|
|
266
|
+
if (r.id === 'id1') {
|
|
267
|
+
return { ...r, k3: 2 };
|
|
268
|
+
}
|
|
269
|
+
if (r.id === 'id2') {
|
|
270
|
+
return { ...r, k3: 4 };
|
|
271
|
+
}
|
|
272
|
+
return r;
|
|
276
273
|
});
|
|
277
|
-
|
|
274
|
+
expectMatch(expected, rows, quirks);
|
|
275
|
+
});
|
|
278
276
|
}
|
|
279
277
|
if (support.queries) {
|
|
280
278
|
test('cleanup', async () => {
|