@naturalcycles/db-lib 8.29.0 → 8.33.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/commondao/common.dao.d.ts +1 -0
- package/dist/commondao/common.dao.js +13 -2
- package/dist/commondao/common.dao.model.d.ts +8 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/kv/commonKeyValueDao.d.ts +7 -0
- package/dist/kv/commonKeyValueDao.js +20 -0
- package/dist/kv/commonKeyValueDaoMemoCache.d.ts +9 -0
- package/dist/kv/commonKeyValueDaoMemoCache.js +18 -0
- package/dist/query/dbQuery.d.ts +3 -0
- package/dist/query/dbQuery.js +11 -1
- package/dist/testing/test.model.d.ts +1 -1
- package/dist/validation/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/commondao/common.dao.model.ts +9 -3
- package/src/commondao/common.dao.ts +21 -2
- package/src/index.ts +1 -0
- package/src/kv/commonKeyValueDao.ts +39 -3
- package/src/kv/commonKeyValueDaoMemoCache.ts +20 -0
- package/src/query/dbQuery.ts +15 -1
|
@@ -39,6 +39,7 @@ export declare class CommonDao<BM extends Partial<ObjectWithId>, DBM extends Obj
|
|
|
39
39
|
*/
|
|
40
40
|
query(table?: string): RunnableDBQuery<BM, DBM, TM>;
|
|
41
41
|
runQuery(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
42
|
+
runQuerySingleColumn<T = any>(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<T[]>;
|
|
42
43
|
/**
|
|
43
44
|
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
44
45
|
* Does deduplication by id.
|
|
@@ -25,7 +25,8 @@ class CommonDao {
|
|
|
25
25
|
// otherwise to log Operations
|
|
26
26
|
// e.g in Dev (local machine), Test - it will log operations (useful for debugging)
|
|
27
27
|
logLevel: isGAE || isCI ? common_dao_model_1.CommonDaoLogLevel.NONE : common_dao_model_1.CommonDaoLogLevel.OPERATIONS,
|
|
28
|
-
|
|
28
|
+
created: true,
|
|
29
|
+
updated: true,
|
|
29
30
|
logger: console,
|
|
30
31
|
...cfg,
|
|
31
32
|
hooks: {
|
|
@@ -184,6 +185,12 @@ class CommonDao {
|
|
|
184
185
|
const { rows } = await this.runQueryExtended(q, opt);
|
|
185
186
|
return rows;
|
|
186
187
|
}
|
|
188
|
+
async runQuerySingleColumn(q, opt) {
|
|
189
|
+
(0, js_lib_1._assert)(q._selectedFieldNames?.length === 1, `runQuerySingleColumn requires exactly 1 column to be selected: ${q.pretty()}`);
|
|
190
|
+
const col = q._selectedFieldNames[0];
|
|
191
|
+
const { rows } = await this.runQueryExtended(q, opt);
|
|
192
|
+
return rows.map(r => r[col]);
|
|
193
|
+
}
|
|
187
194
|
/**
|
|
188
195
|
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
189
196
|
* Does deduplication by id.
|
|
@@ -399,9 +406,13 @@ class CommonDao {
|
|
|
399
406
|
assignIdCreatedUpdated(obj, opt = {}) {
|
|
400
407
|
const now = Math.floor(Date.now() / 1000);
|
|
401
408
|
obj.id = obj.id || this.cfg.hooks.createId(obj);
|
|
402
|
-
if (this.cfg.
|
|
409
|
+
if (this.cfg.created) {
|
|
403
410
|
Object.assign(obj, {
|
|
404
411
|
created: obj.created || obj.updated || now,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
if (this.cfg.updated) {
|
|
415
|
+
Object.assign(obj, {
|
|
405
416
|
updated: opt.preserveUpdatedCreated && obj.updated ? obj.updated : now,
|
|
406
417
|
});
|
|
407
418
|
}
|
|
@@ -76,10 +76,15 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends Obje
|
|
|
76
76
|
logStarted?: boolean;
|
|
77
77
|
hooks?: Partial<CommonDaoHooks<BM, DBM, TM>>;
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
80
|
-
* Set to false to disable created
|
|
79
|
+
* Defaults to true
|
|
80
|
+
* Set to false to disable `created` field management.
|
|
81
81
|
*/
|
|
82
|
-
|
|
82
|
+
created?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Defaults to true
|
|
85
|
+
* Set to false to disable `updated` field management.
|
|
86
|
+
*/
|
|
87
|
+
updated?: boolean;
|
|
83
88
|
/**
|
|
84
89
|
* Default is false.
|
|
85
90
|
* If true - will run `_filterNullishValues` inside `validateAndConvert` function
|
package/dist/index.d.ts
CHANGED
|
@@ -17,5 +17,6 @@ import { dbPipelineRestore, DBPipelineRestoreOptions } from './pipeline/dbPipeli
|
|
|
17
17
|
import { DBQuery, DBQueryFilter, DBQueryFilterOperator, dbQueryFilterOperatorValues, DBQueryOrder, RunnableDBQuery } from './query/dbQuery';
|
|
18
18
|
import { DBTransaction, RunnableDBTransaction } from './transaction/dbTransaction';
|
|
19
19
|
import { commitDBTransactionSimple, mergeDBOperations } from './transaction/dbTransaction.util';
|
|
20
|
+
export * from './kv/commonKeyValueDaoMemoCache';
|
|
20
21
|
export type { DBQueryFilterOperator, DBQueryFilter, DBQueryOrder, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveOptions, CommonDaoStreamForEachOptions, CommonDaoStreamOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBCreateOptions, CommonDB, RunQueryResult, CommonDaoCfg, CommonDaoCreateIdHook, CommonDaoParseNaturalIdHook, CommonDaoBeforeCreateHook, CommonDaoBeforeDBMValidateHook, CommonDaoBeforeDBMToBMHook, CommonDaoBeforeBMToDBMHook, CommonDaoBeforeTMToBMHook, CommonDaoBeforeBMToTMHook, CommonDaoAnonymizeHook, InMemoryDBCfg, InMemoryKeyValueDBCfg, DBPipelineBackupOptions, DBPipelineRestoreOptions, DBPipelineCopyOptions, CommonDBAdapter, DBOperation, DBSaveBatchOperation, DBDeleteByIdsOperation, CommonKeyValueDB, CommonKeyValueDaoCfg, KeyValueDBTuple, };
|
|
21
22
|
export { DBQuery, dbQueryFilterOperatorValues, RunnableDBQuery, CommonDaoLogLevel, DBRelation, DBModelType, CommonDao, createdUpdatedFields, createdUpdatedIdFields, InMemoryDB, InMemoryKeyValueDB, queryInMemory, serializeJsonField, deserializeJsonField, dbPipelineBackup, dbPipelineRestore, dbPipelineCopy, getDB, DBLibError, BaseCommonDB, DBTransaction, RunnableDBTransaction, mergeDBOperations, commitDBTransactionSimple, CommonKeyValueDao, };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CommonKeyValueDao = exports.commitDBTransactionSimple = exports.mergeDBOperations = exports.RunnableDBTransaction = exports.DBTransaction = exports.BaseCommonDB = exports.DBLibError = exports.getDB = exports.dbPipelineCopy = exports.dbPipelineRestore = exports.dbPipelineBackup = exports.deserializeJsonField = exports.serializeJsonField = exports.queryInMemory = exports.InMemoryKeyValueDB = exports.InMemoryDB = exports.createdUpdatedIdFields = exports.createdUpdatedFields = exports.CommonDao = exports.DBModelType = exports.DBRelation = exports.CommonDaoLogLevel = exports.RunnableDBQuery = exports.dbQueryFilterOperatorValues = exports.DBQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
4
5
|
const inMemory_db_1 = require("./adapter/inmemory/inMemory.db");
|
|
5
6
|
Object.defineProperty(exports, "InMemoryDB", { enumerable: true, get: function () { return inMemory_db_1.InMemoryDB; } });
|
|
6
7
|
const inMemoryKeyValueDB_1 = require("./adapter/inmemory/inMemoryKeyValueDB");
|
|
@@ -43,3 +44,4 @@ Object.defineProperty(exports, "RunnableDBTransaction", { enumerable: true, get:
|
|
|
43
44
|
const dbTransaction_util_1 = require("./transaction/dbTransaction.util");
|
|
44
45
|
Object.defineProperty(exports, "commitDBTransactionSimple", { enumerable: true, get: function () { return dbTransaction_util_1.commitDBTransactionSimple; } });
|
|
45
46
|
Object.defineProperty(exports, "mergeDBOperations", { enumerable: true, get: function () { return dbTransaction_util_1.mergeDBOperations; } });
|
|
47
|
+
(0, tslib_1.__exportStar)(require("./kv/commonKeyValueDaoMemoCache"), exports);
|
|
@@ -25,6 +25,12 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
25
25
|
mapBufferToValue?: (b: Buffer) => Promise<T>;
|
|
26
26
|
beforeCreate?: (v: Partial<T>) => Partial<T>;
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Set to `true` to conveniently enable zipping+JSON.stringify
|
|
30
|
+
* (and unzipping+JSON.parse) of the Buffer value via hooks.
|
|
31
|
+
* Custom hooks will override these hooks (if provided).
|
|
32
|
+
*/
|
|
33
|
+
deflatedJsonValue?: boolean;
|
|
28
34
|
}
|
|
29
35
|
export declare class CommonKeyValueDao<T> {
|
|
30
36
|
cfg: CommonKeyValueDaoCfg<T>;
|
|
@@ -33,6 +39,7 @@ export declare class CommonKeyValueDao<T> {
|
|
|
33
39
|
createTable(opt?: CommonDBCreateOptions): Promise<void>;
|
|
34
40
|
create(input?: Partial<T>): T;
|
|
35
41
|
getById(id?: string): Promise<T | null>;
|
|
42
|
+
requireById(id: string): Promise<T>;
|
|
36
43
|
getByIdOrEmpty(id: string, part?: Partial<T>): Promise<T>;
|
|
37
44
|
patch(id: string, patch: Partial<T>): Promise<T>;
|
|
38
45
|
getByIds(ids: string[]): Promise<KeyValueTuple<string, T>[]>;
|
|
@@ -3,11 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CommonKeyValueDao = void 0;
|
|
4
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
5
5
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
6
|
+
const cnst_1 = require("../cnst");
|
|
6
7
|
// todo: logging
|
|
7
8
|
// todo: readonly
|
|
8
9
|
class CommonKeyValueDao {
|
|
9
10
|
constructor(cfg) {
|
|
10
11
|
this.cfg = cfg;
|
|
12
|
+
if (cfg.deflatedJsonValue) {
|
|
13
|
+
cfg.hooks = {
|
|
14
|
+
mapValueToBuffer: async (v) => await (0, nodejs_lib_1.deflateString)(JSON.stringify(v)),
|
|
15
|
+
mapBufferToValue: async (buf) => JSON.parse(await (0, nodejs_lib_1.inflateToString)(buf)),
|
|
16
|
+
...cfg.hooks,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
11
19
|
}
|
|
12
20
|
async ping() {
|
|
13
21
|
await this.cfg.db.ping();
|
|
@@ -26,6 +34,18 @@ class CommonKeyValueDao {
|
|
|
26
34
|
const [r] = await this.getByIds([id]);
|
|
27
35
|
return r?.[1] || null;
|
|
28
36
|
}
|
|
37
|
+
async requireById(id) {
|
|
38
|
+
const [r] = await this.getByIds([id]);
|
|
39
|
+
if (!r) {
|
|
40
|
+
const { table } = this.cfg;
|
|
41
|
+
throw new js_lib_1.AppError(`DB row required, but not found: ${table}.${id}`, {
|
|
42
|
+
code: cnst_1.DBLibError.DB_ROW_REQUIRED,
|
|
43
|
+
table,
|
|
44
|
+
id,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return r[1];
|
|
48
|
+
}
|
|
29
49
|
async getByIdOrEmpty(id, part = {}) {
|
|
30
50
|
const [r] = await this.getByIds([id]);
|
|
31
51
|
if (r)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AsyncMemoCache } from '@naturalcycles/js-lib';
|
|
2
|
+
import { CommonKeyValueDao } from './commonKeyValueDao';
|
|
3
|
+
export declare class CommonKeyValueDaoMemoCache<VALUE = any> implements AsyncMemoCache<string, VALUE> {
|
|
4
|
+
private dao;
|
|
5
|
+
constructor(dao: CommonKeyValueDao<VALUE>);
|
|
6
|
+
get(k: string): Promise<VALUE | undefined>;
|
|
7
|
+
set(k: string, v: VALUE): Promise<void>;
|
|
8
|
+
clear(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommonKeyValueDaoMemoCache = void 0;
|
|
4
|
+
class CommonKeyValueDaoMemoCache {
|
|
5
|
+
constructor(dao) {
|
|
6
|
+
this.dao = dao;
|
|
7
|
+
}
|
|
8
|
+
async get(k) {
|
|
9
|
+
return (await this.dao.getById(k)) || undefined;
|
|
10
|
+
}
|
|
11
|
+
async set(k, v) {
|
|
12
|
+
await this.dao.save(k, v);
|
|
13
|
+
}
|
|
14
|
+
async clear() {
|
|
15
|
+
throw new Error('CommonKeyValueDaoCacheFactory.clear is not supported, because cache is expected to be persistent');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.CommonKeyValueDaoMemoCache = CommonKeyValueDaoMemoCache;
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export declare class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
65
65
|
*/
|
|
66
66
|
_selectedFieldNames?: (keyof ROW)[];
|
|
67
67
|
_groupByFieldNames?: (keyof ROW)[];
|
|
68
|
+
_distinct: boolean;
|
|
68
69
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this;
|
|
69
70
|
filterEq(name: keyof ROW, val: any): this;
|
|
70
71
|
limit(limit: number): this;
|
|
@@ -72,6 +73,7 @@ export declare class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
72
73
|
order(name: keyof ROW, descending?: boolean): this;
|
|
73
74
|
select(fieldNames: (keyof ROW)[]): this;
|
|
74
75
|
groupBy(fieldNames: (keyof ROW)[]): this;
|
|
76
|
+
distinct(distinct?: boolean): this;
|
|
75
77
|
startCursor(startCursor?: string): this;
|
|
76
78
|
endCursor(endCursor?: string): this;
|
|
77
79
|
clone(): DBQuery<ROW>;
|
|
@@ -88,6 +90,7 @@ export declare class RunnableDBQuery<BM extends Partial<ObjectWithId>, DBM exten
|
|
|
88
90
|
*/
|
|
89
91
|
constructor(dao: CommonDao<BM, DBM, TM>, table?: string);
|
|
90
92
|
runQuery(opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
93
|
+
runQuerySingleColumn<T = any>(opt?: CommonDaoOptions): Promise<T[]>;
|
|
91
94
|
runQueryAsDBM(opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
92
95
|
runQueryAsTM(opt?: CommonDaoOptions): Promise<TM[]>;
|
|
93
96
|
runQueryExtended(opt?: CommonDaoOptions): Promise<RunQueryResult<Saved<BM>>>;
|
package/dist/query/dbQuery.js
CHANGED
|
@@ -30,6 +30,7 @@ class DBQuery {
|
|
|
30
30
|
this._limitValue = 0; // 0 means "no limit"
|
|
31
31
|
this._offsetValue = 0; // 0 means "no offset"
|
|
32
32
|
this._orders = [];
|
|
33
|
+
this._distinct = false;
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* Convenience method.
|
|
@@ -71,6 +72,10 @@ class DBQuery {
|
|
|
71
72
|
this._groupByFieldNames = fieldNames;
|
|
72
73
|
return this;
|
|
73
74
|
}
|
|
75
|
+
distinct(distinct = true) {
|
|
76
|
+
this._distinct = distinct;
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
74
79
|
startCursor(startCursor) {
|
|
75
80
|
this._startCursor = startCursor;
|
|
76
81
|
return this;
|
|
@@ -86,6 +91,8 @@ class DBQuery {
|
|
|
86
91
|
_offsetValue: this._offsetValue,
|
|
87
92
|
_orders: [...this._orders],
|
|
88
93
|
_selectedFieldNames: this._selectedFieldNames && [...this._selectedFieldNames],
|
|
94
|
+
_groupByFieldNames: this._groupByFieldNames && [...this._groupByFieldNames],
|
|
95
|
+
_distinct: this._distinct,
|
|
89
96
|
_startCursor: this._startCursor,
|
|
90
97
|
_endCursor: this._endCursor,
|
|
91
98
|
});
|
|
@@ -99,7 +106,7 @@ class DBQuery {
|
|
|
99
106
|
// tokens.push(`"${this.name}"`)
|
|
100
107
|
// }
|
|
101
108
|
if (this._selectedFieldNames) {
|
|
102
|
-
tokens.push(`select(${this._selectedFieldNames.join(',')})`);
|
|
109
|
+
tokens.push(`select${this._distinct ? ' distinct' : ''}(${this._selectedFieldNames.join(',')})`);
|
|
103
110
|
}
|
|
104
111
|
tokens.push(...this._filters.map(f => `${f.name}${f.op}${f.val}`), ...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`));
|
|
105
112
|
if (this._groupByFieldNames) {
|
|
@@ -135,6 +142,9 @@ class RunnableDBQuery extends DBQuery {
|
|
|
135
142
|
async runQuery(opt) {
|
|
136
143
|
return await this.dao.runQuery(this, opt);
|
|
137
144
|
}
|
|
145
|
+
async runQuerySingleColumn(opt) {
|
|
146
|
+
return await this.dao.runQuerySingleColumn(this, opt);
|
|
147
|
+
}
|
|
138
148
|
async runQueryAsDBM(opt) {
|
|
139
149
|
return await this.dao.runQueryAsDBM(this, opt);
|
|
140
150
|
}
|
|
@@ -17,7 +17,7 @@ export interface TestItemTM {
|
|
|
17
17
|
export declare const testItemBMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemBM, TestItemBM>;
|
|
18
18
|
export declare const testItemDBMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemDBM, TestItemDBM>;
|
|
19
19
|
export declare const testItemTMSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<TestItemTM, TestItemTM>;
|
|
20
|
-
export declare const testItemBMJsonSchema: import("@naturalcycles/js-lib/dist/json-schema/jsonSchemaBuilder").JsonSchemaObjectBuilder<TestItemBM & Partial<import("@naturalcycles/js-lib").SavedDBEntity
|
|
20
|
+
export declare const testItemBMJsonSchema: import("@naturalcycles/js-lib/dist/json-schema/jsonSchemaBuilder").JsonSchemaObjectBuilder<TestItemBM & Partial<import("@naturalcycles/js-lib").SavedDBEntity<string>>>;
|
|
21
21
|
export declare const testItemDBMJsonSchema: import("@naturalcycles/js-lib/dist/json-schema/jsonSchemaBuilder").JsonSchemaObjectBuilder<TestItemDBM>;
|
|
22
22
|
export declare function createTestItemDBM(num?: number): TestItemDBM;
|
|
23
23
|
export declare function createTestItemBM(num?: number): Saved<TestItemBM>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CommonDBOptions, CommonDBSaveOptions } from '../db.model';
|
|
2
2
|
import { DBQuery, DBQueryFilter, DBQueryOrder } from '../query/dbQuery';
|
|
3
3
|
export declare const commonDBOptionsSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<CommonDBOptions, CommonDBOptions>;
|
|
4
|
-
export declare const commonDBSaveOptionsSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<CommonDBSaveOptions<import("@naturalcycles/js-lib").AnyObjectWithId
|
|
4
|
+
export declare const commonDBSaveOptionsSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<CommonDBSaveOptions<import("@naturalcycles/js-lib").AnyObjectWithId<string>>, CommonDBSaveOptions<import("@naturalcycles/js-lib").AnyObjectWithId<string>>>;
|
|
5
5
|
export declare const dbQueryFilterOperatorSchema: import("@naturalcycles/nodejs-lib/dist/validation/joi/string.extensions").ExtendedStringSchema;
|
|
6
|
-
export declare const dbQueryFilterSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<DBQueryFilter<import("@naturalcycles/js-lib").AnyObjectWithId
|
|
7
|
-
export declare const dbQueryOrderSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<DBQueryOrder<import("@naturalcycles/js-lib").AnyObjectWithId
|
|
6
|
+
export declare const dbQueryFilterSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<DBQueryFilter<import("@naturalcycles/js-lib").AnyObjectWithId<string>>, DBQueryFilter<import("@naturalcycles/js-lib").AnyObjectWithId<string>>>;
|
|
7
|
+
export declare const dbQueryOrderSchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<DBQueryOrder<import("@naturalcycles/js-lib").AnyObjectWithId<string>>, DBQueryOrder<import("@naturalcycles/js-lib").AnyObjectWithId<string>>>;
|
|
8
8
|
export declare const dbQuerySchema: import("@naturalcycles/nodejs-lib").ObjectSchemaTyped<DBQuery<any>, DBQuery<any>>;
|
package/package.json
CHANGED
|
@@ -102,10 +102,16 @@ export interface CommonDaoCfg<
|
|
|
102
102
|
hooks?: Partial<CommonDaoHooks<BM, DBM, TM>>
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
|
-
*
|
|
106
|
-
* Set to false to disable created
|
|
105
|
+
* Defaults to true
|
|
106
|
+
* Set to false to disable `created` field management.
|
|
107
107
|
*/
|
|
108
|
-
|
|
108
|
+
created?: boolean
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Defaults to true
|
|
112
|
+
* Set to false to disable `updated` field management.
|
|
113
|
+
*/
|
|
114
|
+
updated?: boolean
|
|
109
115
|
|
|
110
116
|
/**
|
|
111
117
|
* Default is false.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
_assert,
|
|
2
3
|
_filterNullishValues,
|
|
3
4
|
_filterUndefinedValues,
|
|
4
5
|
_passthroughPredicate,
|
|
@@ -68,7 +69,8 @@ export class CommonDao<
|
|
|
68
69
|
// otherwise to log Operations
|
|
69
70
|
// e.g in Dev (local machine), Test - it will log operations (useful for debugging)
|
|
70
71
|
logLevel: isGAE || isCI ? CommonDaoLogLevel.NONE : CommonDaoLogLevel.OPERATIONS,
|
|
71
|
-
|
|
72
|
+
created: true,
|
|
73
|
+
updated: true,
|
|
72
74
|
logger: console,
|
|
73
75
|
...cfg,
|
|
74
76
|
hooks: {
|
|
@@ -262,6 +264,18 @@ export class CommonDao<
|
|
|
262
264
|
return rows
|
|
263
265
|
}
|
|
264
266
|
|
|
267
|
+
async runQuerySingleColumn<T = any>(q: DBQuery<DBM>, opt?: CommonDaoOptions): Promise<T[]> {
|
|
268
|
+
_assert(
|
|
269
|
+
q._selectedFieldNames?.length === 1,
|
|
270
|
+
`runQuerySingleColumn requires exactly 1 column to be selected: ${q.pretty()}`,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
const col = q._selectedFieldNames[0]!
|
|
274
|
+
|
|
275
|
+
const { rows } = await this.runQueryExtended(q, opt)
|
|
276
|
+
return rows.map(r => r[col as any])
|
|
277
|
+
}
|
|
278
|
+
|
|
265
279
|
/**
|
|
266
280
|
* Convenience method that runs multiple queries in parallel and then merges their results together.
|
|
267
281
|
* Does deduplication by id.
|
|
@@ -549,9 +563,14 @@ export class CommonDao<
|
|
|
549
563
|
|
|
550
564
|
obj.id = obj.id || this.cfg.hooks!.createId!(obj)
|
|
551
565
|
|
|
552
|
-
if (this.cfg.
|
|
566
|
+
if (this.cfg.created) {
|
|
553
567
|
Object.assign(obj, {
|
|
554
568
|
created: (obj as any).created || (obj as any).updated || now,
|
|
569
|
+
})
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (this.cfg.updated) {
|
|
573
|
+
Object.assign(obj, {
|
|
555
574
|
updated: opt.preserveUpdatedCreated && (obj as any).updated ? (obj as any).updated : now,
|
|
556
575
|
})
|
|
557
576
|
}
|
package/src/index.ts
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
} from './query/dbQuery'
|
|
59
59
|
import { DBTransaction, RunnableDBTransaction } from './transaction/dbTransaction'
|
|
60
60
|
import { commitDBTransactionSimple, mergeDBOperations } from './transaction/dbTransaction.util'
|
|
61
|
+
export * from './kv/commonKeyValueDaoMemoCache'
|
|
61
62
|
|
|
62
63
|
export type {
|
|
63
64
|
DBQueryFilterOperator,
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { ErrorMode, KeyValueTuple, pMap } from '@naturalcycles/js-lib'
|
|
2
|
-
import {
|
|
1
|
+
import { AppError, ErrorMode, KeyValueTuple, pMap } from '@naturalcycles/js-lib'
|
|
2
|
+
import {
|
|
3
|
+
deflateString,
|
|
4
|
+
inflateToString,
|
|
5
|
+
ReadableTyped,
|
|
6
|
+
transformMap,
|
|
7
|
+
} from '@naturalcycles/nodejs-lib'
|
|
8
|
+
import { DBLibError } from '../cnst'
|
|
3
9
|
import { CommonDaoLogLevel } from '../commondao/common.dao.model'
|
|
4
10
|
import { CommonDBCreateOptions } from '../db.model'
|
|
5
11
|
import { CommonKeyValueDB, KeyValueDBTuple } from './commonKeyValueDB'
|
|
@@ -30,13 +36,28 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
30
36
|
mapBufferToValue?: (b: Buffer) => Promise<T>
|
|
31
37
|
beforeCreate?: (v: Partial<T>) => Partial<T>
|
|
32
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Set to `true` to conveniently enable zipping+JSON.stringify
|
|
42
|
+
* (and unzipping+JSON.parse) of the Buffer value via hooks.
|
|
43
|
+
* Custom hooks will override these hooks (if provided).
|
|
44
|
+
*/
|
|
45
|
+
deflatedJsonValue?: boolean
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
// todo: logging
|
|
36
49
|
// todo: readonly
|
|
37
50
|
|
|
38
51
|
export class CommonKeyValueDao<T> {
|
|
39
|
-
constructor(public cfg: CommonKeyValueDaoCfg<T>) {
|
|
52
|
+
constructor(public cfg: CommonKeyValueDaoCfg<T>) {
|
|
53
|
+
if (cfg.deflatedJsonValue) {
|
|
54
|
+
cfg.hooks = {
|
|
55
|
+
mapValueToBuffer: async v => await deflateString(JSON.stringify(v)),
|
|
56
|
+
mapBufferToValue: async buf => JSON.parse(await inflateToString(buf)),
|
|
57
|
+
...cfg.hooks,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
40
61
|
|
|
41
62
|
async ping(): Promise<void> {
|
|
42
63
|
await this.cfg.db.ping()
|
|
@@ -58,6 +79,21 @@ export class CommonKeyValueDao<T> {
|
|
|
58
79
|
return r?.[1] || null
|
|
59
80
|
}
|
|
60
81
|
|
|
82
|
+
async requireById(id: string): Promise<T> {
|
|
83
|
+
const [r] = await this.getByIds([id])
|
|
84
|
+
|
|
85
|
+
if (!r) {
|
|
86
|
+
const { table } = this.cfg
|
|
87
|
+
throw new AppError(`DB row required, but not found: ${table}.${id}`, {
|
|
88
|
+
code: DBLibError.DB_ROW_REQUIRED,
|
|
89
|
+
table,
|
|
90
|
+
id,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return r[1]
|
|
95
|
+
}
|
|
96
|
+
|
|
61
97
|
async getByIdOrEmpty(id: string, part: Partial<T> = {}): Promise<T> {
|
|
62
98
|
const [r] = await this.getByIds([id])
|
|
63
99
|
if (r) return r[1]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AsyncMemoCache } from '@naturalcycles/js-lib'
|
|
2
|
+
import { CommonKeyValueDao } from './commonKeyValueDao'
|
|
3
|
+
|
|
4
|
+
export class CommonKeyValueDaoMemoCache<VALUE = any> implements AsyncMemoCache<string, VALUE> {
|
|
5
|
+
constructor(private dao: CommonKeyValueDao<VALUE>) {}
|
|
6
|
+
|
|
7
|
+
async get(k: string): Promise<VALUE | undefined> {
|
|
8
|
+
return (await this.dao.getById(k)) || undefined
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async set(k: string, v: VALUE): Promise<void> {
|
|
12
|
+
await this.dao.save(k, v)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async clear(): Promise<void> {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'CommonKeyValueDaoCacheFactory.clear is not supported, because cache is expected to be persistent',
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -97,6 +97,7 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
97
97
|
*/
|
|
98
98
|
_selectedFieldNames?: (keyof ROW)[]
|
|
99
99
|
_groupByFieldNames?: (keyof ROW)[]
|
|
100
|
+
_distinct = false
|
|
100
101
|
|
|
101
102
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this {
|
|
102
103
|
this._filters.push({ name, op, val })
|
|
@@ -136,6 +137,11 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
136
137
|
return this
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
distinct(distinct = true): this {
|
|
141
|
+
this._distinct = distinct
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
|
|
139
145
|
startCursor(startCursor?: string): this {
|
|
140
146
|
this._startCursor = startCursor
|
|
141
147
|
return this
|
|
@@ -153,6 +159,8 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
153
159
|
_offsetValue: this._offsetValue,
|
|
154
160
|
_orders: [...this._orders],
|
|
155
161
|
_selectedFieldNames: this._selectedFieldNames && [...this._selectedFieldNames],
|
|
162
|
+
_groupByFieldNames: this._groupByFieldNames && [...this._groupByFieldNames],
|
|
163
|
+
_distinct: this._distinct,
|
|
156
164
|
_startCursor: this._startCursor,
|
|
157
165
|
_endCursor: this._endCursor,
|
|
158
166
|
})
|
|
@@ -170,7 +178,9 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
170
178
|
// }
|
|
171
179
|
|
|
172
180
|
if (this._selectedFieldNames) {
|
|
173
|
-
tokens.push(
|
|
181
|
+
tokens.push(
|
|
182
|
+
`select${this._distinct ? ' distinct' : ''}(${this._selectedFieldNames.join(',')})`,
|
|
183
|
+
)
|
|
174
184
|
}
|
|
175
185
|
|
|
176
186
|
tokens.push(
|
|
@@ -221,6 +231,10 @@ export class RunnableDBQuery<
|
|
|
221
231
|
return await this.dao.runQuery(this, opt)
|
|
222
232
|
}
|
|
223
233
|
|
|
234
|
+
async runQuerySingleColumn<T = any>(opt?: CommonDaoOptions): Promise<T[]> {
|
|
235
|
+
return await this.dao.runQuerySingleColumn<T>(this, opt)
|
|
236
|
+
}
|
|
237
|
+
|
|
224
238
|
async runQueryAsDBM(opt?: CommonDaoOptions): Promise<DBM[]> {
|
|
225
239
|
return await this.dao.runQueryAsDBM(this, opt)
|
|
226
240
|
}
|