@malloydata/malloy 0.0.245 → 0.0.246-dev250320220920

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.
@@ -52,7 +52,7 @@ class PostgresBase extends dialect_1.Dialect {
52
52
  }
53
53
  }
54
54
  const extracted = `EXTRACT(${units} FROM ${extractFrom})`;
55
- return from.units === 'day_of_week' ? `mod(${extracted}+1,7)` : extracted;
55
+ return from.units === 'day_of_week' ? `(${extracted}+1)` : extracted;
56
56
  }
57
57
  sqlCast(qi, cast) {
58
58
  const expr = cast.e.sql || '';
@@ -257,7 +257,7 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
257
257
  timeframe = 'day';
258
258
  n = `${n}*7`;
259
259
  }
260
- const interval = `make_interval(${pgMakeIntervalMap[timeframe]}=>${n})`;
260
+ const interval = `make_interval(${pgMakeIntervalMap[timeframe]}=>(${n})::integer)`;
261
261
  return `(${df.kids.base.sql})${df.op}${interval}`;
262
262
  }
263
263
  sqlCast(qi, cast) {
@@ -270,8 +270,10 @@ ${(0, utils_1.indent)(sql)}
270
270
  return `EXTRACT(${extractUnits} FROM ${extractFrom})`;
271
271
  }
272
272
  sqlAlterTimeExpr(df) {
273
- const interval = `INTERVAL '${df.kids.delta.sql} ${df.units}'`;
274
- return `(${df.kids.base.sql})${df.op}${interval}`;
273
+ var _a;
274
+ const add = ((_a = df.typeDef) === null || _a === void 0 ? void 0 : _a.type) === 'date' ? 'DATEADD' : 'TIMESTAMPADD';
275
+ const n = df.op === '+' ? df.kids.delta.sql : `-(${df.kids.delta.sql})`;
276
+ return `${add}(${df.units},${n},${df.kids.base.sql})`;
275
277
  }
276
278
  atTz(sqlExpr, tz) {
277
279
  if (tz !== undefined) {
@@ -21,6 +21,7 @@ class ExprFilterExpression extends expression_def_1.ExpressionDef {
21
21
  return this.loggedErrorExpr('filter-expression-type', 'Filter expression illegal here');
22
22
  }
23
23
  apply(fs, op, left, _warnOnComplexTree = false) {
24
+ var _a;
24
25
  if (op === '~' || op === '!~') {
25
26
  const matchExpr = left.getExpression(fs);
26
27
  if (matchExpr.type === 'error') {
@@ -35,6 +36,9 @@ class ExprFilterExpression extends expression_def_1.ExpressionDef {
35
36
  fParse = malloy_filter_1.NumberFilterExpression.parse(this.filterText);
36
37
  break;
37
38
  case 'boolean':
39
+ if ((_a = fs.dialectObj()) === null || _a === void 0 ? void 0 : _a.booleanAsNumbers) {
40
+ return this.loggedErrorExpr('filter-expression-type', 'Boolean filters not supported on this connection type');
41
+ }
38
42
  fParse = malloy_filter_1.BooleanFilterExpression.parse(this.filterText);
39
43
  break;
40
44
  case 'date':
@@ -36,7 +36,7 @@ class ExprNow extends expression_def_1.ExpressionDef {
36
36
  expressionType: 'scalar',
37
37
  // `now` is considered to be a constant, at least in the dialects we support today
38
38
  evalSpace: 'constant',
39
- value: { node: 'now' },
39
+ value: { node: 'now', typeDef: { type: 'timestamp' } },
40
40
  compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
41
41
  };
42
42
  }
@@ -197,7 +197,8 @@ expect.extend({
197
197
  if (!badRefs.pass) {
198
198
  return badRefs;
199
199
  }
200
- const rcvExpr = (0, expr_to_str_1.exprToStr)(bx.generated().value, undefined);
200
+ const toExpr = bx.generated().value;
201
+ const rcvExpr = (0, expr_to_str_1.exprToStr)(toExpr, undefined);
201
202
  const pass = this.equals(rcvExpr, expr);
202
203
  const msg = pass ? `Matched: ${rcvExpr}` : this.utils.diff(expr, rcvExpr);
203
204
  return { pass, message: () => `${msg}` };
@@ -1,9 +1,9 @@
1
- import type { BooleanClause, ClauseBase, NumberClause, StringClause, TemporalClause } from '@malloydata/malloy-filter';
1
+ import type { BooleanFilter, FilterExpression, NumberFilter, StringFilter, TemporalFilter } from '@malloydata/malloy-filter';
2
2
  import type { Dialect } from '../dialect';
3
3
  export declare const FilterCompilers: {
4
- compile(t: string, c: ClauseBase, x: string, d: Dialect): string;
5
- numberCompile(nc: NumberClause, x: string, d: Dialect): string;
6
- booleanCompile(bc: BooleanClause, x: string, _d: Dialect): string;
7
- temporalCompile(tc: TemporalClause, x: string, d: Dialect): string;
8
- stringCompile(sc: StringClause, x: string, d: Dialect): string;
4
+ compile(t: string, c: FilterExpression, x: string, d: Dialect): string;
5
+ numberCompile(nc: NumberFilter, x: string, d: Dialect): string;
6
+ booleanCompile(bc: BooleanFilter, x: string, _d: Dialect): string;
7
+ stringCompile(sc: StringFilter, x: string, d: Dialect): string;
8
+ temporalCompile(tc: TemporalFilter, x: string, d: Dialect): string;
9
9
  };
@@ -8,6 +8,7 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.FilterCompilers = void 0;
10
10
  const malloy_filter_1 = require("@malloydata/malloy-filter");
11
+ const filter_temporal_compiler_1 = require("./filter_temporal_compiler");
11
12
  function escapeForLike(v) {
12
13
  return v.replace(/([%_\\])/g, '\\$1');
13
14
  }
@@ -36,16 +37,16 @@ function unlike(disLiked, x) {
36
37
  */
37
38
  exports.FilterCompilers = {
38
39
  compile(t, c, x, d) {
39
- if (t === 'string' && (0, malloy_filter_1.isStringClause)(c)) {
40
+ if (t === 'string' && (0, malloy_filter_1.isStringFilter)(c)) {
40
41
  return exports.FilterCompilers.stringCompile(c, x, d);
41
42
  }
42
- else if (t === 'number' && (0, malloy_filter_1.isNumberClause)(c)) {
43
+ else if (t === 'number' && (0, malloy_filter_1.isNumberFilter)(c)) {
43
44
  return exports.FilterCompilers.numberCompile(c, x, d);
44
45
  }
45
- else if (t === 'boolean' && (0, malloy_filter_1.isBooleanClause)(c)) {
46
+ else if (t === 'boolean' && (0, malloy_filter_1.isBooleanFilter)(c)) {
46
47
  return exports.FilterCompilers.booleanCompile(c, x, d);
47
48
  }
48
- else if ((t === 'date' || t === 'timestamp') && (0, malloy_filter_1.isTemporalClause)(c)) {
49
+ else if ((t === 'date' || t === 'timestamp') && (0, malloy_filter_1.isTemporalFilter)(c)) {
49
50
  return exports.FilterCompilers.temporalCompile(c, x, d);
50
51
  }
51
52
  throw new Error('INTERNAL ERROR: No filter compiler for ' + t);
@@ -93,7 +94,7 @@ exports.FilterCompilers = {
93
94
  case 'or':
94
95
  return nc.members
95
96
  .map(m => exports.FilterCompilers.numberCompile(m, x, d))
96
- .join(` ${nc.operator.toUpperCase()}`);
97
+ .join(` ${nc.operator.toUpperCase()} `);
97
98
  }
98
99
  },
99
100
  booleanCompile(bc, x, _d) {
@@ -108,10 +109,6 @@ exports.FilterCompilers = {
108
109
  return x;
109
110
  }
110
111
  },
111
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
112
- temporalCompile(tc, x, d) {
113
- return 'false';
114
- },
115
112
  stringCompile(sc, x, d) {
116
113
  switch (sc.operator) {
117
114
  case 'null':
@@ -171,6 +168,8 @@ exports.FilterCompilers = {
171
168
  /*
172
169
  * Basic formula over all members
173
170
  * ALL INCLUDED THINGS OR TOGETHER AND ALL EXCLUDED THINGS ANDED TOGETHER
171
+ *
172
+ * mtoy todo write some tests to see if AND clauses are includes or excludes
174
173
  */
175
174
  const includes = [];
176
175
  const excludes = [];
@@ -243,5 +242,10 @@ exports.FilterCompilers = {
243
242
  }
244
243
  }
245
244
  },
245
+ // mtoy todo figure out what to do about dates
246
+ temporalCompile(tc, x, d) {
247
+ const c = new filter_temporal_compiler_1.TemporalFilterCompiler(x, d);
248
+ return c.compile(tc);
249
+ },
246
250
  };
247
251
  //# sourceMappingURL=filter_compilers.js.map
@@ -0,0 +1,28 @@
1
+ import type { TemporalFilter } from '@malloydata/malloy-filter';
2
+ import type { Dialect } from '../dialect';
3
+ /**
4
+ * I felt like there was enough "helpful functions needed to make everything
5
+ * work, all of which need to know the dialect", to justify making a class
6
+ * for this. Maybe this should just be a set of functions which take
7
+ * a dialect as an argument?
8
+ */
9
+ export declare class TemporalFilterCompiler {
10
+ readonly expr: string;
11
+ readonly timetype: 'timestamp' | 'date';
12
+ readonly d: Dialect;
13
+ constructor(expr: string, dialect: Dialect, timetype?: 'timestamp' | 'date');
14
+ compile(tc: TemporalFilter): string;
15
+ private expandLiteral;
16
+ private literalNode;
17
+ private nowExpr;
18
+ private n;
19
+ private delta;
20
+ private dayofWeek;
21
+ private nowDot;
22
+ private thisUnit;
23
+ private lastUnit;
24
+ private nextUnit;
25
+ mod7(n: string): string;
26
+ private moment;
27
+ private isIn;
28
+ }
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TemporalFilterCompiler = void 0;
10
+ const malloy_types_1 = require("./malloy_types");
11
+ const luxon_1 = require("luxon");
12
+ const fYear = 'yyyy';
13
+ const fMonth = `${fYear}-LL`;
14
+ const fDay = `${fMonth}-dd`;
15
+ const fHour = `${fDay} HH`;
16
+ const fMinute = `${fHour}:mm`;
17
+ const fTimestamp = `${fMinute}:ss`;
18
+ /**
19
+ * I felt like there was enough "helpful functions needed to make everything
20
+ * work, all of which need to know the dialect", to justify making a class
21
+ * for this. Maybe this should just be a set of functions which take
22
+ * a dialect as an argument?
23
+ */
24
+ class TemporalFilterCompiler {
25
+ constructor(expr, dialect, timetype = 'timestamp') {
26
+ this.expr = expr;
27
+ this.timetype = timetype;
28
+ this.d = dialect;
29
+ }
30
+ compile(tc) {
31
+ const x = this.expr;
32
+ switch (tc.operator) {
33
+ case 'after':
34
+ return `${x} ${tc.not ? '<' : '>='} ${this.moment(tc.after).end}`;
35
+ case 'before':
36
+ return `${x} ${tc.not ? '>=' : '<'} ${this.moment(tc.before).begin}`;
37
+ case 'in': {
38
+ // mtoy todo in now
39
+ const m = this.moment(tc.in);
40
+ return this.isIn(tc.not, m.begin.sql, m.end);
41
+ }
42
+ case 'for': {
43
+ const start = this.moment(tc.begin);
44
+ const end = this.delta(start.begin, '+', tc.n, tc.units);
45
+ return this.isIn(tc.not, start.begin.sql, end.sql);
46
+ }
47
+ case 'in_last': {
48
+ // last N units means "N - 1 UNITS AGO FOR N UNITS"
49
+ const back = Number(tc.n) - 1;
50
+ const thisUnit = this.nowDot(tc.units);
51
+ const start = back > 0
52
+ ? this.delta(thisUnit, '-', back.toString(), tc.units)
53
+ : thisUnit;
54
+ const end = this.delta(thisUnit, '+', '1', tc.units);
55
+ return this.isIn(tc.not, start.sql, end.sql);
56
+ }
57
+ case 'to': {
58
+ const firstMoment = this.moment(tc.fromMoment);
59
+ const lastMoment = this.moment(tc.toMoment);
60
+ return this.isIn(tc.not, firstMoment.begin.sql, lastMoment.end);
61
+ }
62
+ case 'last': {
63
+ const thisUnit = this.nowDot(tc.units);
64
+ const start = this.delta(thisUnit, '-', tc.n, tc.units);
65
+ return this.isIn(tc.not, start.sql, thisUnit.sql);
66
+ }
67
+ case 'next': {
68
+ const thisUnit = this.nowDot(tc.units);
69
+ const start = this.delta(thisUnit, '+', '1', tc.units);
70
+ const end = this.delta(thisUnit, '+', (Number(tc.n) + 1).toString(), tc.units);
71
+ return this.isIn(tc.not, start.sql, end.sql);
72
+ }
73
+ case 'null':
74
+ return tc.not ? `${x} IS NOT NULL` : `${x} IS NULL`;
75
+ case '()': {
76
+ const wrapped = '(' + this.compile(tc.expr) + ')';
77
+ return tc.not ? `NOT ${wrapped}` : wrapped;
78
+ }
79
+ case 'and':
80
+ case 'or':
81
+ return tc.members
82
+ .map(m => this.compile(m))
83
+ .join(` ${tc.operator.toUpperCase()} `);
84
+ }
85
+ }
86
+ expandLiteral(tl) {
87
+ let literal = tl.literal;
88
+ switch (tl.units) {
89
+ case 'year': {
90
+ const y = luxon_1.DateTime.fromFormat(literal, fYear);
91
+ const begin = this.literalNode(y.toFormat(fTimestamp));
92
+ const next = y.plus({ year: 1 });
93
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
94
+ }
95
+ case 'month': {
96
+ const yyyymm = luxon_1.DateTime.fromFormat(literal, fMonth);
97
+ const begin = this.literalNode(yyyymm.toFormat(fTimestamp));
98
+ const next = yyyymm.plus({ month: 1 });
99
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
100
+ }
101
+ case 'day': {
102
+ const yyyymmdd = luxon_1.DateTime.fromFormat(literal, fDay);
103
+ const begin = this.literalNode(yyyymmdd.toFormat(fTimestamp));
104
+ const next = yyyymmdd.plus({ day: 1 });
105
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
106
+ }
107
+ case 'hour': {
108
+ const ymdh = luxon_1.DateTime.fromFormat(literal, fHour);
109
+ const begin = this.literalNode(ymdh.toFormat(fTimestamp));
110
+ const next = ymdh.plus({ hour: 1 });
111
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
112
+ }
113
+ case 'minute': {
114
+ const ymdhm = luxon_1.DateTime.fromFormat(literal, fMinute);
115
+ const begin = this.literalNode(ymdhm.toFormat(fTimestamp));
116
+ const next = ymdhm.plus({ minute: 1 });
117
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
118
+ }
119
+ case 'week': {
120
+ const a = luxon_1.DateTime.fromFormat(literal.slice(0, 10), fDay);
121
+ // Luxon uses monday weeks, so look for the Monday week which contains
122
+ // the day after, which for all days except Sunday is the same as
123
+ // the sunday week, and on Sunday it is this monday week instead of
124
+ // last monday week.
125
+ const mondayWeek = a.plus({ day: 1 }).startOf('week');
126
+ // Now back that up by one day and we have the Sunday week
127
+ const ymd_wk = mondayWeek.minus({ day: 1 });
128
+ const begin = this.literalNode(ymd_wk.toFormat(fTimestamp));
129
+ const next = ymd_wk.plus({ days: 7 });
130
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
131
+ }
132
+ case 'quarter': {
133
+ const yyyy = literal.slice(0, 4);
134
+ const q = literal.slice(6);
135
+ if (q === '1') {
136
+ literal = `${yyyy}-01-01 00:00:00`;
137
+ }
138
+ else if (q === '2') {
139
+ literal = `${yyyy}-03-01 00:00:00`;
140
+ }
141
+ else if (q === '3') {
142
+ literal = `${yyyy}-06-01 00:00:00`;
143
+ }
144
+ else {
145
+ literal = `${yyyy}-09-01 00:00:00`;
146
+ }
147
+ const begin = this.literalNode(literal);
148
+ const ymd_q = luxon_1.DateTime.fromFormat(literal, fTimestamp);
149
+ const next = ymd_q.plus({ months: 3 });
150
+ return { begin, end: this.literalNode(next.toFormat(fTimestamp)).sql };
151
+ }
152
+ case undefined:
153
+ case 'second':
154
+ return { begin: this.literalNode(literal), end: literal };
155
+ }
156
+ }
157
+ literalNode(literal) {
158
+ const literalNode = {
159
+ node: 'timeLiteral',
160
+ typeDef: { type: 'timestamp' },
161
+ literal,
162
+ };
163
+ return { ...literalNode, sql: this.d.sqlLiteralTime({}, literalNode) };
164
+ }
165
+ nowExpr() {
166
+ return {
167
+ node: 'now',
168
+ typeDef: { type: 'timestamp' },
169
+ sql: this.d.sqlNowExpr(),
170
+ };
171
+ }
172
+ n(literal) {
173
+ return { node: 'numberLiteral', literal, sql: literal };
174
+ }
175
+ delta(from, op, n, units) {
176
+ const ret = {
177
+ node: 'delta',
178
+ op,
179
+ units,
180
+ kids: {
181
+ base: (0, malloy_types_1.mkTemporal)(from, 'timestamp'),
182
+ delta: this.n(n),
183
+ },
184
+ };
185
+ return { ...ret, sql: this.d.sqlAlterTimeExpr(ret) };
186
+ }
187
+ dayofWeek(e) {
188
+ const t = {
189
+ node: 'extract',
190
+ e: (0, malloy_types_1.mkTemporal)(e, 'timestamp'),
191
+ units: 'day_of_week',
192
+ };
193
+ return { ...t, sql: this.d.sqlTimeExtractExpr({}, t) };
194
+ }
195
+ nowDot(units) {
196
+ const nowTruncExpr = {
197
+ node: 'trunc',
198
+ e: this.nowExpr(),
199
+ units,
200
+ };
201
+ return { ...nowTruncExpr, sql: this.d.sqlTruncExpr({}, nowTruncExpr) };
202
+ }
203
+ thisUnit(units) {
204
+ const thisUnit = this.nowDot(units);
205
+ const nextUnit = this.delta(thisUnit, '+', '1', units);
206
+ return { begin: thisUnit, end: nextUnit.sql };
207
+ }
208
+ lastUnit(units) {
209
+ const thisUnit = this.nowDot(units);
210
+ const lastUnit = this.delta(thisUnit, '-', '1', units);
211
+ return { begin: lastUnit, end: thisUnit.sql };
212
+ }
213
+ nextUnit(units) {
214
+ const thisUnit = this.nowDot(units);
215
+ const nextUnit = this.delta(thisUnit, '+', '1', units);
216
+ const next2Unit = this.delta(thisUnit, '+', '2', units);
217
+ return { begin: nextUnit, end: next2Unit.sql };
218
+ }
219
+ mod7(n) {
220
+ return this.d.hasModOperator ? `(${n})%7` : `MOD(${n},7)`;
221
+ }
222
+ moment(m) {
223
+ switch (m.moment) {
224
+ // mtoy todo moments which have no duration should have somethign in the interface?
225
+ case 'now': {
226
+ const now = this.nowExpr();
227
+ return { begin: now, end: now.sql };
228
+ }
229
+ case 'literal':
230
+ return this.expandLiteral(m);
231
+ case 'ago':
232
+ case 'from_now': {
233
+ // mtoy todo just pretending all units work, they don't
234
+ const nowTruncExpr = {
235
+ node: 'trunc',
236
+ e: this.nowExpr(),
237
+ units: m.units,
238
+ };
239
+ nowTruncExpr.sql = this.d.sqlTruncExpr({}, nowTruncExpr);
240
+ const nowTrunc = (0, malloy_types_1.mkTemporal)(nowTruncExpr, 'timestamp');
241
+ const beginExpr = this.delta(nowTrunc, m.moment === 'ago' ? '-' : '+', m.n, m.units);
242
+ // Now the end is one unit after that .. either n-1 units ago or n+1 units from now
243
+ if (m.moment === 'ago' && m.n === '1') {
244
+ return { begin: beginExpr, end: nowTruncExpr.sql };
245
+ }
246
+ const oneDifferent = Number(m.n) + m.moment === 'ago' ? -1 : 1;
247
+ const endExpr = {
248
+ ...beginExpr,
249
+ kids: { base: nowTrunc, delta: this.n(oneDifferent.toString()) },
250
+ };
251
+ return { begin: beginExpr, end: this.d.sqlAlterTimeExpr(endExpr) };
252
+ }
253
+ case 'today':
254
+ return this.thisUnit('day');
255
+ case 'yesterday':
256
+ return this.lastUnit('day');
257
+ case 'tomorrow':
258
+ return this.nextUnit('day');
259
+ case 'this':
260
+ return this.thisUnit(m.units);
261
+ case 'last':
262
+ return this.lastUnit(m.units);
263
+ case 'next':
264
+ return this.nextUnit(m.units);
265
+ case 'monday':
266
+ case 'tuesday':
267
+ case 'wednesday':
268
+ case 'thursday':
269
+ case 'friday':
270
+ case 'saturday':
271
+ case 'sunday': {
272
+ const destDay = [
273
+ 'sunday',
274
+ 'monday',
275
+ 'tuesday',
276
+ 'wednesday',
277
+ 'thursday',
278
+ 'friday',
279
+ 'saturday',
280
+ ].indexOf(m.moment);
281
+ const dow = this.dayofWeek(this.nowExpr()).sql;
282
+ if (m.which === 'next') {
283
+ const nForwards = `${this.mod7(`${destDay}-(${dow}-1)+6`)}+1`;
284
+ const begin = this.delta(this.thisUnit('day').begin, '+', nForwards, 'day');
285
+ const end = this.delta(this.thisUnit('day').begin, '+', `${nForwards}+1`, 'day');
286
+ // console.log(
287
+ // `SELECT ${
288
+ // this.nowExpr().sql
289
+ // } as now,\n ${destDay} as destDay,\n ${dow} as dow,\n ${nForwards} as nForwards,\n ${
290
+ // begin.sql
291
+ // } as begin,\n ${end.sql} as end`
292
+ // );
293
+ return { begin, end: end.sql };
294
+ }
295
+ // dacks back = mod((daw0 - dst) + 6, 7) + 1;
296
+ // dacks back = mod(((daw - 1) - dst) + 6, 7) + 1;
297
+ // dacks back = mod(((daw) - dst) + 7, 7) + 1;
298
+ const nBack = `${this.mod7(`(${dow}-1)-${destDay}+6`)}+1`;
299
+ const begin = this.delta(this.thisUnit('day').begin, '-', nBack, 'day');
300
+ const end = this.delta(this.thisUnit('day').begin, '-', `(${nBack})-1`, 'day');
301
+ // console.log(
302
+ // `SELECT ${
303
+ // this.nowExpr().sql
304
+ // } as now,\n ${destDay} as destDay,\n ${dow} as dow,\n ${nBack} as nBack,\n ${
305
+ // begin.sql
306
+ // } as begin,\n ${end.sql} as end`
307
+ // );
308
+ return { begin, end: end.sql };
309
+ }
310
+ }
311
+ }
312
+ isIn(notIn, begin, end) {
313
+ let begOp = '>=';
314
+ let endOp = '<';
315
+ let joinOp = 'AND';
316
+ if (notIn) {
317
+ joinOp = 'OR';
318
+ begOp = '<';
319
+ endOp = '>=';
320
+ }
321
+ return `${this.expr} ${begOp} ${begin} ${joinOp} ${this.expr} ${endOp} ${end}`;
322
+ }
323
+ }
324
+ exports.TemporalFilterCompiler = TemporalFilterCompiler;
325
+ //# sourceMappingURL=filter_temporal_compiler.js.map
@@ -31,6 +31,7 @@ const utils_1 = require("./utils");
31
31
  const utils_2 = require("./materialization/utils");
32
32
  const annotation_1 = require("../annotation");
33
33
  const filter_compilers_1 = require("./filter_compilers");
34
+ const malloy_filter_1 = require("@malloydata/malloy-filter");
34
35
  function pathToCol(path) {
35
36
  return path.map(el => encodeURIComponent(el)).join('/');
36
37
  }
@@ -885,9 +886,14 @@ class QueryField extends QueryNode {
885
886
  case 'filterMatch':
886
887
  if (expr.dataType === 'string' ||
887
888
  expr.dataType === 'number' ||
889
+ expr.dataType === 'date' ||
890
+ expr.dataType === 'timestamp' ||
888
891
  expr.dataType === 'boolean') {
889
- return filter_compilers_1.FilterCompilers.compile(expr.dataType, expr.filter, expr.e.sql || '', this.parent.dialect);
892
+ if ((0, malloy_filter_1.isFilterExpression)(expr.filter)) {
893
+ return filter_compilers_1.FilterCompilers.compile(expr.dataType, expr.filter, expr.e.sql || '', this.parent.dialect);
894
+ }
890
895
  }
896
+ // mtoy todo no throw
891
897
  throw new Error(`Internal Error: Filter Compiler Undefined (FCU) ${expr.dataType}`);
892
898
  default:
893
899
  throw new Error(`Internal Error: Unknown expression node '${expr.node}' ${JSON.stringify(expr, undefined, 2)}`);
@@ -114,11 +114,14 @@ export interface ParameterNode extends ExprLeaf {
114
114
  }
115
115
  export interface NowNode extends ExprLeaf {
116
116
  node: 'now';
117
+ typeDef: {
118
+ type: 'timestamp';
119
+ };
117
120
  }
118
121
  interface HasTimeValue {
119
122
  typeDef: TemporalTypeDef;
120
123
  }
121
- type TimeExpr = Expr & HasTimeValue;
124
+ export type TimeExpr = Expr & HasTimeValue;
122
125
  export declare function mkTemporal(e: Expr, timeType: TemporalTypeDef | TemporalFieldType): TimeExpr;
123
126
  export interface MeasureTimeExpr extends ExprWithKids {
124
127
  node: 'timeDiff';
@@ -58,9 +58,11 @@ function canMakeTemporal(e) {
58
58
  return e.node !== 'arrayLiteral' && e.node !== 'recordLiteral';
59
59
  }
60
60
  function mkTemporal(e, timeType) {
61
- const ttd = typeof timeType === 'string' ? { type: timeType } : timeType;
62
- if (canMakeTemporal(e)) {
63
- return { ...e, typeDef: { ...ttd } };
61
+ if (!('typeDef' in e)) {
62
+ const ttd = typeof timeType === 'string' ? { type: timeType } : timeType;
63
+ if (canMakeTemporal(e)) {
64
+ return { ...e, typeDef: { ...ttd } };
65
+ }
64
66
  }
65
67
  return e;
66
68
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.245";
1
+ export declare const MALLOY_VERSION = "0.0.246";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.245';
5
+ exports.MALLOY_VERSION = '0.0.246';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.245",
3
+ "version": "0.0.246-dev250320220920",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -41,9 +41,9 @@
41
41
  "generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
42
42
  },
43
43
  "dependencies": {
44
- "@malloydata/malloy-filter": "^0.0.245",
45
- "@malloydata/malloy-interfaces": "^0.0.245",
46
- "@malloydata/malloy-tag": "^0.0.245",
44
+ "@malloydata/malloy-filter": "^0.0.246-dev250320220920",
45
+ "@malloydata/malloy-interfaces": "^0.0.246-dev250320220920",
46
+ "@malloydata/malloy-tag": "^0.0.246-dev250320220920",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jest-diff": "^29.6.2",