/
V2FilterProcessor.ts
150 lines (132 loc) · 4.8 KB
/
V2FilterProcessor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import {IHash} from '../internal/IHash';
import {Util} from '../internal/Util';
import {IFilterProcessor} from '../api/IFilterProcessor';
import {Filter} from '../api/Filter';
import {Comparator, Comparators} from '../api/Comparator';
import {Restriction} from '../api/Restriction';
import {NestedRestriction} from '../api/NestedRestriction';
import {OnmsError} from '../api/OnmsError';
import {Operator, Operators} from '../api/Operator';
import {Clause} from '../api/Clause';
import {SearchPropertyTypes} from '../api/SearchPropertyType';
import {ISearchPropertyAccessor} from './ISearchPropertyAccessor';
/**
* Converts a [[Filter]] into ReSTv2 FIQL parameters.
* @module V2FilterProcessor
*/
export class V2FilterProcessor implements IFilterProcessor {
/** Constant used to represent null values in the V2 API. */
public static NULL_VALUE = '\u0000';
/** Constant used to represent null dates in the V2 API.
* This must be explicitly set as the restriction value when using
* either the NULL or NOTNULL comparators on date fields.
*/
public static NULL_DATE = '1970-01-01T00:00:00.000+0000';
/**
* pre-encoded to avoid running `encodeURIComponent` every time we deal with a null date
* @hidden
*/
private static NULL_DATE_ENCODED = encodeURIComponent(V2FilterProcessor.NULL_DATE);
/** The accessor for Properties */
private searchPropertyAccessor: ISearchPropertyAccessor;
constructor(searchPropertyAccessor?: ISearchPropertyAccessor) {
this.searchPropertyAccessor = searchPropertyAccessor;
}
/** Given a filter, return a hash of URL parameters. */
public getParameters(filter: Filter) {
const ret = {} as IHash<string>;
if (filter.limit !== undefined) {
ret.limit = '' + filter.limit;
}
const search = this.toFIQL(filter.clauses);
if (search.length > 0) {
ret._s = search;
}
return ret;
}
/**
* Given a comparator, convert it to a correspond comparator
* that can be used in the FIQL expression.
*/
private toFIQLComparator(comparator: Comparator) {
switch (comparator) {
case Comparators.EQ:
case Comparators.NULL:
return '==';
case Comparators.NE:
case Comparators.NOTNULL:
return '!=';
case Comparators.GT:
return '=gt=';
case Comparators.LT:
return '=lt=';
case Comparators.GE:
return '=ge=';
case Comparators.LE:
return '=le=';
case Comparators.LIKE:
return '==';
case Comparators.ILIKE:
default:
throw new OnmsError('Unsupported comparator type: ' + comparator);
}
}
/** Given a restriction, compute the value to use in the FIQL expression. */
private toFIQLValue(restriction: Restriction) {
switch (restriction.comparator) {
case Comparators.NULL:
case Comparators.NOTNULL:
return restriction.value === undefined ? V2FilterProcessor.NULL_VALUE : encodeURIComponent(restriction.value);
default:
if (restriction.value === 'null' || restriction.value === void 0) {
const property = this.searchPropertyAccessor.getProperty(restriction.attribute);
if (property && property.type === SearchPropertyTypes.TIMESTAMP) {
return V2FilterProcessor.NULL_DATE_ENCODED;
}
return V2FilterProcessor.NULL_VALUE;
}
return encodeURIComponent(this.applyDateConversion(restriction.value));
}
}
/** Given an operator, convert it to the corresponding FIQL operator. */
private toFIQLOperator(operator: Operator) {
switch (operator) {
case Operators.AND:
return ';';
case Operators.OR:
return ',';
default:
throw new OnmsError('Unsupported operator type: ' + operator);
}
}
/** Given a list of clauses, recursively generate the FIQL query string. */
private toFIQL(clauses: Clause[]) {
let search = '';
for (const clause of clauses) {
if (search.length > 0) {
search += this.toFIQLOperator(clause.operator);
}
if (clause.restriction instanceof NestedRestriction) {
search += '(' + this.toFIQL(clause.restriction.clauses) + ')';
} else {
const restriction = clause.restriction as Restriction;
const comp = this.toFIQLComparator(restriction.comparator);
const value = this.toFIQLValue(restriction);
search += [restriction.attribute, comp, value].join('');
}
}
return search;
}
/**
* If the given value is a date value, it is converted to be properly parsed by the OpenNMS ReST API,
* otherwise it is not modified.
*
* @param value Any value which may need conversion.
*/
private applyDateConversion(value: any): any {
if (Util.isDateObject(value)) {
return Util.toDateString(value);
}
return value;
}
}