@malloydata/malloy-filter 0.0.237-dev250222034547 → 0.0.237-dev250223010918
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/README.md +32 -22
- package/SAMPLES.md +154 -75
- package/SERIALIZE_SAMPLES.md +37 -24
- 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 +177 -271
- 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 +3 -10
- 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 +201 -298
- 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
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;
|
package/src/string_parser.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
|
|
2
2
|
import {
|
|
3
3
|
StringClause,
|
|
4
|
-
|
|
4
|
+
StringCondition,
|
|
5
|
+
StringConditionOperator,
|
|
5
6
|
QuoteType,
|
|
6
7
|
FilterError,
|
|
7
8
|
StringParserResponse,
|
|
@@ -49,17 +50,13 @@ export class StringParser extends BaseParser {
|
|
|
49
50
|
const token = this.getNext();
|
|
50
51
|
if (token.type === ',') {
|
|
51
52
|
this.index++;
|
|
52
|
-
} else if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
clauses.push({operator: '!=', values: [null]});
|
|
60
|
-
this.index++;
|
|
61
|
-
} else if (token.type === 'NOTEMPTY') {
|
|
62
|
-
clauses.push({operator: 'NOTEMPTY', values: [null]});
|
|
53
|
+
} else if (
|
|
54
|
+
token.type === 'NULL' ||
|
|
55
|
+
token.type === 'NOTNULL' ||
|
|
56
|
+
token.type === 'EMPTY' ||
|
|
57
|
+
token.type === 'NOTEMPTY'
|
|
58
|
+
) {
|
|
59
|
+
clauses.push({operator: token.type});
|
|
63
60
|
this.index++;
|
|
64
61
|
} else if (this.checkSimpleWord(clauses)) {
|
|
65
62
|
this.index++;
|
|
@@ -72,7 +69,15 @@ export class StringParser extends BaseParser {
|
|
|
72
69
|
this.index++;
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
|
-
|
|
72
|
+
const response: StringParserResponse = {
|
|
73
|
+
clauses: StringParser.groupClauses(clauses),
|
|
74
|
+
errors,
|
|
75
|
+
};
|
|
76
|
+
const quotes: QuoteType[] = StringParser.findQuotes(this.inputString);
|
|
77
|
+
if (quotes.length > 0) {
|
|
78
|
+
response.quotes = quotes;
|
|
79
|
+
}
|
|
80
|
+
return response;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
private static findQuotes(str: string): QuoteType[] {
|
|
@@ -131,11 +136,16 @@ export class StringParser extends BaseParser {
|
|
|
131
136
|
let previous: StringClause = clauses[0];
|
|
132
137
|
const outputs: StringClause[] = [previous];
|
|
133
138
|
for (let i = 1; i < clauses.length; i++) {
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
const current = clauses[i];
|
|
140
|
+
if (
|
|
141
|
+
previous.operator === current.operator &&
|
|
142
|
+
'values' in previous &&
|
|
143
|
+
'values' in current
|
|
144
|
+
) {
|
|
145
|
+
previous.values.push(...current.values);
|
|
136
146
|
} else {
|
|
137
|
-
previous =
|
|
138
|
-
outputs.push(
|
|
147
|
+
previous = current;
|
|
148
|
+
outputs.push(current);
|
|
139
149
|
}
|
|
140
150
|
}
|
|
141
151
|
return outputs;
|
|
@@ -166,7 +176,7 @@ export class StringParser extends BaseParser {
|
|
|
166
176
|
const isUnderscore = StringParser.underscoreRegex.test(word);
|
|
167
177
|
const isPercentMiddle = StringParser.percentInMiddle(word);
|
|
168
178
|
|
|
169
|
-
let operator:
|
|
179
|
+
let operator: StringConditionOperator = negatedMatch ? '!=' : '=';
|
|
170
180
|
if (isUnderscore || isPercentMiddle || (isPercentBoth && word.length < 3)) {
|
|
171
181
|
operator = negatedMatch ? '!~' : '~';
|
|
172
182
|
} else if (isPercentBoth && word.length > 2) {
|
|
@@ -189,9 +199,7 @@ export class StringParser extends BaseParser {
|
|
|
189
199
|
return false;
|
|
190
200
|
}
|
|
191
201
|
|
|
192
|
-
const clause:
|
|
193
|
-
//const quotes: QuoteType[] = StringParser.findQuotes(word);
|
|
194
|
-
//if (quotes.length > 0) { clause.quotes = quotes; }
|
|
202
|
+
const clause: StringCondition = {operator: operator, values: [word]};
|
|
195
203
|
clauses.push(clause);
|
|
196
204
|
return true;
|
|
197
205
|
}
|
package/src/string_serializer.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
StringClause,
|
|
3
|
+
StringCondition,
|
|
4
|
+
StringConditionOperator,
|
|
5
|
+
} from './clause_types';
|
|
2
6
|
|
|
3
7
|
export class StringSerializer {
|
|
4
8
|
constructor(private clauses: StringClause[]) {
|
|
@@ -10,9 +14,8 @@ export class StringSerializer {
|
|
|
10
14
|
return result.trim().replace(/,$/, '');
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
private static isNegated(operator:
|
|
17
|
+
private static isNegated(operator: StringConditionOperator): boolean {
|
|
14
18
|
return (
|
|
15
|
-
operator === 'NOTEMPTY' ||
|
|
16
19
|
operator === '!~' ||
|
|
17
20
|
operator === '!=' ||
|
|
18
21
|
operator === 'notStarts' ||
|
|
@@ -29,22 +32,14 @@ export class StringSerializer {
|
|
|
29
32
|
return input.replace(/[_%]/g, match => `\\${match}`);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
// export type StringOperator =
|
|
33
|
-
// '
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// export type StringOperator =
|
|
36
|
+
// | 'starts' | 'ends' | 'contains' | 'notStarts' | 'notEnds' | 'notContains'
|
|
37
|
+
// | '~' | '=' | '!~' | '!=';
|
|
38
|
+
private static StringConditionWordToString(
|
|
39
|
+
operator: StringConditionOperator,
|
|
40
|
+
value: string
|
|
37
41
|
): string {
|
|
38
|
-
if (operator === 'EMPTY') {
|
|
39
|
-
return 'EMPTY';
|
|
40
|
-
} else if (operator === 'NOTEMPTY') {
|
|
41
|
-
return '-EMPTY';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
42
|
const negated: boolean = StringSerializer.isNegated(operator);
|
|
45
|
-
if (value === null) {
|
|
46
|
-
return negated ? '-NULL' : 'NULL';
|
|
47
|
-
}
|
|
48
43
|
if (value === 'NULL' || value === '-NULL') {
|
|
49
44
|
return (negated ? '-' : '') + '\\' + value;
|
|
50
45
|
}
|
|
@@ -67,18 +62,50 @@ export class StringSerializer {
|
|
|
67
62
|
return (negated ? '-' : '') + value;
|
|
68
63
|
}
|
|
69
64
|
|
|
65
|
+
private static StringClauseToString(
|
|
66
|
+
operator:
|
|
67
|
+
| StringConditionOperator
|
|
68
|
+
| 'EMPTY'
|
|
69
|
+
| 'NOTEMPTY'
|
|
70
|
+
| 'NULL'
|
|
71
|
+
| 'NOTNULL',
|
|
72
|
+
clause: StringClause
|
|
73
|
+
): string {
|
|
74
|
+
if (operator === 'EMPTY') {
|
|
75
|
+
return 'EMPTY';
|
|
76
|
+
} else if (operator === 'NOTEMPTY') {
|
|
77
|
+
return '-EMPTY';
|
|
78
|
+
} else if (operator === 'NULL') {
|
|
79
|
+
return 'NULL';
|
|
80
|
+
} else if (operator === 'NOTNULL') {
|
|
81
|
+
return '-NULL';
|
|
82
|
+
}
|
|
83
|
+
if (!('values' in clause) || clause.values.length === 0) {
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
let result = '';
|
|
87
|
+
const condition: StringCondition = clause;
|
|
88
|
+
for (const value of condition.values) {
|
|
89
|
+
const word = StringSerializer.StringConditionWordToString(
|
|
90
|
+
condition.operator,
|
|
91
|
+
value
|
|
92
|
+
);
|
|
93
|
+
if (word) {
|
|
94
|
+
result += word + ', ';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result.trim().replace(/,$/, '');
|
|
98
|
+
}
|
|
99
|
+
|
|
70
100
|
private static clauseToString(clauses: StringClause[]): string {
|
|
71
101
|
let result = '';
|
|
72
|
-
for (const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (word) {
|
|
80
|
-
result += word + ', ';
|
|
81
|
-
}
|
|
102
|
+
for (const clause of clauses) {
|
|
103
|
+
const words = StringSerializer.StringClauseToString(
|
|
104
|
+
clause.operator,
|
|
105
|
+
clause
|
|
106
|
+
);
|
|
107
|
+
if (words) {
|
|
108
|
+
result += words + ', ';
|
|
82
109
|
}
|
|
83
110
|
}
|
|
84
111
|
return result;
|