@malloydata/malloy 0.0.2 → 0.0.4
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 +12 -11
- package/dist/dialect/duckdb.d.ts +1 -1
- package/dist/dialect/postgres.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/lang/ast/ast-expr.d.ts +0 -1
- package/dist/lang/field-space.d.ts +9 -7
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +108 -106
- package/dist/lang/lib/Malloy/MalloyLexer.js +1019 -1006
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +581 -590
- package/dist/lang/lib/Malloy/MalloyParser.js +1141 -1202
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +2015 -0
- package/dist/lang/lib/Malloy/MalloyParserListener.js +4 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +1269 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.js +4 -0
- package/dist/lang/parse-to-ast.d.ts +3 -4
- package/dist/lang/parse-to-ast.js +1 -1
- package/dist/lang/parse-tree-walkers/document-completion-walker.js +2 -0
- package/dist/lang/parse-tree-walkers/explore-query-walker.d.ts +2 -2
- package/dist/malloy.d.ts +1 -1
- package/dist/md5.d.ts +1 -0
- package/dist/md5.js +30 -0
- package/dist/model/malloy_types.d.ts +3 -1
- package/package.json +9 -14
- package/dist/connection_utils.js +0 -56
- package/dist/dialect/dialect-map.d.ts +0 -3
- package/dist/dialect/dialect-map.js +0 -33
- package/dist/dialect/dialect.js +0 -77
- package/dist/dialect/dialect_map.js +0 -35
- package/dist/dialect/duckdb.js +0 -349
- package/dist/dialect/index.js +0 -27
- package/dist/dialect/postgres.js +0 -308
- package/dist/dialect/standardsql.js +0 -361
- package/dist/index.js +0 -47
- package/dist/lang/ast/apply-expr.js +0 -231
- package/dist/lang/ast/ast-expr.js +0 -1051
- package/dist/lang/ast/ast-main.js +0 -2086
- package/dist/lang/ast/ast-time-expr.js +0 -549
- package/dist/lang/ast/ast-types.js +0 -215
- package/dist/lang/ast/index.js +0 -34
- package/dist/lang/ast/time-utils.js +0 -94
- package/dist/lang/field-space.js +0 -629
- package/dist/lang/field-utils.js +0 -33
- package/dist/lang/index.js +0 -22
- package/dist/lang/parse-log.js +0 -41
- package/dist/lang/reference-list.js +0 -80
- package/dist/lang/space-field.js +0 -346
- package/dist/lang/test/document-help-context-walker.spec.js +0 -45
- package/dist/lang/test/document-symbol-walker.spec.js +0 -100
- package/dist/lang/test/field-symbols.spec.js +0 -172
- package/dist/lang/test/parse.spec.js +0 -1936
- package/dist/lang/test/test-translator.js +0 -334
- package/dist/lang/zone.js +0 -97
- package/dist/malloy.js +0 -2354
- package/dist/model/index.js +0 -34
- package/dist/model/malloy-query.d.ts +0 -313
- package/dist/model/malloy-query.js +0 -2603
- package/dist/model/malloy-types.d.ts +0 -404
- package/dist/model/malloy-types.js +0 -242
- package/dist/model/malloy_query.js +0 -2996
- package/dist/model/malloy_types.js +0 -283
- package/dist/model/sql-block.d.ts +0 -11
- package/dist/model/sql-block.js +0 -38
- package/dist/model/sql_block.js +0 -41
- package/dist/model/utils.js +0 -84
- package/dist/runtime-types.d.ts +0 -116
- package/dist/runtime-types.js +0 -40
- package/dist/runtime_types.js +0 -15
|
@@ -1,549 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright 2021 Google LLC
|
|
4
|
-
*
|
|
5
|
-
* This program is free software; you can redistribute it and/or
|
|
6
|
-
* modify it under the terms of the GNU General Public License
|
|
7
|
-
* version 2 as published by the Free Software Foundation.
|
|
8
|
-
*
|
|
9
|
-
* This program is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*/
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.ExprFunc = exports.ExprTimeExtract = exports.ForRange = exports.PartialCompare = exports.Apply = exports.ExprCompare = exports.ExprDuration = exports.ExprNow = exports.GranularLiteral = exports.ExprGranularTime = exports.Timeframe = void 0;
|
|
16
|
-
const luxon_1 = require("luxon");
|
|
17
|
-
const malloy_types_1 = require("../../model/malloy_types");
|
|
18
|
-
const index_1 = require("./index");
|
|
19
|
-
class Timeframe extends index_1.MalloyElement {
|
|
20
|
-
constructor(timeframeName) {
|
|
21
|
-
super();
|
|
22
|
-
this.elementType = "timeframe";
|
|
23
|
-
let tf = timeframeName.toLowerCase();
|
|
24
|
-
if (tf.endsWith("s")) {
|
|
25
|
-
tf = tf.slice(0, -1);
|
|
26
|
-
}
|
|
27
|
-
this.text = (0, malloy_types_1.isTimestampUnit)(tf) ? tf : "second";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
exports.Timeframe = Timeframe;
|
|
31
|
-
/**
|
|
32
|
-
* GranularTime is a moment in time which ALSO has a "granularity"
|
|
33
|
-
* commonly this are created by applying ".datePart" to an expression
|
|
34
|
-
* 1) They have a value, which is the moment in time
|
|
35
|
-
* 2) When used in a comparison, they act like a range, for the
|
|
36
|
-
* duration of 1 unit of granularity
|
|
37
|
-
*/
|
|
38
|
-
class ExprGranularTime extends index_1.ExpressionDef {
|
|
39
|
-
constructor(expr, units, truncate) {
|
|
40
|
-
super({ expr });
|
|
41
|
-
this.expr = expr;
|
|
42
|
-
this.units = units;
|
|
43
|
-
this.truncate = truncate;
|
|
44
|
-
this.elementType = "granularTime";
|
|
45
|
-
this.legalChildTypes = [index_1.FT.timestampT, index_1.FT.dateT];
|
|
46
|
-
}
|
|
47
|
-
granular() {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
getExpression(fs) {
|
|
51
|
-
const timeframe = this.units;
|
|
52
|
-
const exprVal = this.expr.getExpression(fs);
|
|
53
|
-
if ((0, malloy_types_1.isTimeFieldType)(exprVal.dataType)) {
|
|
54
|
-
const tsVal = {
|
|
55
|
-
...exprVal,
|
|
56
|
-
dataType: exprVal.dataType,
|
|
57
|
-
timeframe: timeframe,
|
|
58
|
-
};
|
|
59
|
-
if (this.truncate) {
|
|
60
|
-
tsVal.value = [
|
|
61
|
-
{
|
|
62
|
-
type: "dialect",
|
|
63
|
-
function: "trunc",
|
|
64
|
-
expr: { value: exprVal.value, valueType: exprVal.dataType },
|
|
65
|
-
units: timeframe,
|
|
66
|
-
},
|
|
67
|
-
];
|
|
68
|
-
}
|
|
69
|
-
return tsVal;
|
|
70
|
-
}
|
|
71
|
-
this.log(`Cannot do time truncation on type '${exprVal.dataType}'`);
|
|
72
|
-
return (0, index_1.errorFor)(`granularity typecheck`);
|
|
73
|
-
}
|
|
74
|
-
apply(fs, op, left) {
|
|
75
|
-
const rangeType = this.getExpression(fs).dataType;
|
|
76
|
-
const _valueType = left.getExpression(fs).dataType;
|
|
77
|
-
const granularityType = (0, malloy_types_1.isDateUnit)(this.units) ? "date" : "timestamp";
|
|
78
|
-
if (rangeType == "date" && granularityType == "date") {
|
|
79
|
-
return this.dateRange(fs, op, left);
|
|
80
|
-
}
|
|
81
|
-
return this.timestampRange(fs, op, left);
|
|
82
|
-
/*
|
|
83
|
-
write tests for each of these cases ....
|
|
84
|
-
|
|
85
|
-
vt rt gt use
|
|
86
|
-
dt dt dt dateRange
|
|
87
|
-
dt dt ts == or timeStampRange
|
|
88
|
-
dt ts dt timestampRange
|
|
89
|
-
dt ts ts timeStampRange
|
|
90
|
-
|
|
91
|
-
ts ts ts timestampRange
|
|
92
|
-
ts ts dt timestampRange
|
|
93
|
-
ts dt ts timestampRange
|
|
94
|
-
ts dt dt either
|
|
95
|
-
|
|
96
|
-
*/
|
|
97
|
-
}
|
|
98
|
-
timestampRange(fs, op, expr) {
|
|
99
|
-
const begin = this.getExpression(fs);
|
|
100
|
-
const beginTime = index_1.ExprTime.fromValue("timestamp", begin);
|
|
101
|
-
const endTime = new index_1.ExprTime("timestamp", (0, index_1.timeOffset)("timestamp", begin.value, "+", (0, malloy_types_1.mkExpr) `1`, this.units), begin.aggregate);
|
|
102
|
-
const range = new index_1.Range(beginTime, endTime);
|
|
103
|
-
return range.apply(fs, op, expr);
|
|
104
|
-
}
|
|
105
|
-
dateRange(fs, op, expr) {
|
|
106
|
-
const begin = this.getExpression(fs);
|
|
107
|
-
const beginTime = new index_1.ExprTime("date", begin.value, begin.aggregate);
|
|
108
|
-
const endAt = (0, index_1.timeOffset)("date", begin.value, "+", ["1"], this.units);
|
|
109
|
-
const end = new index_1.ExprTime("date", endAt, begin.aggregate);
|
|
110
|
-
const range = new index_1.Range(beginTime, end);
|
|
111
|
-
return range.apply(fs, op, expr);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
exports.ExprGranularTime = ExprGranularTime;
|
|
115
|
-
/**
|
|
116
|
-
* GranularTime made from a literal. Funky because it doesn't know if it
|
|
117
|
-
* is a date or a timestamp in many cases until it is applied.
|
|
118
|
-
*/
|
|
119
|
-
class GranularLiteral extends index_1.ExpressionDef {
|
|
120
|
-
constructor(moment, until, units) {
|
|
121
|
-
super();
|
|
122
|
-
this.moment = moment;
|
|
123
|
-
this.until = until;
|
|
124
|
-
this.units = units;
|
|
125
|
-
this.elementType = "timeLiteral";
|
|
126
|
-
}
|
|
127
|
-
granular() {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
static parse(possibleLiteral) {
|
|
131
|
-
const s = possibleLiteral.slice(1);
|
|
132
|
-
const fYear = "yyyy";
|
|
133
|
-
const fMonth = `${fYear}-LL`;
|
|
134
|
-
const fDay = `${fMonth}-dd`;
|
|
135
|
-
const fMinute = `${fDay} HH:mm`;
|
|
136
|
-
const fSecond = `${fMinute}:ss`;
|
|
137
|
-
const tss = luxon_1.DateTime.fromFormat(s, fSecond);
|
|
138
|
-
if (tss.isValid) {
|
|
139
|
-
const nextSecond = tss.plus({ second: 1 }).toFormat(fSecond);
|
|
140
|
-
const tsLit = new GranularLiteral(s, nextSecond, "second");
|
|
141
|
-
tsLit.timeType = "timestamp";
|
|
142
|
-
return tsLit;
|
|
143
|
-
}
|
|
144
|
-
const tsm = luxon_1.DateTime.fromFormat(s, fMinute);
|
|
145
|
-
if (tsm.isValid) {
|
|
146
|
-
// working around a weird bigquery bug ...
|
|
147
|
-
const thisMin = s + ":00";
|
|
148
|
-
const nextMinute = tsm.plus({ minute: 1 }).toFormat(fMinute) + ":00";
|
|
149
|
-
const tsLit = new GranularLiteral(thisMin, nextMinute, "minute");
|
|
150
|
-
tsLit.timeType = "timestamp";
|
|
151
|
-
return tsLit;
|
|
152
|
-
}
|
|
153
|
-
const quarter = s.match(/(\d{4})-[qQ](\d)$/);
|
|
154
|
-
if (quarter) {
|
|
155
|
-
const qplus = Number.parseInt(quarter[2]) - 1;
|
|
156
|
-
let qstart = luxon_1.DateTime.fromFormat(quarter[1], "yyyy");
|
|
157
|
-
if (qplus > 0) {
|
|
158
|
-
qstart = qstart.plus({ quarters: qplus });
|
|
159
|
-
}
|
|
160
|
-
const qend = qstart.plus({ quarter: 1 });
|
|
161
|
-
return new GranularLiteral(`${qstart.toFormat(fDay)}`, `${qend.toFormat(fDay)}`, "quarter");
|
|
162
|
-
}
|
|
163
|
-
const yyyymmdd = luxon_1.DateTime.fromFormat(s, fDay);
|
|
164
|
-
if (yyyymmdd.isValid) {
|
|
165
|
-
const next = yyyymmdd.plus({ days: 1 });
|
|
166
|
-
return new GranularLiteral(`${yyyymmdd.toFormat(fDay)}`, `${next.toFormat(fDay)}`, "day");
|
|
167
|
-
}
|
|
168
|
-
const yyyymm = luxon_1.DateTime.fromFormat(s, fMonth);
|
|
169
|
-
if (yyyymm.isValid) {
|
|
170
|
-
const next = yyyymm.plus({ months: 1 });
|
|
171
|
-
return new GranularLiteral(`${yyyymm.toFormat(fDay)}`, `${next.toFormat(fDay)}`, "month");
|
|
172
|
-
}
|
|
173
|
-
const yyyy = luxon_1.DateTime.fromFormat(s, fYear);
|
|
174
|
-
if (yyyy.isValid) {
|
|
175
|
-
const year = yyyy.toFormat(`yyyy-01-01`);
|
|
176
|
-
const nextYear = yyyy.plus({ year: 1 }).toFormat(`yyyy-01-01`);
|
|
177
|
-
return new GranularLiteral(year, nextYear, "year");
|
|
178
|
-
}
|
|
179
|
-
if (s.startsWith("WK")) {
|
|
180
|
-
const yyyymmdd = luxon_1.DateTime.fromFormat(s.slice(2), fDay);
|
|
181
|
-
if (yyyymmdd.isValid) {
|
|
182
|
-
// wonky because luxon uses monday weeks and bigquery uses sunday weeks
|
|
183
|
-
let sunday = yyyymmdd;
|
|
184
|
-
if (yyyymmdd.weekday !== 7) {
|
|
185
|
-
sunday = yyyymmdd.startOf("week").minus({ day: 1 });
|
|
186
|
-
}
|
|
187
|
-
const next = sunday.plus({ days: 7 });
|
|
188
|
-
return new GranularLiteral(`${sunday.toFormat(fDay)}`, `${next.toFormat(fDay)}`, "week");
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return undefined;
|
|
192
|
-
}
|
|
193
|
-
apply(fs, op, left) {
|
|
194
|
-
const lhs = left.getExpression(fs);
|
|
195
|
-
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType)) {
|
|
196
|
-
let rangeType = "timestamp";
|
|
197
|
-
if (lhs.dataType === "date" && !this.timeType) {
|
|
198
|
-
rangeType = "date";
|
|
199
|
-
}
|
|
200
|
-
const range = new index_1.Range(new index_1.ExprTime(rangeType, (0, index_1.timeLiteral)(this.moment, rangeType, "UTC")), new index_1.ExprTime(rangeType, (0, index_1.timeLiteral)(this.until, rangeType, "UTC")));
|
|
201
|
-
return range.apply(fs, op, left);
|
|
202
|
-
}
|
|
203
|
-
return super.apply(fs, op, left);
|
|
204
|
-
}
|
|
205
|
-
getExpression(_fs) {
|
|
206
|
-
const dataType = this.timeType || "date";
|
|
207
|
-
const value = {
|
|
208
|
-
dataType,
|
|
209
|
-
aggregate: false,
|
|
210
|
-
value: (0, index_1.timeLiteral)(this.moment, dataType, "UTC"),
|
|
211
|
-
};
|
|
212
|
-
// Literals with date resolution can be used as timestamps or dates,
|
|
213
|
-
// this is the third attempt to make that work. It still feels like
|
|
214
|
-
// there should be a better way to make this happen, but the point
|
|
215
|
-
// at which the data is needed, the handle is gone to the ExpressionDef
|
|
216
|
-
// which would allow a method call into this class. I think the second
|
|
217
|
-
// if clause is redundant (see "parse" above, but I'm paranoid)
|
|
218
|
-
if (dataType == "date" && (0, malloy_types_1.isDateUnit)(this.units)) {
|
|
219
|
-
value.alsoTimestamp = true;
|
|
220
|
-
}
|
|
221
|
-
if (this.units != "second") {
|
|
222
|
-
return {
|
|
223
|
-
...value,
|
|
224
|
-
timeframe: this.units,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
return value;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
exports.GranularLiteral = GranularLiteral;
|
|
231
|
-
class ExprNow extends index_1.ExpressionDef {
|
|
232
|
-
constructor() {
|
|
233
|
-
super(...arguments);
|
|
234
|
-
this.elementType = "timestamp";
|
|
235
|
-
}
|
|
236
|
-
getExpression(_fs) {
|
|
237
|
-
return {
|
|
238
|
-
dataType: "timestamp",
|
|
239
|
-
aggregate: false,
|
|
240
|
-
value: [
|
|
241
|
-
{
|
|
242
|
-
type: "dialect",
|
|
243
|
-
function: "now",
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
exports.ExprNow = ExprNow;
|
|
250
|
-
class ExprDuration extends index_1.ExpressionDef {
|
|
251
|
-
constructor(n, timeframe) {
|
|
252
|
-
super({ n });
|
|
253
|
-
this.n = n;
|
|
254
|
-
this.timeframe = timeframe;
|
|
255
|
-
this.elementType = "duration";
|
|
256
|
-
this.legalChildTypes = [index_1.FT.timestampT, index_1.FT.dateT];
|
|
257
|
-
}
|
|
258
|
-
apply(fs, op, left) {
|
|
259
|
-
const lhs = left.getExpression(fs);
|
|
260
|
-
this.typeCheck(this, lhs);
|
|
261
|
-
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType) && (op === "+" || op === "-")) {
|
|
262
|
-
const num = this.n.getExpression(fs);
|
|
263
|
-
if (!index_1.FT.typeEq(num, index_1.FT.numberT)) {
|
|
264
|
-
this.log(`Duration units needs number not '${num.dataType}`);
|
|
265
|
-
return (0, index_1.errorFor)("illegal unit expression");
|
|
266
|
-
}
|
|
267
|
-
let resultGranularity;
|
|
268
|
-
// Only allow the output of this to be granular if the
|
|
269
|
-
// granularities match, this is still an area where
|
|
270
|
-
// more thought is required.
|
|
271
|
-
if ((0, index_1.isGranularResult)(lhs) && lhs.timeframe == this.timeframe) {
|
|
272
|
-
resultGranularity = lhs.timeframe;
|
|
273
|
-
}
|
|
274
|
-
if (lhs.dataType === "timestamp") {
|
|
275
|
-
const result = (0, index_1.timeOffset)("timestamp", lhs.value, op, num.value, this.timeframe);
|
|
276
|
-
return (0, index_1.timeResult)({
|
|
277
|
-
dataType: "timestamp",
|
|
278
|
-
aggregate: lhs.aggregate || num.aggregate,
|
|
279
|
-
value: result,
|
|
280
|
-
}, resultGranularity);
|
|
281
|
-
}
|
|
282
|
-
return (0, index_1.timeResult)({
|
|
283
|
-
dataType: "date",
|
|
284
|
-
aggregate: lhs.aggregate || num.aggregate,
|
|
285
|
-
value: (0, index_1.timeOffset)("date", lhs.value, op, num.value, this.timeframe),
|
|
286
|
-
}, resultGranularity);
|
|
287
|
-
}
|
|
288
|
-
return super.apply(fs, op, left);
|
|
289
|
-
}
|
|
290
|
-
getExpression(_fs) {
|
|
291
|
-
return {
|
|
292
|
-
dataType: "duration",
|
|
293
|
-
aggregate: false,
|
|
294
|
-
value: ["__ERROR_DURATION_IS_NOT_A_VALUE__"],
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
exports.ExprDuration = ExprDuration;
|
|
299
|
-
class ExprCompare extends index_1.BinaryBoolean {
|
|
300
|
-
constructor(left, op, right) {
|
|
301
|
-
super(left, op, right);
|
|
302
|
-
this.elementType = "a<=>b";
|
|
303
|
-
this.legalChildTypes = compareTypes[op];
|
|
304
|
-
}
|
|
305
|
-
getExpression(fs) {
|
|
306
|
-
if (!this.right.granular()) {
|
|
307
|
-
const rhs = this.right.requestExpression(fs);
|
|
308
|
-
if (rhs && (0, index_1.isGranularResult)(rhs)) {
|
|
309
|
-
const newRight = new ExprGranularTime(this.right, rhs.timeframe, false);
|
|
310
|
-
return newRight.apply(fs, this.op, this.left);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return this.right.apply(fs, this.op, this.left);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
exports.ExprCompare = ExprCompare;
|
|
317
|
-
class Apply extends ExprCompare {
|
|
318
|
-
constructor(left, right) {
|
|
319
|
-
super(left, "=", right);
|
|
320
|
-
this.left = left;
|
|
321
|
-
this.right = right;
|
|
322
|
-
this.elementType = "apply";
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
exports.Apply = Apply;
|
|
326
|
-
const compareTypes = {
|
|
327
|
-
"~": [index_1.FT.stringT],
|
|
328
|
-
"!~": [index_1.FT.stringT],
|
|
329
|
-
"<": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
330
|
-
"<=": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
331
|
-
"=": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
332
|
-
"!=": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
333
|
-
">=": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
334
|
-
">": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
|
|
335
|
-
};
|
|
336
|
-
class PartialCompare extends index_1.ExpressionDef {
|
|
337
|
-
constructor(op, right) {
|
|
338
|
-
super({ right });
|
|
339
|
-
this.op = op;
|
|
340
|
-
this.right = right;
|
|
341
|
-
this.elementType = "<=> a";
|
|
342
|
-
}
|
|
343
|
-
granular() {
|
|
344
|
-
return this.right.granular();
|
|
345
|
-
}
|
|
346
|
-
apply(fs, op, expr) {
|
|
347
|
-
return this.right.apply(fs, this.op, expr);
|
|
348
|
-
}
|
|
349
|
-
requestExpression(_fs) {
|
|
350
|
-
return undefined;
|
|
351
|
-
}
|
|
352
|
-
getExpression(_fs) {
|
|
353
|
-
this.log(`Partial comparison does not have a value`);
|
|
354
|
-
return (0, index_1.errorFor)("no value for partial compare");
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
exports.PartialCompare = PartialCompare;
|
|
358
|
-
/**
|
|
359
|
-
* TODO: This is sort of a hand clone of the "Range" class, they should
|
|
360
|
-
* be siblings of a common abstract classs.
|
|
361
|
-
*/
|
|
362
|
-
class ForRange extends index_1.ExpressionDef {
|
|
363
|
-
constructor(from, duration, timeframe) {
|
|
364
|
-
super({ from, duration, timeframe });
|
|
365
|
-
this.from = from;
|
|
366
|
-
this.duration = duration;
|
|
367
|
-
this.timeframe = timeframe;
|
|
368
|
-
this.elementType = "forRange";
|
|
369
|
-
this.legalChildTypes = [index_1.FT.timestampT, index_1.FT.dateT];
|
|
370
|
-
}
|
|
371
|
-
apply(fs, op, expr) {
|
|
372
|
-
const startV = this.from.getExpression(fs);
|
|
373
|
-
const checkV = expr.getExpression(fs);
|
|
374
|
-
if (!this.typeCheck(expr, checkV)) {
|
|
375
|
-
return (0, index_1.errorFor)("no time for range");
|
|
376
|
-
}
|
|
377
|
-
const nV = this.duration.getExpression(fs);
|
|
378
|
-
if (nV.dataType !== "number") {
|
|
379
|
-
this.log(`FOR duration count must be a number, not '${nV.dataType}'`);
|
|
380
|
-
return (0, index_1.errorFor)("FOR not number");
|
|
381
|
-
}
|
|
382
|
-
const units = this.timeframe.text;
|
|
383
|
-
// If the duration resolution is smaller than date, we have
|
|
384
|
-
// to do the computaion with timestamps.
|
|
385
|
-
const durationRes = (0, index_1.resolution)(units);
|
|
386
|
-
let rangeType = durationRes;
|
|
387
|
-
// Next, if the beginning of the range is a timestamp, then we
|
|
388
|
-
// also have to do the computation as a timestamp
|
|
389
|
-
if (startV.dataType === "timestamp") {
|
|
390
|
-
rangeType = "timestamp";
|
|
391
|
-
}
|
|
392
|
-
// everything is dates, do date math
|
|
393
|
-
if (checkV.dataType === "date" && rangeType === "date") {
|
|
394
|
-
const rangeStart = this.from;
|
|
395
|
-
const rangeEndV = (0, index_1.timeOffset)("date", startV.value, "+", nV.value, units);
|
|
396
|
-
const rangeEnd = new index_1.ExprTime("date", rangeEndV);
|
|
397
|
-
return new index_1.Range(rangeStart, rangeEnd).apply(fs, op, expr);
|
|
398
|
-
}
|
|
399
|
-
// Now it doesn't matter if the range is a date or a timestamp,
|
|
400
|
-
// the comparison will be in timestamp space,
|
|
401
|
-
const applyTo = index_1.ExprTime.fromValue("timestamp", checkV);
|
|
402
|
-
let rangeStart = this.from;
|
|
403
|
-
let from = startV.value;
|
|
404
|
-
if (startV.dataType === "date") {
|
|
405
|
-
// Time literals with timestamp units can also be used as timestamps;
|
|
406
|
-
const alreadyTs = (0, index_1.isGranularResult)(startV) && startV.alsoTimestamp;
|
|
407
|
-
if (!alreadyTs) {
|
|
408
|
-
// ... not a literal, need a cast
|
|
409
|
-
from = (0, index_1.castDateToTimestamp)(from);
|
|
410
|
-
}
|
|
411
|
-
rangeStart = new index_1.ExprTime("timestamp", from, startV.aggregate);
|
|
412
|
-
}
|
|
413
|
-
const to = (0, index_1.timeOffset)("timestamp", from, "+", nV.value, units);
|
|
414
|
-
const rangeEnd = new index_1.ExprTime("timestamp", to, startV.aggregate);
|
|
415
|
-
return new index_1.Range(rangeStart, rangeEnd).apply(fs, op, applyTo);
|
|
416
|
-
}
|
|
417
|
-
requestExpression(_fs) {
|
|
418
|
-
return undefined;
|
|
419
|
-
}
|
|
420
|
-
getExpression(_fs) {
|
|
421
|
-
this.log("A Range is not a value");
|
|
422
|
-
return (0, index_1.errorFor)("range has no value");
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
exports.ForRange = ForRange;
|
|
426
|
-
class ExprTimeExtract extends index_1.ExpressionDef {
|
|
427
|
-
constructor(extractText, args) {
|
|
428
|
-
super({ args });
|
|
429
|
-
this.extractText = extractText;
|
|
430
|
-
this.args = args;
|
|
431
|
-
this.elementType = "timeExtract";
|
|
432
|
-
}
|
|
433
|
-
static extractor(funcName) {
|
|
434
|
-
const mappedName = ExprTimeExtract.pluralMap[funcName];
|
|
435
|
-
if (mappedName) {
|
|
436
|
-
return mappedName;
|
|
437
|
-
}
|
|
438
|
-
if ((0, malloy_types_1.isExtractUnit)(funcName)) {
|
|
439
|
-
return funcName;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
getExpression(fs) {
|
|
443
|
-
const extractTo = ExprTimeExtract.extractor(this.extractText);
|
|
444
|
-
if (extractTo) {
|
|
445
|
-
if (this.args.length !== 1) {
|
|
446
|
-
this.log(`Extraction function ${extractTo} requires one argument`);
|
|
447
|
-
return (0, index_1.errorFor)(`{this.name} arg count`);
|
|
448
|
-
}
|
|
449
|
-
const from = this.args[0];
|
|
450
|
-
if (from instanceof index_1.Range) {
|
|
451
|
-
const first = from.first.getExpression(fs);
|
|
452
|
-
const last = from.last.getExpression(fs);
|
|
453
|
-
if (!(0, malloy_types_1.isTimeFieldType)(first.dataType)) {
|
|
454
|
-
from.first.log(`Can't extract ${extractTo} from '${first.dataType}'`);
|
|
455
|
-
return (0, index_1.errorFor)(`${extractTo} bad type ${first.dataType}`);
|
|
456
|
-
}
|
|
457
|
-
if (!(0, malloy_types_1.isTimeFieldType)(last.dataType)) {
|
|
458
|
-
from.last.log(`Cannot extract ${extractTo} from '${last.dataType}'`);
|
|
459
|
-
return (0, index_1.errorFor)(`${extractTo} bad type ${last.dataType}`);
|
|
460
|
-
}
|
|
461
|
-
if (!(0, malloy_types_1.isTimestampUnit)(extractTo)) {
|
|
462
|
-
this.log(`Cannot extract ${extractTo} from a range`);
|
|
463
|
-
return (0, index_1.errorFor)(`${extractTo} bad extraction`);
|
|
464
|
-
}
|
|
465
|
-
return {
|
|
466
|
-
dataType: "number",
|
|
467
|
-
aggregate: first.aggregate || last.aggregate,
|
|
468
|
-
value: [
|
|
469
|
-
{
|
|
470
|
-
type: "dialect",
|
|
471
|
-
function: "timeDiff",
|
|
472
|
-
units: extractTo,
|
|
473
|
-
left: { valueType: first.dataType, value: first.value },
|
|
474
|
-
right: { valueType: last.dataType, value: last.value },
|
|
475
|
-
},
|
|
476
|
-
],
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
const argV = from.getExpression(fs);
|
|
481
|
-
if ((0, malloy_types_1.isTimeFieldType)(argV.dataType)) {
|
|
482
|
-
return {
|
|
483
|
-
dataType: "number",
|
|
484
|
-
aggregate: argV.aggregate,
|
|
485
|
-
value: [
|
|
486
|
-
{
|
|
487
|
-
type: "dialect",
|
|
488
|
-
function: "extract",
|
|
489
|
-
expr: { value: argV.value, valueType: argV.dataType },
|
|
490
|
-
units: extractTo,
|
|
491
|
-
},
|
|
492
|
-
],
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
this.log(`${this.extractText}() requires time type, not '${argV.dataType}'`);
|
|
496
|
-
return (0, index_1.errorFor)(`${this.extractText} bad type ${argV.dataType}`);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
throw this.internalError(`Illegal extraction unit '${this.extractText}'`);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
exports.ExprTimeExtract = ExprTimeExtract;
|
|
503
|
-
ExprTimeExtract.pluralMap = {
|
|
504
|
-
years: "year",
|
|
505
|
-
quarters: "quarter",
|
|
506
|
-
months: "month",
|
|
507
|
-
weeks: "week",
|
|
508
|
-
days: "day",
|
|
509
|
-
hours: "hour",
|
|
510
|
-
minutes: "minute",
|
|
511
|
-
seconds: "second",
|
|
512
|
-
};
|
|
513
|
-
class ExprFunc extends index_1.ExpressionDef {
|
|
514
|
-
constructor(name, args) {
|
|
515
|
-
super({ args });
|
|
516
|
-
this.name = name;
|
|
517
|
-
this.args = args;
|
|
518
|
-
this.elementType = "function call()";
|
|
519
|
-
}
|
|
520
|
-
getExpression(fs) {
|
|
521
|
-
var _a, _b, _c;
|
|
522
|
-
let anyAggregate = false;
|
|
523
|
-
let collectType;
|
|
524
|
-
const funcCall = [`${this.name}(`];
|
|
525
|
-
for (const fexpr of this.args) {
|
|
526
|
-
const expr = fexpr.getExpression(fs);
|
|
527
|
-
if (expr.aggregate) {
|
|
528
|
-
anyAggregate = true;
|
|
529
|
-
}
|
|
530
|
-
if (collectType) {
|
|
531
|
-
funcCall.push(",");
|
|
532
|
-
}
|
|
533
|
-
else {
|
|
534
|
-
collectType = expr.dataType;
|
|
535
|
-
}
|
|
536
|
-
funcCall.push(...expr.value);
|
|
537
|
-
}
|
|
538
|
-
funcCall.push(")");
|
|
539
|
-
const dialect = fs.dialectObj();
|
|
540
|
-
const dataType = (_c = (_b = (_a = dialect === null || dialect === void 0 ? void 0 : dialect.getFunctionInfo(this.name)) === null || _a === void 0 ? void 0 : _a.returnType) !== null && _b !== void 0 ? _b : collectType) !== null && _c !== void 0 ? _c : "number";
|
|
541
|
-
return {
|
|
542
|
-
dataType: dataType,
|
|
543
|
-
aggregate: anyAggregate,
|
|
544
|
-
value: (0, index_1.compressExpr)(funcCall),
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
exports.ExprFunc = ExprFunc;
|
|
549
|
-
//# sourceMappingURL=ast-time-expr.js.map
|