tg-client-query-builder 2.14.2 → 2.14.3
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/index.js +2 -2
- package/package.json +1 -18
- package/query-builder/combine-queries.js +22 -17
- package/query-builder/filter-expression/index.js +16 -19
- package/query-builder/index.js +103 -68
- package/build/query-builder/combine-queries.js +0 -21
- package/build/query-builder/filter-expression/index.js +0 -19
- package/build/query-builder/index.js +0 -454
package/index.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
const QueryBuilder = require(
|
1
|
+
const QueryBuilder = require("./query-builder");
|
2
2
|
|
3
|
-
module.exports = QueryBuilder;
|
3
|
+
module.exports = QueryBuilder;
|
package/package.json
CHANGED
@@ -1,27 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "tg-client-query-builder",
|
3
|
-
"version": "2.14.
|
3
|
+
"version": "2.14.3",
|
4
4
|
"description": "Teselagen Client Side (browser) SQL Query Builder",
|
5
|
-
"main": "build/query-builder/index.js",
|
6
|
-
"repository": "https://github.com/TeselaGen/tg-query.git",
|
7
5
|
"author": "TeselaGen",
|
8
6
|
"license": "ISC",
|
9
|
-
"scripts": {
|
10
|
-
"prepublishOnly": "yarn build",
|
11
|
-
"build": "babel --presets=es2015 query-builder/ --out-dir build/query-builder/",
|
12
|
-
"test": "jest"
|
13
|
-
},
|
14
7
|
"dependencies": {
|
15
8
|
"lodash": "^4.17.4"
|
16
|
-
},
|
17
|
-
"devDependencies": {
|
18
|
-
"babel-cli": "^6.26.0",
|
19
|
-
"babel-preset-latest": "^6.24.1",
|
20
|
-
"chai": "^4.0.2",
|
21
|
-
"fs-extra": "^3.0.1",
|
22
|
-
"jest": "^28.1.2",
|
23
|
-
"json-beautify": "^1.0.1",
|
24
|
-
"json-format": "^1.0.1",
|
25
|
-
"jsonfile": "^3.0.0"
|
26
9
|
}
|
27
10
|
}
|
@@ -1,22 +1,27 @@
|
|
1
|
+
module.exports = function combineQueries(qry1, qry2, joinOperator, opts) {
|
2
|
+
if (qry1.__objectType !== "query")
|
3
|
+
throw new Error("First query is not a query type.");
|
4
|
+
if (qry2.__objectType !== "query")
|
5
|
+
throw new Error("Second query is not a query type.");
|
6
|
+
if (qry1.entity != qry2.entity)
|
7
|
+
throw new Error(
|
8
|
+
"Queries are for different entities " +
|
9
|
+
qry1.entity +
|
10
|
+
" and " +
|
11
|
+
qry2.entity
|
12
|
+
);
|
1
13
|
|
14
|
+
if (joinOperator !== "or") joinOperator = "and";
|
2
15
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
16
|
+
var combinedFilters = {
|
17
|
+
type: "group",
|
18
|
+
operator: joinOperator,
|
19
|
+
filters: []
|
20
|
+
};
|
7
21
|
|
8
|
-
|
22
|
+
combinedFilters.filters = qry1.filters.concat(qry2.filters);
|
9
23
|
|
10
|
-
|
11
|
-
{
|
12
|
-
type: "group",
|
13
|
-
operator: joinOperator,
|
14
|
-
filters: [ ]
|
15
|
-
};
|
16
|
-
|
17
|
-
combinedFilters.filters = qry1.filters.concat(qry2.filters);
|
18
|
-
|
19
|
-
qry1.filters = [combinedFilters];
|
24
|
+
qry1.filters = [combinedFilters];
|
20
25
|
|
21
|
-
|
22
|
-
}
|
26
|
+
return qry1;
|
27
|
+
};
|
@@ -1,20 +1,17 @@
|
|
1
|
+
module.exports = (function() {
|
2
|
+
function FilterExpression(opName, args) {
|
3
|
+
this.name = opName;
|
4
|
+
this.args = args;
|
5
|
+
}
|
1
6
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
}
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
operator: this.name,
|
14
|
-
field: argName,
|
15
|
-
args: this.args
|
16
|
-
};
|
17
|
-
return filterDef;
|
18
|
-
}
|
19
|
-
return FilterExpression;
|
20
|
-
})();
|
7
|
+
FilterExpression.prototype.toFilter = function(filterBuilder, argName) {
|
8
|
+
var filterDef = {
|
9
|
+
type: "expression",
|
10
|
+
operator: this.name,
|
11
|
+
field: argName,
|
12
|
+
args: this.args
|
13
|
+
};
|
14
|
+
return filterDef;
|
15
|
+
};
|
16
|
+
return FilterExpression;
|
17
|
+
})();
|
package/query-builder/index.js
CHANGED
@@ -32,25 +32,33 @@ function isDateOrNumber(opName) {
|
|
32
32
|
return () => {
|
33
33
|
var args = [].slice.call(arguments);
|
34
34
|
if (
|
35
|
-
args.some(
|
35
|
+
args.some(arg => {
|
36
36
|
return !(_.isDate(arg) || _.isString(arg) || _.isNumber(arg));
|
37
37
|
})
|
38
38
|
) {
|
39
|
-
throw new Error(
|
39
|
+
throw new Error(
|
40
|
+
`QueryBuilderError: You must pass a date or number as args to ${opName}. You passed: Args ${args.join(
|
41
|
+
","
|
42
|
+
)}`
|
43
|
+
);
|
40
44
|
}
|
41
45
|
};
|
42
46
|
}
|
43
47
|
function isArray(opName) {
|
44
|
-
return
|
48
|
+
return arg => {
|
45
49
|
if (!_.isArray(arg)) {
|
46
|
-
throw new Error(
|
50
|
+
throw new Error(
|
51
|
+
`QueryBuilderError: You must pass an array for ${opName} filters. You passed: ${arg}`
|
52
|
+
);
|
47
53
|
}
|
48
54
|
};
|
49
55
|
}
|
50
56
|
function isString(opName) {
|
51
|
-
return
|
57
|
+
return arg => {
|
52
58
|
if (!_.isString(arg)) {
|
53
|
-
throw new Error(
|
59
|
+
throw new Error(
|
60
|
+
`QueryBuilderError: You must pass a string for ${opName} filters. You passed: ${arg}`
|
61
|
+
);
|
54
62
|
}
|
55
63
|
};
|
56
64
|
}
|
@@ -58,7 +66,9 @@ function isString(opName) {
|
|
58
66
|
function numberOfArgs(opName, argLength) {
|
59
67
|
return (...args) => {
|
60
68
|
if (args.length !== argLength) {
|
61
|
-
throw new Error(
|
69
|
+
throw new Error(
|
70
|
+
`QueryBuilderError: Args for ${opName} are of length ${args.length}, but they should be of length ${argLength}`
|
71
|
+
);
|
62
72
|
}
|
63
73
|
};
|
64
74
|
}
|
@@ -66,124 +76,139 @@ function numberOfArgs(opName, argLength) {
|
|
66
76
|
const expressionOperators = [
|
67
77
|
{
|
68
78
|
opName: "greaterThan",
|
69
|
-
sanityChecks: [
|
79
|
+
sanityChecks: [
|
80
|
+
numberOfArgs("greaterThan", 1),
|
81
|
+
isDateOrNumber("greaterThan")
|
82
|
+
]
|
70
83
|
},
|
71
84
|
{
|
72
85
|
opName: "inList",
|
73
|
-
sanityChecks: [numberOfArgs("inList", 1), isArray("inList")]
|
86
|
+
sanityChecks: [numberOfArgs("inList", 1), isArray("inList")]
|
74
87
|
},
|
75
88
|
{
|
76
89
|
opName: "lessThan",
|
77
|
-
sanityChecks: [numberOfArgs("lessThan", 1), isDateOrNumber("lessThan")]
|
90
|
+
sanityChecks: [numberOfArgs("lessThan", 1), isDateOrNumber("lessThan")]
|
78
91
|
},
|
79
92
|
{
|
80
93
|
opName: "lessThanOrEqual",
|
81
|
-
sanityChecks: [
|
94
|
+
sanityChecks: [
|
95
|
+
numberOfArgs("lessThanOrEqual", 1),
|
96
|
+
isDateOrNumber("lessThanOrEqual")
|
97
|
+
]
|
82
98
|
},
|
83
99
|
{
|
84
100
|
opName: "equals",
|
85
|
-
sanityChecks: [numberOfArgs("equals", 1)]
|
101
|
+
sanityChecks: [numberOfArgs("equals", 1)]
|
86
102
|
},
|
87
103
|
{
|
88
104
|
opName: "greaterThanOrEqual",
|
89
|
-
sanityChecks: [
|
105
|
+
sanityChecks: [
|
106
|
+
numberOfArgs("greaterThanOrEqual", 1),
|
107
|
+
isDateOrNumber("greaterThanOrEqual")
|
108
|
+
]
|
90
109
|
},
|
91
110
|
{
|
92
111
|
opName: "notEquals",
|
93
|
-
sanityChecks: [numberOfArgs("notEquals", 1)]
|
112
|
+
sanityChecks: [numberOfArgs("notEquals", 1)]
|
94
113
|
},
|
95
114
|
{
|
96
115
|
opName: "notNull",
|
97
|
-
sanityChecks: [numberOfArgs("notNull", 0)]
|
116
|
+
sanityChecks: [numberOfArgs("notNull", 0)]
|
98
117
|
},
|
99
118
|
{
|
100
119
|
opName: "isNull",
|
101
|
-
sanityChecks: [numberOfArgs("isNull", 0)]
|
120
|
+
sanityChecks: [numberOfArgs("isNull", 0)]
|
102
121
|
},
|
103
122
|
{
|
104
123
|
opName: "between",
|
105
|
-
sanityChecks: [numberOfArgs("between", 2), isDateOrNumber("between")]
|
124
|
+
sanityChecks: [numberOfArgs("between", 2), isDateOrNumber("between")]
|
106
125
|
},
|
107
126
|
{
|
108
127
|
opName: "notInList",
|
109
|
-
sanityChecks: [numberOfArgs("notInList", 1), isArray("notInList")]
|
128
|
+
sanityChecks: [numberOfArgs("notInList", 1), isArray("notInList")]
|
110
129
|
},
|
111
130
|
{
|
112
131
|
opName: "startsWithExactly",
|
113
|
-
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
132
|
+
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
114
133
|
},
|
115
134
|
{
|
116
135
|
opName: "endsWithExactly",
|
117
|
-
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
136
|
+
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
118
137
|
},
|
119
138
|
{
|
120
139
|
opName: "containsExactly",
|
121
|
-
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
140
|
+
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
122
141
|
},
|
123
142
|
{
|
124
143
|
opName: "startsWith",
|
125
|
-
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
144
|
+
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
126
145
|
},
|
127
146
|
{
|
128
147
|
opName: "notStartsWith",
|
129
|
-
sanityChecks: [numberOfArgs("notStartsWith", 1), isString("notStartsWith")]
|
148
|
+
sanityChecks: [numberOfArgs("notStartsWith", 1), isString("notStartsWith")]
|
130
149
|
},
|
131
150
|
{
|
132
151
|
opName: "endsWith",
|
133
|
-
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
152
|
+
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
134
153
|
},
|
135
154
|
{
|
136
155
|
opName: "notEndsWith",
|
137
|
-
sanityChecks: [numberOfArgs("notEndsWith", 1), isString("notEndsWith")]
|
156
|
+
sanityChecks: [numberOfArgs("notEndsWith", 1), isString("notEndsWith")]
|
138
157
|
},
|
139
158
|
{
|
140
159
|
opName: "contains",
|
141
|
-
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
160
|
+
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
142
161
|
},
|
143
162
|
{
|
144
163
|
opName: "notContains",
|
145
|
-
sanityChecks: [numberOfArgs("notContains", 1), isString("notContains")]
|
164
|
+
sanityChecks: [numberOfArgs("notContains", 1), isString("notContains")]
|
146
165
|
},
|
147
166
|
{
|
148
167
|
opName: "upperCase",
|
149
|
-
sanityChecks: [numberOfArgs("upperCase", 1), isString("upperCase")]
|
168
|
+
sanityChecks: [numberOfArgs("upperCase", 1), isString("upperCase")]
|
150
169
|
},
|
151
170
|
{
|
152
171
|
opName: "lowerCase",
|
153
|
-
sanityChecks: [numberOfArgs("lowerCase", 1), isString("lowerCase")]
|
172
|
+
sanityChecks: [numberOfArgs("lowerCase", 1), isString("lowerCase")]
|
154
173
|
},
|
155
174
|
{
|
156
175
|
opName: "matchesRegex",
|
157
|
-
sanityChecks: [numberOfArgs("matchesRegex", 1), isString("matchesRegex")]
|
176
|
+
sanityChecks: [numberOfArgs("matchesRegex", 1), isString("matchesRegex")]
|
158
177
|
},
|
159
178
|
{
|
160
179
|
opName: "matchesSimilar",
|
161
|
-
sanityChecks: [
|
180
|
+
sanityChecks: [
|
181
|
+
numberOfArgs("matchesSimilar", 1),
|
182
|
+
isString("matchesSimilar")
|
183
|
+
]
|
162
184
|
},
|
163
185
|
{
|
164
186
|
opName: "fuzzy",
|
165
187
|
sanityChecks: [numberOfArgs("fuzzy", 1), isString("fuzzy")],
|
166
|
-
transform:
|
188
|
+
transform: arg => {
|
167
189
|
// Build Regex String
|
168
190
|
var matchTerm = "";
|
169
191
|
// Split all the search terms
|
170
|
-
var terms = arg
|
192
|
+
var terms = arg
|
193
|
+
.replace(/\W/g, "")
|
194
|
+
.replace(" ", "")
|
195
|
+
.split("");
|
171
196
|
for (var i = 0; i < terms.length; i++) {
|
172
197
|
matchTerm += ".*" + terms[i];
|
173
198
|
}
|
174
199
|
matchTerm += ".*";
|
175
200
|
return {
|
176
201
|
newOpName: "matchesRegex",
|
177
|
-
newArgs: [matchTerm]
|
202
|
+
newArgs: [matchTerm]
|
178
203
|
};
|
179
|
-
}
|
180
|
-
}
|
204
|
+
}
|
205
|
+
}
|
181
206
|
|
182
207
|
// 'subString', //tnr: not yet implemented
|
183
208
|
// 'dateOnly', //tnr: not yet implemented
|
184
209
|
];
|
185
210
|
|
186
|
-
module.exports = (function
|
211
|
+
module.exports = (function() {
|
187
212
|
// to be implemented
|
188
213
|
//
|
189
214
|
// filter - done
|
@@ -217,14 +242,15 @@ module.exports = (function () {
|
|
217
242
|
function QueryBuilder(entity) {
|
218
243
|
this.query = {};
|
219
244
|
|
220
|
-
if (entity == null)
|
245
|
+
if (entity == null)
|
246
|
+
throw new Error("You must pass the name of the model being filtered!");
|
221
247
|
|
222
248
|
if (typeof entity === "string") {
|
223
249
|
this.query = {
|
224
250
|
__objectType: "query",
|
225
251
|
type: "root",
|
226
252
|
entity,
|
227
|
-
filters: []
|
253
|
+
filters: []
|
228
254
|
};
|
229
255
|
} else {
|
230
256
|
let subQuery = entity;
|
@@ -236,10 +262,10 @@ module.exports = (function () {
|
|
236
262
|
modifier: subQuery.modifier,
|
237
263
|
isArrayRelation: subQuery.isArrayRelation,
|
238
264
|
filters: [],
|
239
|
-
countExpression: undefined
|
265
|
+
countExpression: undefined
|
240
266
|
};
|
241
267
|
this.parentBuilder = subQuery.parentBuilder;
|
242
|
-
this.toFilter = function
|
268
|
+
this.toFilter = function(filterBuilder, name) {
|
243
269
|
this.query.foreignKey = name;
|
244
270
|
return this.toJSON();
|
245
271
|
};
|
@@ -248,14 +274,14 @@ module.exports = (function () {
|
|
248
274
|
|
249
275
|
QueryBuilder.combineQueries = combineQueries;
|
250
276
|
|
251
|
-
QueryBuilder.prototype.field = function
|
277
|
+
QueryBuilder.prototype.field = function(fieldName) {
|
252
278
|
return {
|
253
279
|
__objectType: "field",
|
254
|
-
field: fieldName
|
280
|
+
field: fieldName
|
255
281
|
};
|
256
282
|
};
|
257
283
|
|
258
|
-
QueryBuilder.prototype.related = function
|
284
|
+
QueryBuilder.prototype.related = function(relatedEntity, isArrayRelation) {
|
259
285
|
var tokens = relatedEntity.split(".");
|
260
286
|
var entity = tokens[0];
|
261
287
|
var key = tokens[1];
|
@@ -266,7 +292,7 @@ module.exports = (function () {
|
|
266
292
|
return createSubQueryBuilder(this, entity, key, isArrayRelation);
|
267
293
|
};
|
268
294
|
|
269
|
-
QueryBuilder.prototype.notRelated = function
|
295
|
+
QueryBuilder.prototype.notRelated = function(relatedEntity, isArrayRelation) {
|
270
296
|
var tokens = relatedEntity.split(".");
|
271
297
|
var entity = tokens[0];
|
272
298
|
var key = tokens[1];
|
@@ -277,7 +303,7 @@ module.exports = (function () {
|
|
277
303
|
return createSubQueryBuilder(this, entity, key, isArrayRelation, "not");
|
278
304
|
};
|
279
305
|
|
280
|
-
QueryBuilder.prototype.toJSON = function
|
306
|
+
QueryBuilder.prototype.toJSON = function() {
|
281
307
|
let qry = JSON.parse(JSON.stringify(this.query));
|
282
308
|
if (qry.filters.length > 1) {
|
283
309
|
qry.filters = [
|
@@ -285,14 +311,14 @@ module.exports = (function () {
|
|
285
311
|
type: "group",
|
286
312
|
operator: "and",
|
287
313
|
chainedWith: "and",
|
288
|
-
filters: qry.filters
|
289
|
-
}
|
314
|
+
filters: qry.filters
|
315
|
+
}
|
290
316
|
];
|
291
317
|
}
|
292
318
|
return qry;
|
293
319
|
};
|
294
320
|
|
295
|
-
QueryBuilder.prototype.convertToFilter = function
|
321
|
+
QueryBuilder.prototype.convertToFilter = function(argDef, operator) {
|
296
322
|
var whereArgs = {};
|
297
323
|
var filters = [];
|
298
324
|
|
@@ -318,7 +344,7 @@ module.exports = (function () {
|
|
318
344
|
if (_.keys(whereArgs).length > 0) {
|
319
345
|
filters.unshift({
|
320
346
|
type: "where",
|
321
|
-
args: whereArgs
|
347
|
+
args: whereArgs
|
322
348
|
});
|
323
349
|
}
|
324
350
|
|
@@ -328,61 +354,63 @@ module.exports = (function () {
|
|
328
354
|
var filterDef = {
|
329
355
|
type: "group",
|
330
356
|
operator: operator || "and",
|
331
|
-
filters
|
357
|
+
filters
|
332
358
|
};
|
333
359
|
return filterDef;
|
334
360
|
};
|
335
361
|
|
336
|
-
QueryBuilder.prototype.where = function
|
362
|
+
QueryBuilder.prototype.where = function() {
|
337
363
|
var args = [].slice.call(arguments);
|
338
364
|
return this.whereAll(args);
|
339
365
|
};
|
340
366
|
|
341
|
-
QueryBuilder.prototype.orWhere = function
|
367
|
+
QueryBuilder.prototype.orWhere = function() {
|
342
368
|
var args = [].slice.call(arguments);
|
343
369
|
return this.orWhereAll(args);
|
344
370
|
};
|
345
371
|
|
346
|
-
QueryBuilder.prototype.andWhere = function
|
372
|
+
QueryBuilder.prototype.andWhere = function() {
|
347
373
|
var args = [].slice.call(arguments);
|
348
374
|
return this.andWhereAll(args);
|
349
375
|
};
|
350
376
|
|
351
|
-
QueryBuilder.prototype.whereAny = function
|
377
|
+
QueryBuilder.prototype.whereAny = function() {
|
352
378
|
var args = [].slice.call(arguments);
|
353
379
|
return whereAny(this, args);
|
354
380
|
};
|
355
381
|
|
356
|
-
QueryBuilder.prototype.whereAll = function
|
382
|
+
QueryBuilder.prototype.whereAll = function() {
|
357
383
|
var args = [].slice.call(arguments);
|
358
384
|
return whereAll(this, args);
|
359
385
|
};
|
360
386
|
|
361
|
-
QueryBuilder.prototype.andWhereAny = function
|
387
|
+
QueryBuilder.prototype.andWhereAny = function() {
|
362
388
|
var args = [].slice.call(arguments);
|
363
389
|
return whereAny(this, args, "and");
|
364
390
|
};
|
365
391
|
|
366
|
-
QueryBuilder.prototype.orWhereAny = function
|
392
|
+
QueryBuilder.prototype.orWhereAny = function() {
|
367
393
|
var args = [].slice.call(arguments);
|
368
394
|
return whereAny(this, args, "or");
|
369
395
|
};
|
370
396
|
|
371
|
-
QueryBuilder.prototype.andWhereAll = function
|
397
|
+
QueryBuilder.prototype.andWhereAll = function() {
|
372
398
|
var args = [].slice.call(arguments);
|
373
399
|
return whereAll(this, args, "and");
|
374
400
|
};
|
375
401
|
|
376
|
-
QueryBuilder.prototype.orWhereAll = function
|
402
|
+
QueryBuilder.prototype.orWhereAll = function() {
|
377
403
|
var args = [].slice.call(arguments);
|
378
404
|
return whereAll(this, args, "or");
|
379
405
|
};
|
380
406
|
|
381
|
-
QueryBuilder.prototype.count = function
|
407
|
+
QueryBuilder.prototype.count = function() {
|
382
408
|
var args = [].slice.call(arguments);
|
383
409
|
if (this.query.type === "subquery") {
|
384
410
|
if (this.query.countExpression) {
|
385
|
-
throw new Error(
|
411
|
+
throw new Error(
|
412
|
+
"QueryBuilder subquery can only have one count expression"
|
413
|
+
);
|
386
414
|
}
|
387
415
|
this.query.countExpression = args[0].toFilter(this, "count");
|
388
416
|
} else {
|
@@ -396,13 +424,19 @@ module.exports = (function () {
|
|
396
424
|
|
397
425
|
return QueryBuilder;
|
398
426
|
|
399
|
-
function createSubQueryBuilder(
|
427
|
+
function createSubQueryBuilder(
|
428
|
+
qb,
|
429
|
+
entity,
|
430
|
+
key,
|
431
|
+
isArrayRelation = true,
|
432
|
+
modifier
|
433
|
+
) {
|
400
434
|
return new QueryBuilder({
|
401
435
|
parentBuilder: qb,
|
402
436
|
entity,
|
403
437
|
key,
|
404
438
|
modifier,
|
405
|
-
isArrayRelation
|
439
|
+
isArrayRelation
|
406
440
|
});
|
407
441
|
}
|
408
442
|
|
@@ -416,7 +450,7 @@ module.exports = (function () {
|
|
416
450
|
argsToUse = newArgs;
|
417
451
|
opNameToUse = newOpName;
|
418
452
|
}
|
419
|
-
sanityChecks.forEach(
|
453
|
+
sanityChecks.forEach(sanityCheck => {
|
420
454
|
sanityCheck(...args);
|
421
455
|
});
|
422
456
|
return new FilterExpression(opNameToUse, argsToUse);
|
@@ -441,16 +475,17 @@ module.exports = (function () {
|
|
441
475
|
}
|
442
476
|
|
443
477
|
function where(filterBuilder, operator, whereArgs, chainedWith) {
|
444
|
-
if (!Array.isArray(whereArgs))
|
478
|
+
if (!Array.isArray(whereArgs))
|
479
|
+
return where(filterBuilder, operator, [whereArgs], chainedWith);
|
445
480
|
|
446
481
|
var filterDef = {
|
447
482
|
type: "group",
|
448
483
|
operator,
|
449
484
|
chainedWith,
|
450
|
-
filters: []
|
485
|
+
filters: []
|
451
486
|
};
|
452
487
|
|
453
|
-
whereArgs.forEach(
|
488
|
+
whereArgs.forEach(arg => {
|
454
489
|
//add check for object type TODO
|
455
490
|
var filter = filterBuilder.convertToFilter(arg, operator);
|
456
491
|
filterDef.filters.push(filter);
|
@@ -1,21 +0,0 @@
|
|
1
|
-
'use strict';
|
2
|
-
|
3
|
-
module.exports = function combineQueries(qry1, qry2, joinOperator, opts) {
|
4
|
-
if (qry1.__objectType !== 'query') throw new Error("First query is not a query type.");
|
5
|
-
if (qry2.__objectType !== 'query') throw new Error("Second query is not a query type.");
|
6
|
-
if (qry1.entity != qry2.entity) throw new Error("Queries are for different entities " + qry1.entity + " and " + qry2.entity);
|
7
|
-
|
8
|
-
if (joinOperator !== 'or') joinOperator = 'and';
|
9
|
-
|
10
|
-
var combinedFilters = {
|
11
|
-
type: "group",
|
12
|
-
operator: joinOperator,
|
13
|
-
filters: []
|
14
|
-
};
|
15
|
-
|
16
|
-
combinedFilters.filters = qry1.filters.concat(qry2.filters);
|
17
|
-
|
18
|
-
qry1.filters = [combinedFilters];
|
19
|
-
|
20
|
-
return qry1;
|
21
|
-
};
|
@@ -1,19 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
module.exports = function () {
|
4
|
-
function FilterExpression(opName, args) {
|
5
|
-
this.name = opName;
|
6
|
-
this.args = args;
|
7
|
-
}
|
8
|
-
|
9
|
-
FilterExpression.prototype.toFilter = function (filterBuilder, argName) {
|
10
|
-
var filterDef = {
|
11
|
-
type: "expression",
|
12
|
-
operator: this.name,
|
13
|
-
field: argName,
|
14
|
-
args: this.args
|
15
|
-
};
|
16
|
-
return filterDef;
|
17
|
-
};
|
18
|
-
return FilterExpression;
|
19
|
-
}();
|
@@ -1,454 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
// valid filters:
|
4
|
-
// greaterThan
|
5
|
-
// inList
|
6
|
-
// lessThan
|
7
|
-
// lessThanOrEqual
|
8
|
-
// equals
|
9
|
-
// greaterThanOrEqual
|
10
|
-
// notEquals
|
11
|
-
// notNull
|
12
|
-
// isNull
|
13
|
-
// between
|
14
|
-
// notInList
|
15
|
-
// startsWithExactly
|
16
|
-
// endsWithExactly
|
17
|
-
// containsExactly
|
18
|
-
// startsWith
|
19
|
-
// notStartsWith
|
20
|
-
// endsWith
|
21
|
-
// notEndsWith
|
22
|
-
// contains
|
23
|
-
// notContains
|
24
|
-
// upperCase
|
25
|
-
// lowerCase
|
26
|
-
// matchesRegex (note: this takes a string like "thomas.*is.*cool", don't include the outer slashes like /asdf/ and don't pass a regex object )
|
27
|
-
// fuzzy
|
28
|
-
var FilterExpression = require("./filter-expression");
|
29
|
-
var _ = require("lodash");
|
30
|
-
|
31
|
-
var combineQueries = require("./combine-queries");
|
32
|
-
|
33
|
-
function isDateOrNumber(opName) {
|
34
|
-
var _arguments = arguments;
|
35
|
-
|
36
|
-
return function () {
|
37
|
-
var args = [].slice.call(_arguments);
|
38
|
-
if (args.some(function (arg) {
|
39
|
-
return !(_.isDate(arg) || _.isString(arg) || _.isNumber(arg));
|
40
|
-
})) {
|
41
|
-
throw new Error("QueryBuilderError: You must pass a date or number as args to " + opName + ". You passed: Args " + args.join(","));
|
42
|
-
}
|
43
|
-
};
|
44
|
-
}
|
45
|
-
function isArray(opName) {
|
46
|
-
return function (arg) {
|
47
|
-
if (!_.isArray(arg)) {
|
48
|
-
throw new Error("QueryBuilderError: You must pass an array for " + opName + " filters. You passed: " + arg);
|
49
|
-
}
|
50
|
-
};
|
51
|
-
}
|
52
|
-
function isString(opName) {
|
53
|
-
return function (arg) {
|
54
|
-
if (!_.isString(arg)) {
|
55
|
-
throw new Error("QueryBuilderError: You must pass a string for " + opName + " filters. You passed: " + arg);
|
56
|
-
}
|
57
|
-
};
|
58
|
-
}
|
59
|
-
|
60
|
-
function numberOfArgs(opName, argLength) {
|
61
|
-
return function () {
|
62
|
-
if (arguments.length !== argLength) {
|
63
|
-
throw new Error("QueryBuilderError: Args for " + opName + " are of length " + arguments.length + ", but they should be of length " + argLength);
|
64
|
-
}
|
65
|
-
};
|
66
|
-
}
|
67
|
-
|
68
|
-
var expressionOperators = [{
|
69
|
-
opName: "greaterThan",
|
70
|
-
sanityChecks: [numberOfArgs("greaterThan", 1), isDateOrNumber("greaterThan")]
|
71
|
-
}, {
|
72
|
-
opName: "inList",
|
73
|
-
sanityChecks: [numberOfArgs("inList", 1), isArray("inList")]
|
74
|
-
}, {
|
75
|
-
opName: "lessThan",
|
76
|
-
sanityChecks: [numberOfArgs("lessThan", 1), isDateOrNumber("lessThan")]
|
77
|
-
}, {
|
78
|
-
opName: "lessThanOrEqual",
|
79
|
-
sanityChecks: [numberOfArgs("lessThanOrEqual", 1), isDateOrNumber("lessThanOrEqual")]
|
80
|
-
}, {
|
81
|
-
opName: "equals",
|
82
|
-
sanityChecks: [numberOfArgs("equals", 1)]
|
83
|
-
}, {
|
84
|
-
opName: "greaterThanOrEqual",
|
85
|
-
sanityChecks: [numberOfArgs("greaterThanOrEqual", 1), isDateOrNumber("greaterThanOrEqual")]
|
86
|
-
}, {
|
87
|
-
opName: "notEquals",
|
88
|
-
sanityChecks: [numberOfArgs("notEquals", 1)]
|
89
|
-
}, {
|
90
|
-
opName: "notNull",
|
91
|
-
sanityChecks: [numberOfArgs("notNull", 0)]
|
92
|
-
}, {
|
93
|
-
opName: "isNull",
|
94
|
-
sanityChecks: [numberOfArgs("isNull", 0)]
|
95
|
-
}, {
|
96
|
-
opName: "between",
|
97
|
-
sanityChecks: [numberOfArgs("between", 2), isDateOrNumber("between")]
|
98
|
-
}, {
|
99
|
-
opName: "notInList",
|
100
|
-
sanityChecks: [numberOfArgs("notInList", 1), isArray("notInList")]
|
101
|
-
}, {
|
102
|
-
opName: "startsWithExactly",
|
103
|
-
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
104
|
-
}, {
|
105
|
-
opName: "endsWithExactly",
|
106
|
-
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
107
|
-
}, {
|
108
|
-
opName: "containsExactly",
|
109
|
-
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
110
|
-
}, {
|
111
|
-
opName: "startsWith",
|
112
|
-
sanityChecks: [numberOfArgs("startsWith", 1), isString("startsWith")]
|
113
|
-
}, {
|
114
|
-
opName: "notStartsWith",
|
115
|
-
sanityChecks: [numberOfArgs("notStartsWith", 1), isString("notStartsWith")]
|
116
|
-
}, {
|
117
|
-
opName: "endsWith",
|
118
|
-
sanityChecks: [numberOfArgs("endsWith", 1), isString("endsWith")]
|
119
|
-
}, {
|
120
|
-
opName: "notEndsWith",
|
121
|
-
sanityChecks: [numberOfArgs("notEndsWith", 1), isString("notEndsWith")]
|
122
|
-
}, {
|
123
|
-
opName: "contains",
|
124
|
-
sanityChecks: [numberOfArgs("contains", 1), isString("contains")]
|
125
|
-
}, {
|
126
|
-
opName: "notContains",
|
127
|
-
sanityChecks: [numberOfArgs("notContains", 1), isString("notContains")]
|
128
|
-
}, {
|
129
|
-
opName: "upperCase",
|
130
|
-
sanityChecks: [numberOfArgs("upperCase", 1), isString("upperCase")]
|
131
|
-
}, {
|
132
|
-
opName: "lowerCase",
|
133
|
-
sanityChecks: [numberOfArgs("lowerCase", 1), isString("lowerCase")]
|
134
|
-
}, {
|
135
|
-
opName: "matchesRegex",
|
136
|
-
sanityChecks: [numberOfArgs("matchesRegex", 1), isString("matchesRegex")]
|
137
|
-
}, {
|
138
|
-
opName: "matchesSimilar",
|
139
|
-
sanityChecks: [numberOfArgs("matchesSimilar", 1), isString("matchesSimilar")]
|
140
|
-
}, {
|
141
|
-
opName: "fuzzy",
|
142
|
-
sanityChecks: [numberOfArgs("fuzzy", 1), isString("fuzzy")],
|
143
|
-
transform: function transform(arg) {
|
144
|
-
// Build Regex String
|
145
|
-
var matchTerm = "";
|
146
|
-
// Split all the search terms
|
147
|
-
var terms = arg.replace(/\W/g, "").replace(" ", "").split("");
|
148
|
-
for (var i = 0; i < terms.length; i++) {
|
149
|
-
matchTerm += ".*" + terms[i];
|
150
|
-
}
|
151
|
-
matchTerm += ".*";
|
152
|
-
return {
|
153
|
-
newOpName: "matchesRegex",
|
154
|
-
newArgs: [matchTerm]
|
155
|
-
};
|
156
|
-
}
|
157
|
-
}];
|
158
|
-
|
159
|
-
module.exports = function () {
|
160
|
-
// to be implemented
|
161
|
-
//
|
162
|
-
// filter - done
|
163
|
-
// lessThan - done
|
164
|
-
// lessThanOrEqual - done
|
165
|
-
// greaterThan - done
|
166
|
-
// greaterThanOrEqual - done
|
167
|
-
// equals - done
|
168
|
-
// notEquals - done
|
169
|
-
// notNull
|
170
|
-
// isNull
|
171
|
-
// between
|
172
|
-
// inList - done
|
173
|
-
// notInList
|
174
|
-
// related - done
|
175
|
-
// notRelated - done
|
176
|
-
// startsWith LIKE adsd%
|
177
|
-
// endsWith
|
178
|
-
// contains LIKE
|
179
|
-
// notContains NOT LIKE
|
180
|
-
// dateOnly
|
181
|
-
// upperCase
|
182
|
-
// lowerCase
|
183
|
-
// subString
|
184
|
-
// matchesRegex
|
185
|
-
// count - Done
|
186
|
-
|
187
|
-
// log("FilterBuilder in QueryBuilder");
|
188
|
-
// log(FilterBuilder);
|
189
|
-
|
190
|
-
function QueryBuilder(entity) {
|
191
|
-
this.query = {};
|
192
|
-
|
193
|
-
if (entity == null) throw new Error("You must pass the name of the model being filtered!");
|
194
|
-
|
195
|
-
if (typeof entity === "string") {
|
196
|
-
this.query = {
|
197
|
-
__objectType: "query",
|
198
|
-
type: "root",
|
199
|
-
entity: entity,
|
200
|
-
filters: []
|
201
|
-
};
|
202
|
-
} else {
|
203
|
-
var subQuery = entity;
|
204
|
-
this.query = {
|
205
|
-
type: "subquery",
|
206
|
-
key: subQuery.key,
|
207
|
-
entity: subQuery.entity,
|
208
|
-
foreignKey: subQuery.foreignKey,
|
209
|
-
modifier: subQuery.modifier,
|
210
|
-
isArrayRelation: subQuery.isArrayRelation,
|
211
|
-
filters: [],
|
212
|
-
countExpression: undefined
|
213
|
-
};
|
214
|
-
this.parentBuilder = subQuery.parentBuilder;
|
215
|
-
this.toFilter = function (filterBuilder, name) {
|
216
|
-
this.query.foreignKey = name;
|
217
|
-
return this.toJSON();
|
218
|
-
};
|
219
|
-
}
|
220
|
-
}
|
221
|
-
|
222
|
-
QueryBuilder.combineQueries = combineQueries;
|
223
|
-
|
224
|
-
QueryBuilder.prototype.field = function (fieldName) {
|
225
|
-
return {
|
226
|
-
__objectType: "field",
|
227
|
-
field: fieldName
|
228
|
-
};
|
229
|
-
};
|
230
|
-
|
231
|
-
QueryBuilder.prototype.related = function (relatedEntity, isArrayRelation) {
|
232
|
-
var tokens = relatedEntity.split(".");
|
233
|
-
var entity = tokens[0];
|
234
|
-
var key = tokens[1];
|
235
|
-
|
236
|
-
// log("FilterBuilder in related");
|
237
|
-
// log(FilterBuilder);
|
238
|
-
|
239
|
-
return createSubQueryBuilder(this, entity, key, isArrayRelation);
|
240
|
-
};
|
241
|
-
|
242
|
-
QueryBuilder.prototype.notRelated = function (relatedEntity, isArrayRelation) {
|
243
|
-
var tokens = relatedEntity.split(".");
|
244
|
-
var entity = tokens[0];
|
245
|
-
var key = tokens[1];
|
246
|
-
|
247
|
-
// log("FilterBuilder in notRelated");
|
248
|
-
// log(FilterBuilder);
|
249
|
-
|
250
|
-
return createSubQueryBuilder(this, entity, key, isArrayRelation, "not");
|
251
|
-
};
|
252
|
-
|
253
|
-
QueryBuilder.prototype.toJSON = function () {
|
254
|
-
var qry = JSON.parse(JSON.stringify(this.query));
|
255
|
-
if (qry.filters.length > 1) {
|
256
|
-
qry.filters = [{
|
257
|
-
type: "group",
|
258
|
-
operator: "and",
|
259
|
-
chainedWith: "and",
|
260
|
-
filters: qry.filters
|
261
|
-
}];
|
262
|
-
}
|
263
|
-
return qry;
|
264
|
-
};
|
265
|
-
|
266
|
-
QueryBuilder.prototype.convertToFilter = function (argDef, operator) {
|
267
|
-
var _this = this;
|
268
|
-
|
269
|
-
var whereArgs = {};
|
270
|
-
var filters = [];
|
271
|
-
|
272
|
-
_.each(argDef, function (arg, name) {
|
273
|
-
// log(name);
|
274
|
-
// if(arg.constructor){
|
275
|
-
// log(arg.constructor.name)
|
276
|
-
// }else{
|
277
|
-
// log("not a prototype")
|
278
|
-
// }
|
279
|
-
if (!isFilterExpresionOrSubQuery(name, arg)) {
|
280
|
-
if (Array.isArray(arg)) {
|
281
|
-
filters.push(_this.inList(arg).toFilter(_this, name));
|
282
|
-
} else {
|
283
|
-
//log("Is Where Filter: " + name);
|
284
|
-
whereArgs[name] = arg;
|
285
|
-
}
|
286
|
-
} else {
|
287
|
-
//log("Is Expression or SubQuery Filter: " + name);
|
288
|
-
filters.push(arg.toFilter(_this, name));
|
289
|
-
}
|
290
|
-
});
|
291
|
-
if (_.keys(whereArgs).length > 0) {
|
292
|
-
filters.unshift({
|
293
|
-
type: "where",
|
294
|
-
args: whereArgs
|
295
|
-
});
|
296
|
-
}
|
297
|
-
|
298
|
-
if (filters.length === 1) {
|
299
|
-
return filters[0];
|
300
|
-
}
|
301
|
-
var filterDef = {
|
302
|
-
type: "group",
|
303
|
-
operator: operator || "and",
|
304
|
-
filters: filters
|
305
|
-
};
|
306
|
-
return filterDef;
|
307
|
-
};
|
308
|
-
|
309
|
-
QueryBuilder.prototype.where = function () {
|
310
|
-
var args = [].slice.call(arguments);
|
311
|
-
return this.whereAll(args);
|
312
|
-
};
|
313
|
-
|
314
|
-
QueryBuilder.prototype.orWhere = function () {
|
315
|
-
var args = [].slice.call(arguments);
|
316
|
-
return this.orWhereAll(args);
|
317
|
-
};
|
318
|
-
|
319
|
-
QueryBuilder.prototype.andWhere = function () {
|
320
|
-
var args = [].slice.call(arguments);
|
321
|
-
return this.andWhereAll(args);
|
322
|
-
};
|
323
|
-
|
324
|
-
QueryBuilder.prototype.whereAny = function () {
|
325
|
-
var args = [].slice.call(arguments);
|
326
|
-
return whereAny(this, args);
|
327
|
-
};
|
328
|
-
|
329
|
-
QueryBuilder.prototype.whereAll = function () {
|
330
|
-
var args = [].slice.call(arguments);
|
331
|
-
return whereAll(this, args);
|
332
|
-
};
|
333
|
-
|
334
|
-
QueryBuilder.prototype.andWhereAny = function () {
|
335
|
-
var args = [].slice.call(arguments);
|
336
|
-
return whereAny(this, args, "and");
|
337
|
-
};
|
338
|
-
|
339
|
-
QueryBuilder.prototype.orWhereAny = function () {
|
340
|
-
var args = [].slice.call(arguments);
|
341
|
-
return whereAny(this, args, "or");
|
342
|
-
};
|
343
|
-
|
344
|
-
QueryBuilder.prototype.andWhereAll = function () {
|
345
|
-
var args = [].slice.call(arguments);
|
346
|
-
return whereAll(this, args, "and");
|
347
|
-
};
|
348
|
-
|
349
|
-
QueryBuilder.prototype.orWhereAll = function () {
|
350
|
-
var args = [].slice.call(arguments);
|
351
|
-
return whereAll(this, args, "or");
|
352
|
-
};
|
353
|
-
|
354
|
-
QueryBuilder.prototype.count = function () {
|
355
|
-
var args = [].slice.call(arguments);
|
356
|
-
if (this.query.type === "subquery") {
|
357
|
-
if (this.query.countExpression) {
|
358
|
-
throw new Error("QueryBuilder subquery can only have one count expression");
|
359
|
-
}
|
360
|
-
this.query.countExpression = args[0].toFilter(this, "count");
|
361
|
-
} else {
|
362
|
-
throw new Error("QueryBuilder is not subquery type on count expression");
|
363
|
-
}
|
364
|
-
|
365
|
-
return this;
|
366
|
-
};
|
367
|
-
QueryBuilder.ExpressionJson = {};
|
368
|
-
attachExpressionFunctions();
|
369
|
-
|
370
|
-
return QueryBuilder;
|
371
|
-
|
372
|
-
function createSubQueryBuilder(qb, entity, key) {
|
373
|
-
var isArrayRelation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
374
|
-
var modifier = arguments[4];
|
375
|
-
|
376
|
-
return new QueryBuilder({
|
377
|
-
parentBuilder: qb,
|
378
|
-
entity: entity,
|
379
|
-
key: key,
|
380
|
-
modifier: modifier,
|
381
|
-
isArrayRelation: isArrayRelation
|
382
|
-
});
|
383
|
-
}
|
384
|
-
|
385
|
-
function attachExpressionFunctions() {
|
386
|
-
expressionOperators.forEach(function (_ref) {
|
387
|
-
var opName = _ref.opName,
|
388
|
-
sanityChecks = _ref.sanityChecks,
|
389
|
-
transform = _ref.transform;
|
390
|
-
|
391
|
-
var filter = function filter() {
|
392
|
-
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
393
|
-
args[_key] = arguments[_key];
|
394
|
-
}
|
395
|
-
|
396
|
-
var argsToUse = args;
|
397
|
-
var opNameToUse = opName;
|
398
|
-
if (transform) {
|
399
|
-
var _transform = transform.apply(undefined, args),
|
400
|
-
newOpName = _transform.newOpName,
|
401
|
-
newArgs = _transform.newArgs;
|
402
|
-
|
403
|
-
argsToUse = newArgs;
|
404
|
-
opNameToUse = newOpName;
|
405
|
-
}
|
406
|
-
sanityChecks.forEach(function (sanityCheck) {
|
407
|
-
sanityCheck.apply(undefined, args);
|
408
|
-
});
|
409
|
-
return new FilterExpression(opNameToUse, argsToUse);
|
410
|
-
};
|
411
|
-
QueryBuilder.prototype[opName] = filter;
|
412
|
-
QueryBuilder.ExpressionJson[opName] = filter;
|
413
|
-
});
|
414
|
-
}
|
415
|
-
|
416
|
-
function isFilterExpresionOrSubQuery(name, arg) {
|
417
|
-
if (arg instanceof FilterExpression) return true;
|
418
|
-
if (arg instanceof QueryBuilder) return true;
|
419
|
-
return false;
|
420
|
-
}
|
421
|
-
|
422
|
-
function whereAny(filterBuilder, whereArgs, chainedWith) {
|
423
|
-
return where(filterBuilder, "or", whereArgs, chainedWith);
|
424
|
-
}
|
425
|
-
|
426
|
-
function whereAll(filterBuilder, whereArgs, chainedWith) {
|
427
|
-
return where(filterBuilder, "and", whereArgs, chainedWith);
|
428
|
-
}
|
429
|
-
|
430
|
-
function where(filterBuilder, operator, whereArgs, chainedWith) {
|
431
|
-
if (!Array.isArray(whereArgs)) return where(filterBuilder, operator, [whereArgs], chainedWith);
|
432
|
-
|
433
|
-
var filterDef = {
|
434
|
-
type: "group",
|
435
|
-
operator: operator,
|
436
|
-
chainedWith: chainedWith,
|
437
|
-
filters: []
|
438
|
-
};
|
439
|
-
|
440
|
-
whereArgs.forEach(function (arg) {
|
441
|
-
//add check for object type TODO
|
442
|
-
var filter = filterBuilder.convertToFilter(arg, operator);
|
443
|
-
filterDef.filters.push(filter);
|
444
|
-
});
|
445
|
-
|
446
|
-
// if (filterDef.filters.length === 1) {
|
447
|
-
// filterBuilder.query.filters.push(filterDef.filters[0]);
|
448
|
-
// } else {
|
449
|
-
// filterBuilder.query.filters.push(filterDef);
|
450
|
-
// }
|
451
|
-
filterBuilder.query.filters.push(filterDef);
|
452
|
-
return filterBuilder;
|
453
|
-
}
|
454
|
-
}();
|