@malloydata/malloy-filter 0.0.237-dev250222034547 → 0.0.237-dev250222205057
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/boolean_parser.js +3 -1
- package/dist/boolean_parser.js.map +1 -1
- package/dist/boolean_serializer.js +9 -1
- package/dist/boolean_serializer.js.map +1 -1
- package/dist/clause_types.d.ts +28 -9
- package/dist/date_parser.js +5 -1
- package/dist/date_parser.js.map +1 -1
- package/dist/date_serializer.js +6 -0
- package/dist/date_serializer.js.map +1 -1
- package/dist/date_types.d.ts +7 -1
- package/dist/generate_samples.js +8 -2
- package/dist/generate_samples.js.map +1 -1
- package/dist/number_parser.d.ts +0 -3
- package/dist/number_parser.js +10 -51
- package/dist/number_parser.js.map +1 -1
- package/dist/number_serializer.js +14 -11
- package/dist/number_serializer.js.map +1 -1
- package/dist/string_parser.js +21 -21
- package/dist/string_parser.js.map +1 -1
- package/dist/string_serializer.d.ts +1 -0
- package/dist/string_serializer.js +35 -21
- package/dist/string_serializer.js.map +1 -1
- package/package.json +1 -1
- package/src/DEVELOPING.md +2 -5
- package/src/boolean_parser.ts +4 -3
- package/src/boolean_serializer.ts +9 -1
- package/src/clause_types.ts +59 -20
- package/src/date_parser.ts +5 -1
- package/src/date_serializer.ts +4 -0
- package/src/date_types.ts +10 -0
- package/src/generate_samples.ts +8 -2
- package/src/number_parser.ts +9 -58
- package/src/number_serializer.ts +14 -14
- package/src/string_parser.ts +29 -21
- package/src/string_serializer.ts +54 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string_parser.js","sourceRoot":"","sources":["../src/string_parser.ts"],"names":[],"mappings":";;;AAAA,2CAAqE;
|
|
1
|
+
{"version":3,"file":"string_parser.js","sourceRoot":"","sources":["../src/string_parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ export declare class StringSerializer {
|
|
|
6
6
|
private static isNegated;
|
|
7
7
|
private static escapeSpecialCharacters;
|
|
8
8
|
private static escapeWildcardCharacters;
|
|
9
|
+
private static StringConditionWordToString;
|
|
9
10
|
private static StringClauseToString;
|
|
10
11
|
private static clauseToString;
|
|
11
12
|
}
|
|
@@ -11,8 +11,7 @@ class StringSerializer {
|
|
|
11
11
|
return result.trim().replace(/,$/, '');
|
|
12
12
|
}
|
|
13
13
|
static isNegated(operator) {
|
|
14
|
-
return (operator === '
|
|
15
|
-
operator === '!~' ||
|
|
14
|
+
return (operator === '!~' ||
|
|
16
15
|
operator === '!=' ||
|
|
17
16
|
operator === 'notStarts' ||
|
|
18
17
|
operator === 'notEnds' ||
|
|
@@ -24,19 +23,11 @@ class StringSerializer {
|
|
|
24
23
|
static escapeWildcardCharacters(input) {
|
|
25
24
|
return input.replace(/[_%]/g, match => `\\${match}`);
|
|
26
25
|
}
|
|
27
|
-
// export type StringOperator =
|
|
28
|
-
// '
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return 'EMPTY';
|
|
32
|
-
}
|
|
33
|
-
else if (operator === 'NOTEMPTY') {
|
|
34
|
-
return '-EMPTY';
|
|
35
|
-
}
|
|
26
|
+
// export type StringOperator =
|
|
27
|
+
// | 'starts' | 'ends' | 'contains' | 'notStarts' | 'notEnds' | 'notContains'
|
|
28
|
+
// | '~' | '=' | '!~' | '!=';
|
|
29
|
+
static StringConditionWordToString(operator, value) {
|
|
36
30
|
const negated = StringSerializer.isNegated(operator);
|
|
37
|
-
if (value === null) {
|
|
38
|
-
return negated ? '-NULL' : 'NULL';
|
|
39
|
-
}
|
|
40
31
|
if (value === 'NULL' || value === '-NULL') {
|
|
41
32
|
return (negated ? '-' : '') + '\\' + value;
|
|
42
33
|
}
|
|
@@ -59,15 +50,38 @@ class StringSerializer {
|
|
|
59
50
|
}
|
|
60
51
|
return (negated ? '-' : '') + value;
|
|
61
52
|
}
|
|
53
|
+
static StringClauseToString(operator, clause) {
|
|
54
|
+
if (operator === 'EMPTY') {
|
|
55
|
+
return 'EMPTY';
|
|
56
|
+
}
|
|
57
|
+
else if (operator === 'NOTEMPTY') {
|
|
58
|
+
return '-EMPTY';
|
|
59
|
+
}
|
|
60
|
+
else if (operator === 'NULL') {
|
|
61
|
+
return 'NULL';
|
|
62
|
+
}
|
|
63
|
+
else if (operator === 'NOTNULL') {
|
|
64
|
+
return '-NULL';
|
|
65
|
+
}
|
|
66
|
+
if (!('values' in clause) || clause.values.length === 0) {
|
|
67
|
+
return '';
|
|
68
|
+
}
|
|
69
|
+
let result = '';
|
|
70
|
+
const condition = clause;
|
|
71
|
+
for (const value of condition.values) {
|
|
72
|
+
const word = StringSerializer.StringConditionWordToString(condition.operator, value);
|
|
73
|
+
if (word) {
|
|
74
|
+
result += word + ', ';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
62
79
|
static clauseToString(clauses) {
|
|
63
80
|
let result = '';
|
|
64
|
-
for (const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (word) {
|
|
69
|
-
result += word + ', ';
|
|
70
|
-
}
|
|
81
|
+
for (const clause of clauses) {
|
|
82
|
+
const words = StringSerializer.StringClauseToString(clause.operator, clause);
|
|
83
|
+
if (words) {
|
|
84
|
+
result += words + ', ';
|
|
71
85
|
}
|
|
72
86
|
}
|
|
73
87
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string_serializer.js","sourceRoot":"","sources":["../src/string_serializer.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"string_serializer.js","sourceRoot":"","sources":["../src/string_serializer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/DEVELOPING.md
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
# Testing
|
|
2
2
|
|
|
3
|
-
The `malloy-filter` tests use Jest.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm install --save-dev jest @types/jest ts-jest
|
|
7
|
-
```
|
|
3
|
+
The `malloy-filter` tests use Jest.
|
|
8
4
|
|
|
9
5
|
## Tokenizer Testing
|
|
10
6
|
|
|
11
7
|
```bash
|
|
8
|
+
npm run build
|
|
12
9
|
npm run test:tokenizer
|
|
13
10
|
```
|
|
14
11
|
|
package/src/boolean_parser.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
|
|
2
2
|
import {
|
|
3
3
|
BooleanClause,
|
|
4
|
-
BooleanOperator,
|
|
5
4
|
BooleanParserResponse,
|
|
6
5
|
FilterError,
|
|
7
6
|
} from './clause_types';
|
|
@@ -18,7 +17,8 @@ export class BooleanParser extends BaseParser {
|
|
|
18
17
|
{type: 'NULL', value: 'null', ignoreCase: true},
|
|
19
18
|
{type: 'NOTNULL', value: '-null', ignoreCase: true},
|
|
20
19
|
{type: 'TRUE', value: 'true', ignoreCase: true},
|
|
21
|
-
{type: 'FALSE', value: 'false', ignoreCase: true},
|
|
20
|
+
{type: 'FALSE', value: '=false', ignoreCase: true},
|
|
21
|
+
{type: 'FALSEORNULL', value: 'false', ignoreCase: true},
|
|
22
22
|
];
|
|
23
23
|
const params: TokenizerParams = {
|
|
24
24
|
trimWordWhitespace: true,
|
|
@@ -45,9 +45,10 @@ export class BooleanParser extends BaseParser {
|
|
|
45
45
|
token.type === 'NULL' ||
|
|
46
46
|
token.type === 'TRUE' ||
|
|
47
47
|
token.type === 'FALSE' ||
|
|
48
|
+
token.type === 'FALSEORNULL' ||
|
|
48
49
|
token.type === 'NOTNULL'
|
|
49
50
|
) {
|
|
50
|
-
const clause: BooleanClause = {operator: token.type
|
|
51
|
+
const clause: BooleanClause = {operator: token.type};
|
|
51
52
|
clauses.push(clause);
|
|
52
53
|
this.index++;
|
|
53
54
|
} else {
|
|
@@ -11,7 +11,15 @@ export class BooleanSerializer {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
private static booleanClauseToString(clause: BooleanClause): string {
|
|
14
|
-
|
|
14
|
+
switch (clause.operator) {
|
|
15
|
+
case 'NOTNULL':
|
|
16
|
+
return '-NULL';
|
|
17
|
+
case 'FALSEORNULL':
|
|
18
|
+
return 'FALSE';
|
|
19
|
+
case 'FALSE':
|
|
20
|
+
return '=FALSE';
|
|
21
|
+
}
|
|
22
|
+
return clause.operator;
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
private static clauseToString(clauses: BooleanClause[]): string {
|
package/src/clause_types.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
export type NumberOperator = '<=' | '>=' | '!=' | '=' | '>' | '<';
|
|
2
2
|
|
|
3
|
-
export type NumberValue = number
|
|
3
|
+
export type NumberValue = number;
|
|
4
4
|
|
|
5
5
|
export interface NumberCondition {
|
|
6
6
|
operator: NumberOperator;
|
|
7
7
|
values: NumberValue[];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface NumberNull {
|
|
11
|
+
operator: 'NULL';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface NumberNotNull {
|
|
15
|
+
operator: 'NOTNULL';
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
export type NumberRangeOperator = '<=' | '>=' | '>' | '<';
|
|
11
19
|
|
|
12
20
|
export interface NumberRange {
|
|
@@ -17,19 +25,13 @@ export interface NumberRange {
|
|
|
17
25
|
endValue: NumberValue;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
|
-
export type
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
| 'TRIPLEDOUBLE'
|
|
26
|
-
| 'ESCAPEDSINGLE'
|
|
27
|
-
| 'ESCAPEDDOUBLE'
|
|
28
|
-
| 'ESCAPEDBACKTICK';
|
|
28
|
+
export type NumberClause =
|
|
29
|
+
| NumberCondition
|
|
30
|
+
| NumberRange
|
|
31
|
+
| NumberNull
|
|
32
|
+
| NumberNotNull;
|
|
29
33
|
|
|
30
|
-
export type
|
|
31
|
-
| 'EMPTY'
|
|
32
|
-
| 'NOTEMPTY'
|
|
34
|
+
export type StringConditionOperator =
|
|
33
35
|
| 'starts'
|
|
34
36
|
| 'ends'
|
|
35
37
|
| 'contains'
|
|
@@ -41,22 +43,47 @@ export type StringOperator =
|
|
|
41
43
|
| '!~'
|
|
42
44
|
| '!=';
|
|
43
45
|
|
|
44
|
-
export type StringValue = string
|
|
46
|
+
export type StringValue = string;
|
|
45
47
|
|
|
46
|
-
export interface
|
|
47
|
-
operator:
|
|
48
|
+
export interface StringCondition {
|
|
49
|
+
operator: StringConditionOperator;
|
|
48
50
|
values: StringValue[];
|
|
49
|
-
quotes?: QuoteType[]; // List of quote types found in the string.
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
export
|
|
53
|
+
export interface StringNull {
|
|
54
|
+
operator: 'NULL';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface StringNotNull {
|
|
58
|
+
operator: 'NOTNULL';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface StringEmpty {
|
|
62
|
+
operator: 'EMPTY';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface StringNotEmpty {
|
|
66
|
+
operator: 'NOTEMPTY';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type StringClause =
|
|
70
|
+
| StringCondition
|
|
71
|
+
| StringNull
|
|
72
|
+
| StringNotNull
|
|
73
|
+
| StringEmpty
|
|
74
|
+
| StringNotEmpty;
|
|
75
|
+
|
|
76
|
+
export type BooleanOperator =
|
|
77
|
+
| 'TRUE'
|
|
78
|
+
| 'FALSE'
|
|
79
|
+
| 'FALSEORNULL'
|
|
80
|
+
| 'NULL'
|
|
81
|
+
| 'NOTNULL';
|
|
53
82
|
|
|
54
83
|
export interface BooleanClause {
|
|
55
84
|
operator: BooleanOperator;
|
|
56
85
|
}
|
|
57
86
|
|
|
58
|
-
export type NumberClause = NumberCondition | NumberRange;
|
|
59
|
-
|
|
60
87
|
export interface FilterError {
|
|
61
88
|
message: string;
|
|
62
89
|
startIndex: number;
|
|
@@ -72,7 +99,19 @@ export interface NumberParserResponse {
|
|
|
72
99
|
clauses: NumberClause[];
|
|
73
100
|
errors: FilterError[];
|
|
74
101
|
}
|
|
102
|
+
|
|
103
|
+
export type QuoteType =
|
|
104
|
+
| 'SINGLE'
|
|
105
|
+
| 'DOUBLE'
|
|
106
|
+
| 'BACKTICK'
|
|
107
|
+
| 'TRIPLESINGLE'
|
|
108
|
+
| 'TRIPLEDOUBLE'
|
|
109
|
+
| 'ESCAPEDSINGLE'
|
|
110
|
+
| 'ESCAPEDDOUBLE'
|
|
111
|
+
| 'ESCAPEDBACKTICK';
|
|
112
|
+
|
|
75
113
|
export interface StringParserResponse {
|
|
76
114
|
clauses: StringClause[];
|
|
77
115
|
errors: FilterError[];
|
|
116
|
+
quotes?: QuoteType[]; // List of quote types found in the string.
|
|
78
117
|
}
|
package/src/date_parser.ts
CHANGED
|
@@ -168,7 +168,9 @@ export class DateParser extends BaseParser {
|
|
|
168
168
|
prefix = undefined;
|
|
169
169
|
} else {
|
|
170
170
|
errors.push({
|
|
171
|
-
message:
|
|
171
|
+
message:
|
|
172
|
+
'Invalid token ' + token.value ||
|
|
173
|
+
(token.values ? token.values.join(' ') : ''),
|
|
172
174
|
startIndex: token.startIndex,
|
|
173
175
|
endIndex: token.endIndex,
|
|
174
176
|
});
|
|
@@ -440,6 +442,8 @@ export class DateParser extends BaseParser {
|
|
|
440
442
|
}
|
|
441
443
|
clauses.push(clause);
|
|
442
444
|
return true;
|
|
445
|
+
} else if (token.type === 'NULL' || token.type === 'NOTNULL') {
|
|
446
|
+
clauses.push({operator: token.type});
|
|
443
447
|
}
|
|
444
448
|
return false;
|
|
445
449
|
}
|
package/src/date_serializer.ts
CHANGED
|
@@ -64,6 +64,10 @@ export class DateSerializer {
|
|
|
64
64
|
return 'AFTER ' + DateSerializer.dateMomentToString(clause.moment);
|
|
65
65
|
} else if (clause.operator === 'ON') {
|
|
66
66
|
return DateSerializer.dateMomentToString(clause.moment);
|
|
67
|
+
} else if (clause.operator === 'NULL') {
|
|
68
|
+
return 'NULL';
|
|
69
|
+
} else if (clause.operator === 'NOTNULL') {
|
|
70
|
+
return '-NULL';
|
|
67
71
|
} else if (clause.operator === 'DURATION') {
|
|
68
72
|
return clause.duration.amount + ' ' + clause.duration.unit;
|
|
69
73
|
} else {
|
package/src/date_types.ts
CHANGED
|
@@ -129,6 +129,14 @@ export interface DateForClause {
|
|
|
129
129
|
duration: Duration;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
export interface DateNullClause {
|
|
133
|
+
operator: 'NULL';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface DateNotNullClause {
|
|
137
|
+
operator: 'NOTNULL';
|
|
138
|
+
}
|
|
139
|
+
|
|
132
140
|
// 3 days
|
|
133
141
|
export interface DateDurationClause {
|
|
134
142
|
operator: 'DURATION';
|
|
@@ -141,6 +149,8 @@ export type DateClause =
|
|
|
141
149
|
| DateOnClause
|
|
142
150
|
| DateBetweenClause
|
|
143
151
|
| DateForClause
|
|
152
|
+
| DateNullClause
|
|
153
|
+
| DateNotNullClause
|
|
144
154
|
| DateDurationClause;
|
|
145
155
|
|
|
146
156
|
export interface DateParserResponse {
|
package/src/generate_samples.ts
CHANGED
|
@@ -15,7 +15,7 @@ type Clause = BooleanClause | DateClause | NumberClause | StringClause;
|
|
|
15
15
|
const numberExamples = [
|
|
16
16
|
'5',
|
|
17
17
|
'!=5',
|
|
18
|
-
'1, 3,
|
|
18
|
+
'1, 3, 5, null',
|
|
19
19
|
'<1, >=100 ',
|
|
20
20
|
'>=1',
|
|
21
21
|
' <= 10 ',
|
|
@@ -70,9 +70,10 @@ const stringExamples = [
|
|
|
70
70
|
const booleanExamples = [
|
|
71
71
|
'true',
|
|
72
72
|
'FALSE',
|
|
73
|
+
'=false',
|
|
73
74
|
'null',
|
|
74
75
|
'-NULL',
|
|
75
|
-
' True , faLSE,NULl,-null',
|
|
76
|
+
' True , faLSE,=false,NULl,-null',
|
|
76
77
|
"-'null'",
|
|
77
78
|
'10',
|
|
78
79
|
'nnull',
|
|
@@ -104,6 +105,8 @@ const dateExamples = [
|
|
|
104
105
|
'next week',
|
|
105
106
|
'now',
|
|
106
107
|
'now to next month',
|
|
108
|
+
'null',
|
|
109
|
+
'-null,',
|
|
107
110
|
' yyesterday ', // Typo
|
|
108
111
|
'before', // Bad syntax
|
|
109
112
|
'for', // Bad syntax
|
|
@@ -251,6 +254,9 @@ function testStringParserSingle(
|
|
|
251
254
|
console.log('Output: ', ...response.clauses);
|
|
252
255
|
}
|
|
253
256
|
}
|
|
257
|
+
if (response.quotes) {
|
|
258
|
+
console.log('Quotes: ', ...response.quotes);
|
|
259
|
+
}
|
|
254
260
|
if (response.errors && response.errors.length > 0) {
|
|
255
261
|
console.log('Errors: ', ...response.errors);
|
|
256
262
|
}
|
package/src/number_parser.ts
CHANGED
|
@@ -98,7 +98,9 @@ export class NumberParser extends BaseParser {
|
|
|
98
98
|
outputs.push(clause);
|
|
99
99
|
} else if (
|
|
100
100
|
previous !== undefined &&
|
|
101
|
-
previous.operator === clause.operator
|
|
101
|
+
previous.operator === clause.operator &&
|
|
102
|
+
'values' in previous &&
|
|
103
|
+
'values' in clause
|
|
102
104
|
) {
|
|
103
105
|
previous.values.push(...clause.values);
|
|
104
106
|
} else {
|
|
@@ -204,59 +206,6 @@ export class NumberParser extends BaseParser {
|
|
|
204
206
|
return clauses;
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
private static getNegatedType(tokenType: NumberOperator): NumberOperator {
|
|
208
|
-
switch (tokenType) {
|
|
209
|
-
case '<=':
|
|
210
|
-
return '>';
|
|
211
|
-
case '>=':
|
|
212
|
-
return '<';
|
|
213
|
-
case '<':
|
|
214
|
-
return '>';
|
|
215
|
-
case '>':
|
|
216
|
-
return '<';
|
|
217
|
-
case '=':
|
|
218
|
-
return '!=';
|
|
219
|
-
case '!=':
|
|
220
|
-
return '=';
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private static getNumberOperator(
|
|
225
|
-
tokenType: string
|
|
226
|
-
): NumberOperator | undefined {
|
|
227
|
-
switch (tokenType) {
|
|
228
|
-
case '<=':
|
|
229
|
-
return '<=';
|
|
230
|
-
case '>=':
|
|
231
|
-
return '>=';
|
|
232
|
-
case '<':
|
|
233
|
-
return '<';
|
|
234
|
-
case '>':
|
|
235
|
-
return '>';
|
|
236
|
-
case '=':
|
|
237
|
-
return '=';
|
|
238
|
-
case '!=':
|
|
239
|
-
return '!=';
|
|
240
|
-
}
|
|
241
|
-
return undefined;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
private static getNumberRnageOperator(
|
|
245
|
-
tokenType: string
|
|
246
|
-
): NumberRangeOperator | undefined {
|
|
247
|
-
switch (tokenType) {
|
|
248
|
-
case '<=':
|
|
249
|
-
return '<=';
|
|
250
|
-
case '>=':
|
|
251
|
-
return '>=';
|
|
252
|
-
case '<':
|
|
253
|
-
return '<';
|
|
254
|
-
case '>':
|
|
255
|
-
return '>';
|
|
256
|
-
}
|
|
257
|
-
return undefined;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
209
|
private checkNumericExpression(
|
|
261
210
|
tokenType: NumberOperator,
|
|
262
211
|
clauses: NumberClause[]
|
|
@@ -297,10 +246,12 @@ export class NumberParser extends BaseParser {
|
|
|
297
246
|
}
|
|
298
247
|
|
|
299
248
|
private checkNull(clauses: NumberClause[]): boolean {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
249
|
+
const type = this.getNext().type;
|
|
250
|
+
if (type === 'NULL') {
|
|
251
|
+
clauses.push({operator: 'NULL'});
|
|
252
|
+
return true;
|
|
253
|
+
} else if (type === 'NOTNULL') {
|
|
254
|
+
clauses.push({operator: 'NOTNULL'});
|
|
304
255
|
return true;
|
|
305
256
|
}
|
|
306
257
|
return false;
|
package/src/number_serializer.ts
CHANGED
|
@@ -16,15 +16,13 @@ export class NumberSerializer {
|
|
|
16
16
|
return result.trim().replace(/,$/, '');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// NumberOperator = '<=' | '>=' | '!=' | '=' | '>' | '<'
|
|
19
|
+
// NumberOperator = '<=' | '>=' | '!=' | '=' | '>' | '<'
|
|
20
20
|
private static numberConditionToString(
|
|
21
21
|
operator: NumberOperator,
|
|
22
|
-
value: number
|
|
22
|
+
value: number
|
|
23
23
|
): string {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
const operatorString = operator === '=' ? '' : operator; // Remove operator for eg "5, 7, 9"
|
|
24
|
+
// Remove operator for eg "5, 7, 9".
|
|
25
|
+
const operatorString = operator === '=' ? '' : operator;
|
|
28
26
|
return operatorString + value;
|
|
29
27
|
}
|
|
30
28
|
|
|
@@ -43,7 +41,7 @@ export class NumberSerializer {
|
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
private static isNumberOperator(value: string):
|
|
44
|
+
private static isNumberOperator(value: string): boolean {
|
|
47
45
|
return ['<=', '>=', '!=', '=', '>', '<'].includes(value);
|
|
48
46
|
}
|
|
49
47
|
|
|
@@ -71,13 +69,17 @@ export class NumberSerializer {
|
|
|
71
69
|
private static clauseToString(clauses: NumberClause[]): string {
|
|
72
70
|
let result = '';
|
|
73
71
|
for (const clause of clauses) {
|
|
74
|
-
if ('operator' in clause
|
|
72
|
+
if (!('operator' in clause)) {
|
|
73
|
+
throw new Error('Invalid number clause ' + JSON.stringify(clause));
|
|
74
|
+
}
|
|
75
|
+
if (clause.operator === 'range') {
|
|
75
76
|
result += NumberSerializer.rangeToString(clause);
|
|
76
77
|
result += ', ';
|
|
77
|
-
} else if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
} else if (clause.operator === 'NULL') {
|
|
79
|
+
result += 'NULL, ';
|
|
80
|
+
} else if (clause.operator === 'NOTNULL') {
|
|
81
|
+
result += '-NULL, ';
|
|
82
|
+
} else if (NumberSerializer.isNumberOperator(clause.operator)) {
|
|
81
83
|
const numberClause: NumberCondition = clause as NumberCondition;
|
|
82
84
|
for (const value of numberClause.values) {
|
|
83
85
|
result += NumberSerializer.numberConditionToString(
|
|
@@ -86,8 +88,6 @@ export class NumberSerializer {
|
|
|
86
88
|
);
|
|
87
89
|
result += ', ';
|
|
88
90
|
}
|
|
89
|
-
} else {
|
|
90
|
-
throw new Error('Invalid number clause ' + JSON.stringify(clause));
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
return result;
|