@naturalcycles/db-lib 8.48.0 → 8.49.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 +1 -0
- package/dist/adapter/cachedb/cache.db.js +30 -0
- package/dist/adapter/file/file.db.d.ts +1 -0
- package/dist/adapter/file/file.db.js +4 -0
- package/dist/adapter/inmemory/inMemory.db.d.ts +1 -0
- package/dist/adapter/inmemory/inMemory.db.js +5 -0
- package/dist/base.common.db.d.ts +1 -0
- package/dist/base.common.db.js +3 -0
- package/dist/common.db.d.ts +5 -0
- package/dist/commondao/common.dao.js +7 -9
- package/dist/testing/dbTest.js +8 -8
- package/package.json +1 -1
- package/src/adapter/cachedb/cache.db.ts +52 -1
- package/src/adapter/file/file.db.ts +9 -0
- package/src/adapter/inmemory/inMemory.db.ts +10 -0
- package/src/base.common.db.ts +4 -0
- package/src/common.db.ts +11 -0
- package/src/commondao/common.dao.ts +7 -10
- package/src/testing/dbTest.ts +9 -12
|
@@ -23,6 +23,7 @@ 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[]>;
|
|
26
27
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CacheDBSaveOptions<ROW>): Promise<void>;
|
|
27
28
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBSaveOptions<ROW>): Promise<RunQueryResult<ROW>>;
|
|
28
29
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
@@ -42,6 +42,36 @@ 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
|
+
}
|
|
45
75
|
async saveBatch(table, rows, opt = {}) {
|
|
46
76
|
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
47
77
|
await this.cfg.downstreamDB.saveBatch(table, rows, opt);
|
|
@@ -21,6 +21,7 @@ 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[]>;
|
|
24
25
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
25
26
|
/**
|
|
26
27
|
* Implementation is optimized for loading/saving _whole files_.
|
|
@@ -34,6 +34,10 @@ 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
|
+
}
|
|
37
41
|
async saveBatch(table, rows, _opt) {
|
|
38
42
|
if (!rows.length)
|
|
39
43
|
return; // save some api calls
|
|
@@ -52,6 +52,7 @@ 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[]>;
|
|
55
56
|
saveBatch<ROW extends Partial<ObjectWithId>>(_table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
56
57
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
57
58
|
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>): Promise<number>;
|
|
@@ -67,6 +67,11 @@ class InMemoryDB {
|
|
|
67
67
|
this.data[table] ||= {};
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
async getByIds(_table, ids, _opt) {
|
|
71
|
+
const table = this.cfg.tablesPrefix + _table;
|
|
72
|
+
this.data[table] ||= {};
|
|
73
|
+
return ids.map(id => this.data[table][id]).filter(Boolean);
|
|
74
|
+
}
|
|
70
75
|
async saveBatch(_table, rows, opt = {}) {
|
|
71
76
|
const table = this.cfg.tablesPrefix + _table;
|
|
72
77
|
this.data[table] ||= {};
|
package/dist/base.common.db.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export declare class BaseCommonDB implements CommonDB {
|
|
|
13
13
|
getTables(): Promise<string[]>;
|
|
14
14
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
15
15
|
createTable<ROW extends ObjectWithId>(table: string, schema: JsonSchemaObject<ROW>): Promise<void>;
|
|
16
|
+
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][]): Promise<ROW[]>;
|
|
16
17
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number>;
|
|
17
18
|
updateByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: DBPatch<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
18
19
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
package/dist/base.common.db.js
CHANGED
package/dist/common.db.d.ts
CHANGED
|
@@ -27,6 +27,11 @@ 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[]>;
|
|
30
35
|
/**
|
|
31
36
|
* Order by 'id' is not supported by all implementations (for example, Datastore doesn't support it).
|
|
32
37
|
*/
|
|
@@ -8,7 +8,6 @@ const db_model_1 = require("../db.model");
|
|
|
8
8
|
const dbQuery_1 = require("../query/dbQuery");
|
|
9
9
|
const dbTransaction_1 = require("../transaction/dbTransaction");
|
|
10
10
|
const common_dao_model_1 = require("./common.dao.model");
|
|
11
|
-
/* eslint-disable no-dupe-class-members */
|
|
12
11
|
const isGAE = !!process.env['GAE_INSTANCE'];
|
|
13
12
|
const isCI = !!process.env['CI'];
|
|
14
13
|
/**
|
|
@@ -113,14 +112,14 @@ class CommonDao {
|
|
|
113
112
|
if (opt.timeout) {
|
|
114
113
|
// todo: possibly remove it after debugging is done
|
|
115
114
|
dbm = await (0, js_lib_1.pTimeout)(async () => {
|
|
116
|
-
return (await this.cfg.db.
|
|
115
|
+
return (await this.cfg.db.getByIds(table, [id]))[0];
|
|
117
116
|
}, {
|
|
118
117
|
timeout: opt.timeout,
|
|
119
118
|
name: `getById(${table})`,
|
|
120
119
|
});
|
|
121
120
|
}
|
|
122
121
|
else {
|
|
123
|
-
dbm = (await this.cfg.db.
|
|
122
|
+
dbm = (await this.cfg.db.getByIds(table, [id]))[0];
|
|
124
123
|
}
|
|
125
124
|
const bm = opt.raw ? dbm : await this.dbmToBM(dbm, opt);
|
|
126
125
|
this.logResult(started, op, bm, table);
|
|
@@ -145,7 +144,7 @@ class CommonDao {
|
|
|
145
144
|
const op = `getByIdAsDBM(${id})`;
|
|
146
145
|
const table = opt.table || this.cfg.table;
|
|
147
146
|
const started = this.logStarted(op, table);
|
|
148
|
-
let [dbm] =
|
|
147
|
+
let [dbm] = await this.cfg.db.getByIds(table, [id]);
|
|
149
148
|
if (!opt.raw) {
|
|
150
149
|
dbm = this.anyToDBM(dbm, opt);
|
|
151
150
|
}
|
|
@@ -158,7 +157,7 @@ class CommonDao {
|
|
|
158
157
|
const op = `getByIdAsTM(${id})`;
|
|
159
158
|
const table = opt.table || this.cfg.table;
|
|
160
159
|
const started = this.logStarted(op, table);
|
|
161
|
-
const [dbm] =
|
|
160
|
+
const [dbm] = await this.cfg.db.getByIds(table, [id]);
|
|
162
161
|
if (opt.raw) {
|
|
163
162
|
this.logResult(started, op, dbm, table);
|
|
164
163
|
return dbm || null;
|
|
@@ -172,7 +171,7 @@ class CommonDao {
|
|
|
172
171
|
const op = `getByIds ${ids.length} id(s) (${(0, js_lib_1._truncate)(ids.slice(0, 10).join(', '), 50)})`;
|
|
173
172
|
const table = opt.table || this.cfg.table;
|
|
174
173
|
const started = this.logStarted(op, table);
|
|
175
|
-
const dbms =
|
|
174
|
+
const dbms = await this.cfg.db.getByIds(table, ids);
|
|
176
175
|
const bms = opt.raw ? dbms : await this.dbmsToBM(dbms, opt);
|
|
177
176
|
this.logResult(started, op, bms, table);
|
|
178
177
|
return bms;
|
|
@@ -181,7 +180,7 @@ class CommonDao {
|
|
|
181
180
|
const op = `getByIdsAsDBM ${ids.length} id(s) (${(0, js_lib_1._truncate)(ids.slice(0, 10).join(', '), 50)})`;
|
|
182
181
|
const table = opt.table || this.cfg.table;
|
|
183
182
|
const started = this.logStarted(op, table);
|
|
184
|
-
const dbms =
|
|
183
|
+
const dbms = await this.cfg.db.getByIds(table, ids);
|
|
185
184
|
this.logResult(started, op, dbms, table);
|
|
186
185
|
return dbms;
|
|
187
186
|
}
|
|
@@ -231,8 +230,7 @@ class CommonDao {
|
|
|
231
230
|
}
|
|
232
231
|
async ensureUniqueId(table, dbm) {
|
|
233
232
|
// todo: retry N times
|
|
234
|
-
const existing =
|
|
235
|
-
.rows;
|
|
233
|
+
const existing = await this.cfg.db.getByIds(table, [dbm.id]);
|
|
236
234
|
if (existing.length) {
|
|
237
235
|
throw new js_lib_1.AppError(cnst_1.DBLibError.NON_UNIQUE_ID, {
|
|
238
236
|
table,
|
package/dist/testing/dbTest.js
CHANGED
|
@@ -37,7 +37,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
37
37
|
// DELETE ALL initially
|
|
38
38
|
test('deleteByIds test items', async () => {
|
|
39
39
|
const { rows } = await db.runQuery(queryAll().select(['id']));
|
|
40
|
-
await db.
|
|
40
|
+
await db.deleteByQuery(queryAll().filterIn('id', rows.map(i => i.id)));
|
|
41
41
|
});
|
|
42
42
|
// QUERY empty
|
|
43
43
|
test('runQuery(all), runQueryCount should return empty', async () => {
|
|
@@ -49,15 +49,15 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
49
49
|
}
|
|
50
50
|
// GET empty
|
|
51
51
|
test('getByIds(item1.id) should return empty', async () => {
|
|
52
|
-
const [item1Loaded] =
|
|
52
|
+
const [item1Loaded] = await db.getByIds(test_model_1.TEST_TABLE, [item1.id]);
|
|
53
53
|
// console.log(a)
|
|
54
54
|
expect(item1Loaded).toBeUndefined();
|
|
55
55
|
});
|
|
56
56
|
test('getByIds([]) should return []', async () => {
|
|
57
|
-
expect(
|
|
57
|
+
expect(await db.getByIds(test_model_1.TEST_TABLE, [])).toEqual([]);
|
|
58
58
|
});
|
|
59
59
|
test('getByIds(...) should return empty', async () => {
|
|
60
|
-
expect(
|
|
60
|
+
expect(await db.getByIds(test_model_1.TEST_TABLE, ['abc', 'abcd'])).toEqual([]);
|
|
61
61
|
});
|
|
62
62
|
// SAVE
|
|
63
63
|
if (nullValues) {
|
|
@@ -68,7 +68,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
68
68
|
};
|
|
69
69
|
(0, test_util_1.deepFreeze)(item3);
|
|
70
70
|
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
71
|
-
const item3Loaded = (await db.
|
|
71
|
+
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
72
72
|
expectMatch([item3], [item3Loaded], quirks);
|
|
73
73
|
expect(item3Loaded.k2).toBeNull();
|
|
74
74
|
});
|
|
@@ -83,7 +83,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
83
83
|
const expected = { ...item3 };
|
|
84
84
|
delete expected.k2;
|
|
85
85
|
await db.saveBatch(test_model_1.TEST_TABLE, [item3]);
|
|
86
|
-
const item3Loaded = (await db.
|
|
86
|
+
const item3Loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item3.id]))[0];
|
|
87
87
|
expectMatch([expected], [item3Loaded], quirks);
|
|
88
88
|
expect(item3Loaded.k2).toBeUndefined();
|
|
89
89
|
expect(Object.keys(item3Loaded)).not.toContain('k2');
|
|
@@ -112,7 +112,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
112
112
|
}
|
|
113
113
|
// GET not empty
|
|
114
114
|
test('getByIds all items', async () => {
|
|
115
|
-
const rows =
|
|
115
|
+
const rows = await db.getByIds(test_model_1.TEST_TABLE, items.map(i => i.id).concat('abcd'));
|
|
116
116
|
expectMatch(items, (0, js_lib_1._sortBy)(rows, r => r.id), quirks);
|
|
117
117
|
});
|
|
118
118
|
// QUERY
|
|
@@ -204,7 +204,7 @@ function runCommonDBTest(db, features = {}, quirks = {}) {
|
|
|
204
204
|
b1,
|
|
205
205
|
};
|
|
206
206
|
await db.saveBatch(test_model_1.TEST_TABLE, [item]);
|
|
207
|
-
const loaded = (await db.
|
|
207
|
+
const loaded = (await db.getByIds(test_model_1.TEST_TABLE, [item.id]))[0];
|
|
208
208
|
const b1Loaded = loaded.b1;
|
|
209
209
|
// console.log({
|
|
210
210
|
// b11: typeof b1,
|
package/package.json
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Readable } from 'node:stream'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
JsonSchemaObject,
|
|
4
|
+
JsonSchemaRootObject,
|
|
5
|
+
ObjectWithId,
|
|
6
|
+
StringMap,
|
|
7
|
+
} from '@naturalcycles/js-lib'
|
|
3
8
|
import { BaseCommonDB } from '../../base.common.db'
|
|
4
9
|
import { CommonDB } from '../../common.db'
|
|
5
10
|
import { CommonDBOptions, DBPatch, RunQueryResult } from '../../db.model'
|
|
@@ -67,6 +72,52 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
|
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
override async getByIds<ROW extends ObjectWithId>(
|
|
76
|
+
table: string,
|
|
77
|
+
ids: ROW['id'][],
|
|
78
|
+
opt: CacheDBSaveOptions<ROW> = {},
|
|
79
|
+
): Promise<ROW[]> {
|
|
80
|
+
const resultMap: StringMap<ROW> = {}
|
|
81
|
+
const missingIds: ROW['id'][] = []
|
|
82
|
+
|
|
83
|
+
if (!opt.skipCache && !this.cfg.skipCache) {
|
|
84
|
+
const results = await this.cfg.cacheDB.getByIds<ROW>(table, ids, opt)
|
|
85
|
+
|
|
86
|
+
results.forEach(r => (resultMap[r.id] = r))
|
|
87
|
+
|
|
88
|
+
missingIds.push(...ids.filter(id => !resultMap[id]))
|
|
89
|
+
|
|
90
|
+
if (this.cfg.logCached) {
|
|
91
|
+
this.cfg.logger?.log(
|
|
92
|
+
`${table}.getByIds ${results.length} rows from cache: [${results
|
|
93
|
+
.map(r => r.id)
|
|
94
|
+
.join(', ')}]`,
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (missingIds.length && !opt.onlyCache && !this.cfg.onlyCache) {
|
|
100
|
+
const results = await this.cfg.downstreamDB.getByIds<ROW>(table, missingIds, opt)
|
|
101
|
+
results.forEach(r => (resultMap[r.id] = r))
|
|
102
|
+
|
|
103
|
+
if (this.cfg.logDownstream) {
|
|
104
|
+
this.cfg.logger?.log(
|
|
105
|
+
`${table}.getByIds ${results.length} rows from downstream: [${results
|
|
106
|
+
.map(r => r.id)
|
|
107
|
+
.join(', ')}]`,
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!opt.skipCache) {
|
|
112
|
+
const cacheResult = this.cfg.cacheDB.saveBatch(table, results, opt)
|
|
113
|
+
if (this.cfg.awaitCache) await cacheResult
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// return in right order
|
|
118
|
+
return ids.map(id => resultMap[id]!).filter(Boolean)
|
|
119
|
+
}
|
|
120
|
+
|
|
70
121
|
override async saveBatch<ROW extends Partial<ObjectWithId>>(
|
|
71
122
|
table: string,
|
|
72
123
|
rows: ROW[],
|
|
@@ -65,6 +65,15 @@ export class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
65
65
|
return tables
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
override async getByIds<ROW extends ObjectWithId>(
|
|
69
|
+
table: string,
|
|
70
|
+
ids: ROW['id'][],
|
|
71
|
+
_opt?: CommonDBOptions,
|
|
72
|
+
): Promise<ROW[]> {
|
|
73
|
+
const byId = _by(await this.loadFile<ROW>(table), r => r.id)
|
|
74
|
+
return ids.map(id => byId[id]!).filter(Boolean)
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
override async saveBatch<ROW extends Partial<ObjectWithId>>(
|
|
69
78
|
table: string,
|
|
70
79
|
rows: ROW[],
|
|
@@ -143,6 +143,16 @@ export class InMemoryDB implements CommonDB {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
async getByIds<ROW extends ObjectWithId>(
|
|
147
|
+
_table: string,
|
|
148
|
+
ids: ROW['id'][],
|
|
149
|
+
_opt?: CommonDBOptions,
|
|
150
|
+
): Promise<ROW[]> {
|
|
151
|
+
const table = this.cfg.tablesPrefix + _table
|
|
152
|
+
this.data[table] ||= {}
|
|
153
|
+
return ids.map(id => this.data[table]![id] as ROW).filter(Boolean)
|
|
154
|
+
}
|
|
155
|
+
|
|
146
156
|
async saveBatch<ROW extends Partial<ObjectWithId>>(
|
|
147
157
|
_table: string,
|
|
148
158
|
rows: ROW[],
|
package/src/base.common.db.ts
CHANGED
|
@@ -33,6 +33,10 @@ export class BaseCommonDB implements CommonDB {
|
|
|
33
33
|
// no-op
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
async getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][]): Promise<ROW[]> {
|
|
37
|
+
throw new Error('getByIds is not implemented')
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
async deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>): Promise<number> {
|
|
37
41
|
throw new Error('deleteByQuery is not implemented')
|
|
38
42
|
}
|
package/src/common.db.ts
CHANGED
|
@@ -43,6 +43,17 @@ export interface CommonDB {
|
|
|
43
43
|
opt?: CommonDBCreateOptions,
|
|
44
44
|
): Promise<void>
|
|
45
45
|
|
|
46
|
+
// GET
|
|
47
|
+
/**
|
|
48
|
+
* Order of items returned is not guaranteed to match order of ids.
|
|
49
|
+
* (Such limitation exists because Datastore doesn't support it).
|
|
50
|
+
*/
|
|
51
|
+
getByIds<ROW extends ObjectWithId>(
|
|
52
|
+
table: string,
|
|
53
|
+
ids: ROW['id'][],
|
|
54
|
+
opt?: CommonDBOptions,
|
|
55
|
+
): Promise<ROW[]>
|
|
56
|
+
|
|
46
57
|
// QUERY
|
|
47
58
|
/**
|
|
48
59
|
* Order by 'id' is not supported by all implementations (for example, Datastore doesn't support it).
|
|
@@ -56,8 +56,6 @@ import {
|
|
|
56
56
|
CommonDaoStreamOptions,
|
|
57
57
|
} from './common.dao.model'
|
|
58
58
|
|
|
59
|
-
/* eslint-disable no-dupe-class-members */
|
|
60
|
-
|
|
61
59
|
const isGAE = !!process.env['GAE_INSTANCE']
|
|
62
60
|
const isCI = !!process.env['CI']
|
|
63
61
|
|
|
@@ -136,7 +134,7 @@ export class CommonDao<
|
|
|
136
134
|
// todo: possibly remove it after debugging is done
|
|
137
135
|
dbm = await pTimeout(
|
|
138
136
|
async () => {
|
|
139
|
-
return (await this.cfg.db.
|
|
137
|
+
return (await this.cfg.db.getByIds<DBM>(table, [id]))[0]
|
|
140
138
|
},
|
|
141
139
|
{
|
|
142
140
|
timeout: opt.timeout,
|
|
@@ -144,7 +142,7 @@ export class CommonDao<
|
|
|
144
142
|
},
|
|
145
143
|
)
|
|
146
144
|
} else {
|
|
147
|
-
dbm = (await this.cfg.db.
|
|
145
|
+
dbm = (await this.cfg.db.getByIds<DBM>(table, [id]))[0]
|
|
148
146
|
}
|
|
149
147
|
|
|
150
148
|
const bm = opt.raw ? (dbm as any) : await this.dbmToBM(dbm, opt)
|
|
@@ -174,7 +172,7 @@ export class CommonDao<
|
|
|
174
172
|
const op = `getByIdAsDBM(${id})`
|
|
175
173
|
const table = opt.table || this.cfg.table
|
|
176
174
|
const started = this.logStarted(op, table)
|
|
177
|
-
let [dbm] =
|
|
175
|
+
let [dbm] = await this.cfg.db.getByIds<DBM>(table, [id])
|
|
178
176
|
if (!opt.raw) {
|
|
179
177
|
dbm = this.anyToDBM(dbm!, opt)
|
|
180
178
|
}
|
|
@@ -189,7 +187,7 @@ export class CommonDao<
|
|
|
189
187
|
const op = `getByIdAsTM(${id})`
|
|
190
188
|
const table = opt.table || this.cfg.table
|
|
191
189
|
const started = this.logStarted(op, table)
|
|
192
|
-
const [dbm] =
|
|
190
|
+
const [dbm] = await this.cfg.db.getByIds<DBM>(table, [id])
|
|
193
191
|
if (opt.raw) {
|
|
194
192
|
this.logResult(started, op, dbm, table)
|
|
195
193
|
return (dbm as any) || null
|
|
@@ -204,7 +202,7 @@ export class CommonDao<
|
|
|
204
202
|
const op = `getByIds ${ids.length} id(s) (${_truncate(ids.slice(0, 10).join(', '), 50)})`
|
|
205
203
|
const table = opt.table || this.cfg.table
|
|
206
204
|
const started = this.logStarted(op, table)
|
|
207
|
-
const dbms =
|
|
205
|
+
const dbms = await this.cfg.db.getByIds<DBM>(table, ids)
|
|
208
206
|
const bms = opt.raw ? (dbms as any) : await this.dbmsToBM(dbms, opt)
|
|
209
207
|
this.logResult(started, op, bms, table)
|
|
210
208
|
return bms
|
|
@@ -214,7 +212,7 @@ export class CommonDao<
|
|
|
214
212
|
const op = `getByIdsAsDBM ${ids.length} id(s) (${_truncate(ids.slice(0, 10).join(', '), 50)})`
|
|
215
213
|
const table = opt.table || this.cfg.table
|
|
216
214
|
const started = this.logStarted(op, table)
|
|
217
|
-
const dbms =
|
|
215
|
+
const dbms = await this.cfg.db.getByIds<DBM>(table, ids)
|
|
218
216
|
this.logResult(started, op, dbms, table)
|
|
219
217
|
return dbms
|
|
220
218
|
}
|
|
@@ -270,8 +268,7 @@ export class CommonDao<
|
|
|
270
268
|
|
|
271
269
|
private async ensureUniqueId(table: string, dbm: DBM): Promise<void> {
|
|
272
270
|
// todo: retry N times
|
|
273
|
-
const existing =
|
|
274
|
-
.rows
|
|
271
|
+
const existing = await this.cfg.db.getByIds<DBM>(table, [dbm.id])
|
|
275
272
|
if (existing.length) {
|
|
276
273
|
throw new AppError(DBLibError.NON_UNIQUE_ID, {
|
|
277
274
|
table,
|
package/src/testing/dbTest.ts
CHANGED
|
@@ -129,10 +129,9 @@ export function runCommonDBTest(
|
|
|
129
129
|
// DELETE ALL initially
|
|
130
130
|
test('deleteByIds test items', async () => {
|
|
131
131
|
const { rows } = await db.runQuery(queryAll().select(['id']))
|
|
132
|
-
await db.
|
|
133
|
-
queryAll().
|
|
132
|
+
await db.deleteByQuery(
|
|
133
|
+
queryAll().filterIn(
|
|
134
134
|
'id',
|
|
135
|
-
'in',
|
|
136
135
|
rows.map(i => i.id),
|
|
137
136
|
),
|
|
138
137
|
)
|
|
@@ -148,17 +147,17 @@ export function runCommonDBTest(
|
|
|
148
147
|
|
|
149
148
|
// GET empty
|
|
150
149
|
test('getByIds(item1.id) should return empty', async () => {
|
|
151
|
-
const [item1Loaded] =
|
|
150
|
+
const [item1Loaded] = await db.getByIds(TEST_TABLE, [item1.id])
|
|
152
151
|
// console.log(a)
|
|
153
152
|
expect(item1Loaded).toBeUndefined()
|
|
154
153
|
})
|
|
155
154
|
|
|
156
155
|
test('getByIds([]) should return []', async () => {
|
|
157
|
-
expect(
|
|
156
|
+
expect(await db.getByIds(TEST_TABLE, [])).toEqual([])
|
|
158
157
|
})
|
|
159
158
|
|
|
160
159
|
test('getByIds(...) should return empty', async () => {
|
|
161
|
-
expect(
|
|
160
|
+
expect(await db.getByIds(TEST_TABLE, ['abc', 'abcd'])).toEqual([])
|
|
162
161
|
})
|
|
163
162
|
|
|
164
163
|
// SAVE
|
|
@@ -170,7 +169,7 @@ export function runCommonDBTest(
|
|
|
170
169
|
}
|
|
171
170
|
deepFreeze(item3)
|
|
172
171
|
await db.saveBatch(TEST_TABLE, [item3])
|
|
173
|
-
const item3Loaded = (await db.
|
|
172
|
+
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
174
173
|
expectMatch([item3], [item3Loaded], quirks)
|
|
175
174
|
expect(item3Loaded.k2).toBeNull()
|
|
176
175
|
})
|
|
@@ -187,7 +186,7 @@ export function runCommonDBTest(
|
|
|
187
186
|
delete expected.k2
|
|
188
187
|
|
|
189
188
|
await db.saveBatch(TEST_TABLE, [item3])
|
|
190
|
-
const item3Loaded = (await db.
|
|
189
|
+
const item3Loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item3.id]))[0]!
|
|
191
190
|
expectMatch([expected], [item3Loaded], quirks)
|
|
192
191
|
expect(item3Loaded.k2).toBeUndefined()
|
|
193
192
|
expect(Object.keys(item3Loaded)).not.toContain('k2')
|
|
@@ -222,9 +221,7 @@ export function runCommonDBTest(
|
|
|
222
221
|
|
|
223
222
|
// GET not empty
|
|
224
223
|
test('getByIds all items', async () => {
|
|
225
|
-
const rows = (
|
|
226
|
-
await db.runQuery(queryAll().filter('id', 'in', items.map(i => i.id).concat('abcd')))
|
|
227
|
-
).rows
|
|
224
|
+
const rows = await db.getByIds<TestItemDBM>(TEST_TABLE, items.map(i => i.id).concat('abcd'))
|
|
228
225
|
expectMatch(
|
|
229
226
|
items,
|
|
230
227
|
_sortBy(rows, r => r.id),
|
|
@@ -349,7 +346,7 @@ export function runCommonDBTest(
|
|
|
349
346
|
b1,
|
|
350
347
|
}
|
|
351
348
|
await db.saveBatch(TEST_TABLE, [item])
|
|
352
|
-
const loaded = (await db.
|
|
349
|
+
const loaded = (await db.getByIds<TestItemDBM>(TEST_TABLE, [item.id]))[0]!
|
|
353
350
|
const b1Loaded = loaded.b1!
|
|
354
351
|
// console.log({
|
|
355
352
|
// b11: typeof b1,
|