@malloydata/malloy 0.0.123-dev240205203120 → 0.0.123-dev240207164302

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.
@@ -76,7 +76,7 @@ class DuckDBDialect extends dialect_1.Dialect {
76
76
  return `__udf${Math.floor(Math.random() * 100000)}`;
77
77
  }
78
78
  quoteTablePath(tableName) {
79
- return tableName.match(/\//) ? `'${tableName}'` : tableName;
79
+ return tableName.match(/[/*:]/) ? `'${tableName}'` : tableName;
80
80
  }
81
81
  sqlGroupSetTable(groupSetCount) {
82
82
  return `CROSS JOIN (SELECT UNNEST(GENERATE_SERIES(0,${groupSetCount},1)) as group_set ) as group_set`;
@@ -87,7 +87,8 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
87
87
  // locality to be that join path
88
88
  const joinUsage = this.getJoinUsage(inputFS);
89
89
  const allUsagesSame = joinUsage.length === 1 ||
90
- joinUsage.slice(1).every(p => joinPathEq(p, joinUsage[0]));
90
+ (joinUsage.length > 1 &&
91
+ joinUsage.slice(1).every(p => joinPathEq(p, joinUsage[0])));
91
92
  if (allUsagesSame) {
92
93
  structPath = joinUsage[0].map(p => p.name);
93
94
  sourceRelationship = joinUsage[0];
@@ -227,7 +228,6 @@ function getJoinUsage(fs, expr) {
227
228
  };
228
229
  (0, utils_1.exprWalk)(expr, frag => {
229
230
  if (typeof frag !== 'string') {
230
- // TODO make this work for field references inside sql_* functions
231
231
  if (frag.type === 'field') {
232
232
  const def = lookup(fs, frag.path);
233
233
  if (def.def.type !== 'struct' && def.def.type !== 'turtle') {
@@ -240,6 +240,15 @@ function getJoinUsage(fs, expr) {
240
240
  }
241
241
  }
242
242
  }
243
+ else if (frag.type === 'source-reference') {
244
+ if (frag.path) {
245
+ const def = lookup(fs, frag.path);
246
+ result.push(def.relationship);
247
+ }
248
+ else {
249
+ result.push([]);
250
+ }
251
+ }
243
252
  }
244
253
  });
245
254
  return result;
@@ -35,7 +35,7 @@ class ExprMinus extends expression_def_1.ExpressionDef {
35
35
  }
36
36
  getExpression(fs) {
37
37
  const expr = this.expr.getExpression(fs);
38
- if (this.typeCheck(this.expr, expr)) {
38
+ if (fragtype_utils_1.FT.typeIn(expr, this.legalChildTypes)) {
39
39
  if (expr.value.length > 1) {
40
40
  return { ...expr, dataType: 'number', value: ['-(', ...expr.value, ')'] };
41
41
  }
@@ -15,6 +15,12 @@ export declare class FT {
15
15
  * @param checkThis The possibly undefined candidate
16
16
  */
17
17
  static eq(good: TypeDesc, checkThis: TypeDesc | undefined): boolean;
18
+ /**
19
+ * Checks if a given type is in a list, ignoring aggregate
20
+ * @param check The type to check (can be undefined)
21
+ * @param from List of types which are OK
22
+ */
23
+ static typeIn(check: TypeDesc | undefined, from: TypeDesc[]): boolean;
18
24
  /**
19
25
  * Checks if the base types, ignoring aggregate, are equal
20
26
  * @param left Left type
@@ -53,6 +53,18 @@ class FT {
53
53
  good.dataType === checkThis.dataType &&
54
54
  good.expressionType === checkThis.expressionType);
55
55
  }
56
+ /**
57
+ * Checks if a given type is in a list, ignoring aggregate
58
+ * @param check The type to check (can be undefined)
59
+ * @param from List of types which are OK
60
+ */
61
+ static typeIn(check, from) {
62
+ if (check) {
63
+ const found = from.find(okType => FT.typeEq(okType, check));
64
+ return found !== undefined;
65
+ }
66
+ return false;
67
+ }
56
68
  /**
57
69
  * Checks if the base types, ignoring aggregate, are equal
58
70
  * @param left Left type
@@ -475,6 +475,18 @@ describe('expressions', () => {
475
475
  test('source.sum(nested.column)', () => {
476
476
  expect(modelX `source.sum(nested.column)`).translationToFailWith('Cannot compute `sum` across repeated relationship `nested`; use `nested.column.sum()`');
477
477
  });
478
+ test('can aggregate field defined with no join usage', () => {
479
+ expect((0, test_translator_1.markSource) `
480
+ ##! experimental { sql_functions }
481
+ source: s is a extend {
482
+ measure: c is count()
483
+ dimension: f is 1
484
+ }
485
+ run: s -> {
486
+ aggregate: v is f.sum()
487
+ }
488
+ `).toTranslate();
489
+ });
478
490
  test('sum(inline.column)', () => {
479
491
  expect(modelX `sum(inline.column)`).toTranslateWithWarnings('Join path is required for this calculation; use `inline.column.sum()` or `source.sum(inline.column)` to get a result weighted with respect to `source`');
480
492
  });
@@ -799,6 +811,11 @@ describe('unspported fields in schema', () => {
799
811
  test('negative numbers are not tokens', () => {
800
812
  expect((0, test_translator_1.expr) `ai-1`).toTranslate();
801
813
  });
814
+ describe('sql functions', () => {
815
+ test('can aggregate a sql_ function', () => {
816
+ expect((0, test_translator_1.expr) `sum(sql_number("\${a} * 2"))`).toTranslate();
817
+ });
818
+ });
802
819
  describe('cast', () => {
803
820
  // The "+ 1"s are there to make sure the result is of type 'number'
804
821
  test('sql cast', () => {
@@ -875,5 +875,19 @@ describe('m3/m4 source query sentences', () => {
875
875
  `).toTranslate();
876
876
  });
877
877
  });
878
+ describe('sql_functions', () => {
879
+ test('can aggregate sql function', () => {
880
+ expect((0, test_translator_1.markSource) `
881
+ ##! experimental { sql_functions }
882
+ source: s is a extend {
883
+ measure: c is count()
884
+ dimension: sql_expr is sql_number("LENGTH(\${TABLE}.astr)")
885
+ }
886
+ run: s -> {
887
+ aggregate: v is sql_expr.sum()
888
+ }
889
+ `).toTranslate();
890
+ });
891
+ });
878
892
  test('non breaking space in source', () => expect('source:\u00a0z\u00a0is\u00a0a').toParse());
879
893
  //# sourceMappingURL=parse.spec.js.map
@@ -125,6 +125,9 @@ function exprMap(expr, func) {
125
125
  case 'function_parameter':
126
126
  case 'parameter':
127
127
  case 'outputField':
128
+ case 'source-reference':
129
+ case 'aggregate_limit':
130
+ case 'aggregate_order_by':
128
131
  return fragment;
129
132
  case 'sql-string':
130
133
  return {
@@ -231,6 +234,9 @@ function exprWalk(expr, func) {
231
234
  case 'function_parameter':
232
235
  case 'parameter':
233
236
  case 'outputField':
237
+ case 'source-reference':
238
+ case 'aggregate_limit':
239
+ case 'aggregate_order_by':
234
240
  return fragment;
235
241
  case 'function_call':
236
242
  return {
@@ -304,7 +310,7 @@ function exprWalk(expr, func) {
304
310
  }
305
311
  }
306
312
  default:
307
- throw new Error('unexpected');
313
+ throw new Error(`unexpected fragment type ${fragment.type}`);
308
314
  }
309
315
  });
310
316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.123-dev240205203120",
3
+ "version": "0.0.123-dev240207164302",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",