@malloydata/malloy 0.0.137-dev240327175808 → 0.0.137-dev240328161656

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.
@@ -1,8 +1,11 @@
1
1
  import { ExprCompare } from './expr-compare';
2
2
  import { ExpressionDef } from '../types/expression-def';
3
+ import { ExprValue } from '../types/expr-value';
4
+ import { FieldSpace } from '../types/field-space';
3
5
  export declare class Apply extends ExprCompare {
4
6
  readonly left: ExpressionDef;
5
7
  readonly right: ExpressionDef;
6
8
  elementType: string;
7
9
  constructor(left: ExpressionDef, right: ExpressionDef);
10
+ getExpression(fs: FieldSpace): ExprValue;
8
11
  }
@@ -25,6 +25,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.Apply = void 0;
26
26
  const comparison_1 = require("../types/comparison");
27
27
  const expr_compare_1 = require("./expr-compare");
28
+ const granular_result_1 = require("../types/granular-result");
29
+ const expr_granular_time_1 = require("./expr-granular-time");
28
30
  class Apply extends expr_compare_1.ExprCompare {
29
31
  constructor(left, right) {
30
32
  super(left, comparison_1.Comparison.EqualTo, right);
@@ -32,6 +34,20 @@ class Apply extends expr_compare_1.ExprCompare {
32
34
  this.right = right;
33
35
  this.elementType = 'apply';
34
36
  }
37
+ getExpression(fs) {
38
+ let right = this.right;
39
+ if (!this.right.granular()) {
40
+ const rhs = this.right.requestExpression(fs);
41
+ if (rhs && (0, granular_result_1.isGranularResult)(rhs)) {
42
+ // Need to wrap granular computations to get granular behavior
43
+ right = new expr_granular_time_1.ExprGranularTime(this.right, rhs.timeframe, false);
44
+ }
45
+ }
46
+ if (right instanceof expr_granular_time_1.ExprGranularTime) {
47
+ return right.toRange(fs).apply(fs, this.op, this.left);
48
+ }
49
+ return super.getExpression(fs);
50
+ }
35
51
  }
36
52
  exports.Apply = Apply;
37
53
  //# sourceMappingURL=apply.js.map
@@ -24,9 +24,7 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ExprCompare = void 0;
26
26
  const fragtype_utils_1 = require("../fragtype-utils");
27
- const granular_result_1 = require("../types/granular-result");
28
27
  const binary_boolean_1 = require("./binary-boolean");
29
- const expr_granular_time_1 = require("./expr-granular-time");
30
28
  const compareTypes = {
31
29
  '~': [fragtype_utils_1.FT.stringT],
32
30
  '!~': [fragtype_utils_1.FT.stringT],
@@ -44,13 +42,6 @@ class ExprCompare extends binary_boolean_1.BinaryBoolean {
44
42
  this.legalChildTypes = compareTypes[op];
45
43
  }
46
44
  getExpression(fs) {
47
- if (!this.right.granular()) {
48
- const rhs = this.right.requestExpression(fs);
49
- if (rhs && (0, granular_result_1.isGranularResult)(rhs)) {
50
- const newRight = new expr_granular_time_1.ExprGranularTime(this.right, rhs.timeframe, false);
51
- return newRight.apply(fs, this.op, this.left);
52
- }
53
- }
54
45
  return this.right.apply(fs, this.op, this.left);
55
46
  }
56
47
  }
@@ -19,6 +19,5 @@ export declare class ExprGranularTime extends ExpressionDef {
19
19
  constructor(expr: ExpressionDef, units: TimestampUnit, truncate: boolean);
20
20
  granular(): boolean;
21
21
  getExpression(fs: FieldSpace): ExprValue;
22
- apply(fs: FieldSpace, op: string, left: ExpressionDef): ExprValue;
23
- protected getRange(fs: FieldSpace): Range;
22
+ toRange(fs: FieldSpace): Range;
24
23
  }
@@ -85,25 +85,22 @@ class ExprGranularTime extends expression_def_1.ExpressionDef {
85
85
  evalSpace: 'constant',
86
86
  };
87
87
  }
88
- apply(fs, op, left) {
89
- return this.getRange(fs).apply(fs, op, left);
90
- /*
91
- write tests for each of these cases ....
92
-
93
- vt rt gt use
94
- dt dt dt dateRange
95
- dt dt ts == or timeStampRange
96
- dt ts dt timestampRange
97
- dt ts ts timeStampRange
98
-
99
- ts ts ts timestampRange
100
- ts ts dt timestampRange
101
- ts dt ts timestampRange
102
- ts dt dt either
103
-
104
- */
105
- }
106
- getRange(fs) {
88
+ // apply(fs: FieldSpace, op: string, left: ExpressionDef): ExprValue {
89
+ // return this.getRange(fs).apply(fs, op, left);
90
+ // /*
91
+ // write tests for each of these cases ....
92
+ // vt rt gt use
93
+ // dt dt dt dateRange
94
+ // dt dt ts == or timeStampRange
95
+ // dt ts dt timestampRange
96
+ // dt ts ts timeStampRange
97
+ // ts ts ts timestampRange
98
+ // ts ts dt timestampRange
99
+ // ts dt ts timestampRange
100
+ // ts dt dt either
101
+ // */
102
+ // }
103
+ toRange(fs) {
107
104
  const begin = this.getExpression(fs);
108
105
  if (begin.dataType === 'timestamp') {
109
106
  const beginTS = expr_time_1.ExprTime.fromValue('timestamp', begin);
@@ -25,6 +25,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  const model_1 = require("../../model");
26
26
  const test_translator_1 = require("./test-translator");
27
27
  require("./parse-expects");
28
+ /**
29
+ * Convert an expression to a string, any fragment which is not a string turns into a variable,
30
+ * useful for maybe checking simple code generation, but it sort of hints at an interesting matcher
31
+ * @param expr Compiled expression
32
+ * @returns A string with variables A,B,... substituded for non string elements
33
+ */
34
+ function exprToString(expr) {
35
+ let varCode = 'A'.charCodeAt(0);
36
+ const vars = {};
37
+ return expr
38
+ .map(f => {
39
+ if (typeof f === 'string') {
40
+ return f;
41
+ }
42
+ const key = JSON.stringify(f);
43
+ if (!vars[key]) {
44
+ vars[key] = String.fromCharCode(varCode);
45
+ varCode += 1;
46
+ }
47
+ return vars[key];
48
+ })
49
+ .join('');
50
+ }
28
51
  describe('expressions', () => {
29
52
  describe('timeframes', () => {
30
53
  const timeframes = [
@@ -125,6 +148,39 @@ describe('expressions', () => {
125
148
  test('disallow interval from date to timestamp', () => {
126
149
  expect(new test_translator_1.BetaExpression('days(ad to ats)')).translationToFailWith('Cannot measure from date to timestamp');
127
150
  });
151
+ test('compare to truncation uses straight comparison', () => {
152
+ const compare = (0, test_translator_1.expr) `ad = ad.quarter`;
153
+ expect(compare).toTranslate();
154
+ const compare_expr = compare.translator.generated().value;
155
+ expect(exprToString(compare_expr)).toEqual('A=B');
156
+ });
157
+ test('compare to granular result expression uses straight comparison', () => {
158
+ const compare = (0, test_translator_1.expr) `ad = ad.quarter + 1`;
159
+ expect(compare).toTranslate();
160
+ const compare_expr = compare.translator.generated().value;
161
+ expect(exprToString(compare_expr)).toEqual('A=B');
162
+ });
163
+ test('apply granular-truncation uses range', () => {
164
+ const compare = (0, test_translator_1.expr) `ad ? ad.quarter`;
165
+ expect(compare).toTranslate();
166
+ const compare_expr = compare.translator.generated().value;
167
+ expect(exprToString(compare_expr)).toEqual('(A>=B)and(A<C)');
168
+ });
169
+ test('apply granular-literal alternation uses range', () => {
170
+ const compare = (0, test_translator_1.expr) `ad ? @2020 | @2022`;
171
+ expect(compare).toTranslate();
172
+ const compare_expr = compare.translator.generated().value;
173
+ expect(exprToString(compare_expr)).toEqual('((A>=B)and(A<C))or((A>=D)and(A<E))');
174
+ });
175
+ // this should use range, but it uses = and alternations are
176
+ // kind of needing help so this is a placeholder for
177
+ // future work
178
+ test.skip('apply granular-result alternation uses range', () => {
179
+ const compare = (0, test_translator_1.expr) `ad ? ad.year | ad.month`;
180
+ expect(compare).toTranslate();
181
+ const compare_expr = compare.translator.generated().value;
182
+ expect(exprToString(compare_expr)).toEqual('((A>=B)and(A<C))or((A>=D)and(A<E))');
183
+ });
128
184
  test('comparison promotes date literal to timestamp', () => {
129
185
  expect((0, test_translator_1.expr) `@2001 = ats`).toTranslate();
130
186
  });
@@ -59,16 +59,16 @@ export interface MarkedSource {
59
59
  locations: DocumentLocation[];
60
60
  translator?: TestTranslator;
61
61
  }
62
- interface HasTranslator extends MarkedSource {
63
- translator: TestTranslator;
62
+ interface HasTranslator<TT extends TestTranslator> extends MarkedSource {
63
+ translator: TT;
64
64
  }
65
- export declare function expr(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator;
66
- export declare function model(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator;
65
+ export declare function expr(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator<BetaExpression>;
66
+ export declare function model(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator<TestTranslator>;
67
67
  export declare function makeModelFunc(options: {
68
68
  model?: ModelDef;
69
69
  prefix?: string;
70
70
  wrap?: (code: string) => string;
71
- }): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator;
71
+ }): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator<TestTranslator>;
72
72
  export declare function markSource(unmarked: TemplateStringsArray, ...marked: string[]): MarkedSource;
73
73
  export declare function getSelectOneStruct(sqlBlock: SQLBlockSource): SQLBlockStructDef;
74
74
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.137-dev240327175808",
3
+ "version": "0.0.137-dev240328161656",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",