@malloydata/malloy 0.0.1

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 (104) hide show
  1. package/README.md +39 -0
  2. package/dist/connection_utils.d.ts +1 -0
  3. package/dist/connection_utils.js +56 -0
  4. package/dist/dialect/dialect-map.d.ts +3 -0
  5. package/dist/dialect/dialect-map.js +33 -0
  6. package/dist/dialect/dialect.d.ts +64 -0
  7. package/dist/dialect/dialect.js +64 -0
  8. package/dist/dialect/dialect_map.d.ts +3 -0
  9. package/dist/dialect/dialect_map.js +35 -0
  10. package/dist/dialect/duckdb.d.ts +49 -0
  11. package/dist/dialect/duckdb.js +349 -0
  12. package/dist/dialect/index.d.ts +6 -0
  13. package/dist/dialect/index.js +27 -0
  14. package/dist/dialect/postgres.d.ts +49 -0
  15. package/dist/dialect/postgres.js +308 -0
  16. package/dist/dialect/standardsql.d.ts +46 -0
  17. package/dist/dialect/standardsql.js +361 -0
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.js +47 -0
  20. package/dist/lang/ast/apply-expr.d.ts +16 -0
  21. package/dist/lang/ast/apply-expr.js +215 -0
  22. package/dist/lang/ast/ast-expr.d.ts +291 -0
  23. package/dist/lang/ast/ast-expr.js +1056 -0
  24. package/dist/lang/ast/ast-main.d.ts +480 -0
  25. package/dist/lang/ast/ast-main.js +2096 -0
  26. package/dist/lang/ast/ast-time-expr.d.ts +109 -0
  27. package/dist/lang/ast/ast-time-expr.js +550 -0
  28. package/dist/lang/ast/ast-types.d.ts +83 -0
  29. package/dist/lang/ast/ast-types.js +215 -0
  30. package/dist/lang/ast/index.d.ts +5 -0
  31. package/dist/lang/ast/index.js +34 -0
  32. package/dist/lang/ast/time-utils.d.ts +8 -0
  33. package/dist/lang/ast/time-utils.js +83 -0
  34. package/dist/lang/field-space.d.ts +157 -0
  35. package/dist/lang/field-space.js +651 -0
  36. package/dist/lang/field-utils.d.ts +5 -0
  37. package/dist/lang/field-utils.js +33 -0
  38. package/dist/lang/index.d.ts +9 -0
  39. package/dist/lang/index.js +22 -0
  40. package/dist/lang/lib/Malloy/MalloyLexer.d.ts +156 -0
  41. package/dist/lang/lib/Malloy/MalloyLexer.js +1163 -0
  42. package/dist/lang/lib/Malloy/MalloyListener.d.ts +2026 -0
  43. package/dist/lang/lib/Malloy/MalloyListener.js +4 -0
  44. package/dist/lang/lib/Malloy/MalloyParser.d.ts +1920 -0
  45. package/dist/lang/lib/Malloy/MalloyParser.js +11790 -0
  46. package/dist/lang/lib/Malloy/MalloyVisitor.d.ts +1276 -0
  47. package/dist/lang/lib/Malloy/MalloyVisitor.js +4 -0
  48. package/dist/lang/parse-log.d.ts +27 -0
  49. package/dist/lang/parse-log.js +41 -0
  50. package/dist/lang/parse-malloy.d.ts +245 -0
  51. package/dist/lang/parse-malloy.js +729 -0
  52. package/dist/lang/parse-to-ast.d.ts +156 -0
  53. package/dist/lang/parse-to-ast.js +945 -0
  54. package/dist/lang/parse-tree-walkers/document-completion-walker.d.ts +10 -0
  55. package/dist/lang/parse-tree-walkers/document-completion-walker.js +136 -0
  56. package/dist/lang/parse-tree-walkers/document-help-context-walker.d.ts +9 -0
  57. package/dist/lang/parse-tree-walkers/document-help-context-walker.js +97 -0
  58. package/dist/lang/parse-tree-walkers/document-highlight-walker.d.ts +83 -0
  59. package/dist/lang/parse-tree-walkers/document-highlight-walker.js +375 -0
  60. package/dist/lang/parse-tree-walkers/document-symbol-walker.d.ts +11 -0
  61. package/dist/lang/parse-tree-walkers/document-symbol-walker.js +172 -0
  62. package/dist/lang/parse-tree-walkers/explore-query-walker.d.ts +34 -0
  63. package/dist/lang/parse-tree-walkers/explore-query-walker.js +64 -0
  64. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +11 -0
  65. package/dist/lang/parse-tree-walkers/find-external-references.js +51 -0
  66. package/dist/lang/reference-list.d.ts +10 -0
  67. package/dist/lang/reference-list.js +80 -0
  68. package/dist/lang/space-field.d.ts +119 -0
  69. package/dist/lang/space-field.js +339 -0
  70. package/dist/lang/test/document-help-context-walker.spec.d.ts +1 -0
  71. package/dist/lang/test/document-help-context-walker.spec.js +45 -0
  72. package/dist/lang/test/document-symbol-walker.spec.d.ts +1 -0
  73. package/dist/lang/test/document-symbol-walker.spec.js +100 -0
  74. package/dist/lang/test/field-symbols.spec.d.ts +1 -0
  75. package/dist/lang/test/field-symbols.spec.js +172 -0
  76. package/dist/lang/test/parse.spec.d.ts +12 -0
  77. package/dist/lang/test/parse.spec.js +1936 -0
  78. package/dist/lang/test/test-translator.d.ts +38 -0
  79. package/dist/lang/test/test-translator.js +334 -0
  80. package/dist/lang/zone.d.ts +57 -0
  81. package/dist/lang/zone.js +97 -0
  82. package/dist/malloy.d.ts +1134 -0
  83. package/dist/malloy.js +2354 -0
  84. package/dist/model/index.d.ts +2 -0
  85. package/dist/model/index.js +34 -0
  86. package/dist/model/malloy-query.d.ts +313 -0
  87. package/dist/model/malloy-query.js +2603 -0
  88. package/dist/model/malloy-types.d.ts +404 -0
  89. package/dist/model/malloy-types.js +242 -0
  90. package/dist/model/malloy_query.d.ts +353 -0
  91. package/dist/model/malloy_query.js +2990 -0
  92. package/dist/model/malloy_types.d.ts +502 -0
  93. package/dist/model/malloy_types.js +283 -0
  94. package/dist/model/sql-block.d.ts +11 -0
  95. package/dist/model/sql-block.js +38 -0
  96. package/dist/model/sql_block.d.ts +11 -0
  97. package/dist/model/sql_block.js +41 -0
  98. package/dist/model/utils.d.ts +21 -0
  99. package/dist/model/utils.js +84 -0
  100. package/dist/runtime-types.d.ts +116 -0
  101. package/dist/runtime-types.js +40 -0
  102. package/dist/runtime_types.d.ts +119 -0
  103. package/dist/runtime_types.js +15 -0
  104. package/package.json +36 -0
@@ -0,0 +1,109 @@
1
+ import { TimestampUnit, ExtractUnit, TimeFieldType } from "../../model/malloy_types";
2
+ import { FSPair } from "../field-space";
3
+ import { ExpressionDef, BinaryBoolean, ExprValue, MalloyElement, Comparison } from "./index";
4
+ export declare class Timeframe extends MalloyElement {
5
+ elementType: string;
6
+ readonly text: TimestampUnit;
7
+ constructor(timeframeName: string);
8
+ }
9
+ /**
10
+ * GranularTime is a moment in time which ALSO has a "granularity"
11
+ * commonly this are created by applying ".datePart" to an expression
12
+ * 1) They have a value, which is the moment in time
13
+ * 2) When used in a comparison, they act like a range, for the
14
+ * duration of 1 unit of granularity
15
+ */
16
+ export declare class ExprGranularTime extends ExpressionDef {
17
+ readonly expr: ExpressionDef;
18
+ readonly units: TimestampUnit;
19
+ readonly truncate: boolean;
20
+ elementType: string;
21
+ legalChildTypes: import("./ast-types").FragType[];
22
+ constructor(expr: ExpressionDef, units: TimestampUnit, truncate: boolean);
23
+ granular(): boolean;
24
+ getExpression(fs: FSPair): ExprValue;
25
+ apply(fs: FSPair, op: string, left: ExpressionDef): ExprValue;
26
+ protected timestampRange(fs: FSPair, op: string, expr: ExpressionDef): ExprValue;
27
+ protected dateRange(fs: FSPair, op: string, expr: ExpressionDef): ExprValue;
28
+ }
29
+ /**
30
+ * GranularTime made from a literal. Funky because it doesn't know if it
31
+ * is a date or a timestamp in many cases until it is applied.
32
+ */
33
+ export declare class GranularLiteral extends ExpressionDef {
34
+ readonly moment: string;
35
+ readonly until: string;
36
+ readonly units: TimestampUnit;
37
+ elementType: string;
38
+ timeType?: TimeFieldType;
39
+ constructor(moment: string, until: string, units: TimestampUnit);
40
+ granular(): boolean;
41
+ static parse(possibleLiteral: string): GranularLiteral | undefined;
42
+ apply(fs: FSPair, op: string, left: ExpressionDef): ExprValue;
43
+ getExpression(fs: FSPair): ExprValue;
44
+ }
45
+ export declare class ExprNow extends ExpressionDef {
46
+ elementType: string;
47
+ getExpression(_fs: FSPair): ExprValue;
48
+ }
49
+ export declare class ExprDuration extends ExpressionDef {
50
+ readonly n: ExpressionDef;
51
+ readonly timeframe: TimestampUnit;
52
+ elementType: string;
53
+ legalChildTypes: import("./ast-types").FragType[];
54
+ constructor(n: ExpressionDef, timeframe: TimestampUnit);
55
+ apply(fs: FSPair, op: string, left: ExpressionDef): ExprValue;
56
+ getExpression(_fs: FSPair): ExprValue;
57
+ }
58
+ export declare class ExprCompare extends BinaryBoolean<Comparison> {
59
+ elementType: string;
60
+ constructor(left: ExpressionDef, op: Comparison, right: ExpressionDef);
61
+ getExpression(fs: FSPair): ExprValue;
62
+ }
63
+ export declare class Apply extends ExprCompare {
64
+ readonly left: ExpressionDef;
65
+ readonly right: ExpressionDef;
66
+ elementType: string;
67
+ constructor(left: ExpressionDef, right: ExpressionDef);
68
+ }
69
+ export declare class PartialCompare extends ExpressionDef {
70
+ readonly op: Comparison;
71
+ readonly right: ExpressionDef;
72
+ elementType: string;
73
+ constructor(op: Comparison, right: ExpressionDef);
74
+ granular(): boolean;
75
+ apply(fs: FSPair, op: string, expr: ExpressionDef): ExprValue;
76
+ requestExpression(_fs: FSPair): ExprValue | undefined;
77
+ getExpression(_fs: FSPair): ExprValue;
78
+ }
79
+ /**
80
+ * TODO: This is sort of a hand clone of the "Range" class, they should
81
+ * be siblings of a common abstract classs.
82
+ */
83
+ export declare class ForRange extends ExpressionDef {
84
+ readonly from: ExpressionDef;
85
+ readonly duration: ExpressionDef;
86
+ readonly timeframe: Timeframe;
87
+ elementType: string;
88
+ legalChildTypes: import("./ast-types").FragType[];
89
+ constructor(from: ExpressionDef, duration: ExpressionDef, timeframe: Timeframe);
90
+ apply(fs: FSPair, op: string, expr: ExpressionDef): ExprValue;
91
+ requestExpression(_fs: FSPair): ExprValue | undefined;
92
+ getExpression(_fs: FSPair): ExprValue;
93
+ }
94
+ export declare class ExprTimeExtract extends ExpressionDef {
95
+ readonly extractText: string;
96
+ readonly args: ExpressionDef[];
97
+ elementType: string;
98
+ static pluralMap: Record<string, ExtractUnit>;
99
+ static extractor(funcName: string): ExtractUnit | undefined;
100
+ constructor(extractText: string, args: ExpressionDef[]);
101
+ getExpression(fs: FSPair): ExprValue;
102
+ }
103
+ export declare class ExprFunc extends ExpressionDef {
104
+ readonly name: string;
105
+ readonly args: ExpressionDef[];
106
+ elementType: string;
107
+ constructor(name: string, args: ExpressionDef[]);
108
+ getExpression(fs: FSPair): ExprValue;
109
+ }
@@ -0,0 +1,550 @@
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 dialect = fs.in.getDialect();
201
+ const range = new index_1.Range(new index_1.ExprTime(rangeType, dialect.sqlLiteralTime(this.moment, rangeType, "UTC")), new index_1.ExprTime(rangeType, dialect.sqlLiteralTime(this.until, rangeType, "UTC")));
202
+ return range.apply(fs, op, left);
203
+ }
204
+ return super.apply(fs, op, left);
205
+ }
206
+ getExpression(fs) {
207
+ const dataType = this.timeType || "date";
208
+ const value = {
209
+ dataType,
210
+ aggregate: false,
211
+ value: [fs.in.getDialect().sqlLiteralTime(this.moment, dataType, "UTC")],
212
+ };
213
+ // Literals with date resolution can be used as timestamps or dates,
214
+ // this is the third attempt to make that work. It still feels like
215
+ // there should be a better way to make this happen, but the point
216
+ // at which the data is needed, the handle is gone to the ExpressionDef
217
+ // which would allow a method call into this class. I think the second
218
+ // if clause is redundant (see "parse" above, but I'm paranoid)
219
+ if (dataType == "date" && (0, malloy_types_1.isDateUnit)(this.units)) {
220
+ value.alsoTimestamp = true;
221
+ }
222
+ if (this.units != "second") {
223
+ return {
224
+ ...value,
225
+ timeframe: this.units,
226
+ };
227
+ }
228
+ return value;
229
+ }
230
+ }
231
+ exports.GranularLiteral = GranularLiteral;
232
+ class ExprNow extends index_1.ExpressionDef {
233
+ constructor() {
234
+ super(...arguments);
235
+ this.elementType = "timestamp";
236
+ }
237
+ getExpression(_fs) {
238
+ return {
239
+ dataType: "timestamp",
240
+ aggregate: false,
241
+ value: [
242
+ {
243
+ type: "dialect",
244
+ function: "now",
245
+ },
246
+ ],
247
+ };
248
+ }
249
+ }
250
+ exports.ExprNow = ExprNow;
251
+ class ExprDuration extends index_1.ExpressionDef {
252
+ constructor(n, timeframe) {
253
+ super({ n });
254
+ this.n = n;
255
+ this.timeframe = timeframe;
256
+ this.elementType = "duration";
257
+ this.legalChildTypes = [index_1.FT.timestampT, index_1.FT.dateT];
258
+ }
259
+ apply(fs, op, left) {
260
+ const lhs = left.getExpression(fs);
261
+ this.typeCheck(this, lhs);
262
+ if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType) && (op === "+" || op === "-")) {
263
+ const num = this.n.getExpression(fs);
264
+ if (!index_1.FT.typeEq(num, index_1.FT.numberT)) {
265
+ this.log(`Duration units needs number not '${num.dataType}`);
266
+ return (0, index_1.errorFor)("illegal unit expression");
267
+ }
268
+ let resultGranularity;
269
+ // Only allow the output of this to be granular if the
270
+ // granularities match, this is still an area where
271
+ // more thought is required.
272
+ if ((0, index_1.isGranularResult)(lhs) && lhs.timeframe == this.timeframe) {
273
+ resultGranularity = lhs.timeframe;
274
+ }
275
+ if (lhs.dataType === "timestamp") {
276
+ const result = (0, index_1.timeOffset)("timestamp", lhs.value, op, num.value, this.timeframe);
277
+ return (0, index_1.timeResult)({
278
+ dataType: "timestamp",
279
+ aggregate: lhs.aggregate || num.aggregate,
280
+ value: result,
281
+ }, resultGranularity);
282
+ }
283
+ return (0, index_1.timeResult)({
284
+ dataType: "date",
285
+ aggregate: lhs.aggregate || num.aggregate,
286
+ value: (0, index_1.timeOffset)("date", lhs.value, op, num.value, this.timeframe),
287
+ }, resultGranularity);
288
+ }
289
+ return super.apply(fs, op, left);
290
+ }
291
+ getExpression(_fs) {
292
+ return {
293
+ dataType: "duration",
294
+ aggregate: false,
295
+ value: ["__ERROR_DURATION_IS_NOT_A_VALUE__"],
296
+ };
297
+ }
298
+ }
299
+ exports.ExprDuration = ExprDuration;
300
+ class ExprCompare extends index_1.BinaryBoolean {
301
+ constructor(left, op, right) {
302
+ super(left, op, right);
303
+ this.elementType = "a<=>b";
304
+ this.legalChildTypes = compareTypes[op];
305
+ }
306
+ getExpression(fs) {
307
+ if (!this.right.granular()) {
308
+ const rhs = this.right.requestExpression(fs);
309
+ if (rhs && (0, index_1.isGranularResult)(rhs)) {
310
+ const newRight = new ExprGranularTime(this.right, rhs.timeframe, false);
311
+ return newRight.apply(fs, this.op, this.left);
312
+ }
313
+ }
314
+ return this.right.apply(fs, this.op, this.left);
315
+ }
316
+ }
317
+ exports.ExprCompare = ExprCompare;
318
+ class Apply extends ExprCompare {
319
+ constructor(left, right) {
320
+ super(left, "=", right);
321
+ this.left = left;
322
+ this.right = right;
323
+ this.elementType = "apply";
324
+ }
325
+ }
326
+ exports.Apply = Apply;
327
+ const compareTypes = {
328
+ "~": [index_1.FT.stringT],
329
+ "!~": [index_1.FT.stringT],
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
+ ">": [index_1.FT.numberT, index_1.FT.stringT, index_1.FT.dateT, index_1.FT.timestampT],
336
+ };
337
+ class PartialCompare extends index_1.ExpressionDef {
338
+ constructor(op, right) {
339
+ super({ right });
340
+ this.op = op;
341
+ this.right = right;
342
+ this.elementType = "<=> a";
343
+ }
344
+ granular() {
345
+ return this.right.granular();
346
+ }
347
+ apply(fs, op, expr) {
348
+ return this.right.apply(fs, this.op, expr);
349
+ }
350
+ requestExpression(_fs) {
351
+ return undefined;
352
+ }
353
+ getExpression(_fs) {
354
+ this.log(`Partial comparison does not have a value`);
355
+ return (0, index_1.errorFor)("no value for partial compare");
356
+ }
357
+ }
358
+ exports.PartialCompare = PartialCompare;
359
+ /**
360
+ * TODO: This is sort of a hand clone of the "Range" class, they should
361
+ * be siblings of a common abstract classs.
362
+ */
363
+ class ForRange extends index_1.ExpressionDef {
364
+ constructor(from, duration, timeframe) {
365
+ super({ from, duration, timeframe });
366
+ this.from = from;
367
+ this.duration = duration;
368
+ this.timeframe = timeframe;
369
+ this.elementType = "forRange";
370
+ this.legalChildTypes = [index_1.FT.timestampT, index_1.FT.dateT];
371
+ }
372
+ apply(fs, op, expr) {
373
+ const startV = this.from.getExpression(fs);
374
+ const checkV = expr.getExpression(fs);
375
+ if (!this.typeCheck(expr, checkV)) {
376
+ return (0, index_1.errorFor)("no time for range");
377
+ }
378
+ const nV = this.duration.getExpression(fs);
379
+ if (nV.dataType !== "number") {
380
+ this.log(`FOR duration count must be a number, not '${nV.dataType}'`);
381
+ return (0, index_1.errorFor)("FOR not number");
382
+ }
383
+ const units = this.timeframe.text;
384
+ // If the duration resolution is smaller than date, we have
385
+ // to do the computaion with timestamps.
386
+ const durationRes = (0, index_1.resolution)(units);
387
+ let rangeType = durationRes;
388
+ // Next, if the beginning of the range is a timestamp, then we
389
+ // also have to do the computation as a timestamp
390
+ if (startV.dataType === "timestamp") {
391
+ rangeType = "timestamp";
392
+ }
393
+ // everything is dates, do date math
394
+ if (checkV.dataType === "date" && rangeType === "date") {
395
+ const rangeStart = this.from;
396
+ const rangeEndV = (0, index_1.timeOffset)("date", startV.value, "+", nV.value, units);
397
+ const rangeEnd = new index_1.ExprTime("date", rangeEndV);
398
+ return new index_1.Range(rangeStart, rangeEnd).apply(fs, op, expr);
399
+ }
400
+ // Now it doesn't matter if the range is a date or a timestamp,
401
+ // the comparison will be in timestamp space,
402
+ const applyTo = index_1.ExprTime.fromValue("timestamp", checkV);
403
+ let rangeStart = this.from;
404
+ let from = startV.value;
405
+ if (startV.dataType === "date") {
406
+ // Time literals with timestamp units can also be used as timestamps;
407
+ const alreadyTs = (0, index_1.isGranularResult)(startV) && startV.alsoTimestamp;
408
+ if (!alreadyTs) {
409
+ // ... not a literal, need a cast
410
+ from = (0, index_1.castDateToTimestamp)(from);
411
+ }
412
+ rangeStart = new index_1.ExprTime("timestamp", from, startV.aggregate);
413
+ }
414
+ const to = (0, index_1.timeOffset)("timestamp", from, "+", nV.value, units);
415
+ const rangeEnd = new index_1.ExprTime("timestamp", to, startV.aggregate);
416
+ return new index_1.Range(rangeStart, rangeEnd).apply(fs, op, applyTo);
417
+ }
418
+ requestExpression(_fs) {
419
+ return undefined;
420
+ }
421
+ getExpression(_fs) {
422
+ this.log("A Range is not a value");
423
+ return (0, index_1.errorFor)("range has no value");
424
+ }
425
+ }
426
+ exports.ForRange = ForRange;
427
+ class ExprTimeExtract extends index_1.ExpressionDef {
428
+ constructor(extractText, args) {
429
+ super({ args });
430
+ this.extractText = extractText;
431
+ this.args = args;
432
+ this.elementType = "timeExtract";
433
+ }
434
+ static extractor(funcName) {
435
+ const mappedName = ExprTimeExtract.pluralMap[funcName];
436
+ if (mappedName) {
437
+ return mappedName;
438
+ }
439
+ if ((0, malloy_types_1.isExtractUnit)(funcName)) {
440
+ return funcName;
441
+ }
442
+ }
443
+ getExpression(fs) {
444
+ const extractTo = ExprTimeExtract.extractor(this.extractText);
445
+ if (extractTo) {
446
+ if (this.args.length !== 1) {
447
+ this.log(`Extraction function ${extractTo} requires one argument`);
448
+ return (0, index_1.errorFor)(`{this.name} arg count`);
449
+ }
450
+ const from = this.args[0];
451
+ if (from instanceof index_1.Range) {
452
+ const first = from.first.getExpression(fs);
453
+ const last = from.last.getExpression(fs);
454
+ if (!(0, malloy_types_1.isTimeFieldType)(first.dataType)) {
455
+ from.first.log(`Can't extract ${extractTo} from '${first.dataType}'`);
456
+ return (0, index_1.errorFor)(`${extractTo} bad type ${first.dataType}`);
457
+ }
458
+ if (!(0, malloy_types_1.isTimeFieldType)(last.dataType)) {
459
+ from.last.log(`Cannot extract ${extractTo} from '${last.dataType}'`);
460
+ return (0, index_1.errorFor)(`${extractTo} bad type ${last.dataType}`);
461
+ }
462
+ if (!(0, malloy_types_1.isTimestampUnit)(extractTo)) {
463
+ this.log(`Cannot extract ${extractTo} from a range`);
464
+ return (0, index_1.errorFor)(`${extractTo} bad extraction`);
465
+ }
466
+ return {
467
+ dataType: "number",
468
+ aggregate: first.aggregate || last.aggregate,
469
+ value: [
470
+ {
471
+ type: "dialect",
472
+ function: "timeDiff",
473
+ units: extractTo,
474
+ left: { valueType: first.dataType, value: first.value },
475
+ right: { valueType: last.dataType, value: last.value },
476
+ },
477
+ ],
478
+ };
479
+ }
480
+ else {
481
+ const argV = from.getExpression(fs);
482
+ if ((0, malloy_types_1.isTimeFieldType)(argV.dataType)) {
483
+ return {
484
+ dataType: "number",
485
+ aggregate: argV.aggregate,
486
+ value: [
487
+ {
488
+ type: "dialect",
489
+ function: "extract",
490
+ expr: { value: argV.value, valueType: argV.dataType },
491
+ units: extractTo,
492
+ },
493
+ ],
494
+ };
495
+ }
496
+ this.log(`${this.extractText}() requires time type, not '${argV.dataType}'`);
497
+ return (0, index_1.errorFor)(`${this.extractText} bad type ${argV.dataType}`);
498
+ }
499
+ }
500
+ throw this.internalError(`Illegal extraction unit '${this.extractText}'`);
501
+ }
502
+ }
503
+ exports.ExprTimeExtract = ExprTimeExtract;
504
+ ExprTimeExtract.pluralMap = {
505
+ years: "year",
506
+ quarters: "quarter",
507
+ months: "month",
508
+ weeks: "week",
509
+ days: "day",
510
+ hours: "hour",
511
+ minutes: "minute",
512
+ seconds: "second",
513
+ };
514
+ class ExprFunc extends index_1.ExpressionDef {
515
+ constructor(name, args) {
516
+ super({ args });
517
+ this.name = name;
518
+ this.args = args;
519
+ this.elementType = "function call()";
520
+ }
521
+ getExpression(fs) {
522
+ var _a, _b;
523
+ let anyAggregate = false;
524
+ let collectType;
525
+ const funcCall = [`${this.name}(`];
526
+ for (const fexpr of this.args) {
527
+ const expr = fexpr.getExpression(fs);
528
+ if (expr.aggregate) {
529
+ anyAggregate = true;
530
+ }
531
+ if (collectType) {
532
+ funcCall.push(",");
533
+ }
534
+ else {
535
+ collectType = expr.dataType;
536
+ }
537
+ funcCall.push(...expr.value);
538
+ }
539
+ funcCall.push(")");
540
+ const funcInfo = fs.in.getDialect().getFunctionInfo(this.name);
541
+ const dataType = (_b = (_a = funcInfo === null || funcInfo === void 0 ? void 0 : funcInfo.returnType) !== null && _a !== void 0 ? _a : collectType) !== null && _b !== void 0 ? _b : "number";
542
+ return {
543
+ dataType: dataType,
544
+ aggregate: anyAggregate,
545
+ value: (0, index_1.compressExpr)(funcCall),
546
+ };
547
+ }
548
+ }
549
+ exports.ExprFunc = ExprFunc;
550
+ //# sourceMappingURL=ast-time-expr.js.map