@malloydata/malloy 0.0.81-dev230910202545 → 0.0.81

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.
@@ -124,7 +124,7 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
124
124
  const noJoinField = !this.source && joinUsage.every(usage => usage.length === 0);
125
125
  if (!noJoinField && !this.isSymmetricFunction()) {
126
126
  const usagePaths = getJoinUsagePaths(sourceRelationship, joinUsage);
127
- const joinError = validateUsagePaths(usagePaths);
127
+ const joinError = validateUsagePaths(this.elementType, usagePaths);
128
128
  const message = sourceSpecified
129
129
  ? joinError
130
130
  : 'Join path is required for this calculation';
@@ -254,14 +254,17 @@ function getJoinUsagePaths(sourceRelationship, joinUsage) {
254
254
  }
255
255
  return sourceToUsagePaths;
256
256
  }
257
- function validateUsagePaths(usagePaths) {
257
+ function validateUsagePaths(functionName, usagePaths) {
258
258
  for (const path of usagePaths) {
259
259
  for (const step of path) {
260
260
  if (step.structRelationship.type === 'cross') {
261
- return `Cannot compute asymmetric aggregate across \`join_cross\` relationship \`${step.name}\``;
261
+ return `Cannot compute \`${functionName}\` across \`join_cross\` relationship \`${step.name}\``;
262
262
  }
263
263
  else if (step.structRelationship.type === 'many' && !step.reverse) {
264
- return `Cannot compute asymmetric aggregate across forward \`join_many\` relationship \`${step.name}\``;
264
+ return `Cannot compute \`${functionName}\` across \`join_many\` relationship \`${step.name}\``;
265
+ }
266
+ else if (step.structRelationship.type === 'nested' && !step.reverse) {
267
+ return `Cannot compute \`${functionName}\` across repeated relationship \`${step.name}\``;
265
268
  }
266
269
  }
267
270
  }
@@ -283,7 +286,7 @@ function suggestNewVersion(joinError, joinUsage, expr, func) {
283
286
  }
284
287
  }
285
288
  const usagePaths = getJoinUsagePaths(longestOverlap, joinUsage);
286
- const usageError = validateUsagePaths(usagePaths);
289
+ const usageError = validateUsagePaths(func, usagePaths);
287
290
  // get rid of everything after the last many/cross
288
291
  const indexFromEndOfLastMany = longestOverlap
289
292
  .slice()
@@ -295,7 +298,7 @@ function suggestNewVersion(joinError, joinUsage, expr, func) {
295
298
  : longestOverlap.length - indexFromEndOfLastMany;
296
299
  const shortestOverlapWithMany = longestOverlap.slice(0, numJoinsToLastMany);
297
300
  const shortUsagePaths = getJoinUsagePaths(shortestOverlapWithMany, joinUsage);
298
- const shortUsageError = validateUsagePaths(shortUsagePaths);
301
+ const shortUsageError = validateUsagePaths(func, shortUsagePaths);
299
302
  const longLocality = longestOverlap.length > 0
300
303
  ? longestOverlap.map(r => r.name).join('.')
301
304
  : 'source';
@@ -76,18 +76,22 @@ class Filter extends malloy_element_1.ListOf {
76
76
  // Aggregates are ALSO checked at SQL generation time, but checking
77
77
  // here allows better reflection of errors back to user.
78
78
  if (this.havingClause !== undefined) {
79
- const needHaving = (0, malloy_types_1.expressionIsCalculation)(fExpr.expressionType);
79
+ const isAggregate = (0, malloy_types_1.expressionIsAggregate)(fExpr.expressionType);
80
+ const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(fExpr.expressionType);
80
81
  if (this.havingClause) {
81
- if (!needHaving) {
82
- oneElement.log('Aggregate or analytic expression expected in HAVING filter');
82
+ if (isAnalytic) {
83
+ oneElement.log('Analytic expressions are not allowed in `having:`');
83
84
  continue;
84
85
  }
85
86
  }
86
87
  else {
87
- if (needHaving) {
88
- oneElement.log('Aggregate or analytic expressions not allowed in WHERE');
88
+ if (isAnalytic) {
89
+ oneElement.log('Analytic expressions are not allowed in `where:`');
89
90
  continue;
90
91
  }
92
+ else if (isAggregate) {
93
+ oneElement.log('Aggregate expressions are not allowed in `where:`; use `having:`');
94
+ }
91
95
  }
92
96
  }
93
97
  checked.push(fExpr);
@@ -176,6 +176,7 @@ describe('expressions', () => {
176
176
  source: root is a {
177
177
  rename: column is ai
178
178
  rename: nested is astruct
179
+ rename: inline is aninline
179
180
  dimension: field is column * 2
180
181
  dimension: many_field is many.column * 2
181
182
  dimension: many_one_field is many.column + one.column
@@ -277,7 +278,7 @@ describe('expressions', () => {
277
278
  expect(modelX `sum(many.column)`).translationToFailWith('Join path is required for this calculation; use `many.column.sum()`');
278
279
  });
279
280
  test('source.sum(many.column)', () => {
280
- expect(modelX `source.sum(many.column)`).translationToFailWith('Cannot compute asymmetric aggregate across forward `join_many` relationship `many`; use `many.column.sum()`');
281
+ expect(modelX `source.sum(many.column)`).translationToFailWith('Cannot compute `sum` across `join_many` relationship `many`; use `many.column.sum()`');
281
282
  });
282
283
  test('many.column.sum()', () => {
283
284
  expect(modelX `many.column.sum()`).toTranslate();
@@ -295,19 +296,28 @@ describe('expressions', () => {
295
296
  expect(modelX `source.sum(many.constant)`).toTranslate();
296
297
  });
297
298
  test('sum(nested.column)', () => {
298
- expect(modelX `sum(nested.column)`).toTranslateWithWarnings('Join path is required for this calculation; use `nested.column.sum()` or `source.sum(nested.column)` to get a result weighted with respect to `source`');
299
+ expect(modelX `sum(nested.column)`).translationToFailWith('Join path is required for this calculation; use `nested.column.sum()`');
299
300
  });
300
301
  test('nested.column.sum()', () => {
301
302
  expect(modelX `nested.column.sum()`).toTranslate();
302
303
  });
303
304
  test('source.sum(nested.column)', () => {
304
- expect(modelX `source.sum(nested.column)`).toTranslate();
305
+ expect(modelX `source.sum(nested.column)`).translationToFailWith('Cannot compute `sum` across repeated relationship `nested`; use `nested.column.sum()`');
306
+ });
307
+ test('sum(inline.column)', () => {
308
+ 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`');
309
+ });
310
+ test('inline.column.sum()', () => {
311
+ expect(modelX `inline.column.sum()`).toTranslate();
312
+ });
313
+ test('source.sum(inline.column)', () => {
314
+ expect(modelX `source.sum(inline.column)`).toTranslate();
305
315
  });
306
316
  test('sum(many.field)', () => {
307
317
  expect(modelX `sum(many.field)`).translationToFailWith('Join path is required for this calculation; use `many.field.sum()`');
308
318
  });
309
319
  test('source.sum(many.field)', () => {
310
- expect(modelX `source.sum(many.field)`).translationToFailWith('Cannot compute asymmetric aggregate across forward `join_many` relationship `many`; use `many.field.sum()`');
320
+ expect(modelX `source.sum(many.field)`).translationToFailWith('Cannot compute `sum` across `join_many` relationship `many`; use `many.field.sum()`');
311
321
  });
312
322
  test('many.field.sum()', () => {
313
323
  expect(modelX `many.field.sum()`).toTranslate();
@@ -319,7 +329,7 @@ describe('expressions', () => {
319
329
  expect(modelX `sum(many.field + many.field)`).translationToFailWith('Join path is required for this calculation; use `many.sum(many.field + many.field)`');
320
330
  });
321
331
  test('source.sum(many.field + many.field)', () => {
322
- expect(modelX `source.sum(many.field + many.field)`).translationToFailWith('Cannot compute asymmetric aggregate across forward `join_many` relationship `many`; use `many.sum(many.field + many.field)`');
332
+ expect(modelX `source.sum(many.field + many.field)`).translationToFailWith('Cannot compute `sum` across `join_many` relationship `many`; use `many.sum(many.field + many.field)`');
323
333
  });
324
334
  test('many.field + many.field.sum()', () => {
325
335
  expect(modelX `many.field + many.field.sum()`).toTranslate();
@@ -331,7 +341,7 @@ describe('expressions', () => {
331
341
  expect(modelX `sum(many_field)`).translationToFailWith('Join path is required for this calculation; use `many_field.sum()`');
332
342
  });
333
343
  test('source.sum(many_field)', () => {
334
- expect(modelX `source.sum(many_field)`).translationToFailWith('Cannot compute asymmetric aggregate across forward `join_many` relationship `many`; use `many_field.sum()`');
344
+ expect(modelX `source.sum(many_field)`).translationToFailWith('Cannot compute `sum` across `join_many` relationship `many`; use `many_field.sum()`');
335
345
  });
336
346
  test('many_field.sum()', () => {
337
347
  expect(modelX `many_field.sum()`).toTranslate();
@@ -343,7 +353,7 @@ describe('expressions', () => {
343
353
  expect(modelX `sum(one.many_field)`).translationToFailWith('Join path is required for this calculation; use `one.many_field.sum()`');
344
354
  });
345
355
  test('source.sum(one.many_field)', () => {
346
- expect(modelX `source.sum(one.many_field)`).translationToFailWith('Cannot compute asymmetric aggregate across forward `join_many` relationship `many`; use `one.many_field.sum()`');
356
+ expect(modelX `source.sum(one.many_field)`).translationToFailWith('Cannot compute `sum` across `join_many` relationship `many`; use `one.many_field.sum()`');
347
357
  });
348
358
  test('one.many_field.sum()', () => {
349
359
  expect(modelX `one.many_field.sum()`).toTranslate();
@@ -382,7 +392,7 @@ describe('expressions', () => {
382
392
  expect(modelX `one.avg(field)`).toTranslate();
383
393
  });
384
394
  test('cross.avg(field)', () => {
385
- expect(modelX `cross.avg(field)`).translationToFailWith('Cannot compute asymmetric aggregate across `join_cross` relationship `cross`; use `field.avg()`');
395
+ expect(modelX `cross.avg(field)`).translationToFailWith('Cannot compute `avg` across `join_cross` relationship `cross`; use `field.avg()`');
386
396
  });
387
397
  test('cross.avg(cross.field)', () => {
388
398
  expect(modelX `cross.avg(cross.field)`).toTranslate();
@@ -805,6 +805,15 @@ describe('query:', () => {
805
805
  }
806
806
  `).toTranslate();
807
807
  });
808
+ test('agg cannot be used in where', () => {
809
+ expect('query:ab->{ aggregate: acount; group_by: astr; where: acount > 10 }').translationToFailWith('Aggregate expressions are not allowed in `where:`; use `having:`');
810
+ });
811
+ test('analytic cannot be used in where', () => {
812
+ expect('query:ab->{ calculate: prevc is lag(count()); group_by: astr; where: prevc > 10 }').translationToFailWith("'prevc' is not defined");
813
+ });
814
+ test('analytic cannot be used in having', () => {
815
+ expect('query:ab->{ calculate: prevc is lag(count()); group_by: astr; having: prevc > 10 }').translationToFailWith('Analytic expressions are not allowed in `having:`');
816
+ });
808
817
  test('where single', () => {
809
818
  expect('query:a->{ group_by: astr; where: af > 10 }').toTranslate();
810
819
  });
@@ -55,6 +55,14 @@ const mockSchema = {
55
55
  type: 'struct',
56
56
  name: 'astruct',
57
57
  structSource: { type: 'nested' },
58
+ structRelationship: { type: 'nested', isArray: true, field: 'foo' },
59
+ fields: [{ type: 'number', name: 'column', numberType: 'integer' }],
60
+ dialect: 'standardsql',
61
+ },
62
+ {
63
+ type: 'struct',
64
+ name: 'aninline',
65
+ structSource: { type: 'nested' },
58
66
  structRelationship: { type: 'inline' },
59
67
  fields: [{ type: 'number', name: 'column', numberType: 'integer' }],
60
68
  dialect: 'standardsql',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.81-dev230910202545",
3
+ "version": "0.0.81",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",