@naturalcycles/db-lib 10.26.1 → 10.27.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 +6 -6
- package/dist/adapter/file/file.db.d.ts +2 -2
- package/dist/adapter/file/file.db.js +5 -6
- package/dist/commondao/common.dao.d.ts +7 -21
- package/dist/commondao/common.dao.js +36 -153
- package/dist/commondao/common.dao.model.d.ts +1 -19
- package/dist/commondb/base.common.db.d.ts +2 -2
- package/dist/commondb/common.db.d.ts +2 -2
- package/dist/inmemory/inMemory.db.d.ts +2 -2
- package/dist/inmemory/inMemory.db.js +2 -2
- package/dist/inmemory/inMemoryKeyValueDB.d.ts +4 -4
- package/dist/inmemory/inMemoryKeyValueDB.js +4 -4
- package/dist/kv/commonKeyValueDB.d.ts +4 -4
- package/dist/kv/commonKeyValueDao.d.ts +5 -5
- package/dist/kv/commonKeyValueDao.js +9 -12
- package/dist/pipeline/dbPipelineBackup.d.ts +1 -1
- package/dist/pipeline/dbPipelineBackup.js +3 -3
- package/dist/pipeline/dbPipelineCopy.d.ts +1 -1
- package/dist/pipeline/dbPipelineCopy.js +3 -4
- package/dist/pipeline/dbPipelineRestore.js +1 -1
- package/dist/query/dbQuery.d.ts +6 -12
- package/dist/query/dbQuery.js +0 -19
- package/dist/testing/commonDaoTest.js +8 -2
- package/package.json +2 -2
- package/src/adapter/cachedb/cache.db.ts +7 -8
- package/src/adapter/file/file.db.ts +6 -10
- package/src/commondao/common.dao.model.ts +1 -26
- package/src/commondao/common.dao.ts +45 -205
- package/src/commondb/base.common.db.ts +2 -2
- package/src/commondb/common.db.ts +2 -2
- package/src/inmemory/inMemory.db.ts +3 -7
- package/src/inmemory/inMemoryKeyValueDB.ts +7 -8
- package/src/kv/commonKeyValueDB.ts +4 -4
- package/src/kv/commonKeyValueDao.ts +16 -20
- package/src/pipeline/dbPipelineBackup.ts +6 -6
- package/src/pipeline/dbPipelineCopy.ts +6 -8
- package/src/pipeline/dbPipelineRestore.ts +1 -1
- package/src/query/dbQuery.ts +5 -39
- package/src/testing/commonDaoTest.ts +8 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
2
2
|
import type { ObjectWithId } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import
|
|
3
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import { BaseCommonDB } from '../../commondb/base.common.db.js';
|
|
5
5
|
import type { CommonDB, CommonDBSupport } from '../../commondb/common.db.js';
|
|
6
6
|
import type { RunQueryResult } from '../../db.model.js';
|
|
@@ -27,7 +27,7 @@ export declare class CacheDB extends BaseCommonDB implements CommonDB {
|
|
|
27
27
|
saveBatch<ROW extends ObjectWithId>(table: string, rows: ROW[], opt?: CacheDBSaveOptions<ROW>): Promise<void>;
|
|
28
28
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBSaveOptions<ROW>): Promise<RunQueryResult<ROW>>;
|
|
29
29
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
30
|
-
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBStreamOptions):
|
|
30
|
+
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBStreamOptions): Pipeline<ROW>;
|
|
31
31
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
32
32
|
patchByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: Partial<ROW>, opt?: CacheDBOptions): Promise<number>;
|
|
33
33
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
2
1
|
import { _isTruthy } from '@naturalcycles/js-lib';
|
|
2
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
3
3
|
import { BaseCommonDB } from '../../commondb/base.common.db.js';
|
|
4
4
|
import { commonDBFullSupport } from '../../commondb/common.db.js';
|
|
5
5
|
/**
|
|
@@ -130,7 +130,7 @@ export class CacheDB extends BaseCommonDB {
|
|
|
130
130
|
}
|
|
131
131
|
streamQuery(q, opt = {}) {
|
|
132
132
|
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
133
|
-
const
|
|
133
|
+
const pipeline = this.cfg.downstreamDB.streamQuery(q, opt);
|
|
134
134
|
// Don't save to cache if it was a projection query
|
|
135
135
|
if (!opt.skipCache && !this.cfg.skipCache && !q._selectedFieldNames) {
|
|
136
136
|
// todo: rethink if we really should download WHOLE stream into memory in order to save it to cache
|
|
@@ -141,11 +141,11 @@ export class CacheDB extends BaseCommonDB {
|
|
|
141
141
|
// await this.cfg.cacheDB.saveBatch(q.table, dbms as any)
|
|
142
142
|
// })
|
|
143
143
|
}
|
|
144
|
-
return
|
|
144
|
+
return pipeline;
|
|
145
145
|
}
|
|
146
146
|
if (opt.skipCache || this.cfg.skipCache)
|
|
147
|
-
return
|
|
148
|
-
const
|
|
147
|
+
return Pipeline.fromArray([]);
|
|
148
|
+
const pipeline = this.cfg.cacheDB.streamQuery(q, opt);
|
|
149
149
|
// if (this.cfg.logCached) {
|
|
150
150
|
// let count = 0
|
|
151
151
|
//
|
|
@@ -156,7 +156,7 @@ export class CacheDB extends BaseCommonDB {
|
|
|
156
156
|
// this.log(`${q.table}.streamQuery ${length} rows from cache`)
|
|
157
157
|
// })
|
|
158
158
|
// }
|
|
159
|
-
return
|
|
159
|
+
return pipeline;
|
|
160
160
|
}
|
|
161
161
|
async deleteByQuery(q, opt = {}) {
|
|
162
162
|
if (!opt.onlyCache && !this.cfg.onlyCache) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
2
2
|
import { type ObjectWithId } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import
|
|
3
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import { BaseCommonDB } from '../../commondb/base.common.db.js';
|
|
5
5
|
import type { CommonDB, CommonDBSupport } from '../../commondb/common.db.js';
|
|
6
6
|
import type { CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, DBSaveBatchOperation, RunQueryResult } from '../../db.model.js';
|
|
@@ -26,7 +26,7 @@ export declare class FileDB extends BaseCommonDB implements CommonDB {
|
|
|
26
26
|
saveBatch<ROW extends ObjectWithId>(table: string, rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
27
27
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
28
28
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
29
|
-
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions):
|
|
29
|
+
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions): Pipeline<ROW>;
|
|
30
30
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
31
31
|
deleteByIds(table: string, ids: string[], _opt?: CommonDBOptions): Promise<number>;
|
|
32
32
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
1
2
|
import { _by, _sortBy } from '@naturalcycles/js-lib/array';
|
|
2
3
|
import { _since, localTime } from '@naturalcycles/js-lib/datetime';
|
|
3
4
|
import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
@@ -5,7 +6,7 @@ import { generateJsonSchemaFromData } from '@naturalcycles/js-lib/json-schema';
|
|
|
5
6
|
import { _deepEquals, _filterUndefinedValues, _sortObjectDeep } from '@naturalcycles/js-lib/object';
|
|
6
7
|
import { _stringMapValues, } from '@naturalcycles/js-lib/types';
|
|
7
8
|
import { dimGrey } from '@naturalcycles/nodejs-lib/colors';
|
|
8
|
-
import {
|
|
9
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
9
10
|
import { BaseCommonDB } from '../../commondb/base.common.db.js';
|
|
10
11
|
import { commonDBFullSupport } from '../../commondb/common.db.js';
|
|
11
12
|
import { queryInMemory } from '../../inmemory/queryInMemory.js';
|
|
@@ -82,12 +83,10 @@ export class FileDB extends BaseCommonDB {
|
|
|
82
83
|
return (await this.loadFile(q.table)).length;
|
|
83
84
|
}
|
|
84
85
|
streamQuery(q, opt) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
readable.push(null); // done
|
|
86
|
+
return Pipeline.fromAsyncReadable(async () => {
|
|
87
|
+
const { rows } = await this.runQuery(q, opt);
|
|
88
|
+
return Readable.from(rows);
|
|
89
89
|
});
|
|
90
|
-
return readable;
|
|
91
90
|
}
|
|
92
91
|
async deleteByQuery(q, _opt) {
|
|
93
92
|
const byId = _by(await this.loadFile(q.table), r => r.id);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Transform } from 'node:stream';
|
|
2
2
|
import type { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
3
|
-
import { type
|
|
4
|
-
import { type
|
|
3
|
+
import { type BaseDBEntity, type NonNegativeInteger, type StringMap, type Unsaved } from '@naturalcycles/js-lib/types';
|
|
4
|
+
import { type Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
5
5
|
import type { CommonDBTransactionOptions, RunQueryResult } from '../db.model.js';
|
|
6
6
|
import type { DBQuery } from '../query/dbQuery.js';
|
|
7
7
|
import { RunnableDBQuery } from '../query/dbQuery.js';
|
|
8
|
-
import type { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoPatchByIdOptions, CommonDaoPatchOptions, CommonDaoReadOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions,
|
|
8
|
+
import type { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoPatchByIdOptions, CommonDaoPatchOptions, CommonDaoReadOptions, CommonDaoSaveBatchOptions, CommonDaoSaveOptions, CommonDaoStreamDeleteOptions, CommonDaoStreamOptions, CommonDaoStreamSaveOptions } from './common.dao.model.js';
|
|
9
9
|
import { CommonDaoTransaction } from './commonDaoTransaction.js';
|
|
10
10
|
/**
|
|
11
11
|
* Lowest common denominator API between supported Databases.
|
|
@@ -45,25 +45,11 @@ export declare class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity
|
|
|
45
45
|
runQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoReadOptions): Promise<DBM[]>;
|
|
46
46
|
runQueryExtendedAsDBM(q: DBQuery<DBM>, opt?: CommonDaoReadOptions): Promise<RunQueryResult<DBM>>;
|
|
47
47
|
runQueryCount(q: DBQuery<DBM>, opt?: CommonDaoReadOptions): Promise<number>;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* Stream as Readable, to be able to .pipe() it further with support of backpressure.
|
|
52
|
-
*/
|
|
53
|
-
streamQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<DBM>): ReadableTyped<DBM>;
|
|
54
|
-
/**
|
|
55
|
-
* Stream as Readable, to be able to .pipe() it further with support of backpressure.
|
|
56
|
-
*
|
|
57
|
-
* Please note that this stream is currently not async-iteration friendly, because of
|
|
58
|
-
* `through2` usage.
|
|
59
|
-
* Will be migrated/fixed at some point in the future.
|
|
60
|
-
*
|
|
61
|
-
* You can do `.pipe(transformNoOp)` to make it "valid again".
|
|
62
|
-
*/
|
|
63
|
-
streamQuery(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<BM>): ReadableTyped<BM>;
|
|
48
|
+
streamQueryAsDBM(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<DBM>): Pipeline<DBM>;
|
|
49
|
+
streamQuery(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<BM>): Pipeline<BM>;
|
|
50
|
+
private streamQueryRaw;
|
|
64
51
|
queryIds(q: DBQuery<DBM>, opt?: CommonDaoReadOptions): Promise<ID[]>;
|
|
65
|
-
streamQueryIds(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<ID>):
|
|
66
|
-
streamQueryIdsForEach(q: DBQuery<DBM>, mapper: AsyncIndexedMapper<ID, void>, opt?: CommonDaoStreamForEachOptions<ID>): Promise<void>;
|
|
52
|
+
streamQueryIds(q: DBQuery<DBM>, opt?: CommonDaoStreamOptions<ID>): Pipeline<ID>;
|
|
67
53
|
/**
|
|
68
54
|
* Mutates!
|
|
69
55
|
*/
|
|
@@ -8,8 +8,8 @@ import { pMap } from '@naturalcycles/js-lib/promise/pMap.js';
|
|
|
8
8
|
import { _stringMapEntries, _stringMapValues, } from '@naturalcycles/js-lib/types';
|
|
9
9
|
import { _passthroughPredicate, _typeCast } from '@naturalcycles/js-lib/types';
|
|
10
10
|
import { stringId } from '@naturalcycles/nodejs-lib';
|
|
11
|
-
import {
|
|
12
|
-
import { transformChunk, transformLogProgress, transformMap,
|
|
11
|
+
import { transformFlatten } from '@naturalcycles/nodejs-lib/stream';
|
|
12
|
+
import { transformChunk, transformLogProgress, transformMap, } from '@naturalcycles/nodejs-lib/stream';
|
|
13
13
|
import { DBLibError } from '../cnst.js';
|
|
14
14
|
import { RunnableDBQuery } from '../query/dbQuery.js';
|
|
15
15
|
import { CommonDaoTransaction } from './commonDaoTransaction.js';
|
|
@@ -36,7 +36,6 @@ export class CommonDao {
|
|
|
36
36
|
hooks: {
|
|
37
37
|
parseNaturalId: () => ({}),
|
|
38
38
|
beforeCreate: bm => bm,
|
|
39
|
-
anonymize: dbm => dbm,
|
|
40
39
|
onValidationError: err => err,
|
|
41
40
|
...cfg.hooks,
|
|
42
41
|
},
|
|
@@ -161,116 +160,28 @@ export class CommonDao {
|
|
|
161
160
|
q.table = opt.table || q.table;
|
|
162
161
|
return await this.cfg.db.runQueryCount(q, opt);
|
|
163
162
|
}
|
|
164
|
-
|
|
165
|
-
this.
|
|
166
|
-
q.table = opt.table || q.table;
|
|
167
|
-
opt.skipValidation = opt.skipValidation !== false; // default true
|
|
168
|
-
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
163
|
+
streamQueryAsDBM(q, opt = {}) {
|
|
164
|
+
const pipeline = this.streamQueryRaw(q, opt);
|
|
169
165
|
const isPartialQuery = !!q._selectedFieldNames;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return dbm;
|
|
174
|
-
return await this.dbmToBM(dbm, opt);
|
|
175
|
-
}, {
|
|
176
|
-
errorMode: opt.errorMode,
|
|
177
|
-
})
|
|
178
|
-
.map(mapper, {
|
|
179
|
-
...opt,
|
|
180
|
-
predicate: _passthroughPredicate, // to be able to logProgress
|
|
181
|
-
})
|
|
182
|
-
// LogProgress should be AFTER the mapper, to be able to report correct stats
|
|
183
|
-
.logProgress({
|
|
184
|
-
metric: q.table,
|
|
185
|
-
...opt,
|
|
186
|
-
})
|
|
187
|
-
.run();
|
|
188
|
-
}
|
|
189
|
-
async streamQueryAsDBMForEach(q, mapper, opt = {}) {
|
|
190
|
-
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
191
|
-
q.table = opt.table || q.table;
|
|
192
|
-
opt.skipValidation = opt.skipValidation !== false; // default true
|
|
166
|
+
if (isPartialQuery)
|
|
167
|
+
return pipeline;
|
|
168
|
+
opt.skipValidation ??= true;
|
|
193
169
|
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
194
|
-
|
|
195
|
-
await Pipeline.from(this.cfg.db.streamQuery(q, opt))
|
|
196
|
-
.mapSync(dbm => {
|
|
197
|
-
if (isPartialQuery)
|
|
198
|
-
return dbm;
|
|
199
|
-
return this.anyToDBM(dbm, opt);
|
|
200
|
-
}, {
|
|
201
|
-
errorMode: opt.errorMode,
|
|
202
|
-
})
|
|
203
|
-
.map(mapper, {
|
|
204
|
-
...opt,
|
|
205
|
-
predicate: _passthroughPredicate, // to be able to logProgress
|
|
206
|
-
})
|
|
207
|
-
.logProgress({
|
|
208
|
-
metric: q.table,
|
|
209
|
-
...opt,
|
|
210
|
-
})
|
|
211
|
-
.run();
|
|
170
|
+
return pipeline.mapSync(dbm => this.anyToDBM(dbm, opt), { errorMode: opt.errorMode });
|
|
212
171
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
*/
|
|
216
|
-
streamQueryAsDBM(q, opt = {}) {
|
|
217
|
-
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
218
|
-
q.table = opt.table || q.table;
|
|
219
|
-
opt.skipValidation = opt.skipValidation !== false; // default true
|
|
220
|
-
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
172
|
+
streamQuery(q, opt = {}) {
|
|
173
|
+
const pipeline = this.streamQueryRaw(q, opt);
|
|
221
174
|
const isPartialQuery = !!q._selectedFieldNames;
|
|
222
|
-
const stream = this.cfg.db.streamQuery(q, opt);
|
|
223
175
|
if (isPartialQuery)
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.pipe(transformMapSync(dbm => {
|
|
229
|
-
return this.anyToDBM(dbm, opt);
|
|
230
|
-
}, {
|
|
231
|
-
errorMode: opt.errorMode,
|
|
232
|
-
})));
|
|
176
|
+
return pipeline;
|
|
177
|
+
opt.skipValidation ??= true;
|
|
178
|
+
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
179
|
+
return pipeline.map(async (dbm) => await this.dbmToBM(dbm, opt), { errorMode: opt.errorMode });
|
|
233
180
|
}
|
|
234
|
-
|
|
235
|
-
* Stream as Readable, to be able to .pipe() it further with support of backpressure.
|
|
236
|
-
*
|
|
237
|
-
* Please note that this stream is currently not async-iteration friendly, because of
|
|
238
|
-
* `through2` usage.
|
|
239
|
-
* Will be migrated/fixed at some point in the future.
|
|
240
|
-
*
|
|
241
|
-
* You can do `.pipe(transformNoOp)` to make it "valid again".
|
|
242
|
-
*/
|
|
243
|
-
streamQuery(q, opt = {}) {
|
|
181
|
+
streamQueryRaw(q, opt = {}) {
|
|
244
182
|
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
245
183
|
q.table = opt.table || q.table;
|
|
246
|
-
|
|
247
|
-
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
248
|
-
const stream = this.cfg.db.streamQuery(q, opt);
|
|
249
|
-
const isPartialQuery = !!q._selectedFieldNames;
|
|
250
|
-
if (isPartialQuery)
|
|
251
|
-
return stream;
|
|
252
|
-
// This almost works, but hard to implement `errorMode: THROW_AGGREGATED` in this case
|
|
253
|
-
// return stream.flatMap(async (dbm: DBM) => {
|
|
254
|
-
// return [await this.dbmToBM(dbm, opt)] satisfies BM[]
|
|
255
|
-
// }, {
|
|
256
|
-
// concurrency: 16,
|
|
257
|
-
// })
|
|
258
|
-
return (stream
|
|
259
|
-
// optimization: 1 validation is enough
|
|
260
|
-
// .pipe(transformMap<any, DBM>(dbm => this.anyToDBM(dbm, opt), safeOpt))
|
|
261
|
-
// .pipe(transformMap<DBM, BM>(dbm => this.dbmToBM(dbm, opt), safeOpt))
|
|
262
|
-
// the commented out line was causing RangeError: Maximum call stack size exceeded
|
|
263
|
-
// .on('error', err => stream.emit('error', err))
|
|
264
|
-
.pipe(transformMap(async (dbm) => {
|
|
265
|
-
return await this.dbmToBM(dbm, opt);
|
|
266
|
-
}, {
|
|
267
|
-
errorMode: opt.errorMode,
|
|
268
|
-
}))
|
|
269
|
-
// this can make the stream async-iteration-friendly
|
|
270
|
-
// but not applying it now for perf reasons
|
|
271
|
-
// UPD: applying, to be compliant with `.toArray()`, etc.
|
|
272
|
-
.on('error', err => stream.destroy(err))
|
|
273
|
-
.pipe(transformNoOp()));
|
|
184
|
+
return this.cfg.db.streamQuery(q, opt);
|
|
274
185
|
}
|
|
275
186
|
async queryIds(q, opt = {}) {
|
|
276
187
|
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
@@ -282,36 +193,7 @@ export class CommonDao {
|
|
|
282
193
|
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
283
194
|
q.table = opt.table || q.table;
|
|
284
195
|
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
285
|
-
|
|
286
|
-
const stream = this.cfg.db
|
|
287
|
-
.streamQuery(q.select(['id']), opt)
|
|
288
|
-
// .on('error', err => stream.emit('error', err))
|
|
289
|
-
.map((r) => r.id);
|
|
290
|
-
// const stream: ReadableTyped<string> = this.cfg.db
|
|
291
|
-
// .streamQuery<DBM>(q.select(['id']), opt)
|
|
292
|
-
// .on('error', err => stream.emit('error', err))
|
|
293
|
-
// .pipe(
|
|
294
|
-
// transformMapSimple<DBM, string>(r => r.id, {
|
|
295
|
-
// errorMode: ErrorMode.SUPPRESS, // cause .pipe() cannot propagate errors
|
|
296
|
-
// }),
|
|
297
|
-
// )
|
|
298
|
-
return stream;
|
|
299
|
-
}
|
|
300
|
-
async streamQueryIdsForEach(q, mapper, opt = {}) {
|
|
301
|
-
this.validateQueryIndexes(q); // throws if query uses `excludeFromIndexes` property
|
|
302
|
-
q.table = opt.table || q.table;
|
|
303
|
-
opt.errorMode ||= ErrorMode.SUPPRESS;
|
|
304
|
-
await Pipeline.from(this.cfg.db.streamQuery(q.select(['id']), opt).map(r => r.id))
|
|
305
|
-
.map(mapper, {
|
|
306
|
-
...opt,
|
|
307
|
-
predicate: _passthroughPredicate,
|
|
308
|
-
})
|
|
309
|
-
// LogProgress should be AFTER the mapper, to be able to report correct stats
|
|
310
|
-
.logProgress({
|
|
311
|
-
metric: q.table,
|
|
312
|
-
...opt,
|
|
313
|
-
})
|
|
314
|
-
.run();
|
|
196
|
+
return this.cfg.db.streamQuery(q.select(['id']), opt).mapSync((r) => r.id);
|
|
315
197
|
}
|
|
316
198
|
/**
|
|
317
199
|
* Mutates!
|
|
@@ -590,7 +472,9 @@ export class CommonDao {
|
|
|
590
472
|
let deleted = 0;
|
|
591
473
|
if (opt.chunkSize) {
|
|
592
474
|
const { chunkSize, chunkConcurrency = 8 } = opt;
|
|
593
|
-
await
|
|
475
|
+
await this.cfg.db
|
|
476
|
+
.streamQuery(q.select(['id']), opt)
|
|
477
|
+
.mapSync(r => r.id)
|
|
594
478
|
.chunk(chunkSize)
|
|
595
479
|
.map(async (ids) => {
|
|
596
480
|
await this.cfg.db.deleteByIds(q.table, ids, opt);
|
|
@@ -656,10 +540,7 @@ export class CommonDao {
|
|
|
656
540
|
return null;
|
|
657
541
|
// optimization: no need to run full joi DBM validation, cause BM validation will be run
|
|
658
542
|
// const dbm = this.anyToDBM(_dbm, opt)
|
|
659
|
-
|
|
660
|
-
if (opt.anonymize) {
|
|
661
|
-
dbm = this.cfg.hooks.anonymize(dbm);
|
|
662
|
-
}
|
|
543
|
+
const dbm = { ..._dbm, ...this.cfg.hooks.parseNaturalId(_dbm.id) };
|
|
663
544
|
// DBM > BM
|
|
664
545
|
const bm = ((await this.cfg.hooks.beforeDBMToBM?.(dbm)) || dbm);
|
|
665
546
|
// Validate/convert BM
|
|
@@ -680,17 +561,12 @@ export class CommonDao {
|
|
|
680
561
|
// try/catch?
|
|
681
562
|
return await pMap(bms, async (bm) => await this.bmToDBM(bm, opt));
|
|
682
563
|
}
|
|
683
|
-
anyToDBM(dbm,
|
|
564
|
+
anyToDBM(dbm, _opt = {}) {
|
|
684
565
|
if (!dbm)
|
|
685
566
|
return null;
|
|
686
567
|
// this shouldn't be happening on load! but should on save!
|
|
687
568
|
// this.assignIdCreatedUpdated(dbm, opt)
|
|
688
569
|
dbm = { ...dbm, ...this.cfg.hooks.parseNaturalId(dbm.id) };
|
|
689
|
-
// todo: is this the right place?
|
|
690
|
-
// todo: is anyToDBM even needed?
|
|
691
|
-
if (opt.anonymize) {
|
|
692
|
-
dbm = this.cfg.hooks.anonymize(dbm);
|
|
693
|
-
}
|
|
694
570
|
// Validate/convert DBM
|
|
695
571
|
// return this.validateAndConvert(dbm, this.cfg.dbmSchema, DBModelType.DBM, opt)
|
|
696
572
|
return dbm;
|
|
@@ -949,13 +825,20 @@ export class CommonDao {
|
|
|
949
825
|
* Throws if query uses a property that is in `excludeFromIndexes` list.
|
|
950
826
|
*/
|
|
951
827
|
validateQueryIndexes(q) {
|
|
952
|
-
const { excludeFromIndexes } = this.cfg;
|
|
953
|
-
if (
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
}
|
|
828
|
+
const { excludeFromIndexes, indexes } = this.cfg;
|
|
829
|
+
if (excludeFromIndexes) {
|
|
830
|
+
for (const f of q._filters) {
|
|
831
|
+
_assert(!excludeFromIndexes.includes(f.name), `cannot query on non-indexed property: ${this.cfg.table}.${f.name}`, {
|
|
832
|
+
query: q.pretty(),
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (indexes) {
|
|
837
|
+
for (const f of q._filters) {
|
|
838
|
+
_assert(f.name === 'id' || indexes.includes(f.name), `cannot query on non-indexed property: ${this.cfg.table}.${f.name}`, {
|
|
839
|
+
query: q.pretty(),
|
|
840
|
+
});
|
|
841
|
+
}
|
|
959
842
|
}
|
|
960
843
|
}
|
|
961
844
|
}
|
|
@@ -2,7 +2,7 @@ import type { ValidationFunction } from '@naturalcycles/js-lib';
|
|
|
2
2
|
import type { AppError, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
3
3
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
4
4
|
import type { BaseDBEntity, UnixTimestamp } from '@naturalcycles/js-lib/types';
|
|
5
|
-
import type { TransformLogProgressOptions
|
|
5
|
+
import type { TransformLogProgressOptions } from '@naturalcycles/nodejs-lib/stream';
|
|
6
6
|
import type { CommonDB } from '../commondb/common.db.js';
|
|
7
7
|
import type { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model.js';
|
|
8
8
|
export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntity, ID extends string = BM['id']> {
|
|
@@ -54,16 +54,6 @@ export interface CommonDaoHooks<BM extends BaseDBEntity, DBM extends BaseDBEntit
|
|
|
54
54
|
* Or, you can mutate the DBM if needed.
|
|
55
55
|
*/
|
|
56
56
|
beforeSave?: (dbm: DBM) => void;
|
|
57
|
-
/**
|
|
58
|
-
* Called in:
|
|
59
|
-
* - dbmToBM (applied before DBM becomes BM)
|
|
60
|
-
* - anyToDBM
|
|
61
|
-
*
|
|
62
|
-
* Hook only allows to apply anonymization to DBM (not to BM).
|
|
63
|
-
* It still applies to BM "transitively", during dbmToBM
|
|
64
|
-
* (e.g after loaded from the Database).
|
|
65
|
-
*/
|
|
66
|
-
anonymize: (dbm: DBM) => DBM;
|
|
67
57
|
/**
|
|
68
58
|
* If hook is defined - allows to prevent or modify the error thrown.
|
|
69
59
|
* Return `false` to prevent throwing an error.
|
|
@@ -230,12 +220,6 @@ export interface CommonDaoOptions extends CommonDBOptions {
|
|
|
230
220
|
* @default false (for streams). Setting to true enables deletion of immutable objects
|
|
231
221
|
*/
|
|
232
222
|
allowMutability?: boolean;
|
|
233
|
-
/**
|
|
234
|
-
* If true - data will be anonymized (by calling a BaseDao.anonymize() hook that you can extend in your Dao implementation).
|
|
235
|
-
* Only applicable to loading/querying/streaming_loading operations (n/a for saving).
|
|
236
|
-
* There is additional validation applied AFTER Anonymization, so your anonymization implementation should keep the object valid.
|
|
237
|
-
*/
|
|
238
|
-
anonymize?: boolean;
|
|
239
223
|
/**
|
|
240
224
|
* Allows to override the Table that this Dao is connected to, only in the context of this call.
|
|
241
225
|
*
|
|
@@ -288,8 +272,6 @@ export interface CommonDaoStreamDeleteOptions<DBM extends BaseDBEntity> extends
|
|
|
288
272
|
}
|
|
289
273
|
export interface CommonDaoStreamSaveOptions<DBM extends BaseDBEntity> extends CommonDaoSaveBatchOptions<DBM>, CommonDaoStreamOptions<DBM> {
|
|
290
274
|
}
|
|
291
|
-
export interface CommonDaoStreamForEachOptions<IN> extends CommonDaoStreamOptions<IN>, TransformMapOptions<IN, any> {
|
|
292
|
-
}
|
|
293
275
|
export interface CommonDaoStreamOptions<IN> extends CommonDaoReadOptions, TransformLogProgressOptions<IN> {
|
|
294
276
|
/**
|
|
295
277
|
* @default true (for streams)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
2
2
|
import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions, CommonDBTransactionOptions, DBTransaction, DBTransactionFn, RunQueryResult } from '../db.model.js';
|
|
5
5
|
import type { DBQuery } from '../query/dbQuery.js';
|
|
6
6
|
import type { CommonDB, CommonDBSupport } from './common.db.js';
|
|
@@ -23,7 +23,7 @@ export declare class BaseCommonDB implements CommonDB {
|
|
|
23
23
|
runQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<RunQueryResult<ROW>>;
|
|
24
24
|
runQueryCount<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Promise<number>;
|
|
25
25
|
saveBatch<ROW extends ObjectWithId>(_table: string, _rows: ROW[], _opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
26
|
-
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>):
|
|
26
|
+
streamQuery<ROW extends ObjectWithId>(_q: DBQuery<ROW>): Pipeline<ROW>;
|
|
27
27
|
deleteByIds(_table: string, _ids: string[], _opt?: CommonDBOptions): Promise<number>;
|
|
28
28
|
runInTransaction(fn: DBTransactionFn, _opt?: CommonDBTransactionOptions): Promise<void>;
|
|
29
29
|
createTransaction(_opt?: CommonDBTransactionOptions): Promise<DBTransaction>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
2
2
|
import type { NonNegativeInteger, ObjectWithId, StringMap } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { CommonDBCreateOptions, CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBTransactionOptions, DBTransaction, DBTransactionFn, RunQueryResult } from '../db.model.js';
|
|
5
5
|
import type { DBQuery } from '../query/dbQuery.js';
|
|
6
6
|
export interface CommonDB {
|
|
@@ -62,7 +62,7 @@ export interface CommonDB {
|
|
|
62
62
|
*/
|
|
63
63
|
runQuery: <ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBReadOptions) => Promise<RunQueryResult<ROW>>;
|
|
64
64
|
runQueryCount: <ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBReadOptions) => Promise<NonNegativeInteger>;
|
|
65
|
-
streamQuery: <ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions) =>
|
|
65
|
+
streamQuery: <ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: CommonDBStreamOptions) => Pipeline<ROW>;
|
|
66
66
|
/**
|
|
67
67
|
* rows can have missing ids only if DB supports auto-generating them (like mysql auto_increment).
|
|
68
68
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type JsonSchemaObject, type JsonSchemaRootObject } from '@naturalcycles/js-lib/json-schema';
|
|
2
2
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
3
3
|
import { type AnyObjectWithId, type ObjectWithId, type StringMap } from '@naturalcycles/js-lib/types';
|
|
4
|
-
import
|
|
4
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
5
5
|
import type { CommonDB, CommonDBSupport } from '../commondb/common.db.js';
|
|
6
6
|
import { CommonDBType } from '../commondb/common.db.js';
|
|
7
7
|
import type { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBTransactionOptions, DBOperation, DBTransaction, DBTransactionFn, RunQueryResult } from '../db.model.js';
|
|
@@ -60,7 +60,7 @@ export declare class InMemoryDB implements CommonDB {
|
|
|
60
60
|
patchByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, patch: Partial<ROW>): Promise<number>;
|
|
61
61
|
runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
62
62
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
63
|
-
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions):
|
|
63
|
+
streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Pipeline<ROW>;
|
|
64
64
|
runInTransaction(fn: DBTransactionFn, opt?: CommonDBTransactionOptions): Promise<void>;
|
|
65
65
|
createTransaction(opt?: CommonDBTransactionOptions): Promise<DBTransaction>;
|
|
66
66
|
incrementBatch(table: string, prop: string, incrementMap: StringMap<number>, _opt?: CommonDBOptions): Promise<StringMap<number>>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
2
1
|
import { _isEmptyObject } from '@naturalcycles/js-lib';
|
|
3
2
|
import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
4
3
|
import { generateJsonSchemaFromData, } from '@naturalcycles/js-lib/json-schema';
|
|
5
4
|
import { _deepCopy, _sortObjectDeep } from '@naturalcycles/js-lib/object';
|
|
6
5
|
import { _stringMapEntries, _stringMapValues, } from '@naturalcycles/js-lib/types';
|
|
6
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
7
7
|
import { bufferReviver } from '@naturalcycles/nodejs-lib/stream/ndjson/transformJsonParse.js';
|
|
8
8
|
import { commonDBFullSupport, CommonDBType } from '../commondb/common.db.js';
|
|
9
9
|
import { queryInMemory } from './queryInMemory.js';
|
|
@@ -161,7 +161,7 @@ export class InMemoryDB {
|
|
|
161
161
|
}
|
|
162
162
|
streamQuery(q, _opt) {
|
|
163
163
|
const table = this.cfg.tablesPrefix + q.table;
|
|
164
|
-
return
|
|
164
|
+
return Pipeline.fromArray(queryInMemory(q, Object.values(this.data[table] || {})));
|
|
165
165
|
}
|
|
166
166
|
async runInTransaction(fn, opt = {}) {
|
|
167
167
|
const tx = new InMemoryDBTransaction(this, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StringMap } from '@naturalcycles/js-lib/types';
|
|
2
|
-
import
|
|
2
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
3
3
|
import type { CommonDBCreateOptions } from '../db.model.js';
|
|
4
4
|
import type { CommonKeyValueDB, IncrementTuple, KeyValueDBTuple } from '../kv/commonKeyValueDB.js';
|
|
5
5
|
export interface InMemoryKeyValueDBCfg {
|
|
@@ -17,9 +17,9 @@ export declare class InMemoryKeyValueDB implements CommonKeyValueDB {
|
|
|
17
17
|
deleteByIds(table: string, ids: string[]): Promise<void>;
|
|
18
18
|
getByIds(table: string, ids: string[]): Promise<KeyValueDBTuple[]>;
|
|
19
19
|
saveBatch(table: string, entries: KeyValueDBTuple[]): Promise<void>;
|
|
20
|
-
streamIds(table: string, limit?: number):
|
|
21
|
-
streamValues(table: string, limit?: number):
|
|
22
|
-
streamEntries(table: string, limit?: number):
|
|
20
|
+
streamIds(table: string, limit?: number): Pipeline<string>;
|
|
21
|
+
streamValues(table: string, limit?: number): Pipeline<Buffer>;
|
|
22
|
+
streamEntries(table: string, limit?: number): Pipeline<KeyValueDBTuple>;
|
|
23
23
|
count(table: string): Promise<number>;
|
|
24
24
|
incrementBatch(table: string, entries: IncrementTuple[]): Promise<IncrementTuple[]>;
|
|
25
25
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
2
2
|
import { commonKeyValueDBFullSupport } from '../kv/commonKeyValueDB.js';
|
|
3
3
|
export class InMemoryKeyValueDB {
|
|
4
4
|
cfg;
|
|
@@ -29,13 +29,13 @@ export class InMemoryKeyValueDB {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
streamIds(table, limit) {
|
|
32
|
-
return
|
|
32
|
+
return Pipeline.fromArray(Object.keys(this.data[table] || {}).slice(0, limit));
|
|
33
33
|
}
|
|
34
34
|
streamValues(table, limit) {
|
|
35
|
-
return
|
|
35
|
+
return Pipeline.fromArray(Object.values(this.data[table] || {}).slice(0, limit));
|
|
36
36
|
}
|
|
37
37
|
streamEntries(table, limit) {
|
|
38
|
-
return
|
|
38
|
+
return Pipeline.fromArray(Object.entries(this.data[table] || {}).slice(0, limit));
|
|
39
39
|
}
|
|
40
40
|
async count(table) {
|
|
41
41
|
this.data[table] ||= {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Integer, UnixTimestamp } from '@naturalcycles/js-lib/types';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
3
3
|
import type { CommonDBCreateOptions } from '../db.model.js';
|
|
4
4
|
/**
|
|
5
5
|
* Common interface for Key-Value database implementations.
|
|
@@ -28,9 +28,9 @@ export interface CommonKeyValueDB {
|
|
|
28
28
|
getByIds: (table: string, ids: string[]) => Promise<KeyValueDBTuple[]>;
|
|
29
29
|
deleteByIds: (table: string, ids: string[]) => Promise<void>;
|
|
30
30
|
saveBatch: (table: string, entries: KeyValueDBTuple[], opt?: CommonKeyValueDBSaveBatchOptions) => Promise<void>;
|
|
31
|
-
streamIds: (table: string, limit?: number) =>
|
|
32
|
-
streamValues: (table: string, limit?: number) =>
|
|
33
|
-
streamEntries: (table: string, limit?: number) =>
|
|
31
|
+
streamIds: (table: string, limit?: number) => Pipeline<string>;
|
|
32
|
+
streamValues: (table: string, limit?: number) => Pipeline<Buffer>;
|
|
33
|
+
streamEntries: (table: string, limit?: number) => Pipeline<KeyValueDBTuple>;
|
|
34
34
|
count: (table: string) => Promise<number>;
|
|
35
35
|
/**
|
|
36
36
|
* Perform a batch of Increment operations.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
2
|
+
import { type KeyValueTuple } from '@naturalcycles/js-lib/types';
|
|
3
|
+
import type { Pipeline } from '@naturalcycles/nodejs-lib/stream';
|
|
4
4
|
import type { CommonDaoLogLevel } from '../commondao/common.dao.model.js';
|
|
5
5
|
import type { CommonDBCreateOptions } from '../db.model.js';
|
|
6
6
|
import type { CommonKeyValueDB, CommonKeyValueDBSaveBatchOptions, IncrementTuple, KeyValueDBTuple } from './commonKeyValueDB.js';
|
|
@@ -49,9 +49,9 @@ export declare class CommonKeyValueDao<K extends string = string, V = Buffer> {
|
|
|
49
49
|
saveBatch(entries: KeyValueTuple<K, V>[], opt?: CommonKeyValueDaoSaveOptions): Promise<void>;
|
|
50
50
|
deleteByIds(ids: K[]): Promise<void>;
|
|
51
51
|
deleteById(id: K): Promise<void>;
|
|
52
|
-
streamIds(limit?: number):
|
|
53
|
-
streamValues(limit?: number):
|
|
54
|
-
streamEntries(limit?: number):
|
|
52
|
+
streamIds(limit?: number): Pipeline<K>;
|
|
53
|
+
streamValues(limit?: number): Pipeline<V>;
|
|
54
|
+
streamEntries(limit?: number): Pipeline<KeyValueTuple<K, V>>;
|
|
55
55
|
getAllKeys(limit?: number): Promise<K[]>;
|
|
56
56
|
getAllValues(limit?: number): Promise<V[]>;
|
|
57
57
|
getAllEntries(limit?: number): Promise<KeyValueTuple<K, V>[]>;
|