orange-orm 5.1.0 → 5.2.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.
@@ -212,6 +212,7 @@ function rdbClient(options = {}) {
212
212
  count,
213
213
  getMany,
214
214
  aggregate: groupBy,
215
+ distinct,
215
216
  getAll,
216
217
  getOne,
217
218
  getById,
@@ -267,9 +268,17 @@ function rdbClient(options = {}) {
267
268
  }
268
269
 
269
270
  async function groupBy(strategy) {
271
+ return executeGroupBy('aggregate', strategy);
272
+ }
273
+
274
+ async function distinct(strategy) {
275
+ return executeGroupBy('distinct', strategy);
276
+ }
277
+
278
+ async function executeGroupBy(path, strategy) {
270
279
  let args = negotiateGroupBy(null, strategy);
271
280
  let body = stringify({
272
- path: 'aggregate',
281
+ path,
273
282
  args
274
283
  });
275
284
  let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions });
@@ -1064,12 +1073,20 @@ function groupByAggregate(path, arg) {
1064
1073
  }
1065
1074
  }
1066
1075
 
1076
+ const isColumnProxyKey = '__isColumnProxy';
1077
+ const columnPathKey = '__columnPath';
1078
+ const columnRefKey = '__columnRef';
1079
+
1067
1080
  function column(path, ...previous) {
1068
1081
  function c() {
1069
1082
  let args = [];
1070
1083
  for (let i = 0; i < arguments.length; i++) {
1071
- if (typeof arguments[i] === 'function')
1072
- args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.')));
1084
+ if (typeof arguments[i] === 'function') {
1085
+ if (arguments[i][isColumnProxyKey])
1086
+ args[i] = { [columnRefKey]: arguments[i][columnPathKey] };
1087
+ else
1088
+ args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.')));
1089
+ }
1073
1090
  else
1074
1091
  args[i] = arguments[i];
1075
1092
  }
@@ -1092,6 +1109,10 @@ function column(path, ...previous) {
1092
1109
  }
1093
1110
  let handler = {
1094
1111
  get(_target, property) {
1112
+ if (property === isColumnProxyKey)
1113
+ return true;
1114
+ if (property === columnPathKey)
1115
+ return path;
1095
1116
  if (property === 'toJSON')
1096
1117
  return Reflect.get(...arguments);
1097
1118
  else if (property === 'then')
@@ -4,7 +4,7 @@ var newJoinSql = require('../../table/query/singleQuery/newJoinSql');
4
4
  var newParameterized = require('../../table/query/newParameterized');
5
5
  var getSessionSingleton = require('../../table/getSessionSingleton');
6
6
 
7
- function _new(context,table,filter,span, alias,orderBy,limit,offset) {
7
+ function _new(context,table,filter,span, alias,orderBy,limit,offset,distinct = false) {
8
8
  var quote = getSessionSingleton(context, 'quote');
9
9
  var name = quote(table._dbName);
10
10
  var columnSql = newColumnSql(context,table,span,alias,true);
@@ -12,9 +12,10 @@ function _new(context,table,filter,span, alias,orderBy,limit,offset) {
12
12
  var whereSql = newWhereSql(context,table,filter,alias);
13
13
  if (limit)
14
14
  limit = limit + ' ';
15
+ const selectClause = distinct ? 'select distinct ' : 'select ';
15
16
 
16
- return newParameterized('select ' + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset);
17
+ return newParameterized(selectClause + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset);
17
18
 
18
19
  }
19
20
 
20
- module.exports = _new;
21
+ module.exports = _new;
@@ -76,7 +76,7 @@ function _executePath(context, ...rest) {
76
76
 
77
77
  async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) {
78
78
  let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) };
79
- let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, count, delete: _delete, cascadeDelete, update, replace };
79
+ let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, distinct, count, delete: _delete, cascadeDelete, update, replace };
80
80
 
81
81
  let res = await parseFilter(JSONFilter, table);
82
82
  if (res === undefined)
@@ -90,9 +90,12 @@ function _executePath(context, ...rest) {
90
90
 
91
91
  let anyAllNone = tryGetAnyAllNone(json.path, table);
92
92
  if (anyAllNone) {
93
- if (isHttp)
94
- validateArgs(json.args[0]);
95
- const f = anyAllNone(context, x => parseFilter(json.args[0], x));
93
+ const arg0 = json.args[0];
94
+ if (isHttp && arg0 !== undefined)
95
+ validateArgs(arg0);
96
+ const f = arg0 === undefined
97
+ ? anyAllNone(context)
98
+ : anyAllNone(context, x => parseFilter(arg0, x));
96
99
  if(!('isSafe' in f))
97
100
  f.isSafe = isSafe;
98
101
  return f;
@@ -111,17 +114,22 @@ function _executePath(context, ...rest) {
111
114
  }
112
115
  return result;
113
116
  }
117
+ else if (isColumnRef(json)) {
118
+ return resolveColumnRef(table, json.__columnRef);
119
+ }
114
120
  return json;
115
121
 
116
122
  function tryGetAnyAllNone(path, table) {
117
- path = path.split('.');
118
- for (let i = 0; i < path.length; i++) {
119
- table = table[path[i]];
123
+ const parts = path.split('.');
124
+ for (let i = 0; i < parts.length; i++) {
125
+ table = table[parts[i]];
120
126
  }
121
127
 
122
128
  let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']);
123
129
  // let ops = new Set(['all', 'any', 'none', 'where']);
124
- let last = path.slice(-1)[0];
130
+ let last = parts[parts.length - 1];
131
+ if (last === 'count' && parts.length > 1)
132
+ ops.add('count');
125
133
  if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all))))
126
134
  return table;
127
135
  }
@@ -154,8 +162,21 @@ function _executePath(context, ...rest) {
154
162
  target = target[pathArray[i]];
155
163
  }
156
164
 
157
- if (!target)
165
+ if (!target) {
166
+ const left = args && args[0];
167
+ if (left) {
168
+ target = left;
169
+ for (let i = 0; i < pathArray.length; i++) {
170
+ target = target[pathArray[i]];
171
+ }
172
+ if (target) {
173
+ let res = target.apply(null, [context].concat(args.slice(1)));
174
+ setSafe(res);
175
+ return res;
176
+ }
177
+ }
158
178
  throw new Error(`Method '${path}' does not exist`);
179
+ }
159
180
  let res = target.apply(null, [context, ...args]);
160
181
  setSafe(res);
161
182
  return res;
@@ -201,7 +222,7 @@ function _executePath(context, ...rest) {
201
222
 
202
223
  function nextTable(path, table) {
203
224
  path = path.split('.');
204
- let ops = new Set(['all', 'any', 'none']);
225
+ let ops = new Set(['all', 'any', 'none', 'count']);
205
226
  let last = path.slice(-1)[0];
206
227
  if (ops.has(last)) {
207
228
  for (let i = 0; i < path.length - 1; i++) {
@@ -351,6 +372,17 @@ function _executePath(context, ...rest) {
351
372
  return table.aggregate.apply(null, args);
352
373
  }
353
374
 
375
+ async function distinct(filter, strategy) {
376
+ validateStrategy(table, strategy);
377
+ filter = negotiateFilter(filter);
378
+ const _baseFilter = await invokeBaseFilter();
379
+ if (_baseFilter)
380
+ filter = filter.and(context, _baseFilter);
381
+ let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1));
382
+ await negotiateWhereAndAggregate(strategy);
383
+ return table.distinct.apply(null, args);
384
+ }
385
+
354
386
 
355
387
 
356
388
  async function negotiateWhereAndAggregate(strategy) {
@@ -460,6 +492,27 @@ function _executePath(context, ...rest) {
460
492
  return json instanceof Object && 'path' in json && 'args' in json;
461
493
  }
462
494
 
495
+ function isColumnRef(json) {
496
+ return json instanceof Object && typeof json.__columnRef === 'string';
497
+ }
498
+
499
+ function resolveColumnRef(table, path) {
500
+ let current = table;
501
+ const parts = path.split('.');
502
+ for (let i = 0; i < parts.length; i++) {
503
+ if (current)
504
+ current = current[parts[i]];
505
+ }
506
+
507
+ if (!current || typeof current._toFilterArg !== 'function') {
508
+ let e = new Error(`Column reference '${path}' is invalid`);
509
+ // @ts-ignore
510
+ e.status = 400;
511
+ throw e;
512
+ }
513
+ return current;
514
+ }
515
+
463
516
  function setSafe(o) {
464
517
  if (o instanceof Object)
465
518
  Object.defineProperty(o, 'isSafe', {
@@ -500,4 +553,4 @@ function _executePath(context, ...rest) {
500
553
 
501
554
  }
502
555
  }
503
- module.exports = _executePath;
556
+ module.exports = _executePath;
package/src/hostLocal.js CHANGED
@@ -5,7 +5,7 @@ let executeQuery = require('./query');
5
5
  let executeSqliteFunction = require('./sqliteFunction');
6
6
  let hostExpress = require('./hostExpress');
7
7
  let hostHono = require('./hostHono');
8
- const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'count'];
8
+ const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'distinct', 'count'];
9
9
  // { db, table, defaultConcurrency,
10
10
  // concurrency,
11
11
  // customFilters,
package/src/map2.d.ts CHANGED
@@ -75,34 +75,40 @@ export interface Filter extends RawFilter {
75
75
  not(): Filter;
76
76
  }
77
77
 
78
- type StringOnlyMethods = {
79
- startsWith(value: string | null | undefined): Filter;
80
- iStartsWith(value: string | null | undefined): Filter;
81
- endsWith(value: string | null | undefined): Filter;
82
- iEndsWith(value: string | null | undefined): Filter;
83
- contains(value: string | null | undefined): Filter;
84
- iContains(value: string | null | undefined): Filter;
85
- iEqual(value: string | null | undefined): Filter;
86
- ieq(value: string | null | undefined): Filter;
78
+ type ComparableValue<Val, ColumnType = any> =
79
+ | Val
80
+ | null
81
+ | undefined
82
+ | ColumnFilterType<any, ColumnType>;
83
+
84
+ type StringOnlyMethods<ColumnType = 'string'> = {
85
+ startsWith(value: ComparableValue<string, ColumnType>): Filter;
86
+ iStartsWith(value: ComparableValue<string, ColumnType>): Filter;
87
+ endsWith(value: ComparableValue<string, ColumnType>): Filter;
88
+ iEndsWith(value: ComparableValue<string, ColumnType>): Filter;
89
+ contains(value: ComparableValue<string, ColumnType>): Filter;
90
+ iContains(value: ComparableValue<string, ColumnType>): Filter;
91
+ iEqual(value: ComparableValue<string, ColumnType>): Filter;
92
+ ieq(value: ComparableValue<string, ColumnType>): Filter;
87
93
  };
88
94
 
89
95
  export type ColumnFilterType<Val, ColumnType = any> = {
90
- equal(value: Val | null | undefined): Filter;
91
- eq(value: Val | null | undefined): Filter;
92
- notEqual(value: Val | null | undefined): Filter;
93
- ne(value: Val | null | undefined): Filter;
94
- lessThan(value: Val | null | undefined): Filter;
95
- lt(value: Val | null | undefined): Filter;
96
- lessThanOrEqual(value: Val | null | undefined): Filter;
97
- le(value: Val | null | undefined): Filter;
98
- greaterThan(value: Val | null | undefined): Filter;
99
- gt(value: Val | null | undefined): Filter;
100
- greaterThanOrEqual(value: Val | null | undefined): Filter;
101
- ge(value: Val | null | undefined): Filter;
102
- in(values: readonly (Val | null | undefined)[]): Filter;
103
- between(from: Val | null | undefined, to: Val | null | undefined): Filter;
104
- notIn(values: readonly (Val | null | undefined)[]): Filter;
105
- } & (ColumnType extends 'string' ? StringOnlyMethods : {});
96
+ equal(value: ComparableValue<Val, ColumnType>): Filter;
97
+ eq(value: ComparableValue<Val, ColumnType>): Filter;
98
+ notEqual(value: ComparableValue<Val, ColumnType>): Filter;
99
+ ne(value: ComparableValue<Val, ColumnType>): Filter;
100
+ lessThan(value: ComparableValue<Val, ColumnType>): Filter;
101
+ lt(value: ComparableValue<Val, ColumnType>): Filter;
102
+ lessThanOrEqual(value: ComparableValue<Val, ColumnType>): Filter;
103
+ le(value: ComparableValue<Val, ColumnType>): Filter;
104
+ greaterThan(value: ComparableValue<Val, ColumnType>): Filter;
105
+ gt(value: ComparableValue<Val, ColumnType>): Filter;
106
+ greaterThanOrEqual(value: ComparableValue<Val, ColumnType>): Filter;
107
+ ge(value: ComparableValue<Val, ColumnType>): Filter;
108
+ in(values: readonly ComparableValue<Val, ColumnType>[]): Filter;
109
+ between(from: ComparableValue<Val, ColumnType>, to: ComparableValue<Val, ColumnType>): Filter;
110
+ notIn(values: readonly ComparableValue<Val, ColumnType>[]): Filter;
111
+ } & (ColumnType extends 'string' ? StringOnlyMethods<ColumnType> : {});
106
112
 
107
113
  export type JsonArray = Array<JsonValue>;
108
114
  export type JsonObject = { [key: string]: JsonValue };
@@ -128,6 +134,8 @@ export type HasManyRelationFilter<M extends Record<string, TableDefinition<M>>,
128
134
  all(predicate: (row: RelationTableRefs<M, Target>) => Filter): Filter;
129
135
  none(predicate: (row: RelationTableRefs<M, Target>) => Filter): Filter;
130
136
  exists(): Filter;
137
+ count(): ColumnFilterType<number, 'numeric'>;
138
+ count(predicate: (row: RelationTableRefs<M, Target>) => Filter): ColumnFilterType<number, 'numeric'>;
131
139
  };
132
140
 
133
141
  export type FilterableSingleRelation<M extends Record<string, TableDefinition<M>>, Target extends keyof M> =
@@ -688,6 +696,7 @@ export type TableClient<M extends Record<string, TableDefinition<M>>, K extends
688
696
 
689
697
  // Aggregate methods - return plain objects (no active record methods)
690
698
  aggregate<strategy extends AggregateStrategy<M, K>>(strategy: strategy): Promise<Array<DeepExpand<AggregateCustomSelectorProperties<M, K, strategy>>>>;
699
+ distinct<strategy extends AggregateStrategy<M, K>>(strategy: strategy): Promise<Array<DeepExpand<AggregateCustomSelectorProperties<M, K, strategy>>>>;
691
700
 
692
701
  // Single item methods - return individual objects with individual active record methods
693
702
  getOne<strategy extends FetchStrategy<M, K>>(
@@ -1,8 +1,10 @@
1
1
  function encodeFilterArg(context, column, arg) {
2
+ if (arg && typeof arg._toFilterArg === 'function')
3
+ return arg._toFilterArg(context);
2
4
  if (column.encode.safe)
3
5
  return column.encode.safe(context, arg);
4
6
  else
5
7
  return column.encode(context, arg);
6
8
  }
7
9
 
8
- module.exports = encodeFilterArg;
10
+ module.exports = encodeFilterArg;
@@ -9,6 +9,7 @@ const _extractAlias = require('./extractAlias');
9
9
  const quote = require('../../table/quote');
10
10
  const aggregate = require('./columnAggregate');
11
11
  const aggregateGroup = require('./columnAggregateGroup');
12
+ const newParameterized = require('../query/newParameterized');
12
13
 
13
14
  module.exports = function(table, name) {
14
15
  var c = {};
@@ -16,6 +17,16 @@ module.exports = function(table, name) {
16
17
  c._dbName = name;
17
18
  c.alias = name;
18
19
  table._aliases.add(name);
20
+ Object.defineProperty(c, '_table', {
21
+ value: table,
22
+ enumerable: false,
23
+ writable: false
24
+ });
25
+ Object.defineProperty(c, '_toFilterArg', {
26
+ value: toFilterArg,
27
+ enumerable: false,
28
+ writable: false
29
+ });
19
30
 
20
31
  c.dbNull = null;
21
32
  table._columns.push(c);
@@ -101,5 +112,11 @@ module.exports = function(table, name) {
101
112
  };
102
113
  }
103
114
 
115
+ function toFilterArg(context) {
116
+ const tableAlias = quote(context, table._rootAlias || table._dbName);
117
+ const columnName = quote(context, c._dbName);
118
+ return newParameterized(`${tableAlias}.${columnName}`);
119
+ }
120
+
104
121
  return c;
105
122
  };
@@ -1,13 +1,17 @@
1
1
  const quote = require('../../quote');
2
2
  var newBoolean = require('../newBoolean');
3
3
  var nullOperator = ' is ';
4
+ var encodeFilterArg = require('../encodeFilterArg');
5
+ var newLikeColumnArg = require('./newLikeColumnArg');
4
6
 
5
- function endsWithCore(context, operator, column,arg,alias) {
7
+ function containsCore(context, operator, column,arg,alias) {
6
8
  alias = quote(context, alias);
7
9
  operator = ' ' + operator + ' ';
8
- var encoded = column.encode(context, arg);
10
+ var encoded = encodeFilterArg(context, column, arg);
9
11
  if (encoded.sql() == 'null')
10
12
  operator = nullOperator;
13
+ else if (arg && typeof arg._toFilterArg === 'function')
14
+ encoded = newLikeColumnArg(context, column, encoded, '%', '%');
11
15
  else
12
16
  encoded = column.encode(context, '%' + arg + '%');
13
17
  var firstPart = alias + '.' + quote(context, column._dbName) + operator;
@@ -15,4 +19,4 @@ function endsWithCore(context, operator, column,arg,alias) {
15
19
  return newBoolean(filter);
16
20
  }
17
21
 
18
- module.exports = endsWithCore;
22
+ module.exports = containsCore;
@@ -1,13 +1,17 @@
1
1
  const quote = require('../../quote');
2
2
  var newBoolean = require('../newBoolean');
3
3
  var nullOperator = ' is ';
4
+ var encodeFilterArg = require('../encodeFilterArg');
5
+ var newLikeColumnArg = require('./newLikeColumnArg');
4
6
 
5
7
  function endsWithCore(context, operator, column,arg,alias) {
6
8
  alias = quote(context, alias);
7
9
  operator = ' ' + operator + ' ';
8
- var encoded = column.encode(context, arg);
10
+ var encoded = encodeFilterArg(context, column, arg);
9
11
  if (encoded.sql() == 'null')
10
12
  operator = nullOperator;
13
+ else if (arg && typeof arg._toFilterArg === 'function')
14
+ encoded = newLikeColumnArg(context, column, encoded, '%', null);
11
15
  else
12
16
  encoded = column.encode(context, '%' + arg);
13
17
  var firstPart = alias + '.' + quote(context, column._dbName) + operator;
@@ -15,4 +19,4 @@ function endsWithCore(context, operator, column,arg,alias) {
15
19
  return newBoolean(filter);
16
20
  }
17
21
 
18
- module.exports = endsWithCore;
22
+ module.exports = endsWithCore;
@@ -0,0 +1,38 @@
1
+ var getSessionSingleton = require('../../getSessionSingleton');
2
+ var newParameterized = require('../../query/newParameterized');
3
+
4
+ function newLikeColumnArg(context, column, encodedArg, prefix, suffix) {
5
+ var encodedPrefix = prefix ? column.encode(context, prefix) : null;
6
+ var encodedSuffix = suffix ? column.encode(context, suffix) : null;
7
+ var engine = getSessionSingleton(context, 'engine');
8
+
9
+ if (engine === 'mysql')
10
+ return concatWithFunction(encodedPrefix, encodedArg, encodedSuffix);
11
+ if (engine === 'mssql' || engine === 'mssqlNative')
12
+ return concatWithOperator('+', encodedPrefix, encodedArg, encodedSuffix);
13
+ return concatWithOperator('||', encodedPrefix, encodedArg, encodedSuffix);
14
+ }
15
+
16
+ function concatWithFunction(prefix, value, suffix) {
17
+ var args = [prefix, value, suffix].filter(Boolean);
18
+ var sql = 'CONCAT(' + args.map(x => x.sql()).join(',') + ')';
19
+ var parameters = [];
20
+ for (var i = 0; i < args.length; i++)
21
+ parameters = parameters.concat(args[i].parameters);
22
+ return newParameterized(sql, parameters);
23
+ }
24
+
25
+ function concatWithOperator(operator, prefix, value, suffix) {
26
+ var args = [prefix, value, suffix].filter(Boolean);
27
+ var sql = '';
28
+ var parameters = [];
29
+ for (var i = 0; i < args.length; i++) {
30
+ if (i > 0)
31
+ sql += ' ' + operator + ' ';
32
+ sql += args[i].sql();
33
+ parameters = parameters.concat(args[i].parameters);
34
+ }
35
+ return newParameterized(sql, parameters);
36
+ }
37
+
38
+ module.exports = newLikeColumnArg;
@@ -1,12 +1,16 @@
1
1
  var newBoolean = require('../newBoolean');
2
2
  var nullOperator = ' is ';
3
3
  var quote = require('../../quote');
4
+ var encodeFilterArg = require('../encodeFilterArg');
5
+ var newLikeColumnArg = require('./newLikeColumnArg');
4
6
 
5
7
  function startsWithCore(context, operator, column,arg,alias) {
6
8
  operator = ' ' + operator + ' ';
7
- var encoded = column.encode(context, arg);
9
+ var encoded = encodeFilterArg(context, column, arg);
8
10
  if (encoded.sql() == 'null')
9
11
  operator = nullOperator;
12
+ else if (arg && typeof arg._toFilterArg === 'function')
13
+ encoded = newLikeColumnArg(context, column, encoded, null, '%');
10
14
  else
11
15
  encoded = column.encode(context, arg + '%');
12
16
  var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator;
@@ -14,4 +18,4 @@ function startsWithCore(context, operator, column,arg,alias) {
14
18
  return newBoolean(filter);
15
19
  }
16
20
 
17
- module.exports = startsWithCore;
21
+ module.exports = startsWithCore;
@@ -4,13 +4,17 @@ var extractLimit = require('../query/extractLimit');
4
4
  var newParameterized = require('../query/newParameterized');
5
5
  var extractOffset = require('../query/extractOffset');
6
6
 
7
- function newQuery(context, table,filter,span,alias) {
7
+ function newQuery(context, table,filter,span,alias,options = {}) {
8
8
  filter = extractFilter(filter);
9
9
  var orderBy = '';
10
10
  var limit = extractLimit(context, span);
11
11
  var offset = extractOffset(context, span);
12
+ const useDistinct = options.distinct && canUseDistinct(span);
13
+
14
+ var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset,useDistinct);
15
+ if (useDistinct)
16
+ return query;
12
17
 
13
- var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset);
14
18
  const groupClause = groupBy(span);
15
19
  return newParameterized(query.sql(), query.parameters).append(groupClause);
16
20
  }
@@ -22,4 +26,9 @@ function groupBy(span) {
22
26
  return ' GROUP BY ' + keys.map(key => span.aggregates[key].groupBy).join(',');
23
27
  }
24
28
 
25
- module.exports = newQuery;
29
+ function canUseDistinct(span) {
30
+ const keys = Object.keys(span.aggregates);
31
+ return keys.every(key => !!span.aggregates[key].column);
32
+ }
33
+
34
+ module.exports = newQuery;
@@ -3,7 +3,7 @@ const negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter');
3
3
  const strategyToSpan = require('./strategyToSpan');
4
4
  const executeQueries = require('./executeQueries');
5
5
 
6
- async function groupBy(context, table, filter, strategy) {
6
+ async function groupBy(context, table, filter, strategy, options) {
7
7
  filter = negotiateRawSqlFilter(context, filter, table);
8
8
  if (strategy && strategy.where) {
9
9
  let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where;
@@ -15,7 +15,7 @@ async function groupBy(context, table, filter, strategy) {
15
15
 
16
16
  let alias = table._dbName;
17
17
 
18
- const query = newQuery(context, table, filter, span, alias);
18
+ const query = newQuery(context, table, filter, span, alias, options);
19
19
  const res = await executeQueries(context, [query]);
20
20
  return decode(context, span, await res[0]);
21
21
  }
@@ -62,4 +62,4 @@ async function decode(context, span, rows, keys = rows.length > 0 ? Object.keys(
62
62
  return outRows;
63
63
  }
64
64
 
65
- module.exports = groupBy;
65
+ module.exports = groupBy;
@@ -5,6 +5,7 @@ var all = require('./relatedTable/all');
5
5
  var where = require('./relatedTable/where');
6
6
  var aggregate = require('./relatedTable/aggregate');
7
7
  var none = require('./relatedTable/none');
8
+ var count = require('./relatedTable/count');
8
9
 
9
10
  function newRelatedTable(relations, isShallow, depth = 0) {
10
11
  var table = relations[relations.length - 1].childTable;
@@ -26,6 +27,9 @@ function newRelatedTable(relations, isShallow, depth = 0) {
26
27
  // @ts-ignore
27
28
  c.where = where(relations, depth);
28
29
 
30
+ // @ts-ignore
31
+ c.count = count(newRelatedTable, relations, depth);
32
+
29
33
  // @ts-ignore
30
34
  c._aggregate = aggregate(relations);
31
35
 
@@ -90,4 +94,4 @@ function newRelatedTable(relations, isShallow, depth = 0) {
90
94
  return cProxy;
91
95
  }
92
96
 
93
- module.exports = newRelatedTable;
97
+ module.exports = newRelatedTable;