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/README.md +69 -1
- package/bin/build.js +1 -0
- package/dist/index.browser.mjs +385 -28
- package/dist/index.mjs +385 -28
- package/docs/changelog.md +4 -0
- package/package.json +1 -1
- package/src/client/index.js +24 -3
- package/src/getManyDto/query/newSingleQuery.js +4 -3
- package/src/hostExpress/executePath.js +64 -11
- package/src/hostLocal.js +1 -1
- package/src/map2.d.ts +34 -25
- package/src/table/column/encodeFilterArg.js +3 -1
- package/src/table/column/newColumn.js +17 -0
- package/src/table/column/string/containsCore.js +7 -3
- package/src/table/column/string/endsWithCore.js +6 -2
- package/src/table/column/string/newLikeColumnArg.js +38 -0
- package/src/table/column/string/startsWithCore.js +6 -2
- package/src/table/groupBy/newQuery.js +12 -3
- package/src/table/groupBy.js +3 -3
- package/src/table/newRelatedTable.js +5 -1
- package/src/table/relatedTable/count.js +139 -0
- package/src/table/relatedTable/newFilterArg.js +20 -0
- package/src/table/relatedTable/relatedColumn.js +11 -1
- package/src/table.js +4 -0
package/src/client/index.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
118
|
-
for (let i = 0; i <
|
|
119
|
-
table = table[
|
|
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 =
|
|
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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
91
|
-
eq(value: Val
|
|
92
|
-
notEqual(value: Val
|
|
93
|
-
ne(value: Val
|
|
94
|
-
lessThan(value: Val
|
|
95
|
-
lt(value: Val
|
|
96
|
-
lessThanOrEqual(value: Val
|
|
97
|
-
le(value: Val
|
|
98
|
-
greaterThan(value: Val
|
|
99
|
-
gt(value: Val
|
|
100
|
-
greaterThanOrEqual(value: Val
|
|
101
|
-
ge(value: Val
|
|
102
|
-
in(values: readonly
|
|
103
|
-
between(from: Val
|
|
104
|
-
notIn(values: readonly
|
|
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
|
|
7
|
+
function containsCore(context, operator, column,arg,alias) {
|
|
6
8
|
alias = quote(context, alias);
|
|
7
9
|
operator = ' ' + operator + ' ';
|
|
8
|
-
var encoded =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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;
|
package/src/table/groupBy.js
CHANGED
|
@@ -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;
|