@naturalcycles/db-lib 8.27.0 → 8.29.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 +3 -4
- package/dist/commondao/common.dao.js +7 -13
- package/dist/commondao/common.dao.model.d.ts +1 -1
- package/dist/kv/commonKeyValueDao.d.ts +6 -2
- package/dist/kv/commonKeyValueDao.js +22 -0
- package/dist/query/dbQuery.d.ts +2 -0
- package/dist/query/dbQuery.js +7 -0
- package/package.json +1 -1
- package/src/commondao/common.dao.model.ts +1 -1
- package/src/commondao/common.dao.ts +12 -15
- package/src/kv/commonKeyValueDao.ts +34 -6
- package/src/query/dbQuery.ts +10 -0
|
@@ -13,12 +13,11 @@ import { CommonDaoCfg, CommonDaoCreateOptions, CommonDaoOptions, CommonDaoSaveOp
|
|
|
13
13
|
export declare class CommonDao<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId = Saved<BM>, TM = BM> {
|
|
14
14
|
cfg: CommonDaoCfg<BM, DBM, TM>;
|
|
15
15
|
constructor(cfg: CommonDaoCfg<BM, DBM, TM>);
|
|
16
|
-
create(
|
|
16
|
+
create(part?: Partial<BM>, opt?: CommonDaoOptions): Saved<BM>;
|
|
17
17
|
getById(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
18
18
|
getById(id?: string, opt?: CommonDaoOptions): Promise<Saved<BM> | null>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
getByIdAsDBMOrEmpty(id: string, opt?: CommonDaoOptions): Promise<DBM>;
|
|
19
|
+
getByIdOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<Saved<BM>>;
|
|
20
|
+
getByIdAsDBMOrEmpty(id: string, part?: Partial<BM>, opt?: CommonDaoOptions): Promise<DBM>;
|
|
22
21
|
getByIdAsDBM(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
23
22
|
getByIdAsDBM(id?: string, opt?: CommonDaoOptions): Promise<DBM | null>;
|
|
24
23
|
getByIdAsTM(id: undefined, opt?: CommonDaoOptions): Promise<null>;
|
|
@@ -44,8 +44,8 @@ class CommonDao {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
// CREATE
|
|
47
|
-
create(
|
|
48
|
-
let bm = this.cfg.hooks.beforeCreate(
|
|
47
|
+
create(part = {}, opt = {}) {
|
|
48
|
+
let bm = this.cfg.hooks.beforeCreate(part);
|
|
49
49
|
bm = this.validateAndConvert(bm, this.cfg.bmSchema, db_model_1.DBModelType.BM, opt);
|
|
50
50
|
// If no SCHEMA - return as is
|
|
51
51
|
return this.assignIdCreatedUpdated(bm, opt);
|
|
@@ -71,23 +71,17 @@ class CommonDao {
|
|
|
71
71
|
this.logResult(started, op, bm, table);
|
|
72
72
|
return bm || null;
|
|
73
73
|
}
|
|
74
|
-
async
|
|
74
|
+
async getByIdOrEmpty(id, part = {}, opt) {
|
|
75
75
|
const bm = await this.getById(id, opt);
|
|
76
76
|
if (bm)
|
|
77
77
|
return bm;
|
|
78
|
-
return this.create({ ...
|
|
78
|
+
return this.create({ ...part, id }, opt);
|
|
79
79
|
}
|
|
80
|
-
async
|
|
81
|
-
const bm = await this.getById(id, opt);
|
|
82
|
-
if (bm)
|
|
83
|
-
return bm;
|
|
84
|
-
return this.create({ id }, opt);
|
|
85
|
-
}
|
|
86
|
-
async getByIdAsDBMOrEmpty(id, opt) {
|
|
80
|
+
async getByIdAsDBMOrEmpty(id, part = {}, opt) {
|
|
87
81
|
const dbm = await this.getByIdAsDBM(id, opt);
|
|
88
82
|
if (dbm)
|
|
89
83
|
return dbm;
|
|
90
|
-
const bm = this.create({ id }, opt);
|
|
84
|
+
const bm = this.create({ ...part, id }, opt);
|
|
91
85
|
return await this.bmToDBM(bm, opt);
|
|
92
86
|
}
|
|
93
87
|
async getByIdAsDBM(id, opt = {}) {
|
|
@@ -458,7 +452,7 @@ class CommonDao {
|
|
|
458
452
|
*/
|
|
459
453
|
async patch(id, patch, opt = {}) {
|
|
460
454
|
return await this.save({
|
|
461
|
-
...(await this.
|
|
455
|
+
...(await this.getByIdOrEmpty(id, patch, opt)),
|
|
462
456
|
...patch,
|
|
463
457
|
}, opt);
|
|
464
458
|
}
|
|
@@ -4,7 +4,7 @@ import { CommonDB } from '../common.db';
|
|
|
4
4
|
import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model';
|
|
5
5
|
export declare type CommonDaoCreateIdHook<BM, DBM> = (obj: DBM | BM) => string;
|
|
6
6
|
export declare type CommonDaoParseNaturalIdHook<DBM> = (id: string) => Partial<DBM>;
|
|
7
|
-
export declare type CommonDaoBeforeCreateHook<BM> = (bm: Partial<BM>) => BM
|
|
7
|
+
export declare type CommonDaoBeforeCreateHook<BM> = (bm: Partial<BM>) => Partial<BM>;
|
|
8
8
|
export declare type CommonDaoBeforeDBMValidateHook<DBM> = (dbm: Partial<DBM>) => Partial<DBM>;
|
|
9
9
|
export declare type CommonDaoBeforeDBMToBMHook<BM, DBM> = (dbm: DBM) => Partial<BM> | Promise<Partial<BM>>;
|
|
10
10
|
export declare type CommonDaoBeforeBMToDBMHook<BM, DBM> = (bm: BM) => Partial<DBM> | Promise<Partial<DBM>>;
|
|
@@ -21,8 +21,9 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
21
21
|
*/
|
|
22
22
|
logStarted?: boolean;
|
|
23
23
|
hooks?: {
|
|
24
|
-
mapValueToBuffer(v: T)
|
|
25
|
-
mapBufferToValue(b: Buffer)
|
|
24
|
+
mapValueToBuffer?: (v: T) => Promise<Buffer>;
|
|
25
|
+
mapBufferToValue?: (b: Buffer) => Promise<T>;
|
|
26
|
+
beforeCreate?: (v: Partial<T>) => Partial<T>;
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
export declare class CommonKeyValueDao<T> {
|
|
@@ -30,7 +31,10 @@ export declare class CommonKeyValueDao<T> {
|
|
|
30
31
|
constructor(cfg: CommonKeyValueDaoCfg<T>);
|
|
31
32
|
ping(): Promise<void>;
|
|
32
33
|
createTable(opt?: CommonDBCreateOptions): Promise<void>;
|
|
34
|
+
create(input?: Partial<T>): T;
|
|
33
35
|
getById(id?: string): Promise<T | null>;
|
|
36
|
+
getByIdOrEmpty(id: string, part?: Partial<T>): Promise<T>;
|
|
37
|
+
patch(id: string, patch: Partial<T>): Promise<T>;
|
|
34
38
|
getByIds(ids: string[]): Promise<KeyValueTuple<string, T>[]>;
|
|
35
39
|
save(id: string, value: T): Promise<void>;
|
|
36
40
|
saveBatch(entries: KeyValueTuple<string, T>[]): Promise<void>;
|
|
@@ -15,12 +15,34 @@ class CommonKeyValueDao {
|
|
|
15
15
|
async createTable(opt = {}) {
|
|
16
16
|
await this.cfg.db.createTable(this.cfg.table, opt);
|
|
17
17
|
}
|
|
18
|
+
create(input = {}) {
|
|
19
|
+
return {
|
|
20
|
+
...this.cfg.hooks?.beforeCreate?.(input),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
18
23
|
async getById(id) {
|
|
19
24
|
if (!id)
|
|
20
25
|
return null;
|
|
21
26
|
const [r] = await this.getByIds([id]);
|
|
22
27
|
return r?.[1] || null;
|
|
23
28
|
}
|
|
29
|
+
async getByIdOrEmpty(id, part = {}) {
|
|
30
|
+
const [r] = await this.getByIds([id]);
|
|
31
|
+
if (r)
|
|
32
|
+
return r[1];
|
|
33
|
+
return {
|
|
34
|
+
...this.cfg.hooks?.beforeCreate?.({}),
|
|
35
|
+
...part,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async patch(id, patch) {
|
|
39
|
+
const v = {
|
|
40
|
+
...(await this.getByIdOrEmpty(id)),
|
|
41
|
+
...patch,
|
|
42
|
+
};
|
|
43
|
+
await this.save(id, v);
|
|
44
|
+
return v;
|
|
45
|
+
}
|
|
24
46
|
async getByIds(ids) {
|
|
25
47
|
const entries = await this.cfg.db.getByIds(this.cfg.table, ids);
|
|
26
48
|
if (!this.cfg.hooks?.mapBufferToValue)
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -64,12 +64,14 @@ export declare class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
64
64
|
* In undefined - all fields (*) will be returned.
|
|
65
65
|
*/
|
|
66
66
|
_selectedFieldNames?: (keyof ROW)[];
|
|
67
|
+
_groupByFieldNames?: (keyof ROW)[];
|
|
67
68
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this;
|
|
68
69
|
filterEq(name: keyof ROW, val: any): this;
|
|
69
70
|
limit(limit: number): this;
|
|
70
71
|
offset(offset: number): this;
|
|
71
72
|
order(name: keyof ROW, descending?: boolean): this;
|
|
72
73
|
select(fieldNames: (keyof ROW)[]): this;
|
|
74
|
+
groupBy(fieldNames: (keyof ROW)[]): this;
|
|
73
75
|
startCursor(startCursor?: string): this;
|
|
74
76
|
endCursor(endCursor?: string): this;
|
|
75
77
|
clone(): DBQuery<ROW>;
|
package/dist/query/dbQuery.js
CHANGED
|
@@ -67,6 +67,10 @@ class DBQuery {
|
|
|
67
67
|
this._selectedFieldNames = fieldNames;
|
|
68
68
|
return this;
|
|
69
69
|
}
|
|
70
|
+
groupBy(fieldNames) {
|
|
71
|
+
this._groupByFieldNames = fieldNames;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
70
74
|
startCursor(startCursor) {
|
|
71
75
|
this._startCursor = startCursor;
|
|
72
76
|
return this;
|
|
@@ -98,6 +102,9 @@ class DBQuery {
|
|
|
98
102
|
tokens.push(`select(${this._selectedFieldNames.join(',')})`);
|
|
99
103
|
}
|
|
100
104
|
tokens.push(...this._filters.map(f => `${f.name}${f.op}${f.val}`), ...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`));
|
|
105
|
+
if (this._groupByFieldNames) {
|
|
106
|
+
tokens.push(`groupBy(${this._groupByFieldNames.join(',')})`);
|
|
107
|
+
}
|
|
101
108
|
if (this._offsetValue) {
|
|
102
109
|
tokens.push(`offset ${this._offsetValue}`);
|
|
103
110
|
}
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../
|
|
|
13
13
|
// Hook DBM, BM, TM types should follow this exact order
|
|
14
14
|
export type CommonDaoCreateIdHook<BM, DBM> = (obj: DBM | BM) => string
|
|
15
15
|
export type CommonDaoParseNaturalIdHook<DBM> = (id: string) => Partial<DBM>
|
|
16
|
-
export type CommonDaoBeforeCreateHook<BM> = (bm: Partial<BM>) => BM
|
|
16
|
+
export type CommonDaoBeforeCreateHook<BM> = (bm: Partial<BM>) => Partial<BM>
|
|
17
17
|
export type CommonDaoBeforeDBMValidateHook<DBM> = (dbm: Partial<DBM>) => Partial<DBM>
|
|
18
18
|
export type CommonDaoBeforeDBMToBMHook<BM, DBM> = (dbm: DBM) => Partial<BM> | Promise<Partial<BM>>
|
|
19
19
|
export type CommonDaoBeforeBMToDBMHook<BM, DBM> = (bm: BM) => Partial<DBM> | Promise<Partial<DBM>>
|
|
@@ -88,8 +88,8 @@ export class CommonDao<
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// CREATE
|
|
91
|
-
create(
|
|
92
|
-
let bm = this.cfg.hooks!.beforeCreate!(
|
|
91
|
+
create(part: Partial<BM> = {}, opt: CommonDaoOptions = {}): Saved<BM> {
|
|
92
|
+
let bm = this.cfg.hooks!.beforeCreate!(part) as BM
|
|
93
93
|
bm = this.validateAndConvert(bm, this.cfg.bmSchema, DBModelType.BM, opt)
|
|
94
94
|
|
|
95
95
|
// If no SCHEMA - return as is
|
|
@@ -124,29 +124,26 @@ export class CommonDao<
|
|
|
124
124
|
return bm || null
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
async
|
|
127
|
+
async getByIdOrEmpty(
|
|
128
128
|
id: string,
|
|
129
|
-
|
|
129
|
+
part: Partial<BM> = {},
|
|
130
130
|
opt?: CommonDaoOptions,
|
|
131
131
|
): Promise<Saved<BM>> {
|
|
132
132
|
const bm = await this.getById(id, opt)
|
|
133
133
|
if (bm) return bm
|
|
134
134
|
|
|
135
|
-
return this.create({ ...
|
|
135
|
+
return this.create({ ...part, id }, opt)
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
async
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async getByIdAsDBMOrEmpty(id: string, opt?: CommonDaoOptions): Promise<DBM> {
|
|
138
|
+
async getByIdAsDBMOrEmpty(
|
|
139
|
+
id: string,
|
|
140
|
+
part: Partial<BM> = {},
|
|
141
|
+
opt?: CommonDaoOptions,
|
|
142
|
+
): Promise<DBM> {
|
|
146
143
|
const dbm = await this.getByIdAsDBM(id, opt)
|
|
147
144
|
if (dbm) return dbm
|
|
148
145
|
|
|
149
|
-
const bm: BM = this.create({ id }
|
|
146
|
+
const bm: BM = this.create({ ...part, id }, opt) as any
|
|
150
147
|
return await this.bmToDBM(bm, opt)
|
|
151
148
|
}
|
|
152
149
|
|
|
@@ -614,7 +611,7 @@ export class CommonDao<
|
|
|
614
611
|
): Promise<Saved<BM>> {
|
|
615
612
|
return await this.save(
|
|
616
613
|
{
|
|
617
|
-
...(await this.
|
|
614
|
+
...(await this.getByIdOrEmpty(id, patch, opt)),
|
|
618
615
|
...patch,
|
|
619
616
|
} as any,
|
|
620
617
|
opt,
|
|
@@ -26,8 +26,9 @@ export interface CommonKeyValueDaoCfg<T> {
|
|
|
26
26
|
logStarted?: boolean
|
|
27
27
|
|
|
28
28
|
hooks?: {
|
|
29
|
-
mapValueToBuffer(v: T)
|
|
30
|
-
mapBufferToValue(b: Buffer)
|
|
29
|
+
mapValueToBuffer?: (v: T) => Promise<Buffer>
|
|
30
|
+
mapBufferToValue?: (b: Buffer) => Promise<T>
|
|
31
|
+
beforeCreate?: (v: Partial<T>) => Partial<T>
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -45,19 +46,46 @@ export class CommonKeyValueDao<T> {
|
|
|
45
46
|
await this.cfg.db.createTable(this.cfg.table, opt)
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
create(input: Partial<T> = {}): T {
|
|
50
|
+
return {
|
|
51
|
+
...this.cfg.hooks?.beforeCreate?.(input),
|
|
52
|
+
} as T
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
async getById(id?: string): Promise<T | null> {
|
|
49
56
|
if (!id) return null
|
|
50
57
|
const [r] = await this.getByIds([id])
|
|
51
58
|
return r?.[1] || null
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
async getByIdOrEmpty(id: string, part: Partial<T> = {}): Promise<T> {
|
|
62
|
+
const [r] = await this.getByIds([id])
|
|
63
|
+
if (r) return r[1]
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...this.cfg.hooks?.beforeCreate?.({}),
|
|
67
|
+
...part,
|
|
68
|
+
} as T
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async patch(id: string, patch: Partial<T>): Promise<T> {
|
|
72
|
+
const v: T = {
|
|
73
|
+
...(await this.getByIdOrEmpty(id)),
|
|
74
|
+
...patch,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await this.save(id, v)
|
|
78
|
+
|
|
79
|
+
return v
|
|
80
|
+
}
|
|
81
|
+
|
|
54
82
|
async getByIds(ids: string[]): Promise<KeyValueTuple<string, T>[]> {
|
|
55
83
|
const entries = await this.cfg.db.getByIds(this.cfg.table, ids)
|
|
56
84
|
if (!this.cfg.hooks?.mapBufferToValue) return entries as any
|
|
57
85
|
|
|
58
86
|
return await pMap(entries, async ([id, buf]) => [
|
|
59
87
|
id,
|
|
60
|
-
await this.cfg.hooks!.mapBufferToValue(buf),
|
|
88
|
+
await this.cfg.hooks!.mapBufferToValue!(buf),
|
|
61
89
|
])
|
|
62
90
|
}
|
|
63
91
|
|
|
@@ -73,7 +101,7 @@ export class CommonKeyValueDao<T> {
|
|
|
73
101
|
} else {
|
|
74
102
|
bufferEntries = await pMap(entries, async ([id, v]) => [
|
|
75
103
|
id,
|
|
76
|
-
await this.cfg.hooks!.mapValueToBuffer(v),
|
|
104
|
+
await this.cfg.hooks!.mapValueToBuffer!(v),
|
|
77
105
|
])
|
|
78
106
|
}
|
|
79
107
|
|
|
@@ -100,7 +128,7 @@ export class CommonKeyValueDao<T> {
|
|
|
100
128
|
// todo: consider it when readableMap supports `errorMode: SUPPRESS`
|
|
101
129
|
// readableMap(this.cfg.db.streamValues(this.cfg.table, limit), async buf => await this.cfg.hooks!.mapBufferToValue(buf))
|
|
102
130
|
return this.cfg.db.streamValues(this.cfg.table, limit).pipe(
|
|
103
|
-
transformMap(async buf => await this.cfg.hooks!.mapBufferToValue(buf), {
|
|
131
|
+
transformMap(async buf => await this.cfg.hooks!.mapBufferToValue!(buf), {
|
|
104
132
|
errorMode: ErrorMode.SUPPRESS, // cause .pipe cannot propagate errors
|
|
105
133
|
}),
|
|
106
134
|
)
|
|
@@ -112,7 +140,7 @@ export class CommonKeyValueDao<T> {
|
|
|
112
140
|
}
|
|
113
141
|
|
|
114
142
|
return this.cfg.db.streamEntries(this.cfg.table, limit).pipe(
|
|
115
|
-
transformMap(async ([id, buf]) => [id, await this.cfg.hooks!.mapBufferToValue(buf)], {
|
|
143
|
+
transformMap(async ([id, buf]) => [id, await this.cfg.hooks!.mapBufferToValue!(buf)], {
|
|
116
144
|
errorMode: ErrorMode.SUPPRESS, // cause .pipe cannot propagate errors
|
|
117
145
|
}),
|
|
118
146
|
)
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -96,6 +96,7 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
96
96
|
* In undefined - all fields (*) will be returned.
|
|
97
97
|
*/
|
|
98
98
|
_selectedFieldNames?: (keyof ROW)[]
|
|
99
|
+
_groupByFieldNames?: (keyof ROW)[]
|
|
99
100
|
|
|
100
101
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this {
|
|
101
102
|
this._filters.push({ name, op, val })
|
|
@@ -130,6 +131,11 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
130
131
|
return this
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
groupBy(fieldNames: (keyof ROW)[]): this {
|
|
135
|
+
this._groupByFieldNames = fieldNames
|
|
136
|
+
return this
|
|
137
|
+
}
|
|
138
|
+
|
|
133
139
|
startCursor(startCursor?: string): this {
|
|
134
140
|
this._startCursor = startCursor
|
|
135
141
|
return this
|
|
@@ -172,6 +178,10 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
172
178
|
...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`),
|
|
173
179
|
)
|
|
174
180
|
|
|
181
|
+
if (this._groupByFieldNames) {
|
|
182
|
+
tokens.push(`groupBy(${this._groupByFieldNames.join(',')})`)
|
|
183
|
+
}
|
|
184
|
+
|
|
175
185
|
if (this._offsetValue) {
|
|
176
186
|
tokens.push(`offset ${this._offsetValue}`)
|
|
177
187
|
}
|