@naturalcycles/db-lib 8.28.2 → 8.32.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/kv/commonKeyValueDao.d.ts +1 -0
- package/dist/kv/commonKeyValueDao.js +13 -0
- package/dist/query/dbQuery.d.ts +5 -0
- package/dist/query/dbQuery.js +18 -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/kv/commonKeyValueDao.ts +17 -1
- package/src/query/dbQuery.ts +25 -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
|
|
@@ -33,6 +33,7 @@ export declare class CommonKeyValueDao<T> {
|
|
|
33
33
|
createTable(opt?: CommonDBCreateOptions): Promise<void>;
|
|
34
34
|
create(input?: Partial<T>): T;
|
|
35
35
|
getById(id?: string): Promise<T | null>;
|
|
36
|
+
requireById(id: string): Promise<T>;
|
|
36
37
|
getByIdOrEmpty(id: string, part?: Partial<T>): Promise<T>;
|
|
37
38
|
patch(id: string, patch: Partial<T>): Promise<T>;
|
|
38
39
|
getByIds(ids: string[]): Promise<KeyValueTuple<string, T>[]>;
|
|
@@ -3,6 +3,7 @@ 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 {
|
|
@@ -26,6 +27,18 @@ class CommonKeyValueDao {
|
|
|
26
27
|
const [r] = await this.getByIds([id]);
|
|
27
28
|
return r?.[1] || null;
|
|
28
29
|
}
|
|
30
|
+
async requireById(id) {
|
|
31
|
+
const [r] = await this.getByIds([id]);
|
|
32
|
+
if (!r) {
|
|
33
|
+
const { table } = this.cfg;
|
|
34
|
+
throw new js_lib_1.AppError(`DB row required, but not found: ${table}.${id}`, {
|
|
35
|
+
code: cnst_1.DBLibError.DB_ROW_REQUIRED,
|
|
36
|
+
table,
|
|
37
|
+
id,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return r[1];
|
|
41
|
+
}
|
|
29
42
|
async getByIdOrEmpty(id, part = {}) {
|
|
30
43
|
const [r] = await this.getByIds([id]);
|
|
31
44
|
if (r)
|
package/dist/query/dbQuery.d.ts
CHANGED
|
@@ -64,12 +64,16 @@ 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)[];
|
|
68
|
+
_distinct: boolean;
|
|
67
69
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this;
|
|
68
70
|
filterEq(name: keyof ROW, val: any): this;
|
|
69
71
|
limit(limit: number): this;
|
|
70
72
|
offset(offset: number): this;
|
|
71
73
|
order(name: keyof ROW, descending?: boolean): this;
|
|
72
74
|
select(fieldNames: (keyof ROW)[]): this;
|
|
75
|
+
groupBy(fieldNames: (keyof ROW)[]): this;
|
|
76
|
+
distinct(distinct?: boolean): this;
|
|
73
77
|
startCursor(startCursor?: string): this;
|
|
74
78
|
endCursor(endCursor?: string): this;
|
|
75
79
|
clone(): DBQuery<ROW>;
|
|
@@ -86,6 +90,7 @@ export declare class RunnableDBQuery<BM extends Partial<ObjectWithId>, DBM exten
|
|
|
86
90
|
*/
|
|
87
91
|
constructor(dao: CommonDao<BM, DBM, TM>, table?: string);
|
|
88
92
|
runQuery(opt?: CommonDaoOptions): Promise<Saved<BM>[]>;
|
|
93
|
+
runQuerySingleColumn<T = any>(opt?: CommonDaoOptions): Promise<T[]>;
|
|
89
94
|
runQueryAsDBM(opt?: CommonDaoOptions): Promise<DBM[]>;
|
|
90
95
|
runQueryAsTM(opt?: CommonDaoOptions): Promise<TM[]>;
|
|
91
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.
|
|
@@ -67,6 +68,14 @@ class DBQuery {
|
|
|
67
68
|
this._selectedFieldNames = fieldNames;
|
|
68
69
|
return this;
|
|
69
70
|
}
|
|
71
|
+
groupBy(fieldNames) {
|
|
72
|
+
this._groupByFieldNames = fieldNames;
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
distinct(distinct = true) {
|
|
76
|
+
this._distinct = distinct;
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
70
79
|
startCursor(startCursor) {
|
|
71
80
|
this._startCursor = startCursor;
|
|
72
81
|
return this;
|
|
@@ -82,6 +91,8 @@ class DBQuery {
|
|
|
82
91
|
_offsetValue: this._offsetValue,
|
|
83
92
|
_orders: [...this._orders],
|
|
84
93
|
_selectedFieldNames: this._selectedFieldNames && [...this._selectedFieldNames],
|
|
94
|
+
_groupByFieldNames: this._groupByFieldNames && [...this._groupByFieldNames],
|
|
95
|
+
_distinct: this._distinct,
|
|
85
96
|
_startCursor: this._startCursor,
|
|
86
97
|
_endCursor: this._endCursor,
|
|
87
98
|
});
|
|
@@ -95,9 +106,12 @@ class DBQuery {
|
|
|
95
106
|
// tokens.push(`"${this.name}"`)
|
|
96
107
|
// }
|
|
97
108
|
if (this._selectedFieldNames) {
|
|
98
|
-
tokens.push(`select(${this._selectedFieldNames.join(',')})`);
|
|
109
|
+
tokens.push(`select${this._distinct ? ' distinct' : ''}(${this._selectedFieldNames.join(',')})`);
|
|
99
110
|
}
|
|
100
111
|
tokens.push(...this._filters.map(f => `${f.name}${f.op}${f.val}`), ...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`));
|
|
112
|
+
if (this._groupByFieldNames) {
|
|
113
|
+
tokens.push(`groupBy(${this._groupByFieldNames.join(',')})`);
|
|
114
|
+
}
|
|
101
115
|
if (this._offsetValue) {
|
|
102
116
|
tokens.push(`offset ${this._offsetValue}`);
|
|
103
117
|
}
|
|
@@ -128,6 +142,9 @@ class RunnableDBQuery extends DBQuery {
|
|
|
128
142
|
async runQuery(opt) {
|
|
129
143
|
return await this.dao.runQuery(this, opt);
|
|
130
144
|
}
|
|
145
|
+
async runQuerySingleColumn(opt) {
|
|
146
|
+
return await this.dao.runQuerySingleColumn(this, opt);
|
|
147
|
+
}
|
|
131
148
|
async runQueryAsDBM(opt) {
|
|
132
149
|
return await this.dao.runQueryAsDBM(this, opt);
|
|
133
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
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ErrorMode, KeyValueTuple, pMap } from '@naturalcycles/js-lib'
|
|
1
|
+
import { AppError, ErrorMode, KeyValueTuple, pMap } from '@naturalcycles/js-lib'
|
|
2
2
|
import { ReadableTyped, transformMap } from '@naturalcycles/nodejs-lib'
|
|
3
|
+
import { DBLibError } from '../cnst'
|
|
3
4
|
import { CommonDaoLogLevel } from '../commondao/common.dao.model'
|
|
4
5
|
import { CommonDBCreateOptions } from '../db.model'
|
|
5
6
|
import { CommonKeyValueDB, KeyValueDBTuple } from './commonKeyValueDB'
|
|
@@ -58,6 +59,21 @@ export class CommonKeyValueDao<T> {
|
|
|
58
59
|
return r?.[1] || null
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
async requireById(id: string): Promise<T> {
|
|
63
|
+
const [r] = await this.getByIds([id])
|
|
64
|
+
|
|
65
|
+
if (!r) {
|
|
66
|
+
const { table } = this.cfg
|
|
67
|
+
throw new AppError(`DB row required, but not found: ${table}.${id}`, {
|
|
68
|
+
code: DBLibError.DB_ROW_REQUIRED,
|
|
69
|
+
table,
|
|
70
|
+
id,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return r[1]
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
async getByIdOrEmpty(id: string, part: Partial<T> = {}): Promise<T> {
|
|
62
78
|
const [r] = await this.getByIds([id])
|
|
63
79
|
if (r) return r[1]
|
package/src/query/dbQuery.ts
CHANGED
|
@@ -96,6 +96,8 @@ 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)[]
|
|
100
|
+
_distinct = false
|
|
99
101
|
|
|
100
102
|
filter(name: keyof ROW, op: DBQueryFilterOperator, val: any): this {
|
|
101
103
|
this._filters.push({ name, op, val })
|
|
@@ -130,6 +132,16 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
130
132
|
return this
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
groupBy(fieldNames: (keyof ROW)[]): this {
|
|
136
|
+
this._groupByFieldNames = fieldNames
|
|
137
|
+
return this
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
distinct(distinct = true): this {
|
|
141
|
+
this._distinct = distinct
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
|
|
133
145
|
startCursor(startCursor?: string): this {
|
|
134
146
|
this._startCursor = startCursor
|
|
135
147
|
return this
|
|
@@ -147,6 +159,8 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
147
159
|
_offsetValue: this._offsetValue,
|
|
148
160
|
_orders: [...this._orders],
|
|
149
161
|
_selectedFieldNames: this._selectedFieldNames && [...this._selectedFieldNames],
|
|
162
|
+
_groupByFieldNames: this._groupByFieldNames && [...this._groupByFieldNames],
|
|
163
|
+
_distinct: this._distinct,
|
|
150
164
|
_startCursor: this._startCursor,
|
|
151
165
|
_endCursor: this._endCursor,
|
|
152
166
|
})
|
|
@@ -164,7 +178,9 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
164
178
|
// }
|
|
165
179
|
|
|
166
180
|
if (this._selectedFieldNames) {
|
|
167
|
-
tokens.push(
|
|
181
|
+
tokens.push(
|
|
182
|
+
`select${this._distinct ? ' distinct' : ''}(${this._selectedFieldNames.join(',')})`,
|
|
183
|
+
)
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
tokens.push(
|
|
@@ -172,6 +188,10 @@ export class DBQuery<ROW extends ObjectWithId = AnyObjectWithId> {
|
|
|
172
188
|
...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`),
|
|
173
189
|
)
|
|
174
190
|
|
|
191
|
+
if (this._groupByFieldNames) {
|
|
192
|
+
tokens.push(`groupBy(${this._groupByFieldNames.join(',')})`)
|
|
193
|
+
}
|
|
194
|
+
|
|
175
195
|
if (this._offsetValue) {
|
|
176
196
|
tokens.push(`offset ${this._offsetValue}`)
|
|
177
197
|
}
|
|
@@ -211,6 +231,10 @@ export class RunnableDBQuery<
|
|
|
211
231
|
return await this.dao.runQuery(this, opt)
|
|
212
232
|
}
|
|
213
233
|
|
|
234
|
+
async runQuerySingleColumn<T = any>(opt?: CommonDaoOptions): Promise<T[]> {
|
|
235
|
+
return await this.dao.runQuerySingleColumn<T>(this, opt)
|
|
236
|
+
}
|
|
237
|
+
|
|
214
238
|
async runQueryAsDBM(opt?: CommonDaoOptions): Promise<DBM[]> {
|
|
215
239
|
return await this.dao.runQueryAsDBM(this, opt)
|
|
216
240
|
}
|