@syncfusion/ej2-querybuilder 30.2.4 → 31.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ej2-querybuilder.min.js +2 -2
- package/dist/ej2-querybuilder.umd.min.js +2 -2
- package/dist/ej2-querybuilder.umd.min.js.map +1 -1
- package/dist/es6/ej2-querybuilder.es2015.js +10 -1
- package/dist/es6/ej2-querybuilder.es2015.js.map +1 -1
- package/dist/es6/ej2-querybuilder.es5.js +13 -4
- package/dist/es6/ej2-querybuilder.es5.js.map +1 -1
- package/dist/global/ej2-querybuilder.min.js +2 -2
- package/dist/global/ej2-querybuilder.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/index.d.ts +4 -0
- package/dist/ts/index.ts +4 -0
- package/dist/ts/query-builder/index.d.ts +6 -0
- package/dist/ts/query-builder/index.ts +6 -0
- package/dist/ts/query-builder/query-builder-model.d.ts +569 -0
- package/dist/ts/query-builder/query-builder.d.ts +1172 -0
- package/dist/ts/query-builder/query-builder.ts +7612 -0
- package/dist/ts/query-builder/query-library.d.ts +24 -0
- package/dist/ts/query-builder/query-library.ts +625 -0
- package/package.json +46 -14
- package/src/query-builder/query-builder.js +13 -4
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { QueryBuilder } from './query-builder';
|
|
2
|
+
export declare class QueryLibrary {
|
|
3
|
+
private parent;
|
|
4
|
+
constructor(parent?: QueryBuilder);
|
|
5
|
+
destroy(): void;
|
|
6
|
+
private addEventListener;
|
|
7
|
+
private removeEventListener;
|
|
8
|
+
private queryLibrary;
|
|
9
|
+
private getMongoFromRules;
|
|
10
|
+
private getOperatorFromMongoOperator;
|
|
11
|
+
private convertMongoQuery;
|
|
12
|
+
private mongoParser;
|
|
13
|
+
private mongoRecursion;
|
|
14
|
+
private convertParamSqlToSql;
|
|
15
|
+
private convertNamedParamSqlToSql;
|
|
16
|
+
private getParameterSql;
|
|
17
|
+
private getNamedParameterSql;
|
|
18
|
+
private getParameterSQLVal;
|
|
19
|
+
private getNamedParameterSQLVal;
|
|
20
|
+
private updateRuleValue;
|
|
21
|
+
private updateValue;
|
|
22
|
+
private getNamedParameter;
|
|
23
|
+
getModuleName(): string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
import { extend, isNullOrUndefined } from '@syncfusion/ej2-base';
|
|
2
|
+
import { ParameterizedNamedSql, ParameterizedSql, QueryBuilder } from './query-builder';
|
|
3
|
+
import { RuleModel } from './query-builder-model';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class QueryLibrary {
|
|
7
|
+
private parent: QueryBuilder;
|
|
8
|
+
|
|
9
|
+
constructor(parent?: QueryBuilder) {
|
|
10
|
+
this.parent = parent;
|
|
11
|
+
this.addEventListener();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public destroy(): void {
|
|
15
|
+
if (this.parent.isDestroyed) { return; }
|
|
16
|
+
this.removeEventListener();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private addEventListener(): void {
|
|
20
|
+
if (this.parent.isDestroyed) { return; }
|
|
21
|
+
this.parent.on('query-library', this.queryLibrary, this);
|
|
22
|
+
this.parent.on('destroyed', this.destroy, this);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private removeEventListener(): void {
|
|
26
|
+
this.parent.off('query-library', this.queryLibrary);
|
|
27
|
+
this.parent.off('destroyed', this.destroy);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private queryLibrary(args?: { onPropertyChange: boolean, prop: string, value?: object }): void {
|
|
31
|
+
switch (args.prop) {
|
|
32
|
+
case 'getMongoFromRules':
|
|
33
|
+
args.value['obj']['mongoQuery'] = this.getMongoFromRules(args.value['rule'], args.value['mongoQuery']);
|
|
34
|
+
break;
|
|
35
|
+
case 'mongoParser':
|
|
36
|
+
this.mongoParser(args.value['mongoQuery'], args.value['rule'], args.value['mongoLocale']);
|
|
37
|
+
break;
|
|
38
|
+
case 'getParameterSql':
|
|
39
|
+
args.value['obj']['sql'] = this.getParameterSql(args.value['rule']);
|
|
40
|
+
break;
|
|
41
|
+
case 'getNamedParameterSql':
|
|
42
|
+
args.value['obj']['sql'] = this.getNamedParameterSql(args.value['rule']);
|
|
43
|
+
break;
|
|
44
|
+
case 'convertParamSqlToSql':
|
|
45
|
+
args.value['obj']['sql'] = this.convertParamSqlToSql(args.value['sql']);
|
|
46
|
+
break;
|
|
47
|
+
case 'convertNamedParamSqlToSql':
|
|
48
|
+
args.value['obj']['sql'] = this.convertNamedParamSqlToSql(args.value['sql']);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private getMongoFromRules(rule: RuleModel, mongoQuery: string): string {
|
|
54
|
+
mongoQuery = '{';
|
|
55
|
+
if (rule.condition === 'or') {
|
|
56
|
+
mongoQuery += '"$or":[';
|
|
57
|
+
mongoQuery = this.convertMongoQuery(rule.rules, mongoQuery) + ']';
|
|
58
|
+
} else {
|
|
59
|
+
mongoQuery += '"$and":[';
|
|
60
|
+
mongoQuery = this.convertMongoQuery(rule.rules, mongoQuery) + ']';
|
|
61
|
+
}
|
|
62
|
+
mongoQuery += '}';
|
|
63
|
+
return mongoQuery;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private getOperatorFromMongoOperator(operator: string): string {
|
|
67
|
+
let operatorValue: string;
|
|
68
|
+
switch (operator) {
|
|
69
|
+
case '$ne':
|
|
70
|
+
operatorValue = 'notequal';
|
|
71
|
+
break;
|
|
72
|
+
case '$gt':
|
|
73
|
+
operatorValue = 'greaterthan';
|
|
74
|
+
break;
|
|
75
|
+
case '$gte':
|
|
76
|
+
operatorValue = 'greaterthanorequal';
|
|
77
|
+
break;
|
|
78
|
+
case '$lt':
|
|
79
|
+
operatorValue = 'lessthan';
|
|
80
|
+
break;
|
|
81
|
+
case '$lte':
|
|
82
|
+
operatorValue = 'lessthanorequal';
|
|
83
|
+
break;
|
|
84
|
+
case '$nin':
|
|
85
|
+
operatorValue = 'notin';
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
return operatorValue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
private convertMongoQuery(rules: any, mongoQuery: string): string {
|
|
93
|
+
let i: number = 0;
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
|
+
(rules as any).forEach((item: any) => {
|
|
96
|
+
i++;
|
|
97
|
+
mongoQuery += '{';
|
|
98
|
+
if (item.rules !== undefined) {
|
|
99
|
+
if (item.condition === 'or') {
|
|
100
|
+
mongoQuery += ' "$or":[';
|
|
101
|
+
mongoQuery = this.convertMongoQuery(item.rules, mongoQuery) + ']';
|
|
102
|
+
} else {
|
|
103
|
+
mongoQuery += ' "$and":[';
|
|
104
|
+
mongoQuery = this.convertMongoQuery(item.rules, mongoQuery) + ']';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
let itVal: string = item.type === 'string' && item.operator !== 'in' && item.operator !== 'notin' && item.value && item.value.trim() !== '' ? item.value.replace(/'/g, '\\') : '';
|
|
108
|
+
if (item.type === 'string' && (item.operator === 'in' || item.operator === 'notin') && item.value && item.value.length === 1) {
|
|
109
|
+
itVal = item.value[0].replace(/'/g, '\\');
|
|
110
|
+
}
|
|
111
|
+
const field: string = item.field ? item.field.substring(0) : '';
|
|
112
|
+
switch (item.operator) {
|
|
113
|
+
case 'contains':
|
|
114
|
+
mongoQuery += '"' + field + '":{"$regex":"' + itVal + '"}';
|
|
115
|
+
break;
|
|
116
|
+
case 'notcontains':
|
|
117
|
+
mongoQuery += '"' + field + '":{"$not":{"$regex":"' + item.value + '"}}';
|
|
118
|
+
break;
|
|
119
|
+
case 'startswith':
|
|
120
|
+
mongoQuery += '"' + field + '":{"$regex":"^' + itVal + '"}';
|
|
121
|
+
break;
|
|
122
|
+
case 'notstartswith':
|
|
123
|
+
mongoQuery += '"' + field + '":{"$not":{"$regex":"^' + item.value + '"}}';
|
|
124
|
+
break;
|
|
125
|
+
case 'endswith':
|
|
126
|
+
mongoQuery += '"' + field + '":{"$regex":"' + itVal + '$"}';
|
|
127
|
+
break;
|
|
128
|
+
case 'notendswith':
|
|
129
|
+
mongoQuery += '"' + field + '":{"$not":{"$regex":"' + item.value + '$"}}';
|
|
130
|
+
break;
|
|
131
|
+
case 'isnull':
|
|
132
|
+
mongoQuery += '"' + field + '": null';
|
|
133
|
+
break;
|
|
134
|
+
case 'isnotnull':
|
|
135
|
+
mongoQuery += '"' + field + '":{"$ne": null}';
|
|
136
|
+
break;
|
|
137
|
+
case 'isempty':
|
|
138
|
+
mongoQuery += '"' + field + '": ""';
|
|
139
|
+
break;
|
|
140
|
+
case 'isnotempty':
|
|
141
|
+
mongoQuery += '"' + field + '":{"$ne": ""}';
|
|
142
|
+
break;
|
|
143
|
+
case 'equal':
|
|
144
|
+
if (item.type === 'string') {
|
|
145
|
+
mongoQuery += '"' + field + '":"' + itVal + '"';
|
|
146
|
+
} else if (item.type === 'date') {
|
|
147
|
+
mongoQuery += '"' + field + '":"' + item.value + '"';
|
|
148
|
+
} else if (item.type === 'boolean') {
|
|
149
|
+
mongoQuery += '"' + field + '":' + item.value + '';
|
|
150
|
+
} else {
|
|
151
|
+
mongoQuery += '"' + field + '":' + item.value + '';
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
case 'notequal':
|
|
155
|
+
if (item.type === 'string') {
|
|
156
|
+
mongoQuery += '"' + field + '":{"$ne":"' + itVal + '"}';
|
|
157
|
+
} else if (item.type === 'date') {
|
|
158
|
+
mongoQuery += '"' + field + '":{"$ne":"' + item.value + '"}';
|
|
159
|
+
} else {
|
|
160
|
+
mongoQuery += '"' + field + '":{"$ne":' + item.value + '}';
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
case 'in':
|
|
164
|
+
if (item.type === 'string') {
|
|
165
|
+
if (item.value.length > 1) {
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
|
+
let s: any = item.value.map((x: number, j: number) => (j < item.value.length ? `"${x}"` : '')).toString();
|
|
168
|
+
s = s.endsWith(',') ? s.substring(0, s.length - 1) : s;
|
|
169
|
+
mongoQuery += '"' + field + '": { "$in": [' + s + ']}';
|
|
170
|
+
} else {
|
|
171
|
+
mongoQuery += '"' + field + '": { "$in": ["' + itVal + '"]}';
|
|
172
|
+
}
|
|
173
|
+
} else if (item.type === 'number') {
|
|
174
|
+
if (item.value.length > 1) {
|
|
175
|
+
mongoQuery += '"' + field + '": { "$in": [' + item.value.toString() + ']}';
|
|
176
|
+
} else {
|
|
177
|
+
mongoQuery += '"' + field + '": { "$in": [' + item.value + ']}';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case 'notin':
|
|
182
|
+
if (item.type === 'string') {
|
|
183
|
+
if (item.value.length > 1) {
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
let s: any = item.value.map((x: number, j: number) => (j < item.value.length ? `"${x}"` : '')).toString();
|
|
186
|
+
s = s.endsWith(',') ? s.substring(0, s.length - 1) : s;
|
|
187
|
+
mongoQuery += '"' + field + '": { "$nin": [' + s + ']}';
|
|
188
|
+
} else {
|
|
189
|
+
mongoQuery += '"' + field + '": { "$nin": ["' + itVal + '"]}';
|
|
190
|
+
}
|
|
191
|
+
} else if (item.type === 'number') {
|
|
192
|
+
if (item.value.length > 1) {
|
|
193
|
+
mongoQuery += '"' + field + '": { "$nin": [' + item.value.toString() + ']}';
|
|
194
|
+
} else {
|
|
195
|
+
mongoQuery += '"' + field + '": { "$nin": [' + item.value + ']}';
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
case 'greaterthan':
|
|
200
|
+
if (item.type === 'number') {
|
|
201
|
+
mongoQuery += '"' + field + '": { "$gt": ' + item.value + '}';
|
|
202
|
+
} else {
|
|
203
|
+
mongoQuery += '"' + field + '": { "$gt": "' + item.value + '"}';
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case 'greaterthanorequal':
|
|
207
|
+
if (item.type === 'number') {
|
|
208
|
+
mongoQuery += '"' + field + '": { "$gte": ' + item.value + '}';
|
|
209
|
+
} else {
|
|
210
|
+
mongoQuery += '"' + field + '": { "$gte": "' + item.value + '"}';
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
case 'between':
|
|
214
|
+
if (item.type === 'number') {
|
|
215
|
+
mongoQuery += '"' + field + '": {"$gte":' + item.value[0] + ', "$lte":' + item.value[1] + '}';
|
|
216
|
+
} else {
|
|
217
|
+
mongoQuery += '"' + field + '": {"$gte": "' + item.value[0] + '", "$lte": "' + item.value[1] + '"}';
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
case 'notbetween':
|
|
221
|
+
if (item.type === 'number') {
|
|
222
|
+
mongoQuery += '"$or":[{"' + field + '": {"$lt":' + item.value[0] + '}}, {"' + field + '": {"$gt":' + item.value[1] + '}}]';
|
|
223
|
+
} else {
|
|
224
|
+
mongoQuery += '"$or":[{"' + field + '": {"$lt": "' + item.value[0] + '"}}, {"' + field + '": {"$gt": "' + item.value[1] + '"}}]';
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
case 'lessthan':
|
|
228
|
+
if (item.type === 'number') {
|
|
229
|
+
mongoQuery += '"' + field + '": { "$lt": ' + item.value + '}';
|
|
230
|
+
} else {
|
|
231
|
+
mongoQuery += '"' + field + '": { "$lt": "' + item.value + '"}';
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case 'lessthanorequal':
|
|
235
|
+
if (item.type === 'number') {
|
|
236
|
+
mongoQuery += '"' + field + '": { "$lte": ' + item.value + '}';
|
|
237
|
+
} else {
|
|
238
|
+
mongoQuery += '"' + field + '": { "$lte": "' + item.value + '"}';
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
mongoQuery += '}';
|
|
243
|
+
if ((rules as string).length !== i) {
|
|
244
|
+
mongoQuery += ',';
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
return mongoQuery;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private mongoParser(mongoQuery: object, rule: RuleModel, mongoLocale: boolean): void {
|
|
251
|
+
let mongoList: string[];
|
|
252
|
+
if (Object.keys(mongoQuery).indexOf('$and') > -1) {
|
|
253
|
+
mongoList = mongoQuery['$and'];
|
|
254
|
+
rule.condition = 'and';
|
|
255
|
+
} else if (Object.keys(mongoQuery).indexOf('$or') > -1) {
|
|
256
|
+
mongoList = mongoQuery['$or'];
|
|
257
|
+
rule.condition = 'or';
|
|
258
|
+
}
|
|
259
|
+
rule.rules = [];
|
|
260
|
+
this.mongoRecursion(mongoList, rule.rules, mongoLocale);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private mongoRecursion(mongoList: string[], rules: RuleModel[], mongoLocale: boolean): void {
|
|
264
|
+
let operatorValue: string; let type: string;
|
|
265
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
266
|
+
let stringValue: any; let key: any; let betweenValue: any;
|
|
267
|
+
let fieldType: string;
|
|
268
|
+
let condition: object[] | string; let value: object; let subRules: RuleModel; let rule: RuleModel; let keyObj: string[];
|
|
269
|
+
let ruleValue: string | number | boolean | string[] | number[];
|
|
270
|
+
for (let i: number = 0, len: number = mongoList.length; i < len; i++) {
|
|
271
|
+
const betweenOperatorArray: string[] | number[] = [];
|
|
272
|
+
let inOperatorArray: string[] | number[] = [];
|
|
273
|
+
condition = Object.keys(mongoList[i as number] as Object)[0];
|
|
274
|
+
value = mongoList[i as number][condition as string];
|
|
275
|
+
if (condition === '$and') {
|
|
276
|
+
if (this.parent.enableNotCondition) {
|
|
277
|
+
subRules = { condition: condition.replace('$', ''), rules: [], not: false };
|
|
278
|
+
} else {
|
|
279
|
+
subRules = { condition: condition.replace('$', ''), rules: [] };
|
|
280
|
+
}
|
|
281
|
+
rules.push(subRules);
|
|
282
|
+
this.mongoRecursion(mongoList[i as number][condition as string], rules[rules.length as number - 1].rules, mongoLocale);
|
|
283
|
+
}
|
|
284
|
+
else if (condition === '$or') {
|
|
285
|
+
let notBetween: boolean;
|
|
286
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
287
|
+
let innerObject: any = []; let keys: any = []; let firstKey: any = []; let secondKey: any = []; let innerKeys: any = [];
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
289
|
+
let firstValue: any = []; let secondValue: any = []; let innerFirstValue: any = []; let innerSecondValue: any = [];
|
|
290
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
291
|
+
keys = Object.keys(value);
|
|
292
|
+
innerFirstValue = value[keys[0]];
|
|
293
|
+
innerSecondValue = value[keys[1]];
|
|
294
|
+
if (typeof innerFirstValue === 'object') {
|
|
295
|
+
innerObject = Object.keys(innerFirstValue)[0];
|
|
296
|
+
innerKeys = Object.keys(innerFirstValue[Object.keys(innerFirstValue)[0]]);
|
|
297
|
+
firstKey = innerKeys[0];
|
|
298
|
+
secondKey = Object.keys(innerSecondValue[Object.keys(innerSecondValue)[0]])[0];
|
|
299
|
+
if (firstKey === '$lt' && secondKey === '$gt') {
|
|
300
|
+
operatorValue = 'notbetween';
|
|
301
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
302
|
+
firstValue = innerFirstValue[innerObject][firstKey];
|
|
303
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
304
|
+
secondValue = innerSecondValue[innerObject][secondKey];
|
|
305
|
+
type = typeof firstValue === 'number' ? 'number' : 'date';
|
|
306
|
+
ruleValue = [firstValue, secondValue];
|
|
307
|
+
rule = { field: innerObject, label: innerObject, value: ruleValue, operator: operatorValue, type: type };
|
|
308
|
+
rules.push(rule);
|
|
309
|
+
notBetween = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (!notBetween) {
|
|
314
|
+
if (this.parent.enableNotCondition) {
|
|
315
|
+
subRules = { condition: condition.replace('$', ''), rules: [], not: false };
|
|
316
|
+
} else {
|
|
317
|
+
subRules = { condition: condition.replace('$', ''), rules: [] };
|
|
318
|
+
}
|
|
319
|
+
rules.push(subRules);
|
|
320
|
+
this.mongoRecursion(mongoList[i as number][condition as string], rules[rules.length as number - 1].rules, mongoLocale);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
value = mongoList[i as number][condition as string];
|
|
325
|
+
if (value === null) { // isnull operator
|
|
326
|
+
operatorValue = 'isnull';
|
|
327
|
+
}
|
|
328
|
+
if (typeof value === 'boolean') { // boolean type values
|
|
329
|
+
operatorValue = 'equal';
|
|
330
|
+
type = 'boolean';
|
|
331
|
+
ruleValue = value;
|
|
332
|
+
}
|
|
333
|
+
if (typeof (value) === 'number') {
|
|
334
|
+
ruleValue = value; type = 'number'; operatorValue = 'equal';
|
|
335
|
+
} else if (typeof(value) === 'object' && value !== null) {
|
|
336
|
+
keyObj = Object.keys(value);
|
|
337
|
+
for (let i: number = 0; i < keyObj.length; i++) {
|
|
338
|
+
key = keyObj[i as number];
|
|
339
|
+
stringValue = (value)[keyObj[i as number]];
|
|
340
|
+
if (key === '$ne' && isNullOrUndefined(stringValue)) { // not null operator
|
|
341
|
+
operatorValue = 'isnotnull'; ruleValue = null;
|
|
342
|
+
}
|
|
343
|
+
if (key === '$ne' && typeof stringValue === 'boolean') { // not equal operator for boolean
|
|
344
|
+
operatorValue = 'notequal'; ruleValue = stringValue;
|
|
345
|
+
type = 'boolean';
|
|
346
|
+
}
|
|
347
|
+
if (keyObj.length >= 2 && keyObj[i as number]) {
|
|
348
|
+
if (typeof (stringValue) == 'object') { // between and notbetween operators
|
|
349
|
+
operatorValue = 'notbetween';
|
|
350
|
+
condition = Object.keys(stringValue)[0];
|
|
351
|
+
betweenValue = [Object.keys(stringValue[condition as string])[0]];
|
|
352
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
353
|
+
(betweenOperatorArray as string[]).push(stringValue[condition as string][betweenValue as any]);
|
|
354
|
+
type = 'number';
|
|
355
|
+
} else {
|
|
356
|
+
operatorValue = 'between';
|
|
357
|
+
(betweenOperatorArray as string[]).push(stringValue);
|
|
358
|
+
}
|
|
359
|
+
if (typeof (stringValue) === 'number') {
|
|
360
|
+
type = 'number';
|
|
361
|
+
}
|
|
362
|
+
} else if (typeof (stringValue) === 'object' && stringValue !== null) { // "in" and "notin" operator
|
|
363
|
+
if (key === '$not' && Object.keys(stringValue)[0] === '$regex') {
|
|
364
|
+
if (stringValue['$regex'].indexOf('^') > -1) {
|
|
365
|
+
operatorValue = 'notstartswith';
|
|
366
|
+
ruleValue = stringValue['$regex'].replace('^', '');
|
|
367
|
+
} else if (stringValue['$regex'].indexOf('$') > -1) {
|
|
368
|
+
operatorValue = 'notendswith';
|
|
369
|
+
ruleValue = stringValue['$regex'].replace('$', '');
|
|
370
|
+
} else {
|
|
371
|
+
operatorValue = 'notcontains';
|
|
372
|
+
ruleValue = stringValue['$regex'];
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
operatorValue = key === '$in' ? 'in' : 'notin';
|
|
376
|
+
inOperatorArray = stringValue;
|
|
377
|
+
type = typeof(stringValue[0]) === 'number' ? 'number' : 'string';
|
|
378
|
+
}
|
|
379
|
+
} else if (typeof (stringValue) === 'number') { // number type values
|
|
380
|
+
operatorValue = this.getOperatorFromMongoOperator(key);
|
|
381
|
+
type = 'number'; ruleValue = stringValue;
|
|
382
|
+
}
|
|
383
|
+
if (typeof (stringValue) === 'string') { // string type values
|
|
384
|
+
if (key === '$regex') {
|
|
385
|
+
operatorValue = 'contains'; ruleValue = stringValue; type = 'string';
|
|
386
|
+
}
|
|
387
|
+
if (key === '$ne') { // not equal
|
|
388
|
+
if (stringValue !== null && stringValue.length > 0 && isNaN(Date.parse(stringValue))) {
|
|
389
|
+
operatorValue = 'notequal'; ruleValue = stringValue;
|
|
390
|
+
} else if (isNullOrUndefined(stringValue)) { // is not null operator
|
|
391
|
+
operatorValue = 'isnotnull'; ruleValue = stringValue;
|
|
392
|
+
} else if (stringValue === '') { // is not empty operator
|
|
393
|
+
operatorValue = 'isnotempty'; ruleValue = stringValue;
|
|
394
|
+
}
|
|
395
|
+
type = 'string';
|
|
396
|
+
}
|
|
397
|
+
if (stringValue.indexOf('^') > -1) {
|
|
398
|
+
operatorValue = 'startswith'; ruleValue = stringValue.replace('^', ''); type = 'string';
|
|
399
|
+
}
|
|
400
|
+
if (stringValue.indexOf('$') > -1 && key !== '$not') {
|
|
401
|
+
operatorValue = 'endswith';
|
|
402
|
+
ruleValue = stringValue.replace('$', '');
|
|
403
|
+
type = 'string';
|
|
404
|
+
}
|
|
405
|
+
for (const column of this.parent.columns) {
|
|
406
|
+
if (column.field === condition) {
|
|
407
|
+
fieldType = column.type;
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (!isNaN(Date.parse(stringValue)) || fieldType === 'date') { // Date type operators
|
|
412
|
+
operatorValue = operatorValue || this.getOperatorFromMongoOperator(key);
|
|
413
|
+
type = 'date';
|
|
414
|
+
ruleValue = stringValue;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} else if (value && typeof(value) === 'string' && !isNaN(Date.parse(value))) {
|
|
419
|
+
operatorValue = 'equal';
|
|
420
|
+
ruleValue = value;
|
|
421
|
+
type = 'date';
|
|
422
|
+
} else if (typeof (value) === 'string' && value !== '' && value !== 'true' && value !== 'false') {
|
|
423
|
+
operatorValue = 'equal';
|
|
424
|
+
ruleValue = value;
|
|
425
|
+
type = 'string';
|
|
426
|
+
} else if (typeof (value) === 'string' && value === '') {
|
|
427
|
+
operatorValue = 'isempty';
|
|
428
|
+
ruleValue = value;
|
|
429
|
+
type = 'string';
|
|
430
|
+
}
|
|
431
|
+
if (betweenOperatorArray && betweenOperatorArray.length > 1) { // between opertor value
|
|
432
|
+
rule = { field: condition, label: condition, value: betweenOperatorArray, operator: operatorValue, type: type };
|
|
433
|
+
} else if (inOperatorArray && inOperatorArray.length > 1) { // in operator value
|
|
434
|
+
rule = { field: condition, label: condition, value: inOperatorArray, operator: operatorValue, type: type };
|
|
435
|
+
} else {
|
|
436
|
+
rule = { field: condition, label: condition, value: ruleValue, operator: operatorValue, type: type };
|
|
437
|
+
}
|
|
438
|
+
rules.push(rule);
|
|
439
|
+
operatorValue = '';
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private convertParamSqlToSql(sql: ParameterizedSql): string {
|
|
445
|
+
const paramSql: string = sql.sql; const paramValues: object[] = sql.params;
|
|
446
|
+
const parts: string[] = paramSql.split('?');
|
|
447
|
+
let normalSql: string = parts[0];
|
|
448
|
+
for (let i: number = 0; i < paramValues.length; i++) {
|
|
449
|
+
normalSql += (typeof(paramValues[i as number]) === 'string' ? `'${paramValues[i as number]}'` + parts[i + 1] : paramValues[i as number] + parts[i + 1]);
|
|
450
|
+
}
|
|
451
|
+
if (normalSql.length >= 2 && normalSql[0] === '(' && normalSql[normalSql.length - 1] === ')') {
|
|
452
|
+
normalSql = normalSql.slice(1, -1);
|
|
453
|
+
}
|
|
454
|
+
normalSql = normalSql.replace(/!= ''(?! =)/g, 'IS NOT EMPTY').replace(/= ''/g, 'IS EMPTY');
|
|
455
|
+
return normalSql;
|
|
456
|
+
}
|
|
457
|
+
private convertNamedParamSqlToSql(sql: ParameterizedNamedSql): string {
|
|
458
|
+
const namedParamSql: string = sql.sql; const params: Record<string, object> = sql.params;
|
|
459
|
+
let normalSql: string = namedParamSql;
|
|
460
|
+
Object.keys(params).forEach((paramName: string) => {
|
|
461
|
+
const paramValue: object = params[paramName as string];
|
|
462
|
+
paramName = ':' + paramName;
|
|
463
|
+
normalSql = normalSql.replace(paramName, typeof(paramValue) === 'string' ? `'${paramValue}'` : String(paramValue));
|
|
464
|
+
});
|
|
465
|
+
if (normalSql.length >= 2 && normalSql[0] === '(' && normalSql[normalSql.length - 1] === ')') {
|
|
466
|
+
normalSql = normalSql.slice(1, -1);
|
|
467
|
+
}
|
|
468
|
+
normalSql = normalSql.replace(/!= ''(?! =)/g, 'IS NOT EMPTY').replace(/= ''/g, 'IS EMPTY');
|
|
469
|
+
return normalSql;
|
|
470
|
+
}
|
|
471
|
+
private getParameterSql(qbrule: RuleModel): ParameterizedSql {
|
|
472
|
+
const qbRule: RuleModel = extend({}, qbrule, null, true);
|
|
473
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
474
|
+
const value: any = this.updateRuleValue(qbRule, false);
|
|
475
|
+
return this.getParameterSQLVal(this.parent.getSqlFromRules(qbRule), value['ruleVal']);
|
|
476
|
+
}
|
|
477
|
+
private getNamedParameterSql(qbrule: RuleModel): ParameterizedNamedSql {
|
|
478
|
+
const qbRule: RuleModel = extend({}, qbrule, null, true);
|
|
479
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
480
|
+
const value: any = this.updateRuleValue(qbRule, true);
|
|
481
|
+
return this.getNamedParameterSQLVal(this.parent.getSqlFromRules(qbRule), value['namedRuleVal']);
|
|
482
|
+
}
|
|
483
|
+
private getParameterSQLVal(content: string, ruleValue: object[]): ParameterizedSql {
|
|
484
|
+
const replacedString: string = content.replace(/[%']/g, '');
|
|
485
|
+
return { sql: '(' + replacedString + ')', params: ruleValue };
|
|
486
|
+
}
|
|
487
|
+
private getNamedParameterSQLVal(content: string, ruleValue: Record<string, object>): ParameterizedNamedSql {
|
|
488
|
+
const replacedString: string = content.replace(/[%']/g, '');
|
|
489
|
+
return { sql: '(' + replacedString + ')', params: ruleValue};
|
|
490
|
+
}
|
|
491
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
492
|
+
private updateRuleValue(rule: RuleModel, isNamedParameter: boolean): any {
|
|
493
|
+
const ruleVal: object[] = []; const namedRuleVal: Record<string, object> = {};
|
|
494
|
+
const namedParameters: string[] = [];
|
|
495
|
+
return this.updateValue(rule.rules, isNamedParameter, ruleVal, namedRuleVal, namedParameters);
|
|
496
|
+
}
|
|
497
|
+
private updateValue(rules: RuleModel[], isNamedParameter: boolean, ruleVal: object[],
|
|
498
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
499
|
+
namedRuleVal: Record<string, object>, namedParameters: string[]): any {
|
|
500
|
+
if (isNullOrUndefined(rules)) { return {ruleVal, namedRuleVal}; }
|
|
501
|
+
for (let i: number = 0; i < rules.length; i++) {
|
|
502
|
+
if (rules[i as number].rules) {
|
|
503
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
504
|
+
const value: any = this.updateValue(rules[i as number].rules, isNamedParameter, ruleVal, namedRuleVal, namedParameters);
|
|
505
|
+
ruleVal = value['ruleVal']; namedRuleVal = value['namedRuleVal'];
|
|
506
|
+
} else {
|
|
507
|
+
let namedField: string;
|
|
508
|
+
if (rules[i as number].value instanceof Array) {
|
|
509
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
510
|
+
for (let j: number = 0; j < ((rules[i as number].value) as any).length; j++) {
|
|
511
|
+
if (isNamedParameter) {
|
|
512
|
+
namedField = this.getNamedParameter(rules[i as number].field, namedParameters);
|
|
513
|
+
}
|
|
514
|
+
if (!isNullOrUndefined(rules[i as number].value[j as number])) {
|
|
515
|
+
if (rules[i as number].type === 'string' || rules[i as number].type === 'date') {
|
|
516
|
+
if (isNamedParameter) {
|
|
517
|
+
namedRuleVal[namedField as string] = rules[i as number].value[j as number];
|
|
518
|
+
} else {
|
|
519
|
+
ruleVal.push(rules[i as number].value[j as number]);
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
if (isNamedParameter) {
|
|
523
|
+
namedRuleVal[namedField as string] = rules[i as number].value[j as number];
|
|
524
|
+
} else {
|
|
525
|
+
ruleVal.push(rules[i as number].value[j as number]);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (isNamedParameter) {
|
|
530
|
+
rules[i as number].value[j as number] = ':' + namedField;
|
|
531
|
+
} else {
|
|
532
|
+
rules[i as number].value[j as number] = '?';
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
if (isNamedParameter) {
|
|
537
|
+
namedField = this.getNamedParameter(rules[i as number].field, namedParameters);
|
|
538
|
+
}
|
|
539
|
+
if (rules[i as number].operator.indexOf('null') < 1) {
|
|
540
|
+
if (rules[i as number].type !== 'string' || (rules[i as number].type === 'string' && (rules[i as number].value !== '' || rules[i as number].value === 0))) {
|
|
541
|
+
if (rules[i as number].type === 'string' || rules[i as number].type === 'date') {
|
|
542
|
+
if (rules[i as number].operator.indexOf('empty') < 1) {
|
|
543
|
+
let value: string = rules[i as number].value.toString();
|
|
544
|
+
switch (rules[i as number].operator) {
|
|
545
|
+
case 'startswith':
|
|
546
|
+
case 'notstartswith':
|
|
547
|
+
value = value + '%';
|
|
548
|
+
break;
|
|
549
|
+
case 'endswith':
|
|
550
|
+
case 'notendswith':
|
|
551
|
+
value = '%' + value;
|
|
552
|
+
break;
|
|
553
|
+
case 'contains':
|
|
554
|
+
case 'notcontains':
|
|
555
|
+
value = '%' + value + '%';
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
if (isNamedParameter) {
|
|
559
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
560
|
+
namedRuleVal[namedField as string] = value as any;
|
|
561
|
+
} else {
|
|
562
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
563
|
+
ruleVal.push(value as any);
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
if (isNamedParameter) {
|
|
567
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
568
|
+
namedRuleVal[namedField as string] = '' as any;
|
|
569
|
+
} else {
|
|
570
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
571
|
+
ruleVal.push('' as any);
|
|
572
|
+
}
|
|
573
|
+
if (rules[i as number].operator === 'isempty') {
|
|
574
|
+
rules[i as number].operator = 'equal';
|
|
575
|
+
} else {
|
|
576
|
+
rules[i as number].operator = 'notequal';
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
} else {
|
|
580
|
+
if (!isNullOrUndefined(rules[i as number].value)) {
|
|
581
|
+
if (isNamedParameter) {
|
|
582
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
583
|
+
namedRuleVal[namedField as string] = rules[i as number].value as any;
|
|
584
|
+
} else {
|
|
585
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
586
|
+
ruleVal.push(rules[i as number].value as any);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (isNamedParameter) {
|
|
591
|
+
rules[i as number].value = ':' + namedField;
|
|
592
|
+
} else {
|
|
593
|
+
rules[i as number].value = '?';
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return {ruleVal, namedRuleVal};
|
|
601
|
+
}
|
|
602
|
+
private getNamedParameter(field: string, namedParameters: string[]): string {
|
|
603
|
+
let newField: string = null;
|
|
604
|
+
if (namedParameters.length > 0) {
|
|
605
|
+
for (let i: number = namedParameters.length - 1; i >= 0; i--) {
|
|
606
|
+
const currField: string = namedParameters[i as number];
|
|
607
|
+
if (currField.indexOf(field) > -1) {
|
|
608
|
+
const idx: number = parseInt(currField.split('_')[1], 10) + 1;
|
|
609
|
+
newField = field + '_' + idx;
|
|
610
|
+
namedParameters.push(newField);
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (!newField) {
|
|
616
|
+
newField = field + '_1';
|
|
617
|
+
namedParameters.push(newField);
|
|
618
|
+
}
|
|
619
|
+
return newField;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
public getModuleName(): string {
|
|
623
|
+
return 'query-library';
|
|
624
|
+
}
|
|
625
|
+
}
|