@malloydata/malloy 0.0.38-dev230605182241 → 0.0.38-dev230606045241

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.
@@ -29,6 +29,9 @@ const fragtype_utils_1 = require("../fragtype-utils");
29
29
  const expression_def_1 = require("../types/expression-def");
30
30
  const malloy_element_1 = require("../types/malloy-element");
31
31
  const utils_1 = require("./utils");
32
+ function typeCoalesce(ev1, ev2) {
33
+ return ev1 === undefined || ev1.dataType === 'null' ? ev2 : ev1;
34
+ }
32
35
  class Pick extends expression_def_1.ExpressionDef {
33
36
  constructor(choices, elsePick) {
34
37
  super({ choices });
@@ -65,21 +68,17 @@ class Pick extends expression_def_1.ExpressionDef {
65
68
  ? choice.pick.getExpression(fs)
66
69
  : expr.getExpression(fs);
67
70
  anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(whenExpr.expressionType, thenExpr.expressionType));
68
- if (returnType) {
69
- if (!fragtype_utils_1.FT.typeEq(returnType, thenExpr, true)) {
70
- const whenType = fragtype_utils_1.FT.inspect(thenExpr);
71
- this.log(`pick type '${whenType}', expected '${returnType.dataType}'`);
72
- return (0, ast_utils_1.errorFor)('pick when type');
73
- }
74
- }
75
- else {
76
- returnType = thenExpr;
71
+ if (returnType && !fragtype_utils_1.FT.typeEq(returnType, thenExpr, true)) {
72
+ const whenType = fragtype_utils_1.FT.inspect(thenExpr);
73
+ this.log(`pick type '${whenType}', expected '${returnType.dataType}'`);
74
+ return (0, ast_utils_1.errorFor)('pick when type');
77
75
  }
76
+ returnType = typeCoalesce(returnType, thenExpr);
78
77
  caseValue.push(' WHEN ', ...whenExpr.value, ' THEN ', ...thenExpr.value);
79
78
  }
80
79
  const elsePart = this.elsePick || expr;
81
80
  const elseVal = elsePart.getExpression(fs);
82
- returnType || (returnType = elseVal);
81
+ returnType = typeCoalesce(returnType, elseVal);
83
82
  if (!fragtype_utils_1.FT.typeEq(returnType, elseVal, true)) {
84
83
  const errSrc = this.elsePick ? 'else' : 'pick default';
85
84
  this.log(`${errSrc} type '${fragtype_utils_1.FT.inspect(elseVal)}', expected '${returnType.dataType}'`);
@@ -112,24 +111,26 @@ class Pick extends expression_def_1.ExpressionDef {
112
111
  when: c.when.getExpression(fs),
113
112
  });
114
113
  }
115
- const returnType = choiceValues[0].pick;
114
+ let returnType;
116
115
  const caseValue = ['CASE'];
117
- let anyExpressionType = returnType.expressionType;
116
+ let anyExpressionType = 'scalar';
118
117
  for (const aChoice of choiceValues) {
119
118
  if (!fragtype_utils_1.FT.typeEq(aChoice.when, fragtype_utils_1.FT.boolT)) {
120
119
  this.log(`when expression must be boolean, not '${fragtype_utils_1.FT.inspect(aChoice.when)}`);
121
120
  return (0, ast_utils_1.errorFor)('pick when type');
122
121
  }
123
- if (!fragtype_utils_1.FT.typeEq(returnType, aChoice.pick, true)) {
122
+ if (returnType && !fragtype_utils_1.FT.typeEq(returnType, aChoice.pick, true)) {
124
123
  const whenType = fragtype_utils_1.FT.inspect(aChoice.pick);
125
124
  this.log(`pick type '${whenType}', expected '${returnType.dataType}'`);
126
125
  return (0, ast_utils_1.errorFor)('pick value type');
127
126
  }
127
+ returnType = typeCoalesce(returnType, aChoice.pick);
128
128
  anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(aChoice.pick.expressionType, aChoice.when.expressionType));
129
129
  caseValue.push(' WHEN ', ...aChoice.when.value, ' THEN ', ...aChoice.pick.value);
130
130
  }
131
131
  const defVal = this.elsePick.getExpression(fs);
132
132
  anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, defVal.expressionType);
133
+ returnType = typeCoalesce(returnType, defVal);
133
134
  if (!fragtype_utils_1.FT.typeEq(returnType, defVal, true)) {
134
135
  this.elsePick.log(`else type '${fragtype_utils_1.FT.inspect(defVal)}', expected '${returnType.dataType}'`);
135
136
  return (0, ast_utils_1.errorFor)('pick value type mismatch');
@@ -37,6 +37,14 @@ function exprOK(s) {
37
37
  return undefined;
38
38
  };
39
39
  }
40
+ function exprType(s, t) {
41
+ return () => {
42
+ const expr = new test_translator_1.BetaExpression(s);
43
+ expect(expr).modelParsed();
44
+ expect(expr.generated().dataType).toBe(t);
45
+ return undefined;
46
+ };
47
+ }
40
48
  function modelOK(s) {
41
49
  return () => {
42
50
  const m = new test_translator_1.TestTranslator(s);
@@ -720,6 +728,9 @@ describe('expressions', () => {
720
728
  test('filtering', exprOK(`
721
729
  astr ? pick 'missing value' when NULL
722
730
  `));
731
+ test('null branch with else', exprType("astr ? pick null when = '42' else 3", 'number'));
732
+ test('null branch no else', exprType("astr ? pick null when = '42'", 'string'));
733
+ test('null branch no apply', exprType('pick null when 1 = 1 else 3', 'number'));
723
734
  test('tiering', exprOK(`
724
735
  ai ?
725
736
  pick 1 when < 10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.38-dev230605182241",
3
+ "version": "0.0.38-dev230606045241",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",