tg-client-query-builder 2.14.1 → 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 -16
- package/query-builder/combine-queries.js +22 -17
- package/query-builder/filter-expression/index.js +16 -19
- package/query-builder/index.js +104 -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 -453
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,25 +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
|
-
},
|
13
7
|
"dependencies": {
|
14
8
|
"lodash": "^4.17.4"
|
15
|
-
},
|
16
|
-
"devDependencies": {
|
17
|
-
"babel-cli": "^6.26.0",
|
18
|
-
"babel-preset-latest": "^6.24.1",
|
19
|
-
"chai": "^4.0.2",
|
20
|
-
"fs-extra": "^3.0.1",
|
21
|
-
"json-beautify": "^1.0.1",
|
22
|
-
"json-format": "^1.0.1",
|
23
|
-
"jsonfile": "^3.0.0"
|
24
9
|
}
|
25
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;
|
@@ -234,11 +260,12 @@ module.exports = (function () {
|
|
234
260
|
entity: subQuery.entity,
|
235
261
|
foreignKey: subQuery.foreignKey,
|
236
262
|
modifier: subQuery.modifier,
|
263
|
+
isArrayRelation: subQuery.isArrayRelation,
|
237
264
|
filters: [],
|
238
|
-
countExpression: undefined
|
265
|
+
countExpression: undefined
|
239
266
|
};
|
240
267
|
this.parentBuilder = subQuery.parentBuilder;
|
241
|
-
this.toFilter = function
|
268
|
+
this.toFilter = function(filterBuilder, name) {
|
242
269
|
this.query.foreignKey = name;
|
243
270
|
return this.toJSON();
|
244
271
|
};
|
@@ -247,14 +274,14 @@ module.exports = (function () {
|
|
247
274
|
|
248
275
|
QueryBuilder.combineQueries = combineQueries;
|
249
276
|
|
250
|
-
QueryBuilder.prototype.field = function
|
277
|
+
QueryBuilder.prototype.field = function(fieldName) {
|
251
278
|
return {
|
252
279
|
__objectType: "field",
|
253
|
-
field: fieldName
|
280
|
+
field: fieldName
|
254
281
|
};
|
255
282
|
};
|
256
283
|
|
257
|
-
QueryBuilder.prototype.related = function
|
284
|
+
QueryBuilder.prototype.related = function(relatedEntity, isArrayRelation) {
|
258
285
|
var tokens = relatedEntity.split(".");
|
259
286
|
var entity = tokens[0];
|
260
287
|
var key = tokens[1];
|
@@ -265,7 +292,7 @@ module.exports = (function () {
|
|
265
292
|
return createSubQueryBuilder(this, entity, key, isArrayRelation);
|
266
293
|
};
|
267
294
|
|
268
|
-
QueryBuilder.prototype.notRelated = function
|
295
|
+
QueryBuilder.prototype.notRelated = function(relatedEntity, isArrayRelation) {
|
269
296
|
var tokens = relatedEntity.split(".");
|
270
297
|
var entity = tokens[0];
|
271
298
|
var key = tokens[1];
|
@@ -276,7 +303,7 @@ module.exports = (function () {
|
|
276
303
|
return createSubQueryBuilder(this, entity, key, isArrayRelation, "not");
|
277
304
|
};
|
278
305
|
|
279
|
-
QueryBuilder.prototype.toJSON = function
|
306
|
+
QueryBuilder.prototype.toJSON = function() {
|
280
307
|
let qry = JSON.parse(JSON.stringify(this.query));
|
281
308
|
if (qry.filters.length > 1) {
|
282
309
|
qry.filters = [
|
@@ -284,14 +311,14 @@ module.exports = (function () {
|
|
284
311
|
type: "group",
|
285
312
|
operator: "and",
|
286
313
|
chainedWith: "and",
|
287
|
-
filters: qry.filters
|
288
|
-
}
|
314
|
+
filters: qry.filters
|
315
|
+
}
|
289
316
|
];
|
290
317
|
}
|
291
318
|
return qry;
|
292
319
|
};
|
293
320
|
|
294
|
-
QueryBuilder.prototype.convertToFilter = function
|
321
|
+
QueryBuilder.prototype.convertToFilter = function(argDef, operator) {
|
295
322
|
var whereArgs = {};
|
296
323
|
var filters = [];
|
297
324
|
|
@@ -317,7 +344,7 @@ module.exports = (function () {
|
|
317
344
|
if (_.keys(whereArgs).length > 0) {
|
318
345
|
filters.unshift({
|
319
346
|
type: "where",
|
320
|
-
args: whereArgs
|
347
|
+
args: whereArgs
|
321
348
|
});
|
322
349
|
}
|
323
350
|
|
@@ -327,61 +354,63 @@ module.exports = (function () {
|
|
327
354
|
var filterDef = {
|
328
355
|
type: "group",
|
329
356
|
operator: operator || "and",
|
330
|
-
filters
|
357
|
+
filters
|
331
358
|
};
|
332
359
|
return filterDef;
|
333
360
|
};
|
334
361
|
|
335
|
-
QueryBuilder.prototype.where = function
|
362
|
+
QueryBuilder.prototype.where = function() {
|
336
363
|
var args = [].slice.call(arguments);
|
337
364
|
return this.whereAll(args);
|
338
365
|
};
|
339
366
|
|
340
|
-
QueryBuilder.prototype.orWhere = function
|
367
|
+
QueryBuilder.prototype.orWhere = function() {
|
341
368
|
var args = [].slice.call(arguments);
|
342
369
|
return this.orWhereAll(args);
|
343
370
|
};
|
344
371
|
|
345
|
-
QueryBuilder.prototype.andWhere = function
|
372
|
+
QueryBuilder.prototype.andWhere = function() {
|
346
373
|
var args = [].slice.call(arguments);
|
347
374
|
return this.andWhereAll(args);
|
348
375
|
};
|
349
376
|
|
350
|
-
QueryBuilder.prototype.whereAny = function
|
377
|
+
QueryBuilder.prototype.whereAny = function() {
|
351
378
|
var args = [].slice.call(arguments);
|
352
379
|
return whereAny(this, args);
|
353
380
|
};
|
354
381
|
|
355
|
-
QueryBuilder.prototype.whereAll = function
|
382
|
+
QueryBuilder.prototype.whereAll = function() {
|
356
383
|
var args = [].slice.call(arguments);
|
357
384
|
return whereAll(this, args);
|
358
385
|
};
|
359
386
|
|
360
|
-
QueryBuilder.prototype.andWhereAny = function
|
387
|
+
QueryBuilder.prototype.andWhereAny = function() {
|
361
388
|
var args = [].slice.call(arguments);
|
362
389
|
return whereAny(this, args, "and");
|
363
390
|
};
|
364
391
|
|
365
|
-
QueryBuilder.prototype.orWhereAny = function
|
392
|
+
QueryBuilder.prototype.orWhereAny = function() {
|
366
393
|
var args = [].slice.call(arguments);
|
367
394
|
return whereAny(this, args, "or");
|
368
395
|
};
|
369
396
|
|
370
|
-
QueryBuilder.prototype.andWhereAll = function
|
397
|
+
QueryBuilder.prototype.andWhereAll = function() {
|
371
398
|
var args = [].slice.call(arguments);
|
372
399
|
return whereAll(this, args, "and");
|
373
400
|
};
|
374
401
|
|
375
|
-
QueryBuilder.prototype.orWhereAll = function
|
402
|
+
QueryBuilder.prototype.orWhereAll = function() {
|
376
403
|
var args = [].slice.call(arguments);
|
377
404
|
return whereAll(this, args, "or");
|
378
405
|
};
|
379
406
|
|
380
|
-
QueryBuilder.prototype.count = function
|
407
|
+
QueryBuilder.prototype.count = function() {
|
381
408
|
var args = [].slice.call(arguments);
|
382
409
|
if (this.query.type === "subquery") {
|
383
410
|
if (this.query.countExpression) {
|
384
|
-
throw new Error(
|
411
|
+
throw new Error(
|
412
|
+
"QueryBuilder subquery can only have one count expression"
|
413
|
+
);
|
385
414
|
}
|
386
415
|
this.query.countExpression = args[0].toFilter(this, "count");
|
387
416
|
} else {
|
@@ -395,13 +424,19 @@ module.exports = (function () {
|
|
395
424
|
|
396
425
|
return QueryBuilder;
|
397
426
|
|
398
|
-
function createSubQueryBuilder(
|
427
|
+
function createSubQueryBuilder(
|
428
|
+
qb,
|
429
|
+
entity,
|
430
|
+
key,
|
431
|
+
isArrayRelation = true,
|
432
|
+
modifier
|
433
|
+
) {
|
399
434
|
return new QueryBuilder({
|
400
435
|
parentBuilder: qb,
|
401
436
|
entity,
|
402
437
|
key,
|
403
438
|
modifier,
|
404
|
-
isArrayRelation
|
439
|
+
isArrayRelation
|
405
440
|
});
|
406
441
|
}
|
407
442
|
|
@@ -415,7 +450,7 @@ module.exports = (function () {
|
|
415
450
|
argsToUse = newArgs;
|
416
451
|
opNameToUse = newOpName;
|
417
452
|
}
|
418
|
-
sanityChecks.forEach(
|
453
|
+
sanityChecks.forEach(sanityCheck => {
|
419
454
|
sanityCheck(...args);
|
420
455
|
});
|
421
456
|
return new FilterExpression(opNameToUse, argsToUse);
|
@@ -440,16 +475,17 @@ module.exports = (function () {
|
|
440
475
|
}
|
441
476
|
|
442
477
|
function where(filterBuilder, operator, whereArgs, chainedWith) {
|
443
|
-
if (!Array.isArray(whereArgs))
|
478
|
+
if (!Array.isArray(whereArgs))
|
479
|
+
return where(filterBuilder, operator, [whereArgs], chainedWith);
|
444
480
|
|
445
481
|
var filterDef = {
|
446
482
|
type: "group",
|
447
483
|
operator,
|
448
484
|
chainedWith,
|
449
|
-
filters: []
|
485
|
+
filters: []
|
450
486
|
};
|
451
487
|
|
452
|
-
whereArgs.forEach(
|
488
|
+
whereArgs.forEach(arg => {
|
453
489
|
//add check for object type TODO
|
454
490
|
var filter = filterBuilder.convertToFilter(arg, operator);
|
455
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,453 +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
|
-
filters: [],
|
211
|
-
countExpression: undefined
|
212
|
-
};
|
213
|
-
this.parentBuilder = subQuery.parentBuilder;
|
214
|
-
this.toFilter = function (filterBuilder, name) {
|
215
|
-
this.query.foreignKey = name;
|
216
|
-
return this.toJSON();
|
217
|
-
};
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
|
-
QueryBuilder.combineQueries = combineQueries;
|
222
|
-
|
223
|
-
QueryBuilder.prototype.field = function (fieldName) {
|
224
|
-
return {
|
225
|
-
__objectType: "field",
|
226
|
-
field: fieldName
|
227
|
-
};
|
228
|
-
};
|
229
|
-
|
230
|
-
QueryBuilder.prototype.related = function (relatedEntity, isArrayRelation) {
|
231
|
-
var tokens = relatedEntity.split(".");
|
232
|
-
var entity = tokens[0];
|
233
|
-
var key = tokens[1];
|
234
|
-
|
235
|
-
// log("FilterBuilder in related");
|
236
|
-
// log(FilterBuilder);
|
237
|
-
|
238
|
-
return createSubQueryBuilder(this, entity, key, isArrayRelation);
|
239
|
-
};
|
240
|
-
|
241
|
-
QueryBuilder.prototype.notRelated = function (relatedEntity, isArrayRelation) {
|
242
|
-
var tokens = relatedEntity.split(".");
|
243
|
-
var entity = tokens[0];
|
244
|
-
var key = tokens[1];
|
245
|
-
|
246
|
-
// log("FilterBuilder in notRelated");
|
247
|
-
// log(FilterBuilder);
|
248
|
-
|
249
|
-
return createSubQueryBuilder(this, entity, key, isArrayRelation, "not");
|
250
|
-
};
|
251
|
-
|
252
|
-
QueryBuilder.prototype.toJSON = function () {
|
253
|
-
var qry = JSON.parse(JSON.stringify(this.query));
|
254
|
-
if (qry.filters.length > 1) {
|
255
|
-
qry.filters = [{
|
256
|
-
type: "group",
|
257
|
-
operator: "and",
|
258
|
-
chainedWith: "and",
|
259
|
-
filters: qry.filters
|
260
|
-
}];
|
261
|
-
}
|
262
|
-
return qry;
|
263
|
-
};
|
264
|
-
|
265
|
-
QueryBuilder.prototype.convertToFilter = function (argDef, operator) {
|
266
|
-
var _this = this;
|
267
|
-
|
268
|
-
var whereArgs = {};
|
269
|
-
var filters = [];
|
270
|
-
|
271
|
-
_.each(argDef, function (arg, name) {
|
272
|
-
// log(name);
|
273
|
-
// if(arg.constructor){
|
274
|
-
// log(arg.constructor.name)
|
275
|
-
// }else{
|
276
|
-
// log("not a prototype")
|
277
|
-
// }
|
278
|
-
if (!isFilterExpresionOrSubQuery(name, arg)) {
|
279
|
-
if (Array.isArray(arg)) {
|
280
|
-
filters.push(_this.inList(arg).toFilter(_this, name));
|
281
|
-
} else {
|
282
|
-
//log("Is Where Filter: " + name);
|
283
|
-
whereArgs[name] = arg;
|
284
|
-
}
|
285
|
-
} else {
|
286
|
-
//log("Is Expression or SubQuery Filter: " + name);
|
287
|
-
filters.push(arg.toFilter(_this, name));
|
288
|
-
}
|
289
|
-
});
|
290
|
-
if (_.keys(whereArgs).length > 0) {
|
291
|
-
filters.unshift({
|
292
|
-
type: "where",
|
293
|
-
args: whereArgs
|
294
|
-
});
|
295
|
-
}
|
296
|
-
|
297
|
-
if (filters.length === 1) {
|
298
|
-
return filters[0];
|
299
|
-
}
|
300
|
-
var filterDef = {
|
301
|
-
type: "group",
|
302
|
-
operator: operator || "and",
|
303
|
-
filters: filters
|
304
|
-
};
|
305
|
-
return filterDef;
|
306
|
-
};
|
307
|
-
|
308
|
-
QueryBuilder.prototype.where = function () {
|
309
|
-
var args = [].slice.call(arguments);
|
310
|
-
return this.whereAll(args);
|
311
|
-
};
|
312
|
-
|
313
|
-
QueryBuilder.prototype.orWhere = function () {
|
314
|
-
var args = [].slice.call(arguments);
|
315
|
-
return this.orWhereAll(args);
|
316
|
-
};
|
317
|
-
|
318
|
-
QueryBuilder.prototype.andWhere = function () {
|
319
|
-
var args = [].slice.call(arguments);
|
320
|
-
return this.andWhereAll(args);
|
321
|
-
};
|
322
|
-
|
323
|
-
QueryBuilder.prototype.whereAny = function () {
|
324
|
-
var args = [].slice.call(arguments);
|
325
|
-
return whereAny(this, args);
|
326
|
-
};
|
327
|
-
|
328
|
-
QueryBuilder.prototype.whereAll = function () {
|
329
|
-
var args = [].slice.call(arguments);
|
330
|
-
return whereAll(this, args);
|
331
|
-
};
|
332
|
-
|
333
|
-
QueryBuilder.prototype.andWhereAny = function () {
|
334
|
-
var args = [].slice.call(arguments);
|
335
|
-
return whereAny(this, args, "and");
|
336
|
-
};
|
337
|
-
|
338
|
-
QueryBuilder.prototype.orWhereAny = function () {
|
339
|
-
var args = [].slice.call(arguments);
|
340
|
-
return whereAny(this, args, "or");
|
341
|
-
};
|
342
|
-
|
343
|
-
QueryBuilder.prototype.andWhereAll = function () {
|
344
|
-
var args = [].slice.call(arguments);
|
345
|
-
return whereAll(this, args, "and");
|
346
|
-
};
|
347
|
-
|
348
|
-
QueryBuilder.prototype.orWhereAll = function () {
|
349
|
-
var args = [].slice.call(arguments);
|
350
|
-
return whereAll(this, args, "or");
|
351
|
-
};
|
352
|
-
|
353
|
-
QueryBuilder.prototype.count = function () {
|
354
|
-
var args = [].slice.call(arguments);
|
355
|
-
if (this.query.type === "subquery") {
|
356
|
-
if (this.query.countExpression) {
|
357
|
-
throw new Error("QueryBuilder subquery can only have one count expression");
|
358
|
-
}
|
359
|
-
this.query.countExpression = args[0].toFilter(this, "count");
|
360
|
-
} else {
|
361
|
-
throw new Error("QueryBuilder is not subquery type on count expression");
|
362
|
-
}
|
363
|
-
|
364
|
-
return this;
|
365
|
-
};
|
366
|
-
QueryBuilder.ExpressionJson = {};
|
367
|
-
attachExpressionFunctions();
|
368
|
-
|
369
|
-
return QueryBuilder;
|
370
|
-
|
371
|
-
function createSubQueryBuilder(qb, entity, key) {
|
372
|
-
var isArrayRelation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
373
|
-
var modifier = arguments[4];
|
374
|
-
|
375
|
-
return new QueryBuilder({
|
376
|
-
parentBuilder: qb,
|
377
|
-
entity: entity,
|
378
|
-
key: key,
|
379
|
-
modifier: modifier,
|
380
|
-
isArrayRelation: isArrayRelation
|
381
|
-
});
|
382
|
-
}
|
383
|
-
|
384
|
-
function attachExpressionFunctions() {
|
385
|
-
expressionOperators.forEach(function (_ref) {
|
386
|
-
var opName = _ref.opName,
|
387
|
-
sanityChecks = _ref.sanityChecks,
|
388
|
-
transform = _ref.transform;
|
389
|
-
|
390
|
-
var filter = function filter() {
|
391
|
-
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
392
|
-
args[_key] = arguments[_key];
|
393
|
-
}
|
394
|
-
|
395
|
-
var argsToUse = args;
|
396
|
-
var opNameToUse = opName;
|
397
|
-
if (transform) {
|
398
|
-
var _transform = transform.apply(undefined, args),
|
399
|
-
newOpName = _transform.newOpName,
|
400
|
-
newArgs = _transform.newArgs;
|
401
|
-
|
402
|
-
argsToUse = newArgs;
|
403
|
-
opNameToUse = newOpName;
|
404
|
-
}
|
405
|
-
sanityChecks.forEach(function (sanityCheck) {
|
406
|
-
sanityCheck.apply(undefined, args);
|
407
|
-
});
|
408
|
-
return new FilterExpression(opNameToUse, argsToUse);
|
409
|
-
};
|
410
|
-
QueryBuilder.prototype[opName] = filter;
|
411
|
-
QueryBuilder.ExpressionJson[opName] = filter;
|
412
|
-
});
|
413
|
-
}
|
414
|
-
|
415
|
-
function isFilterExpresionOrSubQuery(name, arg) {
|
416
|
-
if (arg instanceof FilterExpression) return true;
|
417
|
-
if (arg instanceof QueryBuilder) return true;
|
418
|
-
return false;
|
419
|
-
}
|
420
|
-
|
421
|
-
function whereAny(filterBuilder, whereArgs, chainedWith) {
|
422
|
-
return where(filterBuilder, "or", whereArgs, chainedWith);
|
423
|
-
}
|
424
|
-
|
425
|
-
function whereAll(filterBuilder, whereArgs, chainedWith) {
|
426
|
-
return where(filterBuilder, "and", whereArgs, chainedWith);
|
427
|
-
}
|
428
|
-
|
429
|
-
function where(filterBuilder, operator, whereArgs, chainedWith) {
|
430
|
-
if (!Array.isArray(whereArgs)) return where(filterBuilder, operator, [whereArgs], chainedWith);
|
431
|
-
|
432
|
-
var filterDef = {
|
433
|
-
type: "group",
|
434
|
-
operator: operator,
|
435
|
-
chainedWith: chainedWith,
|
436
|
-
filters: []
|
437
|
-
};
|
438
|
-
|
439
|
-
whereArgs.forEach(function (arg) {
|
440
|
-
//add check for object type TODO
|
441
|
-
var filter = filterBuilder.convertToFilter(arg, operator);
|
442
|
-
filterDef.filters.push(filter);
|
443
|
-
});
|
444
|
-
|
445
|
-
// if (filterDef.filters.length === 1) {
|
446
|
-
// filterBuilder.query.filters.push(filterDef.filters[0]);
|
447
|
-
// } else {
|
448
|
-
// filterBuilder.query.filters.push(filterDef);
|
449
|
-
// }
|
450
|
-
filterBuilder.query.filters.push(filterDef);
|
451
|
-
return filterBuilder;
|
452
|
-
}
|
453
|
-
}();
|