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