@malloydata/malloy-filter 0.0.237-dev250222025222 → 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/a_simple_parser.js +12 -9
- package/dist/a_simple_parser.js.map +1 -1
- package/dist/base_parser.d.ts +0 -2
- package/dist/base_parser.js.map +1 -1
- package/dist/boolean_parser.d.ts +2 -2
- package/dist/boolean_parser.js +3 -1
- package/dist/boolean_parser.js.map +1 -1
- package/dist/boolean_serializer.d.ts +4 -4
- package/dist/boolean_serializer.js +12 -4
- package/dist/boolean_serializer.js.map +1 -1
- package/dist/clause_types.d.ts +40 -47
- package/dist/date_parser.d.ts +13 -11
- package/dist/date_parser.js +192 -131
- package/dist/date_parser.js.map +1 -1
- package/dist/date_serializer.d.ts +6 -5
- package/dist/date_serializer.js +65 -77
- package/dist/date_serializer.js.map +1 -1
- package/dist/date_types.d.ts +75 -0
- package/dist/{filter_types.js → date_types.js} +1 -1
- package/dist/date_types.js.map +1 -0
- package/dist/generate_samples.js +162 -87
- package/dist/generate_samples.js.map +1 -1
- package/dist/number_parser.d.ts +2 -5
- package/dist/number_parser.js +10 -51
- package/dist/number_parser.js.map +1 -1
- package/dist/number_serializer.d.ts +4 -4
- package/dist/number_serializer.js +17 -14
- package/dist/number_serializer.js.map +1 -1
- package/dist/string_parser.d.ts +2 -2
- package/dist/string_parser.js +21 -21
- package/dist/string_parser.js.map +1 -1
- package/dist/string_serializer.d.ts +6 -5
- package/dist/string_serializer.js +38 -24
- package/dist/string_serializer.js.map +1 -1
- package/package.json +1 -2
- package/src/DEVELOPING.md +2 -5
- package/src/a_simple_parser.ts +12 -9
- package/src/base_parser.ts +0 -3
- package/src/boolean_parser.ts +10 -5
- package/src/boolean_serializer.ts +14 -7
- package/src/clause_types.ts +65 -108
- package/src/date_parser.ts +229 -192
- package/src/date_serializer.ts +59 -87
- package/src/date_types.ts +159 -0
- package/src/generate_samples.ts +178 -109
- package/src/number_parser.ts +14 -63
- package/src/number_serializer.ts +19 -20
- package/src/string_parser.ts +40 -27
- package/src/string_serializer.ts +58 -32
- package/tsconfig.json +1 -6
- package/dist/a_simple_serializer.d.ts +0 -1
- package/dist/a_simple_serializer.js +0 -31
- package/dist/a_simple_serializer.js.map +0 -1
- package/dist/base_serializer.d.ts +0 -6
- package/dist/base_serializer.js +0 -11
- package/dist/base_serializer.js.map +0 -1
- package/dist/filter_parser.d.ts +0 -12
- package/dist/filter_parser.js +0 -66
- package/dist/filter_parser.js.map +0 -1
- package/dist/filter_serializer.d.ts +0 -13
- package/dist/filter_serializer.js +0 -43
- package/dist/filter_serializer.js.map +0 -1
- package/dist/filter_types.d.ts +0 -10
- package/dist/filter_types.js.map +0 -1
- package/src/a_simple_serializer.ts +0 -40
- package/src/base_serializer.ts +0 -9
- package/src/filter_parser.ts +0 -68
- package/src/filter_serializer.ts +0 -49
- package/src/filter_types.ts +0 -12
package/src/date_parser.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
|
|
2
2
|
import {
|
|
3
|
-
DateRange,
|
|
4
|
-
DatePrefix,
|
|
5
|
-
DateMoment,
|
|
6
|
-
DateMomentNow,
|
|
7
|
-
DateMomentInterval,
|
|
8
|
-
DateMomentNumberInterval,
|
|
9
|
-
DateMomentNumberUnit,
|
|
10
|
-
DateMomentNumber,
|
|
11
3
|
DateTimeUnit,
|
|
12
4
|
DateWeekday,
|
|
5
|
+
DateMomentName,
|
|
6
|
+
NamedMoment,
|
|
13
7
|
DateMomentIntervalOperator,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
IntervalMoment,
|
|
9
|
+
DateMomentOffsetFromNowDirection,
|
|
10
|
+
OffsetMoment,
|
|
11
|
+
DateMomentSpanFromNowDirection,
|
|
12
|
+
SpanMoment,
|
|
13
|
+
AbsoluteMoment,
|
|
14
|
+
DateMoment,
|
|
15
|
+
DateBetweenClause,
|
|
16
|
+
Duration,
|
|
17
|
+
DateForClause,
|
|
18
|
+
DateDurationClause,
|
|
18
19
|
DateClause,
|
|
19
|
-
|
|
20
|
-
} from './
|
|
20
|
+
DateParserResponse,
|
|
21
|
+
} from './date_types';
|
|
21
22
|
import {BaseParser} from './base_parser';
|
|
22
23
|
import {Token} from './token_types';
|
|
23
|
-
import {
|
|
24
|
+
import {FilterError} from './clause_types';
|
|
25
|
+
|
|
26
|
+
type DatePrefix = 'BEFORE' | 'AFTER';
|
|
24
27
|
|
|
25
28
|
export class DateParser extends BaseParser {
|
|
26
29
|
private static readonly yearRegex: RegExp = /[%_]/;
|
|
@@ -62,7 +65,7 @@ export class DateParser extends BaseParser {
|
|
|
62
65
|
{type: 'FROM', value: 'from', ignoreCase: true},
|
|
63
66
|
{type: 'FOR', value: 'for', ignoreCase: true},
|
|
64
67
|
{type: 'TO', value: 'to', ignoreCase: true},
|
|
65
|
-
{type: '
|
|
68
|
+
{type: 'YEAR', value: /^\d\d\d\d$/}, // Years are ambiguous, and require special handling.
|
|
66
69
|
{type: 'NUMBER', value: /^[\d.]+/, ignoreCase: true},
|
|
67
70
|
];
|
|
68
71
|
const params: TokenizerParams = {
|
|
@@ -83,44 +86,28 @@ export class DateParser extends BaseParser {
|
|
|
83
86
|
this.index = 0;
|
|
84
87
|
while (this.index < this.tokens.length) {
|
|
85
88
|
if (
|
|
86
|
-
this.matchAndMerge('LAST|UNITOFTIME',
|
|
87
|
-
this.matchAndMerge('LAST|DAYOFWEEK',
|
|
88
|
-
this.matchAndMerge('LAST|NUMBER|UNITOFTIME',
|
|
89
|
-
this.matchAndMerge(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
) ||
|
|
94
|
-
this.matchAndMerge('
|
|
95
|
-
this.matchAndMerge('
|
|
96
|
-
this.matchAndMerge('
|
|
97
|
-
this.matchAndMerge('
|
|
98
|
-
this.matchAndMerge(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
) ||
|
|
103
|
-
this.matchAndMerge('
|
|
104
|
-
this.matchAndMerge(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
) ||
|
|
109
|
-
this.matchAndMerge('NUMBER|UNITOFTIME|FROM|NOW', this.tokens, output) ||
|
|
110
|
-
this.matchAndMerge(
|
|
111
|
-
'YEARORNUMBER|UNITOFTIME|FROM|NOW',
|
|
112
|
-
this.tokens,
|
|
113
|
-
output
|
|
114
|
-
) ||
|
|
115
|
-
this.matchAndMerge('NUMBER|UNITOFTIME', this.tokens, output) ||
|
|
116
|
-
this.matchAndMerge('YEARORNUMBER|UNITOFTIME', this.tokens, output) ||
|
|
117
|
-
this.matchAndMerge('DATE|TIME', this.tokens, output) ||
|
|
118
|
-
this.matchAndMerge('TODAY', this.tokens, output) ||
|
|
119
|
-
this.matchAndMerge('YESTERDAY', this.tokens, output) ||
|
|
120
|
-
this.matchAndMerge('TOMORROW', this.tokens, output) ||
|
|
121
|
-
this.matchAndMerge('DATE', this.tokens, output) ||
|
|
122
|
-
this.matchAndMerge('YEARORNUMBER', this.tokens, output) ||
|
|
123
|
-
this.matchAndMerge('NOW', this.tokens, output)
|
|
89
|
+
this.matchAndMerge('LAST|UNITOFTIME', output) ||
|
|
90
|
+
this.matchAndMerge('LAST|DAYOFWEEK', output) ||
|
|
91
|
+
this.matchAndMerge('LAST|NUMBER|UNITOFTIME', output) ||
|
|
92
|
+
this.matchAndMerge('LAST|YEAR|UNITOFTIME', output) ||
|
|
93
|
+
this.matchAndMerge('THIS|UNITOFTIME', output) ||
|
|
94
|
+
this.matchAndMerge('NEXT|UNITOFTIME', output) ||
|
|
95
|
+
this.matchAndMerge('NEXT|DAYOFWEEK', output) ||
|
|
96
|
+
this.matchAndMerge('NEXT|NUMBER|UNITOFTIME', output) ||
|
|
97
|
+
this.matchAndMerge('NEXT|YEAR|UNITOFTIME', output) ||
|
|
98
|
+
this.matchAndMerge('NUMBER|UNITOFTIME|AGO', output) ||
|
|
99
|
+
this.matchAndMerge('YEAR|UNITOFTIME|AGO', output) ||
|
|
100
|
+
this.matchAndMerge('NUMBER|UNITOFTIME|FROM|NOW', output) ||
|
|
101
|
+
this.matchAndMerge('YEAR|UNITOFTIME|FROM|NOW', output) ||
|
|
102
|
+
this.matchAndMerge('NUMBER|UNITOFTIME', output) ||
|
|
103
|
+
this.matchAndMerge('YEAR|UNITOFTIME', output) ||
|
|
104
|
+
this.matchAndMerge('DATE|TIME', output) ||
|
|
105
|
+
this.matchAndMerge('TODAY', output) ||
|
|
106
|
+
this.matchAndMerge('YESTERDAY', output) ||
|
|
107
|
+
this.matchAndMerge('TOMORROW', output) ||
|
|
108
|
+
this.matchAndMerge('DATE', output) ||
|
|
109
|
+
this.matchAndMerge('YEAR', output) ||
|
|
110
|
+
this.matchAndMerge('NOW', output)
|
|
124
111
|
) {
|
|
125
112
|
continue;
|
|
126
113
|
} else {
|
|
@@ -131,16 +118,12 @@ export class DateParser extends BaseParser {
|
|
|
131
118
|
return output;
|
|
132
119
|
}
|
|
133
120
|
|
|
134
|
-
private matchAndMerge(
|
|
135
|
-
types: string,
|
|
136
|
-
tokens: Token[],
|
|
137
|
-
output: Token[]
|
|
138
|
-
): boolean {
|
|
121
|
+
private matchAndMerge(types: string, output: Token[]): boolean {
|
|
139
122
|
const idx = this.index;
|
|
140
|
-
const matchedTokens = Tokenizer.matchTypes(types, tokens, idx);
|
|
123
|
+
const matchedTokens = Tokenizer.matchTypes(types, this.tokens, idx);
|
|
141
124
|
if (matchedTokens) {
|
|
142
125
|
output.push({
|
|
143
|
-
type: '
|
|
126
|
+
type: 'MERGE:' + types,
|
|
144
127
|
value: '',
|
|
145
128
|
values: matchedTokens,
|
|
146
129
|
startIndex: matchedTokens[0].startIndex,
|
|
@@ -152,7 +135,7 @@ export class DateParser extends BaseParser {
|
|
|
152
135
|
return false;
|
|
153
136
|
}
|
|
154
137
|
|
|
155
|
-
public parse():
|
|
138
|
+
public parse(): DateParserResponse {
|
|
156
139
|
this.tokenize();
|
|
157
140
|
let prefix: DatePrefix | undefined = undefined;
|
|
158
141
|
const clauses: DateClause[] = [];
|
|
@@ -181,11 +164,13 @@ export class DateParser extends BaseParser {
|
|
|
181
164
|
});
|
|
182
165
|
this.index++;
|
|
183
166
|
}
|
|
184
|
-
} else if (this.
|
|
167
|
+
} else if (this.handleMerged(prefix, clauses)) {
|
|
185
168
|
prefix = undefined;
|
|
186
169
|
} else {
|
|
187
170
|
errors.push({
|
|
188
|
-
message:
|
|
171
|
+
message:
|
|
172
|
+
'Invalid token ' + token.value ||
|
|
173
|
+
(token.values ? token.values.join(' ') : ''),
|
|
189
174
|
startIndex: token.startIndex,
|
|
190
175
|
endIndex: token.endIndex,
|
|
191
176
|
});
|
|
@@ -196,151 +181,187 @@ export class DateParser extends BaseParser {
|
|
|
196
181
|
return {clauses, errors};
|
|
197
182
|
}
|
|
198
183
|
|
|
199
|
-
|
|
200
|
-
private static createMomentInterval(
|
|
184
|
+
private static createMomentClause(
|
|
201
185
|
prefix: DatePrefix | undefined,
|
|
202
|
-
|
|
203
|
-
):
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (prefix) {
|
|
211
|
-
moment.prefix = prefix;
|
|
186
|
+
moment: DateMoment
|
|
187
|
+
): DateClause {
|
|
188
|
+
if (!prefix) {
|
|
189
|
+
return {operator: 'ON', moment}; // DateOnClause
|
|
190
|
+
} else if (prefix === 'BEFORE') {
|
|
191
|
+
return {operator: 'BEFORE', moment}; // DateBeforeClause
|
|
192
|
+
} else {
|
|
193
|
+
return {operator: 'AFTER', moment}; // DateAfterClause
|
|
212
194
|
}
|
|
213
|
-
return moment;
|
|
214
195
|
}
|
|
215
196
|
|
|
216
|
-
// LAST|
|
|
217
|
-
private static
|
|
197
|
+
// (BEFORE|AFTER) LAST|DAYOFWEEK
|
|
198
|
+
private static createIntervalMoment(
|
|
218
199
|
prefix: DatePrefix | undefined,
|
|
219
200
|
tokens: Token[]
|
|
220
|
-
):
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const moment:
|
|
227
|
-
|
|
228
|
-
moment.prefix = prefix;
|
|
229
|
-
}
|
|
230
|
-
return moment;
|
|
201
|
+
): DateClause {
|
|
202
|
+
const kind: DateMomentIntervalOperator = tokens[0]
|
|
203
|
+
.type as DateMomentIntervalOperator;
|
|
204
|
+
const unit: DateTimeUnit | DateWeekday = tokens[1].value as
|
|
205
|
+
| DateTimeUnit
|
|
206
|
+
| DateWeekday;
|
|
207
|
+
const moment: IntervalMoment = {type: 'INTERVAL', kind, unit};
|
|
208
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
231
209
|
}
|
|
232
210
|
|
|
233
211
|
// NUMBER|UNITOFTIME|AGO
|
|
234
|
-
|
|
212
|
+
// NUMBER|UNITOFTIME|FROM|NOW
|
|
213
|
+
private static createOffsetMoment(
|
|
235
214
|
prefix: DatePrefix | undefined,
|
|
236
215
|
tokens: Token[]
|
|
237
|
-
):
|
|
238
|
-
const
|
|
239
|
-
const value: string = tokens[0].value;
|
|
216
|
+
): DateClause | undefined {
|
|
217
|
+
const amount = Number(tokens[0].value);
|
|
240
218
|
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
219
|
+
const direction: DateMomentOffsetFromNowDirection =
|
|
220
|
+
tokens[2].type === 'AGO' ? 'AGO' : 'FROMNOW';
|
|
221
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
222
|
+
return undefined;
|
|
244
223
|
}
|
|
245
|
-
|
|
224
|
+
const moment: OffsetMoment = {
|
|
225
|
+
type: 'OFFSET_FROM_NOW',
|
|
226
|
+
direction,
|
|
227
|
+
amount,
|
|
228
|
+
unit,
|
|
229
|
+
};
|
|
230
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
246
231
|
}
|
|
247
232
|
|
|
248
|
-
// NUMBER|UNITOFTIME
|
|
249
|
-
private static
|
|
233
|
+
// (LAST|NEXT)|NUMBER|UNITOFTIME
|
|
234
|
+
private static createSpanMoment(
|
|
250
235
|
prefix: DatePrefix | undefined,
|
|
251
236
|
tokens: Token[]
|
|
252
|
-
):
|
|
253
|
-
const
|
|
254
|
-
const value: string = tokens[0].value;
|
|
237
|
+
): DateClause | undefined {
|
|
238
|
+
const amount = Number(tokens[0].value);
|
|
255
239
|
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
240
|
+
const direction: DateMomentSpanFromNowDirection =
|
|
241
|
+
tokens[2].type === 'LAST' ? 'LAST' : 'NEXT';
|
|
242
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
243
|
+
return undefined;
|
|
259
244
|
}
|
|
260
|
-
|
|
245
|
+
const moment: SpanMoment = {type: 'SPAN_FROM_NOW', direction, amount, unit};
|
|
246
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
261
247
|
}
|
|
262
248
|
|
|
263
|
-
// NUMBER|UNITOFTIME
|
|
264
|
-
private static
|
|
249
|
+
// (NUMBER|YEAR)|UNITOFTIME
|
|
250
|
+
private static createDateDuration(
|
|
265
251
|
prefix: DatePrefix | undefined,
|
|
266
252
|
tokens: Token[]
|
|
267
|
-
):
|
|
268
|
-
const operator: DateMomentNumberUnitOperator = 'TIMEBLOCK';
|
|
269
|
-
const value: string = tokens[0].value;
|
|
270
|
-
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
271
|
-
const moment: DateMomentNumberUnit = {operator, value, unit};
|
|
253
|
+
): DateClause | undefined {
|
|
272
254
|
if (prefix) {
|
|
273
|
-
|
|
255
|
+
return undefined; // before 7 hours is ambiguous, not allowed.
|
|
256
|
+
}
|
|
257
|
+
const operator = 'DURATION';
|
|
258
|
+
const amount = Number(tokens[0].value);
|
|
259
|
+
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
260
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
261
|
+
return undefined;
|
|
274
262
|
}
|
|
275
|
-
|
|
263
|
+
const clause: DateDurationClause = {operator, duration: {amount, unit}};
|
|
264
|
+
return clause;
|
|
276
265
|
}
|
|
277
266
|
|
|
278
|
-
// DATE DATE|TIME
|
|
279
|
-
private static
|
|
267
|
+
// (BEFORE|AFTER) DATE DATE|TIME
|
|
268
|
+
private static createAbsoluteMoment(
|
|
280
269
|
prefix: DatePrefix | undefined,
|
|
281
270
|
tokens: Token[]
|
|
282
|
-
):
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const moment: DateMomentNumber = {operator, date: tokens[0].value};
|
|
271
|
+
): DateClause {
|
|
272
|
+
let unit: DateTimeUnit = 'YEAR';
|
|
273
|
+
let date = tokens[0].value;
|
|
286
274
|
if (tokens.length === 2) {
|
|
287
|
-
|
|
275
|
+
const timeStr = tokens[1].value;
|
|
276
|
+
date += ' ' + timeStr;
|
|
277
|
+
if (timeStr.length > 5) unit = 'SECOND';
|
|
278
|
+
else unit = 'MINUTE';
|
|
279
|
+
} else if (date.length > 7) {
|
|
280
|
+
unit = 'DAY';
|
|
281
|
+
} else if (date.length > 4) {
|
|
282
|
+
unit = 'MONTH';
|
|
288
283
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
return moment;
|
|
284
|
+
const moment: AbsoluteMoment = {type: 'ABSOLUTE', date, unit};
|
|
285
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
293
286
|
}
|
|
294
287
|
|
|
295
288
|
// NOW YESTERDAY TODAY TOMORROW
|
|
296
|
-
private static
|
|
289
|
+
private static createNamedMoment(
|
|
297
290
|
prefix: DatePrefix | undefined,
|
|
298
291
|
tokens: Token[]
|
|
299
|
-
):
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
292
|
+
): DateClause {
|
|
293
|
+
let momentName: DateMomentName = 'NOW';
|
|
294
|
+
switch (tokens[0].type) {
|
|
295
|
+
case 'TODAY':
|
|
296
|
+
momentName = 'TODAY';
|
|
297
|
+
break;
|
|
298
|
+
case 'YESTERDAY':
|
|
299
|
+
momentName = 'YESTERDAY';
|
|
300
|
+
break;
|
|
301
|
+
case 'TOMORROW':
|
|
302
|
+
momentName = 'TOMORROW';
|
|
303
|
+
break;
|
|
305
304
|
}
|
|
306
|
-
|
|
305
|
+
const moment: NamedMoment = {type: 'NAMED', name: momentName};
|
|
306
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
private static
|
|
309
|
+
private static isValidNumber(value: number): boolean {
|
|
310
|
+
return Number.isNaN(value) === false;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private static createDurationFromMerged(token: Token): Duration | undefined {
|
|
314
|
+
if (!token.values || token.values.length !== 2) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
if (
|
|
318
|
+
token.type === 'MERGE:NUMBER|UNITOFTIME' ||
|
|
319
|
+
token.type === 'MERGE:YEAR|UNITOFTIME'
|
|
320
|
+
) {
|
|
321
|
+
const value = Number(token.values[0].value);
|
|
322
|
+
if (!DateParser.isValidNumber(value)) {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
const unit = token.values[1].value as DateTimeUnit;
|
|
326
|
+
return {amount: value, unit: unit};
|
|
327
|
+
}
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private static createClauseFromMerged(
|
|
310
332
|
prefix: DatePrefix | undefined,
|
|
311
333
|
token: Token
|
|
312
|
-
):
|
|
334
|
+
): DateClause | undefined {
|
|
313
335
|
const tokens: Token[] = token.values || [];
|
|
314
336
|
switch (token.type) {
|
|
315
|
-
case '
|
|
316
|
-
case '
|
|
317
|
-
case '
|
|
318
|
-
case '
|
|
319
|
-
case '
|
|
320
|
-
return this.
|
|
321
|
-
case '
|
|
322
|
-
case '
|
|
323
|
-
case '
|
|
324
|
-
case '
|
|
325
|
-
return this.
|
|
326
|
-
case '
|
|
327
|
-
case '
|
|
328
|
-
|
|
329
|
-
case '
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
case '
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
case '
|
|
336
|
-
case '
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
case '
|
|
340
|
-
case '
|
|
341
|
-
case '
|
|
342
|
-
|
|
343
|
-
return this.createMomentNow(prefix, tokens);
|
|
337
|
+
case 'MERGE:LAST|UNITOFTIME':
|
|
338
|
+
case 'MERGE:LAST|DAYOFWEEK':
|
|
339
|
+
case 'MERGE:THIS|UNITOFTIME':
|
|
340
|
+
case 'MERGE:NEXT|UNITOFTIME':
|
|
341
|
+
case 'MERGE:NEXT|DAYOFWEEK':
|
|
342
|
+
return this.createIntervalMoment(prefix, tokens);
|
|
343
|
+
case 'MERGE:LAST|NUMBER|UNITOFTIME':
|
|
344
|
+
case 'MERGE:LAST|YEAR|UNITOFTIME':
|
|
345
|
+
case 'MERGE:NEXT|NUMBER|UNITOFTIME':
|
|
346
|
+
case 'MERGE:NEXT|YEAR|UNITOFTIME':
|
|
347
|
+
return this.createSpanMoment(prefix, tokens);
|
|
348
|
+
case 'MERGE:NUMBER|UNITOFTIME|AGO':
|
|
349
|
+
case 'MERGE:YEAR|UNITOFTIME|AGO':
|
|
350
|
+
case 'MERGE:NUMBER|UNITOFTIME|FROM|NOW':
|
|
351
|
+
case 'MERGE:YEAR|UNITOFTIME|FROM|NOW':
|
|
352
|
+
return this.createOffsetMoment(prefix, tokens);
|
|
353
|
+
case 'MERGE:NUMBER|UNITOFTIME':
|
|
354
|
+
case 'MERGE:YEAR|UNITOFTIME':
|
|
355
|
+
return this.createDateDuration(prefix, tokens);
|
|
356
|
+
case 'MERGE:DATE|TIME':
|
|
357
|
+
case 'MERGE:DATE':
|
|
358
|
+
case 'MERGE:YEAR':
|
|
359
|
+
return this.createAbsoluteMoment(prefix, tokens);
|
|
360
|
+
case 'MERGE:NOW':
|
|
361
|
+
case 'MERGE:TODAY':
|
|
362
|
+
case 'MERGE:YESTERDAY':
|
|
363
|
+
case 'MERGE:TOMORROW':
|
|
364
|
+
return this.createNamedMoment(prefix, tokens);
|
|
344
365
|
default:
|
|
345
366
|
return undefined;
|
|
346
367
|
}
|
|
@@ -359,54 +380,70 @@ export class DateParser extends BaseParser {
|
|
|
359
380
|
: this.tokens[position].type.startsWith(value);
|
|
360
381
|
}
|
|
361
382
|
|
|
362
|
-
private handleRange(clauses:
|
|
383
|
+
private handleRange(clauses: DateClause[]): boolean {
|
|
363
384
|
if (
|
|
364
|
-
this.isMatchingToken(this.index, '
|
|
385
|
+
this.isMatchingToken(this.index, 'MERGE', false) &&
|
|
365
386
|
(this.isMatchingToken(this.index + 1, 'TO', true) ||
|
|
366
387
|
this.isMatchingToken(this.index + 1, 'FOR', true)) &&
|
|
367
|
-
this.isMatchingToken(this.index + 2, '
|
|
388
|
+
this.isMatchingToken(this.index + 2, 'MERGE', false)
|
|
368
389
|
) {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const operator: 'TO' | 'FOR' = this.tokens[this.index + 1].type as
|
|
377
|
-
| 'TO'
|
|
378
|
-
| 'FOR';
|
|
390
|
+
const startToken = this.tokens[this.index];
|
|
391
|
+
const operator = this.tokens[this.index + 1].type; // TO | FOR
|
|
392
|
+
const endToken = this.tokens[this.index + 2];
|
|
393
|
+
const startClause = DateParser.createClauseFromMerged(
|
|
394
|
+
undefined,
|
|
395
|
+
startToken
|
|
396
|
+
);
|
|
379
397
|
this.index += 3;
|
|
380
|
-
if (
|
|
398
|
+
if (startClause === undefined || !('moment' in startClause)) {
|
|
381
399
|
return false;
|
|
382
400
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
401
|
+
if (operator === 'TO') {
|
|
402
|
+
const endClause = DateParser.createClauseFromMerged(
|
|
403
|
+
undefined,
|
|
404
|
+
endToken
|
|
405
|
+
);
|
|
406
|
+
if (endClause === undefined || !('moment' in endClause)) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
const clause: DateBetweenClause = {
|
|
410
|
+
operator: 'TO_RANGE',
|
|
411
|
+
from: startClause.moment,
|
|
412
|
+
to: endClause.moment,
|
|
413
|
+
};
|
|
414
|
+
clauses.push(clause);
|
|
415
|
+
} else {
|
|
416
|
+
const endDuration = DateParser.createDurationFromMerged(endToken);
|
|
417
|
+
if (endDuration === undefined) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const clause: DateForClause = {
|
|
421
|
+
operator: 'FOR_RANGE',
|
|
422
|
+
from: startClause.moment,
|
|
423
|
+
duration: endDuration,
|
|
424
|
+
};
|
|
425
|
+
clauses.push(clause);
|
|
426
|
+
}
|
|
389
427
|
return true;
|
|
390
428
|
}
|
|
391
429
|
return false;
|
|
392
430
|
}
|
|
393
431
|
|
|
394
|
-
private
|
|
432
|
+
private handleMerged(
|
|
395
433
|
prefix: DatePrefix | undefined,
|
|
396
434
|
clauses: DateClause[]
|
|
397
435
|
): boolean {
|
|
398
436
|
const token: Token = this.getNext();
|
|
399
|
-
if (token.type.startsWith('
|
|
400
|
-
const clause
|
|
401
|
-
prefix,
|
|
402
|
-
token
|
|
403
|
-
);
|
|
437
|
+
if (token.type.startsWith('MERGE')) {
|
|
438
|
+
const clause = DateParser.createClauseFromMerged(prefix, token);
|
|
404
439
|
this.index++;
|
|
405
440
|
if (clause === undefined) {
|
|
406
441
|
return false;
|
|
407
442
|
}
|
|
408
443
|
clauses.push(clause);
|
|
409
444
|
return true;
|
|
445
|
+
} else if (token.type === 'NULL' || token.type === 'NOTNULL') {
|
|
446
|
+
clauses.push({operator: token.type});
|
|
410
447
|
}
|
|
411
448
|
return false;
|
|
412
449
|
}
|