@malloydata/malloy 0.0.177-dev240828173040 → 0.0.177-dev240829030921

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 (121) hide show
  1. package/dist/dialect/dialect.d.ts +23 -13
  2. package/dist/dialect/dialect.js +33 -27
  3. package/dist/dialect/duckdb/duckdb.d.ts +7 -11
  4. package/dist/dialect/duckdb/duckdb.js +34 -100
  5. package/dist/dialect/duckdb/functions/greatest_and_least.js +5 -12
  6. package/dist/dialect/functions/concat.js +1 -1
  7. package/dist/dialect/functions/greatest_and_least.js +1 -1
  8. package/dist/dialect/functions/simple_numeric_functions.js +1 -1
  9. package/dist/dialect/functions/sql.js +5 -15
  10. package/dist/dialect/functions/string_agg.js +2 -2
  11. package/dist/dialect/functions/trim_functions.js +2 -2
  12. package/dist/dialect/functions/util.d.ts +6 -9
  13. package/dist/dialect/functions/util.js +29 -38
  14. package/dist/dialect/index.d.ts +1 -1
  15. package/dist/dialect/index.js +1 -2
  16. package/dist/dialect/pg_impl.d.ts +15 -0
  17. package/dist/dialect/pg_impl.js +91 -0
  18. package/dist/dialect/postgres/functions/greatest_and_least.js +1 -3
  19. package/dist/dialect/postgres/functions/string_agg.js +2 -2
  20. package/dist/dialect/postgres/postgres.d.ts +7 -11
  21. package/dist/dialect/postgres/postgres.js +29 -92
  22. package/dist/dialect/snowflake/functions/string_agg.js +2 -2
  23. package/dist/dialect/snowflake/snowflake.d.ts +9 -9
  24. package/dist/dialect/snowflake/snowflake.js +41 -48
  25. package/dist/dialect/standardsql/functions/string_agg.js +4 -4
  26. package/dist/dialect/standardsql/standardsql.d.ts +9 -9
  27. package/dist/dialect/standardsql/standardsql.js +56 -51
  28. package/dist/dialect/trino/functions/concat.js +1 -1
  29. package/dist/dialect/trino/functions/string_agg.js +2 -2
  30. package/dist/dialect/trino/trino.d.ts +11 -12
  31. package/dist/dialect/trino/trino.js +59 -83
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.js +3 -4
  34. package/dist/lang/ast/ast-utils.d.ts +1 -1
  35. package/dist/lang/ast/ast-utils.js +2 -2
  36. package/dist/lang/ast/expressions/apply.js +1 -2
  37. package/dist/lang/ast/expressions/binary-boolean.d.ts +2 -1
  38. package/dist/lang/ast/expressions/binary-boolean.js +6 -3
  39. package/dist/lang/ast/expressions/binary-numeric.d.ts +2 -1
  40. package/dist/lang/ast/expressions/boolean.js +1 -1
  41. package/dist/lang/ast/expressions/constant-expression.d.ts +3 -3
  42. package/dist/lang/ast/expressions/constant-expression.js +0 -23
  43. package/dist/lang/ast/expressions/expr-aggregate-function.js +24 -34
  44. package/dist/lang/ast/expressions/expr-alternation-tree.d.ts +6 -3
  45. package/dist/lang/ast/expressions/expr-alternation-tree.js +10 -5
  46. package/dist/lang/ast/expressions/expr-cast.js +1 -2
  47. package/dist/lang/ast/expressions/expr-coalesce.js +4 -1
  48. package/dist/lang/ast/expressions/expr-compare.d.ts +3 -3
  49. package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
  50. package/dist/lang/ast/expressions/expr-count.js +3 -3
  51. package/dist/lang/ast/expressions/expr-func.js +15 -18
  52. package/dist/lang/ast/expressions/expr-granular-time.js +8 -10
  53. package/dist/lang/ast/expressions/expr-id-reference.js +2 -2
  54. package/dist/lang/ast/expressions/expr-minus.js +5 -4
  55. package/dist/lang/ast/expressions/expr-not.js +1 -1
  56. package/dist/lang/ast/expressions/expr-now.js +1 -6
  57. package/dist/lang/ast/expressions/expr-null.js +1 -1
  58. package/dist/lang/ast/expressions/expr-number.js +1 -1
  59. package/dist/lang/ast/expressions/expr-parens.js +1 -1
  60. package/dist/lang/ast/expressions/expr-props.js +4 -7
  61. package/dist/lang/ast/expressions/expr-regex.js +1 -3
  62. package/dist/lang/ast/expressions/expr-string.js +1 -7
  63. package/dist/lang/ast/expressions/expr-time-extract.js +12 -16
  64. package/dist/lang/ast/expressions/expr-time.d.ts +2 -2
  65. package/dist/lang/ast/expressions/expr-time.js +4 -6
  66. package/dist/lang/ast/expressions/expr-ungroup.js +2 -2
  67. package/dist/lang/ast/expressions/for-range.d.ts +2 -1
  68. package/dist/lang/ast/expressions/function-ordering.js +5 -5
  69. package/dist/lang/ast/expressions/partial-compare.d.ts +3 -3
  70. package/dist/lang/ast/expressions/pick-when.js +24 -8
  71. package/dist/lang/ast/expressions/range.d.ts +2 -1
  72. package/dist/lang/ast/expressions/range.js +4 -2
  73. package/dist/lang/ast/expressions/time-literal.d.ts +4 -3
  74. package/dist/lang/ast/expressions/time-literal.js +5 -10
  75. package/dist/lang/ast/expressions/top-by.js +1 -2
  76. package/dist/lang/ast/expressions/utils.d.ts +3 -12
  77. package/dist/lang/ast/expressions/utils.js +8 -56
  78. package/dist/lang/ast/field-space/reference-field.js +1 -1
  79. package/dist/lang/ast/index.d.ts +1 -1
  80. package/dist/lang/ast/index.js +1 -1
  81. package/dist/lang/ast/query-builders/index-builder.d.ts +2 -2
  82. package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
  83. package/dist/lang/ast/query-items/field-declaration.js +1 -5
  84. package/dist/lang/ast/query-properties/filters.d.ts +3 -3
  85. package/dist/lang/ast/query-properties/filters.js +6 -5
  86. package/dist/lang/ast/query-properties/top.js +1 -2
  87. package/dist/lang/ast/source-elements/refined-source.js +1 -1
  88. package/dist/lang/ast/source-properties/joins.js +11 -10
  89. package/dist/lang/ast/time-utils.d.ts +5 -7
  90. package/dist/lang/ast/time-utils.js +17 -57
  91. package/dist/lang/ast/types/binary_operators.d.ts +9 -0
  92. package/dist/lang/ast/types/binary_operators.js +28 -0
  93. package/dist/lang/ast/types/expr-result.d.ts +3 -3
  94. package/dist/lang/ast/types/expression-def.d.ts +4 -3
  95. package/dist/lang/ast/types/expression-def.js +43 -50
  96. package/dist/lang/lib/Malloy/MalloyParser.d.ts +0 -11
  97. package/dist/lang/lib/Malloy/MalloyParser.js +803 -858
  98. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -13
  99. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -8
  100. package/dist/lang/malloy-to-ast.d.ts +0 -1
  101. package/dist/lang/malloy-to-ast.js +0 -4
  102. package/dist/lang/test/expressions.spec.js +42 -86
  103. package/dist/lang/test/field-symbols.spec.js +8 -6
  104. package/dist/lang/test/literals.spec.js +6 -6
  105. package/dist/lang/test/model_serialization.spec.js +5 -5
  106. package/dist/lang/test/test-translator.js +9 -7
  107. package/dist/malloy.d.ts +3 -3
  108. package/dist/malloy.js +1 -1
  109. package/dist/model/index.d.ts +1 -1
  110. package/dist/model/index.js +2 -1
  111. package/dist/model/malloy_query.d.ts +24 -19
  112. package/dist/model/malloy_query.js +272 -244
  113. package/dist/model/malloy_types.d.ts +224 -205
  114. package/dist/model/malloy_types.js +19 -98
  115. package/dist/model/utils.d.ts +10 -3
  116. package/dist/model/utils.js +84 -219
  117. package/package.json +1 -1
  118. package/dist/lang/ast/types/comparison.d.ts +0 -11
  119. package/dist/lang/ast/types/comparison.js +0 -41
  120. package/dist/lang/ast/types/equality.d.ts +0 -7
  121. package/dist/lang/ast/types/equality.js +0 -37
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.Joins = exports.ExpressionJoin = exports.KeyJoin = exports.Join = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
- const utils_1 = require("../expressions/utils");
28
27
  const join_space_field_1 = require("../field-space/join-space-field");
29
28
  const definition_list_1 = require("../types/definition-list");
30
29
  const malloy_element_1 = require("../types/malloy-element");
@@ -66,7 +65,7 @@ class KeyJoin extends Join {
66
65
  structRelationship: {
67
66
  type: 'one',
68
67
  matrixOperation: 'left',
69
- onExpression: ["('join fixup'='not done yet')"],
68
+ onExpression: { node: 'error', message: "('join fixup'='not done yet')" },
70
69
  },
71
70
  location: this.location,
72
71
  };
@@ -92,14 +91,16 @@ class KeyJoin extends Join {
92
91
  inStruct.structRelationship = {
93
92
  type: 'one',
94
93
  matrixOperation: 'left',
95
- onExpression: [
96
- {
97
- type: 'field',
98
- path: [this.name.refString, inStruct.primaryKey],
94
+ onExpression: {
95
+ node: '=',
96
+ kids: {
97
+ left: {
98
+ node: 'field',
99
+ path: [this.name.refString, inStruct.primaryKey],
100
+ },
101
+ right: exprX.value,
99
102
  },
100
- '=',
101
- ...exprX.value,
102
- ],
103
+ },
103
104
  };
104
105
  return;
105
106
  }
@@ -144,7 +145,7 @@ class ExpressionJoin extends Join {
144
145
  }
145
146
  const joinRel = inStruct.structRelationship;
146
147
  if ((0, malloy_types_1.isJoinOn)(joinRel)) {
147
- joinRel.onExpression = (0, utils_1.compressExpr)(exprX.value);
148
+ joinRel.onExpression = exprX.value;
148
149
  }
149
150
  }
150
151
  structDef(parameterSpace) {
@@ -1,12 +1,10 @@
1
- import { Expr, Fragment, TimeFieldType, TimestampUnit, FieldValueType, CastType } from '../../model/malloy_types';
1
+ import { Expr, TimeFieldType, TimestampUnit, FieldValueType, CastType, TypecastExpr, TimeDeltaExpr } from '../../model/malloy_types';
2
2
  import { TimeResult } from './types/time-result';
3
- export declare function timeOffset(timeType: TimeFieldType, from: Expr, op: '+' | '-', n: Expr, timeframe: TimestampUnit): Expr;
3
+ export declare function timeOffset(timeType: TimeFieldType, from: Expr, op: '+' | '-', n: Expr, timeframe: TimestampUnit): TimeDeltaExpr;
4
4
  export declare function castTo(castType: CastType | {
5
5
  raw: string;
6
- }, from: Expr, fromType: FieldValueType, safe?: boolean): Expr;
7
- export declare function castTimestampToDate(from: Expr, safe?: boolean): Expr;
8
- export declare function castDateToTimestamp(from: Expr, safe?: boolean): Expr;
6
+ }, from: Expr, fromType: FieldValueType, safe?: boolean): TypecastExpr;
7
+ export declare function castTimestampToDate(from: Expr, safe?: boolean): TypecastExpr;
8
+ export declare function castDateToTimestamp(from: Expr, safe?: boolean): TypecastExpr;
9
9
  export declare function resolution(timeframe: string): TimeFieldType;
10
10
  export declare function timeResult(t: TimeResult, tt: TimestampUnit | undefined): TimeResult;
11
- export declare function timestampOffset(from: Fragment[], op: '+' | '-', n: Fragment[], timeframe: TimestampUnit, fromNotTimestamp?: boolean): Fragment[];
12
- export declare function dateOffset(from: Fragment[], op: '+' | '-', n: Fragment[], timeframe: TimestampUnit): Fragment[];
@@ -22,58 +22,53 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.dateOffset = exports.timestampOffset = exports.timeResult = exports.resolution = exports.castDateToTimestamp = exports.castTimestampToDate = exports.castTo = exports.timeOffset = void 0;
25
+ exports.timeResult = exports.resolution = exports.castDateToTimestamp = exports.castTimestampToDate = exports.castTo = exports.timeOffset = void 0;
26
26
  const malloy_types_1 = require("../../model/malloy_types");
27
- const utils_1 = require("./expressions/utils");
28
27
  function timeOffset(timeType, from, op, n, timeframe) {
29
- return [
30
- {
31
- type: 'dialect',
32
- function: 'delta',
33
- base: { valueType: timeType, value: from },
34
- op,
28
+ return {
29
+ node: 'delta',
30
+ kids: {
31
+ base: { ...from, dataType: timeType },
35
32
  delta: n,
36
- units: timeframe,
37
33
  },
38
- ];
34
+ op,
35
+ units: timeframe,
36
+ };
39
37
  }
40
38
  exports.timeOffset = timeOffset;
41
39
  function castTo(castType, from, fromType, safe = false) {
42
40
  const cast = {
43
- type: 'dialect',
44
- function: 'cast',
41
+ node: 'cast',
45
42
  dstType: castType,
46
- expr: from,
43
+ e: from,
47
44
  safe,
48
45
  };
49
46
  if ((0, malloy_types_1.isAtomicFieldType)(fromType)) {
50
47
  cast.srcType = fromType;
51
48
  }
52
- return [cast];
49
+ return cast;
53
50
  }
54
51
  exports.castTo = castTo;
55
52
  function castTimestampToDate(from, safe = false) {
56
53
  const cast = {
57
- type: 'dialect',
58
- function: 'cast',
54
+ node: 'cast',
59
55
  dstType: 'date',
60
56
  srcType: 'timestamp',
61
- expr: from,
57
+ e: from,
62
58
  safe,
63
59
  };
64
- return [cast];
60
+ return cast;
65
61
  }
66
62
  exports.castTimestampToDate = castTimestampToDate;
67
63
  function castDateToTimestamp(from, safe = false) {
68
64
  const cast = {
69
- type: 'dialect',
70
- function: 'cast',
65
+ node: 'cast',
71
66
  dstType: 'timestamp',
72
67
  srcType: 'date',
73
- expr: from,
68
+ e: from,
74
69
  safe,
75
70
  };
76
- return [cast];
71
+ return cast;
77
72
  }
78
73
  exports.castDateToTimestamp = castDateToTimestamp;
79
74
  function resolution(timeframe) {
@@ -95,39 +90,4 @@ function timeResult(t, tt) {
95
90
  return t;
96
91
  }
97
92
  exports.timeResult = timeResult;
98
- function timestampOffset(from, op, n, timeframe, fromNotTimestamp = false) {
99
- const useDatetime = ['week', 'month', 'quarter', 'year'].includes(timeframe);
100
- const add = op === '+' ? '_ADD' : '_SUB';
101
- const units = timeframe.toUpperCase();
102
- if (useDatetime) {
103
- return [
104
- `TIMESTAMP(DATETIME${add}(DATETIME(`,
105
- ...from,
106
- '),INTERVAL ',
107
- ...n,
108
- ` ${units}))`,
109
- ];
110
- }
111
- const typeFrom = fromNotTimestamp ? ['TIMESTAMP(', ...from, ')'] : from;
112
- return (0, utils_1.compressExpr)([
113
- `TIMESTAMP${add}(`,
114
- ...typeFrom,
115
- ',INTERVAL ',
116
- ...n,
117
- ` ${units})`,
118
- ]);
119
- }
120
- exports.timestampOffset = timestampOffset;
121
- function dateOffset(from, op, n, timeframe) {
122
- const add = op === '+' ? '_ADD' : '_SUB';
123
- const units = timeframe.toUpperCase();
124
- return (0, utils_1.compressExpr)([
125
- `DATE${add}(`,
126
- ...from,
127
- ',INTERVAL ',
128
- ...n,
129
- ` ${units})`,
130
- ]);
131
- }
132
- exports.dateOffset = dateOffset;
133
93
  //# sourceMappingURL=time-utils.js.map
@@ -0,0 +1,9 @@
1
+ import { BinaryOperator } from '../../../model';
2
+ export type LogicalMalloyOperator = 'and' | 'or';
3
+ export type ArithmeticMalloyOperator = '+' | '-' | '*' | '/' | '%';
4
+ export type EqualityMalloyOperator = '~' | '!~' | '=' | '!=';
5
+ export type CompareMalloyOperator = '<' | '<=' | '>' | '>=' | EqualityMalloyOperator;
6
+ export type BinaryMalloyOperator = ArithmeticMalloyOperator | CompareMalloyOperator | LogicalMalloyOperator;
7
+ export declare function getExprNode(mo: BinaryMalloyOperator): BinaryOperator;
8
+ export declare function isEquality(op: string): op is EqualityMalloyOperator;
9
+ export declare function isComparison(op: string): op is CompareMalloyOperator;
@@ -0,0 +1,28 @@
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.isComparison = exports.isEquality = exports.getExprNode = void 0;
10
+ function getExprNode(mo) {
11
+ switch (mo) {
12
+ case '~':
13
+ return 'like';
14
+ case '!~':
15
+ return '!like';
16
+ }
17
+ return mo;
18
+ }
19
+ exports.getExprNode = getExprNode;
20
+ function isEquality(op) {
21
+ return op === '=' || op === '!=' || op === '~' || op === '!~';
22
+ }
23
+ exports.isEquality = isEquality;
24
+ function isComparison(op) {
25
+ return (isEquality(op) || op === '>=' || op === '<=' || op === '>' || op === '<');
26
+ }
27
+ exports.isComparison = isComparison;
28
+ //# sourceMappingURL=binary_operators.js.map
@@ -1,7 +1,7 @@
1
- import { Fragment, TypeDesc } from '../../../model/malloy_types';
2
- type MorphicValues = Record<string, Fragment[]>;
1
+ import { Expr, TypeDesc } from '../../../model/malloy_types';
2
+ type MorphicValues = Record<string, Expr>;
3
3
  export interface ExprResult extends TypeDesc {
4
- value: Fragment[];
4
+ value: Expr;
5
5
  morphic?: MorphicValues;
6
6
  }
7
7
  export {};
@@ -2,6 +2,7 @@ import { TimestampUnit, FieldValueType } from '../../../model/malloy_types';
2
2
  import { ExprValue } from './expr-value';
3
3
  import { FieldSpace } from './field-space';
4
4
  import { MalloyElement } from './malloy-element';
5
+ import { BinaryMalloyOperator } from './binary_operators';
5
6
  /**
6
7
  * Root node for any element in an expression. These essentially
7
8
  * create a sub-tree in the larger AST. Expression nodes know
@@ -44,7 +45,7 @@ export declare abstract class ExpressionDef extends MalloyElement {
44
45
  * @param expr The "other" (besdies 'this') value
45
46
  * @return The translated expression
46
47
  */
47
- apply(fs: FieldSpace, op: string, left: ExpressionDef): ExprValue;
48
+ apply(fs: FieldSpace, op: BinaryMalloyOperator, left: ExpressionDef): ExprValue;
48
49
  canSupportPartitionBy(): boolean;
49
50
  canSupportOrderBy(): boolean;
50
51
  canSupportLimit(): boolean;
@@ -56,7 +57,7 @@ export declare class ExprDuration extends ExpressionDef {
56
57
  elementType: string;
57
58
  legalChildTypes: import("../../../model/malloy_types").TypeDesc[];
58
59
  constructor(n: ExpressionDef, timeframe: TimestampUnit);
59
- apply(fs: FieldSpace, op: string, left: ExpressionDef): ExprValue;
60
+ apply(fs: FieldSpace, op: BinaryMalloyOperator, left: ExpressionDef): ExprValue;
60
61
  getExpression(_fs: FieldSpace): ExprValue;
61
62
  }
62
63
  export declare function getMorphicValue(mv: ExprValue, mt: FieldValueType): ExprValue | undefined;
@@ -71,4 +72,4 @@ export declare function getMorphicValue(mv: ExprValue, mt: FieldValueType): Expr
71
72
  * @param right Right Value
72
73
  * @return ExprValue of the expression
73
74
  */
74
- export declare function applyBinary(fs: FieldSpace, left: ExpressionDef, op: string, right: ExpressionDef): ExprValue;
75
+ export declare function applyBinary(fs: FieldSpace, left: ExpressionDef, op: BinaryMalloyOperator, right: ExpressionDef): ExprValue;
@@ -28,10 +28,9 @@ const ast_utils_1 = require("../ast-utils");
28
28
  const utils_1 = require("../expressions/utils");
29
29
  const fragtype_utils_1 = require("../fragtype-utils");
30
30
  const time_utils_1 = require("../time-utils");
31
- const comparison_1 = require("./comparison");
32
- const equality_1 = require("./equality");
33
31
  const granular_result_1 = require("./granular-result");
34
32
  const malloy_element_1 = require("./malloy-element");
33
+ const binary_operators_1 = require("./binary_operators");
35
34
  class TypeMismatch extends Error {
36
35
  }
37
36
  /**
@@ -154,7 +153,7 @@ class ExprDuration extends ExpressionDef {
154
153
  return {
155
154
  dataType: 'duration',
156
155
  expressionType: 'scalar',
157
- value: ['__ERROR_DURATION_IS_NOT_A_VALUE__'],
156
+ value: { node: 'error', message: 'Duration is not a value' },
158
157
  evalSpace: 'constant',
159
158
  };
160
159
  }
@@ -182,70 +181,64 @@ exports.getMorphicValue = getMorphicValue;
182
181
  function timeCompare(left, lhs, op, rhs) {
183
182
  const leftIsTime = (0, malloy_types_1.isTimeFieldType)(lhs.dataType);
184
183
  const rightIsTime = (0, malloy_types_1.isTimeFieldType)(rhs.dataType);
184
+ const node = (0, binary_operators_1.getExprNode)(op);
185
185
  if (leftIsTime && rightIsTime) {
186
186
  if (lhs.dataType !== rhs.dataType) {
187
187
  const lval = willMorphTo(lhs, 'timestamp');
188
188
  const rval = willMorphTo(rhs, 'timestamp');
189
189
  if (lval && rval) {
190
- return (0, utils_1.compose)(lval, op, rval);
190
+ return { node, kids: { left: lval, right: lval } };
191
191
  }
192
192
  }
193
193
  else {
194
- return (0, utils_1.compose)(lhs.value, op, rhs.value);
194
+ return { node, kids: { left: lhs.value, right: rhs.value } };
195
195
  }
196
196
  }
197
197
  if ((leftIsTime || rightIsTime) &&
198
198
  lhs.dataType !== 'null' &&
199
199
  rhs.dataType !== 'null') {
200
200
  left.log(`Cannot compare a ${lhs.dataType} to a ${rhs.dataType}`);
201
- return ['false'];
201
+ return { node: 'false' };
202
202
  }
203
203
  return undefined;
204
204
  }
205
205
  function regexEqual(left, right) {
206
206
  if (left.dataType === 'string') {
207
207
  if (right.dataType === 'regular expression') {
208
- return [
209
- {
210
- type: 'dialect',
211
- function: 'regexpMatch',
212
- expr: left.value,
213
- regexp: right.value,
214
- },
215
- ];
208
+ return {
209
+ node: 'regexpMatch',
210
+ kids: { expr: left.value, regex: right.value },
211
+ };
216
212
  }
217
213
  }
218
214
  else if (right.dataType === 'string') {
219
215
  if (left.dataType === 'regular expression') {
220
- return [
221
- {
222
- type: 'dialect',
223
- function: 'regexpMatch',
224
- expr: right.value,
225
- regexp: left.value,
226
- },
227
- ];
216
+ return {
217
+ node: 'regexpMatch',
218
+ kids: { expr: right.value, regex: left.value },
219
+ };
228
220
  }
229
221
  }
230
222
  return undefined;
231
223
  }
232
224
  function nullCompare(left, op, right) {
233
225
  const not = op === '!=' || op === '!~';
226
+ const nullCmp = not ? 'is-not-null' : 'is-null';
234
227
  if (left.dataType === 'null' || right.dataType === 'null') {
235
- const maybeNot = not ? ' NOT' : '';
236
228
  if (left.dataType !== 'null') {
237
- return [...left.value, ` IS${maybeNot} NULL`];
229
+ return { node: nullCmp, e: left.value };
238
230
  }
239
231
  if (right.dataType !== 'null') {
240
- return [...right.value, `IS${maybeNot} NULL`];
232
+ return { node: nullCmp, e: right.value };
241
233
  }
242
- return [not ? 'false' : 'true'];
234
+ return { node: not ? 'false' : 'true' };
243
235
  }
244
236
  return undefined;
245
237
  }
246
238
  function equality(fs, left, op, right) {
247
239
  const lhs = left.getExpression(fs);
248
240
  const rhs = right.getExpression(fs);
241
+ const node = (0, binary_operators_1.getExprNode)(op);
249
242
  const err = errorCascade('boolean', lhs, rhs);
250
243
  if (err)
251
244
  return err;
@@ -261,15 +254,15 @@ function equality(fs, left, op, right) {
261
254
  }
262
255
  }
263
256
  }
264
- let value = timeCompare(left, lhs, op, rhs) || (0, utils_1.compose)(lhs.value, op, rhs.value);
257
+ let value = timeCompare(left, lhs, op, rhs) || {
258
+ node,
259
+ kids: { left: lhs.value, right: rhs.value },
260
+ };
265
261
  if (lhs.dataType !== 'error' && rhs.dataType !== 'error') {
266
262
  switch (op) {
267
263
  case '~':
268
264
  case '!~': {
269
- if (lhs.dataType === 'string' && rhs.dataType === 'string') {
270
- value = (0, utils_1.compose)(lhs.value, 'LIKE', rhs.value);
271
- }
272
- else {
265
+ if (lhs.dataType !== 'string' || rhs.dataType !== 'string') {
273
266
  const regexCmp = regexEqual(lhs, rhs);
274
267
  if (regexCmp === undefined) {
275
268
  throw new TypeMismatch("Incompatible types for match('~') operator");
@@ -282,11 +275,12 @@ function equality(fs, left, op, right) {
282
275
  case '=':
283
276
  case '!=': {
284
277
  const nullCmp = nullCompare(lhs, op, rhs);
278
+ const eqNode = value;
285
279
  if (nullCmp) {
286
280
  value = nullCmp;
287
281
  }
288
282
  else {
289
- value = (0, utils_1.nullsafeNot)(regexEqual(lhs, rhs) || (0, utils_1.compose)(lhs.value, '=', rhs.value), op);
283
+ value = (0, utils_1.nullsafeNot)(regexEqual(lhs, rhs) || eqNode, op);
290
284
  }
291
285
  break;
292
286
  }
@@ -310,7 +304,10 @@ function compare(fs, left, op, right) {
310
304
  if (noCompare) {
311
305
  return { ...noCompare, dataType: 'boolean' };
312
306
  }
313
- const value = timeCompare(left, lhs, op, rhs) || (0, utils_1.compose)(lhs.value, op, rhs.value);
307
+ const value = timeCompare(left, lhs, op, rhs) || {
308
+ node: (0, binary_operators_1.getExprNode)(op),
309
+ kids: { left: lhs.value, right: rhs.value },
310
+ };
314
311
  return {
315
312
  dataType: 'boolean',
316
313
  expressionType,
@@ -318,9 +315,6 @@ function compare(fs, left, op, right) {
318
315
  value: value,
319
316
  };
320
317
  }
321
- function oneOf(op, ...operators) {
322
- return operators.includes(op);
323
- }
324
318
  function numeric(fs, left, op, right) {
325
319
  const lhs = left.getExpression(fs);
326
320
  const rhs = right.getExpression(fs);
@@ -342,7 +336,7 @@ function numeric(fs, left, op, right) {
342
336
  return {
343
337
  dataType: 'number',
344
338
  expressionType,
345
- value: (0, utils_1.compose)(lhs.value, op, rhs.value),
339
+ value: { node: op, kids: { left: lhs.value, right: rhs.value } },
346
340
  evalSpace: (0, malloy_types_1.mergeEvalSpaces)(lhs.evalSpace, rhs.evalSpace),
347
341
  };
348
342
  }
@@ -389,19 +383,19 @@ function delta(fs, left, op, right) {
389
383
  * @return ExprValue of the expression
390
384
  */
391
385
  function applyBinary(fs, left, op, right) {
392
- if ((0, equality_1.isEquality)(op)) {
386
+ if ((0, binary_operators_1.isEquality)(op)) {
393
387
  return equality(fs, left, op, right);
394
388
  }
395
- if ((0, comparison_1.isComparison)(op)) {
389
+ if ((0, binary_operators_1.isComparison)(op)) {
396
390
  return compare(fs, left, op, right);
397
391
  }
398
- if (oneOf(op, '+', '-')) {
392
+ if (op === '+' || op === '-') {
399
393
  return delta(fs, left, op, right);
400
394
  }
401
395
  if (op === '*') {
402
396
  return numeric(fs, left, op, right);
403
397
  }
404
- if (oneOf(op, '/', '%')) {
398
+ if (op === '/' || op === '%') {
405
399
  const num = left.getExpression(fs);
406
400
  const denom = right.getExpression(fs);
407
401
  const noGo = unsupportError(left, num, right, denom);
@@ -419,17 +413,15 @@ function applyBinary(fs, left, op, right) {
419
413
  right.log('Denominator must be a number');
420
414
  }
421
415
  else {
422
- const div = {
423
- type: 'dialect',
424
- function: op === '/' ? 'div' : 'mod',
425
- numerator: num.value,
426
- denominator: denom.value,
416
+ const divmod = {
417
+ node: op,
418
+ kids: { left: num.value, right: denom.value },
427
419
  };
428
420
  return {
429
421
  dataType: 'number',
430
422
  expressionType: (0, malloy_types_1.maxExpressionType)(num.expressionType, denom.expressionType),
431
423
  evalSpace: (0, malloy_types_1.mergeEvalSpaces)(num.evalSpace, denom.evalSpace),
432
- value: [div],
424
+ value: divmod,
433
425
  };
434
426
  }
435
427
  return (0, ast_utils_1.errorFor)('divide type mismatch');
@@ -443,7 +435,7 @@ function errorCascade(dataType, ...es) {
443
435
  return {
444
436
  dataType,
445
437
  expressionType: (0, malloy_types_1.maxOfExpressionTypes)(es.map(e => e.expressionType)),
446
- value: ["'cascading error'"],
438
+ value: { node: 'error', message: 'cascading error' },
447
439
  evalSpace: (0, malloy_types_1.mergeEvalSpaces)(...es.map(e => e.evalSpace)),
448
440
  };
449
441
  }
@@ -455,12 +447,13 @@ function unsupportError(l, lhs, r, rhs) {
455
447
  const ret = {
456
448
  dataType: lhs.dataType,
457
449
  expressionType: (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType),
458
- value: ["'unsupported operation'"],
450
+ value: { node: 'error', message: 'sql-native unsupported' },
459
451
  evalSpace: (0, malloy_types_1.mergeEvalSpaces)(lhs.evalSpace, rhs.evalSpace),
460
452
  };
461
453
  if (lhs.dataType === 'sql native') {
462
454
  l.log(`Unsupported SQL native type '${lhs.rawType}' not allowed in expression[unsupported-sql-native-type-not-allowed-in-expression]`);
463
- return { ...ret, dataType: rhs.dataType };
455
+ ret.dataType = rhs.dataType;
456
+ return ret;
464
457
  }
465
458
  if (rhs.dataType === 'sql native') {
466
459
  r.log(`Unsupported SQL native type '${rhs.rawType}' not allowed in expression[unsupported-sql-native-type-not-allowed-in-expression]`);
@@ -2170,17 +2170,6 @@ export declare class ExprCoalesceContext extends FieldExprContext {
2170
2170
  exitRule(listener: MalloyParserListener): void;
2171
2171
  accept<Result>(visitor: MalloyParserVisitor<Result>): Result;
2172
2172
  }
2173
- export declare class ExprCountDisinctContext extends FieldExprContext {
2174
- COUNT(): TerminalNode;
2175
- OPAREN(): TerminalNode;
2176
- DISTINCT(): TerminalNode;
2177
- fieldExpr(): FieldExprContext;
2178
- CPAREN(): TerminalNode;
2179
- constructor(ctx: FieldExprContext);
2180
- enterRule(listener: MalloyParserListener): void;
2181
- exitRule(listener: MalloyParserListener): void;
2182
- accept<Result>(visitor: MalloyParserVisitor<Result>): Result;
2183
- }
2184
2173
  export declare class ExprPathlessAggregateContext extends FieldExprContext {
2185
2174
  aggregate(): AggregateContext;
2186
2175
  OPAREN(): TerminalNode;