@malloydata/malloy-filter 0.0.237-dev250224215546 → 0.0.237-dev250225015031

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.
Files changed (58) hide show
  1. package/SAMPLES.md +336 -114
  2. package/SERIALIZE_SAMPLES.md +268 -64
  3. package/dist/a_simple_parser.js +6 -0
  4. package/dist/a_simple_parser.js.map +1 -1
  5. package/dist/base_parser.js +6 -0
  6. package/dist/base_parser.js.map +1 -1
  7. package/dist/boolean_parser.js +28 -13
  8. package/dist/boolean_parser.js.map +1 -1
  9. package/dist/boolean_serializer.js +12 -6
  10. package/dist/boolean_serializer.js.map +1 -1
  11. package/dist/clause_types.d.ts +20 -15
  12. package/dist/clause_types.js +6 -0
  13. package/dist/clause_types.js.map +1 -1
  14. package/dist/date_parser.js +135 -116
  15. package/dist/date_parser.js.map +1 -1
  16. package/dist/date_serializer.js +26 -20
  17. package/dist/date_serializer.js.map +1 -1
  18. package/dist/date_types.d.ts +21 -21
  19. package/dist/date_types.js +6 -0
  20. package/dist/date_types.js.map +1 -1
  21. package/dist/generate_samples.js +32 -25
  22. package/dist/generate_samples.js.map +1 -1
  23. package/dist/index.js +6 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/number_parser.js +43 -25
  26. package/dist/number_parser.js.map +1 -1
  27. package/dist/number_serializer.js +10 -4
  28. package/dist/number_serializer.js.map +1 -1
  29. package/dist/string_parser.d.ts +0 -1
  30. package/dist/string_parser.js +47 -79
  31. package/dist/string_parser.js.map +1 -1
  32. package/dist/string_serializer.d.ts +1 -0
  33. package/dist/string_serializer.js +49 -33
  34. package/dist/string_serializer.js.map +1 -1
  35. package/dist/token_types.js +6 -0
  36. package/dist/token_types.js.map +1 -1
  37. package/dist/tokenizer.js +9 -3
  38. package/dist/tokenizer.js.map +1 -1
  39. package/dist/tokenizer.spec.js +13 -7
  40. package/dist/tokenizer.spec.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/a_simple_parser.ts +7 -0
  43. package/src/base_parser.ts +7 -0
  44. package/src/boolean_parser.ts +30 -18
  45. package/src/boolean_serializer.ts +13 -6
  46. package/src/clause_types.ts +36 -31
  47. package/src/date_parser.ts +136 -118
  48. package/src/date_serializer.ts +27 -20
  49. package/src/date_types.ts +42 -34
  50. package/src/generate_samples.ts +33 -25
  51. package/src/index.ts +7 -0
  52. package/src/number_parser.ts +45 -26
  53. package/src/number_serializer.ts +11 -4
  54. package/src/string_parser.ts +51 -79
  55. package/src/string_serializer.ts +65 -39
  56. package/src/token_types.ts +7 -0
  57. package/src/tokenizer.spec.ts +14 -7
  58. package/src/tokenizer.ts +10 -3
@@ -1,3 +1,10 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
1
8
  import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
2
9
  import {
3
10
  DateTimeUnit,
@@ -21,9 +28,9 @@ import {
21
28
  } from './date_types';
22
29
  import {BaseParser} from './base_parser';
23
30
  import {Token} from './token_types';
24
- import {FilterError} from './clause_types';
31
+ import {FilterLog} from './clause_types';
25
32
 
26
- type DatePrefix = 'BEFORE' | 'AFTER';
33
+ type DatePrefix = 'before' | 'after';
27
34
 
28
35
  export class DateParser extends BaseParser {
29
36
  private static readonly yearRegex: RegExp = /[%_]/;
@@ -38,47 +45,46 @@ export class DateParser extends BaseParser {
38
45
  // Do not reorder.
39
46
  const specialWords: SpecialToken[] = [
40
47
  {
41
- type: 'UNITOFTIME',
48
+ type: 'unitoftime',
42
49
  value: /^(second|minute|hour|day|week|month|quarter|year)s?$/i,
43
50
  ignoreCase: true,
44
51
  },
45
52
  {
46
- type: 'DAYOFWEEK',
53
+ type: 'dayofweek',
47
54
  value: /^(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i,
48
55
  ignoreCase: true,
49
56
  },
50
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}T\d\d$/},
51
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}$/},
52
- {type: 'DATE', value: /^\d{4}-\d{2}$/},
53
- {type: 'DATE', value: /^\d{4}-[Qq][1234]$/},
54
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}-[Ww][Kk]$/},
57
+ {type: 'date', value: /^\d{4}-\d{2}-\d{2}T\d\d$/},
58
+ {type: 'date', value: /^\d{4}-\d{2}-\d{2}$/},
59
+ {type: 'date', value: /^\d{4}-\d{2}$/},
60
+ {type: 'date', value: /^\d{4}-[Qq][1234]$/},
55
61
  {
56
- type: 'DATE',
62
+ type: 'date',
57
63
  value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\d\[[a-zA-Z_/]*\]$/,
58
64
  },
59
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\d[.,]\d+$/},
60
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\d$/},
61
- {type: 'DATE', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d$/},
62
- {type: 'TIME', value: /^\d\d:\d\d:\d\d\[[a-zA-Z_/]*\]$/},
63
- {type: 'TIME', value: /^\d\d:\d\d:\d\d[.,]\d+$/},
64
- {type: 'TIME', value: /^\d\d:\d\d:\d\d$/},
65
- {type: 'TIME', value: /^\d\d:\d\d$/},
66
- {type: 'NOTNULL', value: '-null', ignoreCase: true},
67
- {type: 'NULL', value: 'null', ignoreCase: true},
68
- {type: 'PREFIX', value: /^(before|after)/i, ignoreCase: true},
69
- {type: 'TODAY', value: 'today', ignoreCase: true},
70
- {type: 'YESTERDAY', value: 'yesterday', ignoreCase: true},
71
- {type: 'TOMORROW', value: 'tomorrow', ignoreCase: true},
72
- {type: 'NOW', value: 'now', ignoreCase: true},
73
- {type: 'THIS', value: 'this', ignoreCase: true},
74
- {type: 'LAST', value: 'last', ignoreCase: true},
75
- {type: 'NEXT', value: 'next', ignoreCase: true},
76
- {type: 'AGO', value: 'ago', ignoreCase: true},
77
- {type: 'FROM', value: 'from', ignoreCase: true},
78
- {type: 'FOR', value: 'for', ignoreCase: true},
79
- {type: 'TO', value: 'to', ignoreCase: true},
80
- {type: 'YEAR', value: /^\d\d\d\d$/}, // Years are ambiguous, and require special handling.
81
- {type: 'NUMBER', value: /^[\d.]+/, ignoreCase: true},
65
+ {type: 'date', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\d[.,]\d+$/},
66
+ {type: 'date', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\d$/},
67
+ {type: 'date', value: /^\d{4}-\d{2}-\d{2}T\d\d:\d\d$/},
68
+ {type: 'time', value: /^\d\d:\d\d:\d\d\[[a-zA-Z_/]*\]$/},
69
+ {type: 'time', value: /^\d\d:\d\d:\d\d[.,]\d+$/},
70
+ {type: 'time', value: /^\d\d:\d\d:\d\d$/},
71
+ {type: 'time', value: /^\d\d:\d\d$/},
72
+ {type: 'not_null', value: '-null', ignoreCase: true},
73
+ {type: 'null', value: 'null', ignoreCase: true},
74
+ {type: 'prefix', value: /^(before|after)/i, ignoreCase: true},
75
+ {type: 'today', value: 'today', ignoreCase: true},
76
+ {type: 'yesterday', value: 'yesterday', ignoreCase: true},
77
+ {type: 'tomorrow', value: 'tomorrow', ignoreCase: true},
78
+ {type: 'now', value: 'now', ignoreCase: true},
79
+ {type: 'this', value: 'this', ignoreCase: true},
80
+ {type: 'last', value: 'last', ignoreCase: true},
81
+ {type: 'next', value: 'next', ignoreCase: true},
82
+ {type: 'ago', value: 'ago', ignoreCase: true},
83
+ {type: 'from', value: 'from', ignoreCase: true},
84
+ {type: 'for', value: 'for', ignoreCase: true},
85
+ {type: 'to', value: 'to', ignoreCase: true},
86
+ {type: 'year', value: /^\d\d\d\d$/}, // Years are ambiguous, and require special handling.
87
+ {type: 'number', value: /^[\d.]+/, ignoreCase: true},
82
88
  ];
83
89
  const params: TokenizerParams = {
84
90
  trimWordWhitespace: true,
@@ -101,10 +107,10 @@ export class DateParser extends BaseParser {
101
107
  const token = this.tokens[this.index];
102
108
  if (
103
109
  previous &&
104
- previous.type === 'DATE' &&
110
+ previous.type === 'date' &&
105
111
  previous.value.length >= 10 &&
106
- (token.type === 'TIME' ||
107
- (token.type === 'NUMBER' && token.value.length === 2))
112
+ (token.type === 'time' ||
113
+ (token.type === 'number' && token.value.length === 2))
108
114
  ) {
109
115
  previous.value = previous.value + ' ' + token.value;
110
116
  previous.endIndex = token.endIndex;
@@ -124,27 +130,27 @@ export class DateParser extends BaseParser {
124
130
  while (this.index < this.tokens.length) {
125
131
  // Do not reorder.
126
132
  if (
127
- this.matchAndMerge('LAST|UNITOFTIME', output) ||
128
- this.matchAndMerge('LAST|DAYOFWEEK', output) ||
129
- this.matchAndMerge('LAST|NUMBER|UNITOFTIME', output) ||
130
- this.matchAndMerge('LAST|YEAR|UNITOFTIME', output) ||
131
- this.matchAndMerge('THIS|UNITOFTIME', output) ||
132
- this.matchAndMerge('NEXT|UNITOFTIME', output) ||
133
- this.matchAndMerge('NEXT|DAYOFWEEK', output) ||
134
- this.matchAndMerge('NEXT|NUMBER|UNITOFTIME', output) ||
135
- this.matchAndMerge('NEXT|YEAR|UNITOFTIME', output) ||
136
- this.matchAndMerge('NUMBER|UNITOFTIME|AGO', output) ||
137
- this.matchAndMerge('YEAR|UNITOFTIME|AGO', output) ||
138
- this.matchAndMerge('NUMBER|UNITOFTIME|FROM|NOW', output) ||
139
- this.matchAndMerge('YEAR|UNITOFTIME|FROM|NOW', output) ||
140
- this.matchAndMerge('NUMBER|UNITOFTIME', output) ||
141
- this.matchAndMerge('YEAR|UNITOFTIME', output) ||
142
- this.matchAndMerge('TODAY', output) ||
143
- this.matchAndMerge('YESTERDAY', output) ||
144
- this.matchAndMerge('TOMORROW', output) ||
145
- this.matchAndMerge('DATE', output) ||
146
- this.matchAndMerge('YEAR', output) ||
147
- this.matchAndMerge('NOW', output)
133
+ this.matchAndMerge('last|unitoftime', output) ||
134
+ this.matchAndMerge('last|dayofweek', output) ||
135
+ this.matchAndMerge('last|number|unitoftime', output) ||
136
+ this.matchAndMerge('last|year|unitoftime', output) ||
137
+ this.matchAndMerge('this|unitoftime', output) ||
138
+ this.matchAndMerge('next|unitoftime', output) ||
139
+ this.matchAndMerge('next|dayofweek', output) ||
140
+ this.matchAndMerge('next|number|unitoftime', output) ||
141
+ this.matchAndMerge('next|year|unitoftime', output) ||
142
+ this.matchAndMerge('number|unitoftime|ago', output) ||
143
+ this.matchAndMerge('year|unitoftime|ago', output) ||
144
+ this.matchAndMerge('number|unitoftime|from|now', output) ||
145
+ this.matchAndMerge('year|unitoftime|from|now', output) ||
146
+ this.matchAndMerge('number|unitoftime', output) ||
147
+ this.matchAndMerge('year|unitoftime', output) ||
148
+ this.matchAndMerge('today', output) ||
149
+ this.matchAndMerge('yesterday', output) ||
150
+ this.matchAndMerge('tomorrow', output) ||
151
+ this.matchAndMerge('date', output) ||
152
+ this.matchAndMerge('year', output) ||
153
+ this.matchAndMerge('now', output)
148
154
  ) {
149
155
  continue;
150
156
  } else {
@@ -176,25 +182,34 @@ export class DateParser extends BaseParser {
176
182
  this.tokenize();
177
183
  let prefix: DatePrefix | undefined = undefined;
178
184
  const clauses: DateClause[] = [];
179
- const errors: FilterError[] = [];
185
+ const logs: FilterLog[] = [];
180
186
  this.index = 0;
181
187
  while (this.index < this.tokens.length) {
182
188
  const token = this.getNext();
183
189
  if (token.type === ',') {
184
190
  if (prefix) {
185
- errors.push({
191
+ logs.push({
192
+ severity: 'error',
186
193
  message: 'Invalid ' + prefix,
187
194
  startIndex: token.startIndex,
188
195
  endIndex: token.endIndex,
189
196
  });
197
+ } else if (this.index > 0 && this.tokens[this.index - 1].type === ',') {
198
+ logs.push({
199
+ severity: 'warn',
200
+ message: 'Empty clause',
201
+ startIndex: token.startIndex,
202
+ endIndex: token.endIndex,
203
+ });
190
204
  }
191
205
  this.index++;
192
- } else if (token.type === 'PREFIX') {
206
+ } else if (token.type === 'prefix') {
193
207
  prefix = token.value as DatePrefix;
194
208
  this.index++;
195
209
  } else if (this.handleRange(clauses)) {
196
210
  if (prefix) {
197
- errors.push({
211
+ logs.push({
212
+ severity: 'error',
198
213
  message: 'Invalid ' + prefix,
199
214
  startIndex: token.startIndex,
200
215
  endIndex: token.endIndex,
@@ -203,12 +218,13 @@ export class DateParser extends BaseParser {
203
218
  }
204
219
  } else if (this.handleMerged(prefix, clauses)) {
205
220
  prefix = undefined;
206
- } else if (token.type === 'NULL' || token.type === 'NOTNULL') {
221
+ } else if (token.type === 'null' || token.type === 'not_null') {
207
222
  prefix = undefined;
208
223
  clauses.push({operator: token.type});
209
224
  this.index++;
210
225
  } else {
211
- errors.push({
226
+ logs.push({
227
+ severity: 'error',
212
228
  message:
213
229
  'Invalid token ' + token.value ||
214
230
  (token.values ? token.values.join(' ') : ''),
@@ -219,7 +235,7 @@ export class DateParser extends BaseParser {
219
235
  this.index++;
220
236
  }
221
237
  }
222
- return {clauses, errors};
238
+ return {clauses, logs};
223
239
  }
224
240
 
225
241
  private static createMomentClause(
@@ -227,11 +243,11 @@ export class DateParser extends BaseParser {
227
243
  moment: DateMoment
228
244
  ): DateClause {
229
245
  if (!prefix) {
230
- return {operator: 'ON', moment}; // DateOnClause
231
- } else if (prefix === 'BEFORE') {
232
- return {operator: 'BEFORE', moment}; // DateBeforeClause
246
+ return {operator: 'on', moment}; // DateOnClause
247
+ } else if (prefix === 'before') {
248
+ return {operator: 'before', moment}; // DateBeforeClause
233
249
  } else {
234
- return {operator: 'AFTER', moment}; // DateAfterClause
250
+ return {operator: 'after', moment}; // DateAfterClause
235
251
  }
236
252
  }
237
253
 
@@ -245,7 +261,7 @@ export class DateParser extends BaseParser {
245
261
  const unit: DateTimeUnit | DateWeekday = tokens[1].value as
246
262
  | DateTimeUnit
247
263
  | DateWeekday;
248
- const moment: IntervalMoment = {type: 'INTERVAL', kind, unit};
264
+ const moment: IntervalMoment = {type: 'interval', kind, unit};
249
265
  return DateParser.createMomentClause(prefix, moment);
250
266
  }
251
267
 
@@ -258,12 +274,12 @@ export class DateParser extends BaseParser {
258
274
  const amount = Number(tokens[0].value);
259
275
  const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
260
276
  const direction: DateMomentOffsetFromNowDirection =
261
- tokens[2].type === 'AGO' ? 'AGO' : 'FROMNOW';
277
+ tokens[2].type === 'ago' ? 'ago' : 'from_now';
262
278
  if (!DateParser.isValidNumber(amount)) {
263
279
  return undefined;
264
280
  }
265
281
  const moment: OffsetMoment = {
266
- type: 'OFFSET_FROM_NOW',
282
+ type: 'offset_from_now',
267
283
  direction,
268
284
  amount,
269
285
  unit,
@@ -279,11 +295,11 @@ export class DateParser extends BaseParser {
279
295
  const amount = Number(tokens[0].value);
280
296
  const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
281
297
  const direction: DateMomentSpanFromNowDirection =
282
- tokens[2].type === 'LAST' ? 'LAST' : 'NEXT';
298
+ tokens[2].type === 'last' ? 'last' : 'next';
283
299
  if (!DateParser.isValidNumber(amount)) {
284
300
  return undefined;
285
301
  }
286
- const moment: SpanMoment = {type: 'SPAN_FROM_NOW', direction, amount, unit};
302
+ const moment: SpanMoment = {type: 'span_from_now', direction, amount, unit};
287
303
  return DateParser.createMomentClause(prefix, moment);
288
304
  }
289
305
 
@@ -295,7 +311,7 @@ export class DateParser extends BaseParser {
295
311
  if (prefix) {
296
312
  return undefined; // before 7 hours is ambiguous, not allowed.
297
313
  }
298
- const operator = 'DURATION';
314
+ const operator = 'duration';
299
315
  const amount = Number(tokens[0].value);
300
316
  const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
301
317
  if (!DateParser.isValidNumber(amount)) {
@@ -316,19 +332,21 @@ export class DateParser extends BaseParser {
316
332
  );
317
333
  const timeStr = matcher ? matcher[1] : '';
318
334
 
319
- let unit: DateTimeUnit = 'YEAR';
320
- if (timeStr.length > 5) {
321
- unit = 'SECOND';
335
+ let unit: DateTimeUnit = 'year';
336
+ if (timeStr.length > 8) {
337
+ unit = 'instant';
338
+ } else if (timeStr.length > 5) {
339
+ unit = 'second';
322
340
  } else if (timeStr.length > 2) {
323
- unit = 'MINUTE';
341
+ unit = 'minute';
324
342
  } else if (timeStr.length === 2) {
325
- unit = 'HOUR';
343
+ unit = 'hour';
326
344
  } else if (dateStr.length > 7) {
327
- unit = 'DAY';
345
+ unit = 'day';
328
346
  } else if (dateStr.length > 4) {
329
- unit = /[qQ]/.test(dateStr) ? 'QUARTER' : 'MONTH';
347
+ unit = /[qQ]/.test(dateStr) ? 'quarter' : 'month';
330
348
  }
331
- const moment: AbsoluteMoment = {type: 'ABSOLUTE', date: dateStr, unit};
349
+ const moment: AbsoluteMoment = {type: 'absolute', date: dateStr, unit};
332
350
  return DateParser.createMomentClause(prefix, moment);
333
351
  }
334
352
 
@@ -337,19 +355,19 @@ export class DateParser extends BaseParser {
337
355
  prefix: DatePrefix | undefined,
338
356
  tokens: Token[]
339
357
  ): DateClause {
340
- let momentName: DateMomentName = 'NOW';
358
+ let momentName: DateMomentName = 'now';
341
359
  switch (tokens[0].type) {
342
- case 'TODAY':
343
- momentName = 'TODAY';
360
+ case 'today':
361
+ momentName = 'today';
344
362
  break;
345
- case 'YESTERDAY':
346
- momentName = 'YESTERDAY';
363
+ case 'yesterday':
364
+ momentName = 'yesterday';
347
365
  break;
348
- case 'TOMORROW':
349
- momentName = 'TOMORROW';
366
+ case 'tomorrow':
367
+ momentName = 'tomorrow';
350
368
  break;
351
369
  }
352
- const moment: NamedMoment = {type: 'NAMED', name: momentName};
370
+ const moment: NamedMoment = {type: 'named', name: momentName};
353
371
  return DateParser.createMomentClause(prefix, moment);
354
372
  }
355
373
 
@@ -362,8 +380,8 @@ export class DateParser extends BaseParser {
362
380
  return undefined;
363
381
  }
364
382
  if (
365
- token.type === 'MERGE:NUMBER|UNITOFTIME' ||
366
- token.type === 'MERGE:YEAR|UNITOFTIME'
383
+ token.type === 'MERGE:number|unitoftime' ||
384
+ token.type === 'MERGE:year|unitoftime'
367
385
  ) {
368
386
  const value = Number(token.values[0].value);
369
387
  if (!DateParser.isValidNumber(value)) {
@@ -381,32 +399,32 @@ export class DateParser extends BaseParser {
381
399
  ): DateClause | undefined {
382
400
  const tokens: Token[] = token.values || [];
383
401
  switch (token.type) {
384
- case 'MERGE:LAST|UNITOFTIME':
385
- case 'MERGE:LAST|DAYOFWEEK':
386
- case 'MERGE:THIS|UNITOFTIME':
387
- case 'MERGE:NEXT|UNITOFTIME':
388
- case 'MERGE:NEXT|DAYOFWEEK':
402
+ case 'MERGE:last|unitoftime':
403
+ case 'MERGE:last|dayofweek':
404
+ case 'MERGE:this|unitoftime':
405
+ case 'MERGE:next|unitoftime':
406
+ case 'MERGE:next|dayofweek':
389
407
  return this.createIntervalMoment(prefix, tokens);
390
- case 'MERGE:LAST|NUMBER|UNITOFTIME':
391
- case 'MERGE:LAST|YEAR|UNITOFTIME':
392
- case 'MERGE:NEXT|NUMBER|UNITOFTIME':
393
- case 'MERGE:NEXT|YEAR|UNITOFTIME':
408
+ case 'MERGE:last|number|unitoftime':
409
+ case 'MERGE:last|year|unitoftime':
410
+ case 'MERGE:next|number|unitoftime':
411
+ case 'MERGE:next|year|unitoftime':
394
412
  return this.createSpanMoment(prefix, tokens);
395
- case 'MERGE:NUMBER|UNITOFTIME|AGO':
396
- case 'MERGE:YEAR|UNITOFTIME|AGO':
397
- case 'MERGE:NUMBER|UNITOFTIME|FROM|NOW':
398
- case 'MERGE:YEAR|UNITOFTIME|FROM|NOW':
413
+ case 'MERGE:number|unitoftime|ago':
414
+ case 'MERGE:year|unitoftime|ago':
415
+ case 'MERGE:number|unitoftime|from|now':
416
+ case 'MERGE:year|unitoftime|from|now':
399
417
  return this.createOffsetMoment(prefix, tokens);
400
- case 'MERGE:NUMBER|UNITOFTIME':
401
- case 'MERGE:YEAR|UNITOFTIME':
418
+ case 'MERGE:number|unitoftime':
419
+ case 'MERGE:year|unitoftime':
402
420
  return this.createDateDuration(prefix, tokens);
403
- case 'MERGE:DATE':
404
- case 'MERGE:YEAR':
421
+ case 'MERGE:date':
422
+ case 'MERGE:year':
405
423
  return this.createAbsoluteMoment(prefix, tokens);
406
- case 'MERGE:NOW':
407
- case 'MERGE:TODAY':
408
- case 'MERGE:YESTERDAY':
409
- case 'MERGE:TOMORROW':
424
+ case 'MERGE:now':
425
+ case 'MERGE:today':
426
+ case 'MERGE:yesterday':
427
+ case 'MERGE:tomorrow':
410
428
  return this.createNamedMoment(prefix, tokens);
411
429
  default:
412
430
  return undefined;
@@ -429,8 +447,8 @@ export class DateParser extends BaseParser {
429
447
  private handleRange(clauses: DateClause[]): boolean {
430
448
  if (
431
449
  this.isMatchingToken(this.index, 'MERGE', false) &&
432
- (this.isMatchingToken(this.index + 1, 'TO', true) ||
433
- this.isMatchingToken(this.index + 1, 'FOR', true)) &&
450
+ (this.isMatchingToken(this.index + 1, 'to', true) ||
451
+ this.isMatchingToken(this.index + 1, 'for', true)) &&
434
452
  this.isMatchingToken(this.index + 2, 'MERGE', false)
435
453
  ) {
436
454
  const startToken = this.tokens[this.index];
@@ -444,7 +462,7 @@ export class DateParser extends BaseParser {
444
462
  if (startClause === undefined || !('moment' in startClause)) {
445
463
  return false;
446
464
  }
447
- if (operator === 'TO') {
465
+ if (operator === 'to') {
448
466
  const endClause = DateParser.createClauseFromMerged(
449
467
  undefined,
450
468
  endToken
@@ -453,7 +471,7 @@ export class DateParser extends BaseParser {
453
471
  return false;
454
472
  }
455
473
  const clause: DateBetweenClause = {
456
- operator: 'TO_RANGE',
474
+ operator: 'to_range',
457
475
  from: startClause.moment,
458
476
  to: endClause.moment,
459
477
  };
@@ -464,7 +482,7 @@ export class DateParser extends BaseParser {
464
482
  return false;
465
483
  }
466
484
  const clause: DateForClause = {
467
- operator: 'FOR_RANGE',
485
+ operator: 'for_range',
468
486
  from: startClause.moment,
469
487
  duration: endDuration,
470
488
  };
@@ -1,3 +1,10 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
1
8
  import {
2
9
  DateMoment,
3
10
  DateBetweenClause,
@@ -16,16 +23,16 @@ export class DateSerializer {
16
23
  }
17
24
 
18
25
  private static dateMomentToString(moment: DateMoment): string {
19
- if (moment.type === 'ABSOLUTE') {
26
+ if (moment.type === 'absolute') {
20
27
  return moment.date;
21
- } else if (moment.type === 'INTERVAL') {
28
+ } else if (moment.type === 'interval') {
22
29
  return moment.kind + ' ' + moment.unit;
23
- } else if (moment.type === 'NAMED') {
30
+ } else if (moment.type === 'named') {
24
31
  return moment.name;
25
- } else if (moment.type === 'OFFSET_FROM_NOW') {
26
- const direction = moment.direction === 'FROMNOW' ? 'FROM NOW' : 'AGO';
32
+ } else if (moment.type === 'offset_from_now') {
33
+ const direction = moment.direction === 'from_now' ? 'from now' : 'ago';
27
34
  return moment.amount + ' ' + moment.unit + ' ' + direction;
28
- } else if (moment.type === 'SPAN_FROM_NOW') {
35
+ } else if (moment.type === 'span_from_now') {
29
36
  return moment.direction + ' ' + moment.amount + ' ' + moment.unit;
30
37
  } else {
31
38
  throw new Error('moment type not recognized ' + JSON.stringify(moment));
@@ -35,7 +42,7 @@ export class DateSerializer {
35
42
  private static goDateBetweenClause(clause: DateBetweenClause): string {
36
43
  return (
37
44
  DateSerializer.dateMomentToString(clause.from) +
38
- ' TO ' +
45
+ ' to ' +
39
46
  DateSerializer.dateMomentToString(clause.to)
40
47
  );
41
48
  }
@@ -43,7 +50,7 @@ export class DateSerializer {
43
50
  private static goDateForClause(clause: DateForClause): string {
44
51
  return (
45
52
  DateSerializer.dateMomentToString(clause.from) +
46
- ' FOR ' +
53
+ ' for ' +
47
54
  clause.duration.amount +
48
55
  ' ' +
49
56
  clause.duration.unit
@@ -54,21 +61,21 @@ export class DateSerializer {
54
61
  if (!('operator' in clause)) {
55
62
  throw new Error('Invalid date clause ' + JSON.stringify(clause));
56
63
  }
57
- if (clause.operator === 'TO_RANGE') {
64
+ if (clause.operator === 'to_range') {
58
65
  return DateSerializer.goDateBetweenClause(clause);
59
- } else if (clause.operator === 'FOR_RANGE') {
66
+ } else if (clause.operator === 'for_range') {
60
67
  return DateSerializer.goDateForClause(clause);
61
- } else if (clause.operator === 'BEFORE') {
62
- return 'BEFORE ' + DateSerializer.dateMomentToString(clause.moment);
63
- } else if (clause.operator === 'AFTER') {
64
- return 'AFTER ' + DateSerializer.dateMomentToString(clause.moment);
65
- } else if (clause.operator === 'ON') {
68
+ } else if (clause.operator === 'before') {
69
+ return 'before ' + DateSerializer.dateMomentToString(clause.moment);
70
+ } else if (clause.operator === 'after') {
71
+ return 'after ' + DateSerializer.dateMomentToString(clause.moment);
72
+ } else if (clause.operator === 'on') {
66
73
  return DateSerializer.dateMomentToString(clause.moment);
67
- } else if (clause.operator === 'NULL') {
68
- return 'NULL';
69
- } else if (clause.operator === 'NOTNULL') {
70
- return '-NULL';
71
- } else if (clause.operator === 'DURATION') {
74
+ } else if (clause.operator === 'null') {
75
+ return 'null';
76
+ } else if (clause.operator === 'not_null') {
77
+ return '-null';
78
+ } else if (clause.operator === 'duration') {
72
79
  return clause.duration.amount + ' ' + clause.duration.unit;
73
80
  } else {
74
81
  throw new Error('Clause type not recognized ' + JSON.stringify(clause));