@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/generate_samples.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as fs from 'fs';
|
|
2
2
|
import {BooleanParser} from './boolean_parser';
|
|
3
3
|
import {StringParser} from './string_parser';
|
|
4
4
|
import {NumberParser} from './number_parser';
|
|
@@ -7,15 +7,11 @@ import {BooleanSerializer} from './boolean_serializer';
|
|
|
7
7
|
import {StringSerializer} from './string_serializer';
|
|
8
8
|
import {NumberSerializer} from './number_serializer';
|
|
9
9
|
import {DateSerializer} from './date_serializer';
|
|
10
|
-
import {BooleanClause, NumberClause, StringClause} from './clause_types';
|
|
11
|
-
import {DateClause} from './date_types';
|
|
12
|
-
|
|
13
|
-
type Clause = BooleanClause | DateClause | NumberClause | StringClause;
|
|
14
10
|
|
|
15
11
|
const numberExamples = [
|
|
16
12
|
'5',
|
|
17
13
|
'!=5',
|
|
18
|
-
'1, 3,
|
|
14
|
+
'1, 3, 5, null',
|
|
19
15
|
'<1, >=100 ',
|
|
20
16
|
'>=1',
|
|
21
17
|
' <= 10 ',
|
|
@@ -70,9 +66,10 @@ const stringExamples = [
|
|
|
70
66
|
const booleanExamples = [
|
|
71
67
|
'true',
|
|
72
68
|
'FALSE',
|
|
69
|
+
'=false',
|
|
73
70
|
'null',
|
|
74
71
|
'-NULL',
|
|
75
|
-
' True , faLSE,NULl,-null',
|
|
72
|
+
' True , faLSE,=false,NULl,-null',
|
|
76
73
|
"-'null'",
|
|
77
74
|
'10',
|
|
78
75
|
'nnull',
|
|
@@ -84,7 +81,6 @@ const dateExamples = [
|
|
|
84
81
|
'3 days',
|
|
85
82
|
'3 days ago',
|
|
86
83
|
'3 months ago for 2 days',
|
|
87
|
-
'after 2025 seconds',
|
|
88
84
|
'2025 weeks ago',
|
|
89
85
|
'before 3 days ago',
|
|
90
86
|
'before 2025-08-30 08:30:20',
|
|
@@ -104,341 +100,248 @@ const dateExamples = [
|
|
|
104
100
|
'next week',
|
|
105
101
|
'now',
|
|
106
102
|
'now to next month',
|
|
103
|
+
'null',
|
|
104
|
+
'-null,',
|
|
107
105
|
' yyesterday ', // Typo
|
|
108
106
|
'before', // Bad syntax
|
|
109
107
|
'for', // Bad syntax
|
|
110
108
|
'7', // Bad syntax
|
|
111
109
|
'from now', // Bad syntax
|
|
112
110
|
'2025-12-25 12:32:', // Bad syntax
|
|
111
|
+
'after 2025 seconds', // Bad syntax
|
|
113
112
|
'',
|
|
114
113
|
];
|
|
115
114
|
|
|
116
115
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
117
116
|
/* eslint-disable no-console */
|
|
117
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// Test string parser tokenizer. Do not split on whitespace
|
|
126
|
-
const specialSubstrings: SpecialToken[] = [{type: ',', value: ','}];
|
|
127
|
-
const specialWords: SpecialToken[] = [];
|
|
128
|
-
const params: TokenizerParams = {
|
|
129
|
-
trimWordWhitespace: true,
|
|
130
|
-
combineAdjacentWords: true,
|
|
131
|
-
specialSubstrings,
|
|
132
|
-
specialWords,
|
|
133
|
-
};
|
|
134
|
-
const examples = [
|
|
135
|
-
'CAT, DOG,mouse ',
|
|
136
|
-
'-CAT,-DOG , -mouse',
|
|
137
|
-
' CAT,-"DOG",m o u s e',
|
|
138
|
-
'-CAT,-DOG,mouse, bird, zebra, -horse, -goat',
|
|
139
|
-
'Missing ,NULL',
|
|
140
|
-
'CAT%,D%OG',
|
|
141
|
-
'CAT%,-CATALOG',
|
|
142
|
-
'_CAT,D_G',
|
|
143
|
-
'CAT,-NULL',
|
|
144
|
-
'CAT,-"NULL"',
|
|
145
|
-
'EMPTY',
|
|
146
|
-
'-EMPTY',
|
|
147
|
-
'CAT,-EMPTY',
|
|
148
|
-
'"CAT,DOG"',
|
|
149
|
-
'CAT\\,DOG',
|
|
150
|
-
'CAT,DOG,-, - ',
|
|
151
|
-
'--CAT,DOG,\\',
|
|
152
|
-
'CA--,D-G', // _ = 'CA--' OR _ = 'D-G'
|
|
153
|
-
' hello world, foo="bar baz" , qux=quux',
|
|
154
|
-
'one ,Null , Empty,E M P T Y Y,EEmpty, emptIEs',
|
|
155
|
-
'',
|
|
156
|
-
];
|
|
157
|
-
for (const example of examples) {
|
|
158
|
-
testTokenizerSingle(example, params);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function testTokenizerNumber() {
|
|
163
|
-
// Test number parser tokenizer, split on whitespace
|
|
164
|
-
const specialSubstrings: SpecialToken[] = [
|
|
165
|
-
{type: ',', value: ','},
|
|
166
|
-
{type: '[', value: '['},
|
|
167
|
-
{type: ']', value: ']'},
|
|
168
|
-
{type: '(', value: '('},
|
|
169
|
-
{type: ')', value: ')'},
|
|
170
|
-
{type: '<=', value: '<='},
|
|
171
|
-
{type: '>=', value: '>='},
|
|
172
|
-
{type: '!=', value: '!='},
|
|
173
|
-
{type: '=', value: '='},
|
|
174
|
-
{type: '>', value: '>'},
|
|
175
|
-
{type: '<', value: '<'},
|
|
176
|
-
];
|
|
177
|
-
const specialWords: SpecialToken[] = [
|
|
178
|
-
{type: 'TO', value: 'to', ignoreCase: true},
|
|
179
|
-
{type: '-NULL', value: '-null', ignoreCase: true},
|
|
180
|
-
{type: 'NULL', value: 'null', ignoreCase: true},
|
|
181
|
-
];
|
|
182
|
-
const params: TokenizerParams = {
|
|
183
|
-
trimWordWhitespace: true,
|
|
184
|
-
combineAdjacentWords: false,
|
|
185
|
-
splitOnWhitespace: true,
|
|
186
|
-
specialSubstrings,
|
|
187
|
-
specialWords,
|
|
188
|
-
};
|
|
189
|
-
const examples = [
|
|
190
|
-
'5',
|
|
191
|
-
'!=5',
|
|
192
|
-
'1, 3, null , 7',
|
|
193
|
-
'<1, >=100 ',
|
|
194
|
-
'-5.5 to 10',
|
|
195
|
-
'>=1',
|
|
196
|
-
' <= 10 ',
|
|
197
|
-
'NULL',
|
|
198
|
-
' -NULL',
|
|
199
|
-
'(1, 7)',
|
|
200
|
-
'[-5, 90]',
|
|
201
|
-
' ( 12, 20 ] ',
|
|
202
|
-
'[.12e-20, 20.0e3)',
|
|
203
|
-
'[0,9],[20,29]',
|
|
204
|
-
'[0,10], 20, NULL, ( 72, 82 ] ',
|
|
205
|
-
', notanumber,, -"-null", apple pear orange, nulle, nnull',
|
|
206
|
-
];
|
|
207
|
-
for (const example of examples) {
|
|
208
|
-
testTokenizerSingle(example, params);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
119
|
+
class GenerateSamples {
|
|
120
|
+
public samplesFile: fs.WriteStream = fs.createWriteStream('dist/SAMPLES.md');
|
|
121
|
+
public serializedFile: fs.WriteStream = fs.createWriteStream(
|
|
122
|
+
'dist/SERIALIZE_SAMPLES.md'
|
|
123
|
+
);
|
|
124
|
+
constructor() {}
|
|
211
125
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
): void {
|
|
216
|
-
console.log('Input: ', str);
|
|
217
|
-
const parser = new NumberParser(str);
|
|
218
|
-
const response = parser.parse();
|
|
219
|
-
// console.log('Tokens: ', parser.getTokens());
|
|
220
|
-
if (response.clauses && response.clauses.length > 0) {
|
|
221
|
-
if (outputFormatter) {
|
|
222
|
-
console.log('Output: ', outputFormatter(response.clauses));
|
|
223
|
-
} else {
|
|
224
|
-
console.log('Output: ', ...response.clauses);
|
|
126
|
+
private static removeQuotes(word: string) {
|
|
127
|
+
if (word.startsWith('"')) {
|
|
128
|
+
word = word.substring(1);
|
|
225
129
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
console.log('Errors: ', ...response.errors);
|
|
229
|
-
}
|
|
230
|
-
console.log('');
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function testNumberParser() {
|
|
234
|
-
for (const example of numberExamples) {
|
|
235
|
-
testNumberParserSingle(example);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function testStringParserSingle(
|
|
240
|
-
str: string,
|
|
241
|
-
outputFormatter?: (clauses: Clause[]) => string
|
|
242
|
-
): void {
|
|
243
|
-
console.log('Input: ', str);
|
|
244
|
-
const parser = new StringParser(str);
|
|
245
|
-
const response = parser.parse();
|
|
246
|
-
// console.log('Tokens: ', parser.getTokens());
|
|
247
|
-
if (response.clauses && response.clauses.length > 0) {
|
|
248
|
-
if (outputFormatter) {
|
|
249
|
-
console.log('Output: ', outputFormatter(response.clauses));
|
|
250
|
-
} else {
|
|
251
|
-
console.log('Output: ', ...response.clauses);
|
|
130
|
+
if (word.endsWith('"')) {
|
|
131
|
+
word = word.substring(0, word.length - 1);
|
|
252
132
|
}
|
|
133
|
+
return word;
|
|
253
134
|
}
|
|
254
|
-
if (response.errors && response.errors.length > 0) {
|
|
255
|
-
console.log('Errors: ', ...response.errors);
|
|
256
|
-
}
|
|
257
|
-
console.log('');
|
|
258
|
-
}
|
|
259
135
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
136
|
+
private static writeJson(
|
|
137
|
+
fp: fs.WriteStream,
|
|
138
|
+
title: string,
|
|
139
|
+
...args: any[]
|
|
140
|
+
): void {
|
|
141
|
+
const result: string[] = args.map(str => JSON.stringify(str));
|
|
142
|
+
const result2: string[] = result.map(str =>
|
|
143
|
+
GenerateSamples.removeQuotes(str)
|
|
144
|
+
);
|
|
145
|
+
fp.write(title + ' ' + result2.join(' ') + '\n');
|
|
146
|
+
console.log(title, ...args);
|
|
264
147
|
}
|
|
265
|
-
}
|
|
266
148
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
): void {
|
|
271
|
-
console.log('Input: ', str);
|
|
272
|
-
const parser = new BooleanParser(str);
|
|
273
|
-
const response = parser.parse();
|
|
274
|
-
// console.log('Tokens: ', parser.getTokens());
|
|
275
|
-
if (response.clauses && response.clauses.length > 0) {
|
|
276
|
-
if (outputFormatter) {
|
|
277
|
-
console.log('Output: ', outputFormatter(response.clauses));
|
|
278
|
-
} else {
|
|
279
|
-
console.log('Output: ', ...response.clauses);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (response.errors && response.errors.length > 0) {
|
|
283
|
-
console.log('Errors: ', ...response.errors);
|
|
149
|
+
public static writeRaw(fp: fs.WriteStream, ...args: any[]): void {
|
|
150
|
+
fp.write(args.join(' ') + '\n');
|
|
151
|
+
console.log(...args);
|
|
284
152
|
}
|
|
285
|
-
console.log('');
|
|
286
|
-
}
|
|
287
153
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const parser = new BooleanParser(
|
|
291
|
-
|
|
154
|
+
public booleanSample(str: string, fp: fs.WriteStream): void {
|
|
155
|
+
GenerateSamples.writeRaw(fp, 'Input: ', str);
|
|
156
|
+
const parser = new BooleanParser(str);
|
|
157
|
+
const response = parser.parse();
|
|
158
|
+
// GenerateSamples.writeJson(fp, 'Tokens: ', parser.getTokens());
|
|
159
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
160
|
+
GenerateSamples.writeJson(fp, 'Output: ', ...response.clauses);
|
|
161
|
+
}
|
|
162
|
+
if (response.errors && response.errors.length > 0) {
|
|
163
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
164
|
+
}
|
|
165
|
+
GenerateSamples.writeRaw(fp, '');
|
|
292
166
|
}
|
|
293
|
-
}
|
|
294
167
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
168
|
+
public dateSample(str: string, fp: fs.WriteStream): void {
|
|
169
|
+
GenerateSamples.writeRaw(fp, 'Input: ', str);
|
|
170
|
+
const parser = new DateParser(str);
|
|
171
|
+
const response = parser.parse();
|
|
172
|
+
// GenerateSamples.writeJson(fp, 'Tokens: ', parser.getTokens());
|
|
173
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
174
|
+
GenerateSamples.writeJson(fp, 'Output: ', ...response.clauses);
|
|
175
|
+
}
|
|
176
|
+
if (response.errors && response.errors.length > 0) {
|
|
177
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
178
|
+
}
|
|
179
|
+
GenerateSamples.writeRaw(fp, '');
|
|
299
180
|
}
|
|
300
|
-
return str;
|
|
301
|
-
}
|
|
302
181
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// console.log('Tokens: ', parser.getTokens());
|
|
311
|
-
if (response.clauses && response.clauses.length > 0) {
|
|
312
|
-
if (outputFormatter) {
|
|
313
|
-
console.log('Output: ', outputFormatter(response.clauses));
|
|
314
|
-
} else {
|
|
315
|
-
console.log('Output: ', ...response.clauses);
|
|
182
|
+
public numberSample(str: string, fp: fs.WriteStream): void {
|
|
183
|
+
GenerateSamples.writeRaw(fp, 'Input: ', str);
|
|
184
|
+
const parser = new NumberParser(str);
|
|
185
|
+
const response = parser.parse();
|
|
186
|
+
// GenerateSamples.writeJson(fp, 'Tokens: ', parser.getTokens());
|
|
187
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
188
|
+
GenerateSamples.writeJson(fp, 'Output: ', ...response.clauses);
|
|
316
189
|
}
|
|
190
|
+
if (response.errors && response.errors.length > 0) {
|
|
191
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
192
|
+
}
|
|
193
|
+
GenerateSamples.writeRaw(fp, '');
|
|
317
194
|
}
|
|
318
|
-
if (response.errors && response.errors.length > 0) {
|
|
319
|
-
console.log('Errors: ', ...response.errors);
|
|
320
|
-
}
|
|
321
|
-
console.log('');
|
|
322
|
-
}
|
|
323
195
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const parser = new
|
|
327
|
-
|
|
196
|
+
public stringSample(str: string, fp: fs.WriteStream): void {
|
|
197
|
+
GenerateSamples.writeRaw(fp, 'Input: ', str);
|
|
198
|
+
const parser = new StringParser(str);
|
|
199
|
+
const response = parser.parse();
|
|
200
|
+
// GenerateSamples.writeJson(fp, 'Tokens: ', parser.getTokens());
|
|
201
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
202
|
+
GenerateSamples.writeJson(fp, 'Output: ', ...response.clauses);
|
|
203
|
+
}
|
|
204
|
+
if (response.quotes) {
|
|
205
|
+
GenerateSamples.writeJson(fp, 'Quotes: ', ...response.quotes);
|
|
206
|
+
}
|
|
207
|
+
if (response.errors && response.errors.length > 0) {
|
|
208
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
209
|
+
}
|
|
210
|
+
GenerateSamples.writeRaw(fp, '');
|
|
328
211
|
}
|
|
329
|
-
}
|
|
330
212
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
213
|
+
public booleanSerialized(str: string, fp: fs.WriteStream): void {
|
|
214
|
+
GenerateSamples.writeRaw(fp, 'Input: ' + str);
|
|
215
|
+
const response = new BooleanParser(str).parse();
|
|
216
|
+
// this.writeJson('Clause: ', ...response.clauses, '\n');
|
|
217
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
218
|
+
const result = new BooleanSerializer(response.clauses || []).serialize();
|
|
219
|
+
GenerateSamples.writeRaw(fp, 'Output: ' + result);
|
|
220
|
+
}
|
|
221
|
+
if (response.errors && response.errors.length > 0) {
|
|
222
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
223
|
+
}
|
|
224
|
+
GenerateSamples.writeRaw(fp, '');
|
|
341
225
|
}
|
|
342
|
-
console.log('');
|
|
343
|
-
}
|
|
344
226
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
227
|
+
public dateSerialized(str: string, fp: fs.WriteStream): void {
|
|
228
|
+
GenerateSamples.writeRaw(fp, 'Input: ' + str);
|
|
229
|
+
const response = new DateParser(str).parse();
|
|
230
|
+
// this.writeJson('Clause: ', ...response.clauses, '\n');
|
|
231
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
232
|
+
const result = new DateSerializer(response.clauses || []).serialize();
|
|
233
|
+
GenerateSamples.writeRaw(fp, 'Output: ' + result);
|
|
234
|
+
}
|
|
235
|
+
if (response.errors && response.errors.length > 0) {
|
|
236
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
237
|
+
}
|
|
238
|
+
GenerateSamples.writeRaw(fp, '');
|
|
348
239
|
}
|
|
349
|
-
}
|
|
350
240
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
241
|
+
public numberSerialized(str: string, fp: fs.WriteStream): void {
|
|
242
|
+
GenerateSamples.writeRaw(fp, 'Input: ' + str);
|
|
243
|
+
const response = new NumberParser(str).parse();
|
|
244
|
+
// this.writeJson('Clause: ', ...response.clauses, '\n');
|
|
245
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
246
|
+
const result = new NumberSerializer(response.clauses || []).serialize();
|
|
247
|
+
GenerateSamples.writeRaw(fp, 'Output: ' + result);
|
|
248
|
+
}
|
|
249
|
+
if (response.errors && response.errors.length > 0) {
|
|
250
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
251
|
+
}
|
|
252
|
+
GenerateSamples.writeRaw(fp, '');
|
|
361
253
|
}
|
|
362
|
-
console.log('');
|
|
363
|
-
}
|
|
364
254
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
255
|
+
public stringSerialized(str: string, fp: fs.WriteStream): void {
|
|
256
|
+
GenerateSamples.writeRaw(fp, 'Input: ' + str);
|
|
257
|
+
const response = new StringParser(str).parse();
|
|
258
|
+
// this.writeJson('Clause: ', ...response.clauses, '\n');
|
|
259
|
+
if (response.clauses && response.clauses.length > 0) {
|
|
260
|
+
const result = new StringSerializer(response.clauses || []).serialize();
|
|
261
|
+
GenerateSamples.writeRaw(fp, 'Output: ' + result);
|
|
262
|
+
}
|
|
263
|
+
if (response.errors && response.errors.length > 0) {
|
|
264
|
+
GenerateSamples.writeJson(fp, 'Errors: ', ...response.errors);
|
|
265
|
+
}
|
|
266
|
+
GenerateSamples.writeRaw(fp, '');
|
|
368
267
|
}
|
|
369
|
-
}
|
|
370
268
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
269
|
+
public loop(
|
|
270
|
+
title: string,
|
|
271
|
+
examples: string[],
|
|
272
|
+
func: (str: string, fp: fs.WriteStream) => void,
|
|
273
|
+
fp: fs.WriteStream
|
|
274
|
+
): void {
|
|
275
|
+
GenerateSamples.writeRaw(
|
|
276
|
+
fp,
|
|
277
|
+
'-------------------------------------------------------------------------'
|
|
278
|
+
);
|
|
279
|
+
GenerateSamples.writeRaw(fp, '## ' + title + '\n');
|
|
280
|
+
GenerateSamples.writeRaw(fp, '```code');
|
|
281
|
+
for (const example of examples) {
|
|
282
|
+
func(example, fp);
|
|
283
|
+
}
|
|
284
|
+
GenerateSamples.writeRaw(fp, '```\n');
|
|
381
285
|
}
|
|
382
|
-
console.log('');
|
|
383
286
|
}
|
|
384
287
|
|
|
385
|
-
function
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
288
|
+
// Comment or uncomment the following function calls to disable/enable examples.
|
|
289
|
+
function generateSamples() {
|
|
290
|
+
try {
|
|
291
|
+
const gen = new GenerateSamples();
|
|
292
|
+
GenerateSamples.writeRaw(
|
|
293
|
+
gen.samplesFile,
|
|
294
|
+
`
|
|
295
|
+
# Parsers
|
|
391
296
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (response.clauses && response.clauses.length > 0) {
|
|
397
|
-
const result = new DateSerializer(response.clauses || []).serialize();
|
|
398
|
-
console.log('Output: ' + result);
|
|
399
|
-
}
|
|
400
|
-
if (response.errors && response.errors.length > 0) {
|
|
401
|
-
console.log('Errors: ', ...response.errors);
|
|
402
|
-
}
|
|
403
|
-
console.log('');
|
|
404
|
-
}
|
|
297
|
+
Each filter type is handled by a different parser (strings, numbers, dates and times, etc).
|
|
298
|
+
Sample outputs from each parser follow...
|
|
299
|
+
`
|
|
300
|
+
);
|
|
405
301
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
302
|
+
GenerateSamples.writeRaw(
|
|
303
|
+
gen.serializedFile,
|
|
304
|
+
`
|
|
305
|
+
# Serializers
|
|
411
306
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
);
|
|
416
|
-
console.log('## ', title, '\n');
|
|
417
|
-
}
|
|
307
|
+
Each parser has a complementary serializer that converts the structured clause list back
|
|
308
|
+
to string format. Below are round-trip samples: \`string\` to \`Clause[]\` back to \`string\`.
|
|
309
|
+
Round-trip Examples:
|
|
418
310
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
311
|
+
\`\`\`code
|
|
312
|
+
Input > parse > Clause[] > serialize > Output
|
|
313
|
+
string string
|
|
314
|
+
\`\`\`
|
|
315
|
+
`
|
|
316
|
+
);
|
|
317
|
+
gen.loop('Numbers', numberExamples, gen.numberSample, gen.samplesFile);
|
|
318
|
+
gen.loop('Strings', stringExamples, gen.stringSample, gen.samplesFile);
|
|
319
|
+
gen.loop('Booleans', booleanExamples, gen.booleanSample, gen.samplesFile);
|
|
320
|
+
gen.loop('Dates and Times', dateExamples, gen.dateSample, gen.samplesFile);
|
|
321
|
+
gen.loop(
|
|
322
|
+
'Number Serializer',
|
|
323
|
+
numberExamples,
|
|
324
|
+
gen.numberSerialized,
|
|
325
|
+
gen.serializedFile
|
|
326
|
+
);
|
|
327
|
+
gen.loop(
|
|
328
|
+
'String Serializer',
|
|
329
|
+
stringExamples,
|
|
330
|
+
gen.stringSerialized,
|
|
331
|
+
gen.serializedFile
|
|
332
|
+
);
|
|
333
|
+
gen.loop(
|
|
334
|
+
'Boolean Serializer',
|
|
335
|
+
booleanExamples,
|
|
336
|
+
gen.booleanSerialized,
|
|
337
|
+
gen.serializedFile
|
|
338
|
+
);
|
|
339
|
+
gen.loop(
|
|
340
|
+
'Date Serializer',
|
|
341
|
+
dateExamples,
|
|
342
|
+
gen.dateSerialized,
|
|
343
|
+
gen.serializedFile
|
|
344
|
+
);
|
|
442
345
|
} catch (ex: Error | unknown) {
|
|
443
346
|
if (ex instanceof Error) console.error('Thrown Error: ', ex.message);
|
|
444
347
|
else {
|
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;
|