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.
@@ -1565,7 +1565,7 @@ function requireExecutePath () {
1565
1565
 
1566
1566
  async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) {
1567
1567
  let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) };
1568
- let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, count, delete: _delete, cascadeDelete, update, replace };
1568
+ let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, distinct, count, delete: _delete, cascadeDelete, update, replace };
1569
1569
 
1570
1570
  let res = await parseFilter(JSONFilter, table);
1571
1571
  if (res === undefined)
@@ -1579,9 +1579,12 @@ function requireExecutePath () {
1579
1579
 
1580
1580
  let anyAllNone = tryGetAnyAllNone(json.path, table);
1581
1581
  if (anyAllNone) {
1582
- if (isHttp)
1583
- validateArgs(json.args[0]);
1584
- const f = anyAllNone(context, x => parseFilter(json.args[0], x));
1582
+ const arg0 = json.args[0];
1583
+ if (isHttp && arg0 !== undefined)
1584
+ validateArgs(arg0);
1585
+ const f = arg0 === undefined
1586
+ ? anyAllNone(context)
1587
+ : anyAllNone(context, x => parseFilter(arg0, x));
1585
1588
  if(!('isSafe' in f))
1586
1589
  f.isSafe = isSafe;
1587
1590
  return f;
@@ -1600,17 +1603,22 @@ function requireExecutePath () {
1600
1603
  }
1601
1604
  return result;
1602
1605
  }
1606
+ else if (isColumnRef(json)) {
1607
+ return resolveColumnRef(table, json.__columnRef);
1608
+ }
1603
1609
  return json;
1604
1610
 
1605
1611
  function tryGetAnyAllNone(path, table) {
1606
- path = path.split('.');
1607
- for (let i = 0; i < path.length; i++) {
1608
- table = table[path[i]];
1612
+ const parts = path.split('.');
1613
+ for (let i = 0; i < parts.length; i++) {
1614
+ table = table[parts[i]];
1609
1615
  }
1610
1616
 
1611
1617
  let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']);
1612
1618
  // let ops = new Set(['all', 'any', 'none', 'where']);
1613
- let last = path.slice(-1)[0];
1619
+ let last = parts[parts.length - 1];
1620
+ if (last === 'count' && parts.length > 1)
1621
+ ops.add('count');
1614
1622
  if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all))))
1615
1623
  return table;
1616
1624
  }
@@ -1643,8 +1651,21 @@ function requireExecutePath () {
1643
1651
  target = target[pathArray[i]];
1644
1652
  }
1645
1653
 
1646
- if (!target)
1654
+ if (!target) {
1655
+ const left = args && args[0];
1656
+ if (left) {
1657
+ target = left;
1658
+ for (let i = 0; i < pathArray.length; i++) {
1659
+ target = target[pathArray[i]];
1660
+ }
1661
+ if (target) {
1662
+ let res = target.apply(null, [context].concat(args.slice(1)));
1663
+ setSafe(res);
1664
+ return res;
1665
+ }
1666
+ }
1647
1667
  throw new Error(`Method '${path}' does not exist`);
1668
+ }
1648
1669
  let res = target.apply(null, [context, ...args]);
1649
1670
  setSafe(res);
1650
1671
  return res;
@@ -1690,7 +1711,7 @@ function requireExecutePath () {
1690
1711
 
1691
1712
  function nextTable(path, table) {
1692
1713
  path = path.split('.');
1693
- let ops = new Set(['all', 'any', 'none']);
1714
+ let ops = new Set(['all', 'any', 'none', 'count']);
1694
1715
  let last = path.slice(-1)[0];
1695
1716
  if (ops.has(last)) {
1696
1717
  for (let i = 0; i < path.length - 1; i++) {
@@ -1840,6 +1861,17 @@ function requireExecutePath () {
1840
1861
  return table.aggregate.apply(null, args);
1841
1862
  }
1842
1863
 
1864
+ async function distinct(filter, strategy) {
1865
+ validateStrategy(table, strategy);
1866
+ filter = negotiateFilter(filter);
1867
+ const _baseFilter = await invokeBaseFilter();
1868
+ if (_baseFilter)
1869
+ filter = filter.and(context, _baseFilter);
1870
+ let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1));
1871
+ await negotiateWhereAndAggregate(strategy);
1872
+ return table.distinct.apply(null, args);
1873
+ }
1874
+
1843
1875
 
1844
1876
 
1845
1877
  async function negotiateWhereAndAggregate(strategy) {
@@ -1949,6 +1981,27 @@ function requireExecutePath () {
1949
1981
  return json instanceof Object && 'path' in json && 'args' in json;
1950
1982
  }
1951
1983
 
1984
+ function isColumnRef(json) {
1985
+ return json instanceof Object && typeof json.__columnRef === 'string';
1986
+ }
1987
+
1988
+ function resolveColumnRef(table, path) {
1989
+ let current = table;
1990
+ const parts = path.split('.');
1991
+ for (let i = 0; i < parts.length; i++) {
1992
+ if (current)
1993
+ current = current[parts[i]];
1994
+ }
1995
+
1996
+ if (!current || typeof current._toFilterArg !== 'function') {
1997
+ let e = new Error(`Column reference '${path}' is invalid`);
1998
+ // @ts-ignore
1999
+ e.status = 400;
2000
+ throw e;
2001
+ }
2002
+ return current;
2003
+ }
2004
+
1952
2005
  function setSafe(o) {
1953
2006
  if (o instanceof Object)
1954
2007
  Object.defineProperty(o, 'isSafe', {
@@ -2522,7 +2575,7 @@ function requireHostLocal () {
2522
2575
  let executeSqliteFunction = requireSqliteFunction();
2523
2576
  let hostExpress = requireHostExpress();
2524
2577
  let hostHono = requireHostHono();
2525
- const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'count'];
2578
+ const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'distinct', 'count'];
2526
2579
  // { db, table, defaultConcurrency,
2527
2580
  // concurrency,
2528
2581
  // customFilters,
@@ -3328,6 +3381,7 @@ function requireClient () {
3328
3381
  count,
3329
3382
  getMany,
3330
3383
  aggregate: groupBy,
3384
+ distinct,
3331
3385
  getAll,
3332
3386
  getOne,
3333
3387
  getById,
@@ -3383,9 +3437,17 @@ function requireClient () {
3383
3437
  }
3384
3438
 
3385
3439
  async function groupBy(strategy) {
3440
+ return executeGroupBy('aggregate', strategy);
3441
+ }
3442
+
3443
+ async function distinct(strategy) {
3444
+ return executeGroupBy('distinct', strategy);
3445
+ }
3446
+
3447
+ async function executeGroupBy(path, strategy) {
3386
3448
  let args = negotiateGroupBy(null, strategy);
3387
3449
  let body = stringify({
3388
- path: 'aggregate',
3450
+ path,
3389
3451
  args
3390
3452
  });
3391
3453
  let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions });
@@ -4180,12 +4242,20 @@ function requireClient () {
4180
4242
  }
4181
4243
  }
4182
4244
 
4245
+ const isColumnProxyKey = '__isColumnProxy';
4246
+ const columnPathKey = '__columnPath';
4247
+ const columnRefKey = '__columnRef';
4248
+
4183
4249
  function column(path, ...previous) {
4184
4250
  function c() {
4185
4251
  let args = [];
4186
4252
  for (let i = 0; i < arguments.length; i++) {
4187
- if (typeof arguments[i] === 'function')
4188
- args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.')));
4253
+ if (typeof arguments[i] === 'function') {
4254
+ if (arguments[i][isColumnProxyKey])
4255
+ args[i] = { [columnRefKey]: arguments[i][columnPathKey] };
4256
+ else
4257
+ args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.')));
4258
+ }
4189
4259
  else
4190
4260
  args[i] = arguments[i];
4191
4261
  }
@@ -4208,6 +4278,10 @@ function requireClient () {
4208
4278
  }
4209
4279
  let handler = {
4210
4280
  get(_target, property) {
4281
+ if (property === isColumnProxyKey)
4282
+ return true;
4283
+ if (property === columnPathKey)
4284
+ return path;
4211
4285
  if (property === 'toJSON')
4212
4286
  return Reflect.get(...arguments);
4213
4287
  else if (property === 'then')
@@ -4280,6 +4354,8 @@ function requireEncodeFilterArg () {
4280
4354
  if (hasRequiredEncodeFilterArg) return encodeFilterArg_1;
4281
4355
  hasRequiredEncodeFilterArg = 1;
4282
4356
  function encodeFilterArg(context, column, arg) {
4357
+ if (arg && typeof arg._toFilterArg === 'function')
4358
+ return arg._toFilterArg(context);
4283
4359
  if (column.encode.safe)
4284
4360
  return column.encode.safe(context, arg);
4285
4361
  else
@@ -4688,6 +4764,7 @@ function requireNewColumn () {
4688
4764
  const quote = requireQuote$2();
4689
4765
  const aggregate = requireColumnAggregate$1();
4690
4766
  const aggregateGroup = requireColumnAggregateGroup$1();
4767
+ const newParameterized = requireNewParameterized();
4691
4768
 
4692
4769
  newColumn = function(table, name) {
4693
4770
  var c = {};
@@ -4695,6 +4772,16 @@ function requireNewColumn () {
4695
4772
  c._dbName = name;
4696
4773
  c.alias = name;
4697
4774
  table._aliases.add(name);
4775
+ Object.defineProperty(c, '_table', {
4776
+ value: table,
4777
+ enumerable: false,
4778
+ writable: false
4779
+ });
4780
+ Object.defineProperty(c, '_toFilterArg', {
4781
+ value: toFilterArg,
4782
+ enumerable: false,
4783
+ writable: false
4784
+ });
4698
4785
 
4699
4786
  c.dbNull = null;
4700
4787
  table._columns.push(c);
@@ -4780,6 +4867,12 @@ function requireNewColumn () {
4780
4867
  };
4781
4868
  }
4782
4869
 
4870
+ function toFilterArg(context) {
4871
+ const tableAlias = quote(context, table._rootAlias || table._dbName);
4872
+ const columnName = quote(context, c._dbName);
4873
+ return newParameterized(`${tableAlias}.${columnName}`);
4874
+ }
4875
+
4783
4876
  return c;
4784
4877
  };
4785
4878
  return newColumn;
@@ -4865,6 +4958,53 @@ function requireNewDecodeCore () {
4865
4958
  return newDecodeCore;
4866
4959
  }
4867
4960
 
4961
+ var newLikeColumnArg_1;
4962
+ var hasRequiredNewLikeColumnArg;
4963
+
4964
+ function requireNewLikeColumnArg () {
4965
+ if (hasRequiredNewLikeColumnArg) return newLikeColumnArg_1;
4966
+ hasRequiredNewLikeColumnArg = 1;
4967
+ var getSessionSingleton = requireGetSessionSingleton();
4968
+ var newParameterized = requireNewParameterized();
4969
+
4970
+ function newLikeColumnArg(context, column, encodedArg, prefix, suffix) {
4971
+ var encodedPrefix = prefix ? column.encode(context, prefix) : null;
4972
+ var encodedSuffix = suffix ? column.encode(context, suffix) : null;
4973
+ var engine = getSessionSingleton(context, 'engine');
4974
+
4975
+ if (engine === 'mysql')
4976
+ return concatWithFunction(encodedPrefix, encodedArg, encodedSuffix);
4977
+ if (engine === 'mssql' || engine === 'mssqlNative')
4978
+ return concatWithOperator('+', encodedPrefix, encodedArg, encodedSuffix);
4979
+ return concatWithOperator('||', encodedPrefix, encodedArg, encodedSuffix);
4980
+ }
4981
+
4982
+ function concatWithFunction(prefix, value, suffix) {
4983
+ var args = [prefix, value, suffix].filter(Boolean);
4984
+ var sql = 'CONCAT(' + args.map(x => x.sql()).join(',') + ')';
4985
+ var parameters = [];
4986
+ for (var i = 0; i < args.length; i++)
4987
+ parameters = parameters.concat(args[i].parameters);
4988
+ return newParameterized(sql, parameters);
4989
+ }
4990
+
4991
+ function concatWithOperator(operator, prefix, value, suffix) {
4992
+ var args = [prefix, value, suffix].filter(Boolean);
4993
+ var sql = '';
4994
+ var parameters = [];
4995
+ for (var i = 0; i < args.length; i++) {
4996
+ if (i > 0)
4997
+ sql += ' ' + operator + ' ';
4998
+ sql += args[i].sql();
4999
+ parameters = parameters.concat(args[i].parameters);
5000
+ }
5001
+ return newParameterized(sql, parameters);
5002
+ }
5003
+
5004
+ newLikeColumnArg_1 = newLikeColumnArg;
5005
+ return newLikeColumnArg_1;
5006
+ }
5007
+
4868
5008
  var startsWithCore_1;
4869
5009
  var hasRequiredStartsWithCore;
4870
5010
 
@@ -4874,12 +5014,16 @@ function requireStartsWithCore () {
4874
5014
  var newBoolean = requireNewBoolean();
4875
5015
  var nullOperator = ' is ';
4876
5016
  var quote = requireQuote$2();
5017
+ var encodeFilterArg = requireEncodeFilterArg();
5018
+ var newLikeColumnArg = requireNewLikeColumnArg();
4877
5019
 
4878
5020
  function startsWithCore(context, operator, column,arg,alias) {
4879
5021
  operator = ' ' + operator + ' ';
4880
- var encoded = column.encode(context, arg);
5022
+ var encoded = encodeFilterArg(context, column, arg);
4881
5023
  if (encoded.sql() == 'null')
4882
5024
  operator = nullOperator;
5025
+ else if (arg && typeof arg._toFilterArg === 'function')
5026
+ encoded = newLikeColumnArg(context, column, encoded, null, '%');
4883
5027
  else
4884
5028
  encoded = column.encode(context, arg + '%');
4885
5029
  var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator;
@@ -4912,13 +5056,17 @@ function requireEndsWithCore () {
4912
5056
  const quote = requireQuote$2();
4913
5057
  var newBoolean = requireNewBoolean();
4914
5058
  var nullOperator = ' is ';
5059
+ var encodeFilterArg = requireEncodeFilterArg();
5060
+ var newLikeColumnArg = requireNewLikeColumnArg();
4915
5061
 
4916
5062
  function endsWithCore(context, operator, column,arg,alias) {
4917
5063
  alias = quote(context, alias);
4918
5064
  operator = ' ' + operator + ' ';
4919
- var encoded = column.encode(context, arg);
5065
+ var encoded = encodeFilterArg(context, column, arg);
4920
5066
  if (encoded.sql() == 'null')
4921
5067
  operator = nullOperator;
5068
+ else if (arg && typeof arg._toFilterArg === 'function')
5069
+ encoded = newLikeColumnArg(context, column, encoded, '%', null);
4922
5070
  else
4923
5071
  encoded = column.encode(context, '%' + arg);
4924
5072
  var firstPart = alias + '.' + quote(context, column._dbName) + operator;
@@ -4942,22 +5090,26 @@ function requireEndsWith () {
4942
5090
  return endsWith;
4943
5091
  }
4944
5092
 
4945
- var containsCore;
5093
+ var containsCore_1;
4946
5094
  var hasRequiredContainsCore;
4947
5095
 
4948
5096
  function requireContainsCore () {
4949
- if (hasRequiredContainsCore) return containsCore;
5097
+ if (hasRequiredContainsCore) return containsCore_1;
4950
5098
  hasRequiredContainsCore = 1;
4951
5099
  const quote = requireQuote$2();
4952
5100
  var newBoolean = requireNewBoolean();
4953
5101
  var nullOperator = ' is ';
5102
+ var encodeFilterArg = requireEncodeFilterArg();
5103
+ var newLikeColumnArg = requireNewLikeColumnArg();
4954
5104
 
4955
- function endsWithCore(context, operator, column,arg,alias) {
5105
+ function containsCore(context, operator, column,arg,alias) {
4956
5106
  alias = quote(context, alias);
4957
5107
  operator = ' ' + operator + ' ';
4958
- var encoded = column.encode(context, arg);
5108
+ var encoded = encodeFilterArg(context, column, arg);
4959
5109
  if (encoded.sql() == 'null')
4960
5110
  operator = nullOperator;
5111
+ else if (arg && typeof arg._toFilterArg === 'function')
5112
+ encoded = newLikeColumnArg(context, column, encoded, '%', '%');
4961
5113
  else
4962
5114
  encoded = column.encode(context, '%' + arg + '%');
4963
5115
  var firstPart = alias + '.' + quote(context, column._dbName) + operator;
@@ -4965,8 +5117,8 @@ function requireContainsCore () {
4965
5117
  return newBoolean(filter);
4966
5118
  }
4967
5119
 
4968
- containsCore = endsWithCore;
4969
- return containsCore;
5120
+ containsCore_1 = containsCore;
5121
+ return containsCore_1;
4970
5122
  }
4971
5123
 
4972
5124
  var contains;
@@ -9879,6 +10031,35 @@ function requireChildColumn () {
9879
10031
  return childColumn_1;
9880
10032
  }
9881
10033
 
10034
+ var newFilterArg_1;
10035
+ var hasRequiredNewFilterArg;
10036
+
10037
+ function requireNewFilterArg () {
10038
+ if (hasRequiredNewFilterArg) return newFilterArg_1;
10039
+ hasRequiredNewFilterArg = 1;
10040
+ var newJoin = requireJoinSql();
10041
+ var newWhere = requireWhereSql();
10042
+ var newParameterized = requireNewParameterized();
10043
+ var quote = requireQuote$2();
10044
+
10045
+ function newFilterArg(context, column, relations, depth = 0) {
10046
+ var relationCount = relations.length;
10047
+ var alias = 'x' + relationCount;
10048
+ var table = relations[relationCount - 1].childTable;
10049
+
10050
+ var quotedAlias = quote(context, alias);
10051
+ var quotedColumn = quote(context, column._dbName);
10052
+ var quotedTable = quote(context, table._dbName);
10053
+ var select = newParameterized(`(SELECT ${quotedAlias}.${quotedColumn} FROM ${quotedTable} ${quotedAlias}`);
10054
+ var join = newJoin(context, relations, depth);
10055
+ var where = newWhere(context, relations, null, depth);
10056
+ return select.append(join).append(where).append(')');
10057
+ }
10058
+
10059
+ newFilterArg_1 = newFilterArg;
10060
+ return newFilterArg_1;
10061
+ }
10062
+
9882
10063
  var relatedColumn;
9883
10064
  var hasRequiredRelatedColumn;
9884
10065
 
@@ -9889,6 +10070,7 @@ function requireRelatedColumn () {
9889
10070
  var aggregateGroup = requireColumnAggregateGroup();
9890
10071
  var aggregate = requireColumnAggregate();
9891
10072
  var childColumn = requireChildColumn();
10073
+ var newFilterArg = requireNewFilterArg();
9892
10074
 
9893
10075
  function newRelatedColumn(column, relations, isShallow, depth) {
9894
10076
  var c = {};
@@ -9912,9 +10094,18 @@ function requireRelatedColumn () {
9912
10094
  c.max = (context, ...rest) => aggregate.apply(null, [context, 'max', column, relations, false, ...rest]);
9913
10095
  c.count = (context, ...rest) => aggregate.apply(null, [context, 'count', column, relations, false, ...rest]);
9914
10096
  c.self = (context, ...rest) => childColumn.apply(null, [context, column, relations, ...rest]);
10097
+ Object.defineProperty(c, '_toFilterArg', {
10098
+ value: toFilterArg,
10099
+ enumerable: false,
10100
+ writable: false
10101
+ });
9915
10102
 
9916
10103
  return c;
9917
10104
 
10105
+ function toFilterArg(context) {
10106
+ return newFilterArg(context, column, relations, depth);
10107
+ }
10108
+
9918
10109
  function wrapFilter(filter) {
9919
10110
  return runFilter;
9920
10111
 
@@ -10162,6 +10353,154 @@ function requireNone () {
10162
10353
  return none;
10163
10354
  }
10164
10355
 
10356
+ var count;
10357
+ var hasRequiredCount$1;
10358
+
10359
+ function requireCount$1 () {
10360
+ if (hasRequiredCount$1) return count;
10361
+ hasRequiredCount$1 = 1;
10362
+ const negotiateRawSqlFilter = requireNegotiateRawSqlFilter();
10363
+ const newJoin = requireJoinSql();
10364
+ const newWhere = requireWhereSql();
10365
+ const getSessionSingleton = requireGetSessionSingleton();
10366
+ const newParameterized = requireNewParameterized();
10367
+ const newBoolean = requireNewBoolean();
10368
+
10369
+ const nullOperator = ' is ';
10370
+ const notNullOperator = ' is not ';
10371
+ const isShallow = true;
10372
+
10373
+ function newCount(newRelatedTable, relations, depth) {
10374
+
10375
+ function count(context, fn) {
10376
+ let shallowFilter;
10377
+
10378
+ if (fn !== undefined) {
10379
+ let relatedTable = newRelatedTable(relations, isShallow, depth + 1);
10380
+ let arg = typeof fn === 'function' ? fn(relatedTable) : fn;
10381
+ shallowFilter = negotiateRawSqlFilter(context, arg);
10382
+ }
10383
+
10384
+ const subQuery = newCountSubQuery(context, relations, shallowFilter, depth);
10385
+ return newCountFilter(subQuery);
10386
+ }
10387
+
10388
+ return count;
10389
+ }
10390
+
10391
+ function newCountSubQuery(context, relations, shallowFilter, depth) {
10392
+ const quote = getSessionSingleton(context, 'quote');
10393
+ const relationCount = relations.length;
10394
+ const alias = 'x' + relationCount;
10395
+ const table = relations[relationCount - 1].childTable;
10396
+ const select = newParameterized(`SELECT COUNT(*) FROM ${quote(table._dbName)} ${quote(alias)}`);
10397
+ const join = newJoin(context, relations, depth);
10398
+ const where = newWhere(context, relations, shallowFilter, depth);
10399
+
10400
+ return select.append(join).append(where);
10401
+ }
10402
+
10403
+ function newCountFilter(subQuery) {
10404
+ let c = {};
10405
+
10406
+ c.equal = function(context, arg) {
10407
+ return compare(context, '=', arg);
10408
+ };
10409
+
10410
+ c.notEqual = function(context, arg) {
10411
+ return compare(context, '<>', arg);
10412
+ };
10413
+
10414
+ c.lessThan = function(context, arg) {
10415
+ return compare(context, '<', arg);
10416
+ };
10417
+
10418
+ c.lessThanOrEqual = function(context, arg) {
10419
+ return compare(context, '<=', arg);
10420
+ };
10421
+
10422
+ c.greaterThan = function(context, arg) {
10423
+ return compare(context, '>', arg);
10424
+ };
10425
+
10426
+ c.greaterThanOrEqual = function(context, arg) {
10427
+ return compare(context, '>=', arg);
10428
+ };
10429
+
10430
+ c.between = function(context, from, to) {
10431
+ from = c.greaterThanOrEqual(context, from);
10432
+ to = c.lessThanOrEqual(context, to);
10433
+ return from.and(context, to);
10434
+ };
10435
+
10436
+ c.in = function(context, values) {
10437
+ if (values.length === 0)
10438
+ return newBoolean(newParameterized('1=2'));
10439
+
10440
+ let sqlParts = new Array(values.length);
10441
+ let params = [];
10442
+ for (let i = 0; i < values.length; i++) {
10443
+ const encoded = encodeArg(context, values[i]);
10444
+ sqlParts[i] = encoded.sql();
10445
+ params = params.concat(encoded.parameters);
10446
+ }
10447
+
10448
+ const sql = toSubQuery().sql() + ' in (' + sqlParts.join(',') + ')';
10449
+ const allParams = toSubQuery().parameters.concat(params);
10450
+ return newBoolean(newParameterized(sql, allParams));
10451
+ };
10452
+
10453
+ c.notIn = function(context, values) {
10454
+ return c.in(context, values).not(context);
10455
+ };
10456
+
10457
+ c.eq = c.equal;
10458
+ c.EQ = c.eq;
10459
+ c.ne = c.notEqual;
10460
+ c.NE = c.ne;
10461
+ c.gt = c.greaterThan;
10462
+ c.GT = c.gt;
10463
+ c.ge = c.greaterThanOrEqual;
10464
+ c.GE = c.ge;
10465
+ c.lt = c.lessThan;
10466
+ c.LT = c.lt;
10467
+ c.le = c.lessThanOrEqual;
10468
+ c.LE = c.le;
10469
+ c.IN = c.in;
10470
+
10471
+ return c;
10472
+
10473
+ function compare(context, operator, arg) {
10474
+ let encoded = encodeArg(context, arg);
10475
+ let operatorSql = ' ' + operator + ' ';
10476
+ if (encoded.sql() === 'null') {
10477
+ if (operator === '=')
10478
+ operatorSql = nullOperator;
10479
+ else if (operator === '<>')
10480
+ operatorSql = notNullOperator;
10481
+ }
10482
+
10483
+ let sql = toSubQuery().append(operatorSql).append(encoded);
10484
+ return newBoolean(sql);
10485
+ }
10486
+
10487
+ function encodeArg(context, arg) {
10488
+ if (arg && typeof arg._toFilterArg === 'function')
10489
+ return arg._toFilterArg(context);
10490
+ if (arg == null)
10491
+ return newParameterized('null');
10492
+ return newParameterized('?', [arg]);
10493
+ }
10494
+
10495
+ function toSubQuery() {
10496
+ return subQuery.prepend('(').append(')');
10497
+ }
10498
+ }
10499
+
10500
+ count = newCount;
10501
+ return count;
10502
+ }
10503
+
10165
10504
  var newRelatedTable_1;
10166
10505
  var hasRequiredNewRelatedTable;
10167
10506
 
@@ -10175,6 +10514,7 @@ function requireNewRelatedTable () {
10175
10514
  var where = requireWhere$1();
10176
10515
  var aggregate = requireAggregate$1();
10177
10516
  var none = requireNone();
10517
+ var count = requireCount$1();
10178
10518
 
10179
10519
  function newRelatedTable(relations, isShallow, depth = 0) {
10180
10520
  var table = relations[relations.length - 1].childTable;
@@ -10196,6 +10536,9 @@ function requireNewRelatedTable () {
10196
10536
  // @ts-ignore
10197
10537
  c.where = where(relations, depth);
10198
10538
 
10539
+ // @ts-ignore
10540
+ c.count = count(newRelatedTable, relations, depth);
10541
+
10199
10542
  // @ts-ignore
10200
10543
  c._aggregate = aggregate(relations);
10201
10544
 
@@ -11175,7 +11518,7 @@ function requireNewSingleQuery () {
11175
11518
  var newParameterized = requireNewParameterized();
11176
11519
  var getSessionSingleton = requireGetSessionSingleton();
11177
11520
 
11178
- function _new(context,table,filter,span, alias,orderBy,limit,offset) {
11521
+ function _new(context,table,filter,span, alias,orderBy,limit,offset,distinct = false) {
11179
11522
  var quote = getSessionSingleton(context, 'quote');
11180
11523
  var name = quote(table._dbName);
11181
11524
  var columnSql = newColumnSql(context,table,span,alias,true);
@@ -11183,8 +11526,9 @@ function requireNewSingleQuery () {
11183
11526
  var whereSql = newWhereSql(context,table,filter,alias);
11184
11527
  if (limit)
11185
11528
  limit = limit + ' ';
11529
+ const selectClause = distinct ? 'select distinct ' : 'select ';
11186
11530
 
11187
- return newParameterized('select ' + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset);
11531
+ return newParameterized(selectClause + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset);
11188
11532
 
11189
11533
  }
11190
11534
 
@@ -12751,13 +13095,17 @@ function requireNewQuery () {
12751
13095
  var newParameterized = requireNewParameterized();
12752
13096
  var extractOffset = requireExtractOffset();
12753
13097
 
12754
- function newQuery(context, table,filter,span,alias) {
13098
+ function newQuery(context, table,filter,span,alias,options = {}) {
12755
13099
  filter = extractFilter(filter);
12756
13100
  var orderBy = '';
12757
13101
  var limit = extractLimit(context, span);
12758
13102
  var offset = extractOffset(context, span);
13103
+ const useDistinct = options.distinct && canUseDistinct(span);
13104
+
13105
+ var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset,useDistinct);
13106
+ if (useDistinct)
13107
+ return query;
12759
13108
 
12760
- var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset);
12761
13109
  const groupClause = groupBy(span);
12762
13110
  return newParameterized(query.sql(), query.parameters).append(groupClause);
12763
13111
  }
@@ -12769,6 +13117,11 @@ function requireNewQuery () {
12769
13117
  return ' GROUP BY ' + keys.map(key => span.aggregates[key].groupBy).join(',');
12770
13118
  }
12771
13119
 
13120
+ function canUseDistinct(span) {
13121
+ const keys = Object.keys(span.aggregates);
13122
+ return keys.every(key => !!span.aggregates[key].column);
13123
+ }
13124
+
12772
13125
  newQuery_1 = newQuery;
12773
13126
  return newQuery_1;
12774
13127
  }
@@ -12784,7 +13137,7 @@ function requireGroupBy () {
12784
13137
  const strategyToSpan = requireStrategyToSpan();
12785
13138
  const executeQueries = requireExecuteQueries();
12786
13139
 
12787
- async function groupBy(context, table, filter, strategy) {
13140
+ async function groupBy(context, table, filter, strategy, options) {
12788
13141
  filter = negotiateRawSqlFilter(context, filter, table);
12789
13142
  if (strategy && strategy.where) {
12790
13143
  let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where;
@@ -12796,7 +13149,7 @@ function requireGroupBy () {
12796
13149
 
12797
13150
  let alias = table._dbName;
12798
13151
 
12799
- const query = newQuery(context, table, filter, span, alias);
13152
+ const query = newQuery(context, table, filter, span, alias, options);
12800
13153
  const res = await executeQueries(context, [query]);
12801
13154
  return decode(context, span, await res[0]);
12802
13155
  }
@@ -12934,6 +13287,10 @@ function requireTable () {
12934
13287
  const args = [context, table, ...rest];
12935
13288
  return groupBy.apply(null, args);
12936
13289
  };
13290
+ table.distinct = function(context, ...rest) {
13291
+ const args = [context, table, ...rest, { distinct: true }];
13292
+ return groupBy.apply(null, args);
13293
+ };
12937
13294
 
12938
13295
  table.getMany.exclusive = function(context, ...rest) {
12939
13296
  const args = [context, table, ...rest];