@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.
- package/dist/lang/ast/expressions/apply.d.ts +3 -0
- package/dist/lang/ast/expressions/apply.js +16 -0
- package/dist/lang/ast/expressions/expr-compare.js +0 -9
- package/dist/lang/ast/expressions/expr-granular-time.d.ts +1 -2
- package/dist/lang/ast/expressions/expr-granular-time.js +16 -19
- package/dist/lang/test/expressions.spec.js +56 -0
- package/dist/lang/test/test-translator.d.ts +5 -5
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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:
|
|
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 {};
|