@malloydata/malloy 0.0.297 → 0.0.299

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.
@@ -27,6 +27,7 @@ export interface CompileModelState {
27
27
  translator: MalloyTranslator;
28
28
  done: boolean;
29
29
  hasSource: boolean;
30
+ excludeReferences: boolean;
30
31
  }
31
32
  export declare function updateCompileModelState(state: CompileModelState, needs: Malloy.CompilerNeeds | undefined): void;
32
33
  export declare function newCompileModelState(request: Malloy.CompileModelRequest): CompileModelState;
package/dist/api/core.js CHANGED
@@ -258,17 +258,18 @@ function updateCompileModelState(state, needs) {
258
258
  const update = compilerNeedsToUpdate(needs);
259
259
  performUpdate(state, update);
260
260
  }
261
- function _newCompileModelState(modelURL, compilerNeeds, extendURL) {
261
+ function _newCompileModelState(modelURL, compilerNeeds, extendURL, excludeReferences = false) {
262
262
  var _a, _b, _c, _d;
263
263
  const translator = new lang_1.MalloyTranslator(modelURL, null, compilerNeedsToUpdate(compilerNeeds));
264
264
  const hasSource = ((_b = (_a = compilerNeeds === null || compilerNeeds === void 0 ? void 0 : compilerNeeds.files) === null || _a === void 0 ? void 0 : _a.some(f => f.url === modelURL)) !== null && _b !== void 0 ? _b : false) ||
265
265
  ((_d = (_c = compilerNeeds === null || compilerNeeds === void 0 ? void 0 : compilerNeeds.translations) === null || _c === void 0 ? void 0 : _c.some(t => t.url === modelURL)) !== null && _d !== void 0 ? _d : false);
266
266
  if (extendURL) {
267
267
  return {
268
- extending: _newCompileModelState(extendURL, compilerNeeds),
268
+ extending: _newCompileModelState(extendURL, compilerNeeds, undefined, excludeReferences),
269
269
  translator,
270
270
  done: false,
271
271
  hasSource,
272
+ excludeReferences,
272
273
  };
273
274
  }
274
275
  else {
@@ -276,14 +277,15 @@ function _newCompileModelState(modelURL, compilerNeeds, extendURL) {
276
277
  translator,
277
278
  done: false,
278
279
  hasSource,
280
+ excludeReferences,
279
281
  };
280
282
  }
281
283
  }
282
284
  function newCompileModelState(request) {
283
- return _newCompileModelState(request.model_url, request.compiler_needs, request.extend_model_url);
285
+ return _newCompileModelState(request.model_url, request.compiler_needs, request.extend_model_url, request.exclude_references);
284
286
  }
285
287
  function newCompileSourceState(request) {
286
- return _newCompileModelState(request.model_url, request.compiler_needs, request.extend_model_url);
288
+ return _newCompileModelState(request.model_url, request.compiler_needs, request.extend_model_url, request.exclude_references);
287
289
  }
288
290
  // function hasNeeds(needs: Malloy.CompilerNeeds | undefined): boolean {
289
291
  // if (needs === undefined) return false;
@@ -328,7 +330,7 @@ function _statedCompileModel(state) {
328
330
  const model = (0, to_stable_1.modelDefToModelInfo)(result.modelDef);
329
331
  return {
330
332
  model,
331
- modelDef: result.modelDef,
333
+ modelDef: maybeExcludeReferences(result.modelDef, state.excludeReferences),
332
334
  timingInfo,
333
335
  };
334
336
  }
@@ -348,6 +350,14 @@ function _statedCompileModel(state) {
348
350
  return { compilerNeeds, logs: result.problems, timingInfo };
349
351
  }
350
352
  }
353
+ function maybeExcludeReferences(modelDef, excludeReferences) {
354
+ if (!excludeReferences)
355
+ return modelDef;
356
+ return {
357
+ ...modelDef,
358
+ references: undefined,
359
+ };
360
+ }
351
361
  function wrapResponse(response, defaultURL) {
352
362
  const logs = response.logs ? (0, util_1.mapLogs)(response.logs, defaultURL) : undefined;
353
363
  if (response.compilerNeeds) {
@@ -375,10 +385,6 @@ function wrapResponse(response, defaultURL) {
375
385
  };
376
386
  }
377
387
  }
378
- function _compileModel(modelURL, compilerNeeds, extendURL, state) {
379
- state !== null && state !== void 0 ? state : (state = _newCompileModelState(modelURL, compilerNeeds, extendURL));
380
- return _statedCompileModel(state);
381
- }
382
388
  function compileModel(request, state) {
383
389
  state !== null && state !== void 0 ? state : (state = newCompileModelState(request));
384
390
  return statedCompileModel(state);
@@ -435,7 +441,7 @@ function newCompileQueryState(request) {
435
441
  ...((_b = needs.files) !== null && _b !== void 0 ? _b : []),
436
442
  ];
437
443
  return {
438
- ..._newCompileModelState(queryURL, needs, request.model_url),
444
+ ..._newCompileModelState(queryURL, needs, request.model_url, request.exclude_references),
439
445
  defaultRowLimit: request.default_row_limit,
440
446
  };
441
447
  }
@@ -49,17 +49,16 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
49
49
  }
50
50
  }
51
51
  getPipeSegment(refineIndex) {
52
+ var _a;
52
53
  if (refineIndex) {
53
54
  this.logError('refinement-of-index-segment', 'index query operations cannot be refined');
54
55
  return { type: 'index', indexFields: [] };
55
56
  }
56
57
  let fieldUsage = (0, composite_source_utils_1.emptyFieldUsage)();
57
58
  const indexFields = [];
58
- const source = this.inputSpace().structDef();
59
59
  for (const [name, field] of this.entries()) {
60
60
  if (field instanceof space_field_1.SpaceField) {
61
61
  let nextFieldUsage = undefined;
62
- let logTo = undefined;
63
62
  const wild = this.expandedWild[name];
64
63
  if (wild) {
65
64
  indexFields.push({ type: 'fieldref', path: wild.path, at: wild.at });
@@ -75,10 +74,9 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
75
74
  else {
76
75
  indexFields.push(fieldRef.refToField);
77
76
  nextFieldUsage = check.found.typeDesc().fieldUsage;
78
- logTo = fieldRef;
79
77
  }
80
78
  }
81
- fieldUsage = this.applyNextFieldUsage(source, fieldUsage, nextFieldUsage, logTo);
79
+ fieldUsage = (_a = (0, composite_source_utils_1.mergeFieldUsage)(fieldUsage, nextFieldUsage)) !== null && _a !== void 0 ? _a : [];
82
80
  }
83
81
  }
84
82
  this._fieldUsage = fieldUsage;
@@ -35,12 +35,10 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
35
35
  compositeFieldUsers: ({
36
36
  type: 'filter';
37
37
  filter: model.FilterCondition;
38
- logTo: MalloyElement;
39
38
  } | {
40
39
  type: 'field';
41
40
  name: string;
42
41
  field: SpaceField;
43
- logTo: MalloyElement | undefined;
44
42
  })[];
45
43
  _fieldUsage: model.FieldUsage[] | undefined;
46
44
  get fieldUsage(): model.FieldUsage[];
@@ -52,11 +50,8 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
52
50
  outputSpace(): QueryOperationSpace;
53
51
  protected addWild(wild: WildcardFieldReference): void;
54
52
  protected addValidatedCompositeFieldUserFromEntry(name: string, entry: SpaceEntry): void;
55
- private getJoinOnFieldUsage;
56
- protected getFieldUsageIncludingJoinOns(fieldUsage: model.FieldUsage[]): model.FieldUsage[];
57
- addFieldUserFromFilter(filter: model.FilterCondition, logTo: MalloyElement): void;
53
+ addFieldUserFromFilter(filter: model.FilterCondition): void;
58
54
  newEntry(name: string, logTo: MalloyElement, entry: SpaceEntry): void;
59
- protected applyNextFieldUsage(source: model.SourceDef, fieldUsage: model.FieldUsage[], nextFieldUsage: model.FieldUsage[] | undefined, _logTo: MalloyElement | undefined): model.FieldUsage[];
60
55
  }
61
56
  export declare abstract class QuerySpace extends QueryOperationSpace {
62
57
  addRefineFromFields(refineThis: model.PipeSegment): void;
@@ -66,7 +66,6 @@ const column_space_field_1 = require("./column-space-field");
66
66
  const static_space_1 = require("./static-space");
67
67
  const query_input_space_1 = require("./query-input-space");
68
68
  const composite_source_utils_1 = require("../../../model/composite_source_utils");
69
- const struct_space_field_base_1 = require("./struct-space-field-base");
70
69
  /**
71
70
  * The output space of a query operation. It is not named "QueryOutputSpace"
72
71
  * because this is the namespace of the Query which is a layer of an output and
@@ -174,48 +173,20 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
174
173
  type: 'field',
175
174
  name,
176
175
  field: entry,
177
- logTo: undefined,
178
176
  });
179
177
  }
180
178
  }
181
- getJoinOnFieldUsage(joinPath) {
182
- var _a;
183
- const reference = joinPath.map(n => new field_space_1.FieldName(n));
184
- this.astEl.has({ reference });
185
- const lookup = this.exprSpace.lookup(reference, 'private');
186
- // Should always be found...
187
- if (lookup.found && lookup.found instanceof struct_space_field_base_1.StructSpaceFieldBase) {
188
- return (0, composite_source_utils_1.joinedFieldUsage)(joinPath.slice(0, -1), (_a = lookup.found.fieldDef().onFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyFieldUsage)());
189
- }
190
- throw new Error('Unexpected join lookup was not found or not a struct');
191
- }
192
- getFieldUsageIncludingJoinOns(fieldUsage) {
193
- let fieldUsageIncludingJoinOns = fieldUsage;
194
- const joinPaths = (0, composite_source_utils_1.fieldUsageJoinPaths)(fieldUsage);
195
- for (const joinPath of joinPaths) {
196
- fieldUsageIncludingJoinOns = (0, composite_source_utils_1.mergeFieldUsage)(this.getJoinOnFieldUsage(joinPath), fieldUsageIncludingJoinOns);
197
- }
198
- return fieldUsageIncludingJoinOns;
199
- }
200
- addFieldUserFromFilter(filter, logTo) {
179
+ addFieldUserFromFilter(filter) {
201
180
  if (filter.fieldUsage !== undefined) {
202
- this.compositeFieldUsers.push({ type: 'filter', filter, logTo });
181
+ this.compositeFieldUsers.push({ type: 'filter', filter });
203
182
  }
204
183
  }
205
184
  newEntry(name, logTo, entry) {
206
185
  if (entry instanceof space_field_1.SpaceField) {
207
- this.compositeFieldUsers.push({ type: 'field', name, field: entry, logTo });
186
+ this.compositeFieldUsers.push({ type: 'field', name, field: entry });
208
187
  }
209
188
  super.newEntry(name, logTo, entry);
210
189
  }
211
- applyNextFieldUsage(source, fieldUsage, nextFieldUsage, _logTo) {
212
- var _a;
213
- if (nextFieldUsage) {
214
- const newFieldUsage = this.getFieldUsageIncludingJoinOns(nextFieldUsage);
215
- fieldUsage = (_a = (0, composite_source_utils_1.mergeFieldUsage)(fieldUsage, newFieldUsage)) !== null && _a !== void 0 ? _a : [];
216
- }
217
- return fieldUsage;
218
- }
219
190
  }
220
191
  exports.QueryOperationSpace = QueryOperationSpace;
221
192
  // Project and Reduce or "QuerySegments" are built from a QuerySpace
@@ -264,9 +235,9 @@ class QuerySpace extends QueryOperationSpace {
264
235
  return true;
265
236
  }
266
237
  queryFieldDefs() {
238
+ var _a;
267
239
  const fields = [];
268
240
  let fieldUsage = (0, composite_source_utils_1.emptyFieldUsage)();
269
- const source = this.inputSpace().structDef();
270
241
  for (const user of this.compositeFieldUsers) {
271
242
  let nextFieldUsage = undefined;
272
243
  if (user.type === 'filter') {
@@ -306,7 +277,7 @@ class QuerySpace extends QueryOperationSpace {
306
277
  // fields, but the individual fields didn't have field defs.
307
278
  }
308
279
  }
309
- fieldUsage = this.applyNextFieldUsage(source, fieldUsage, nextFieldUsage, user.logTo);
280
+ fieldUsage = (_a = (0, composite_source_utils_1.mergeFieldUsage)(fieldUsage, nextFieldUsage)) !== null && _a !== void 0 ? _a : [];
310
281
  }
311
282
  this._fieldUsage = fieldUsage;
312
283
  for (const drillDimension of this.drillDimensions) {
@@ -81,14 +81,14 @@ class StructSpaceFieldBase extends space_field_1.SpaceField {
81
81
  type: this.structDef.type,
82
82
  evalSpace: 'input',
83
83
  expressionType: 'scalar',
84
- fieldUsage: (_a = this.structDef.onFieldUsage) !== null && _a !== void 0 ? _a : [],
84
+ fieldUsage: (_a = this.structDef.fieldUsage) !== null && _a !== void 0 ? _a : [],
85
85
  };
86
86
  }
87
87
  return {
88
88
  ...TDU.atomicDef(this.structDef),
89
89
  evalSpace: 'input',
90
90
  expressionType: 'scalar',
91
- fieldUsage: (_b = this.structDef.onFieldUsage) !== null && _b !== void 0 ? _b : [],
91
+ fieldUsage: (_b = this.structDef.fieldUsage) !== null && _b !== void 0 ? _b : [],
92
92
  };
93
93
  }
94
94
  }
@@ -168,7 +168,7 @@ class Filter extends malloy_element_1.ListOf {
168
168
  const fExpr = this.checkedFilterCondition(filterFS, filter);
169
169
  if (fExpr !== undefined) {
170
170
  executeFor.filters.push(fExpr);
171
- executeFor.resultFS.addFieldUserFromFilter(fExpr, filter);
171
+ executeFor.resultFS.addFieldUserFromFilter(fExpr);
172
172
  }
173
173
  }
174
174
  }
@@ -31,6 +31,7 @@ const struct_utils_1 = require("../struct-utils");
31
31
  const static_space_1 = require("../field-space/static-space");
32
32
  const query_property_interface_1 = require("../types/query-property-interface");
33
33
  const partial_builder_1 = require("../query-builders/partial-builder");
34
+ const utils_1 = require("../../utils");
34
35
  class QOpDesc extends malloy_element_1.ListOf {
35
36
  constructor() {
36
37
  super(...arguments);
@@ -55,7 +56,7 @@ class QOpDesc extends malloy_element_1.ListOf {
55
56
  if (el.forceQueryClass) {
56
57
  if (guessType) {
57
58
  if (guessType !== el.forceQueryClass) {
58
- el.logError(`illegal-${guessType}-operation`, `Not legal in ${guessType} query`);
59
+ el.logError(`illegal-${guessType}-operation`, `Use of ${(0, utils_1.modernizeTermsForUserText)(el.forceQueryClass)} is not allowed in a ${(0, utils_1.modernizeTermsForUserText)(guessType)} query`);
59
60
  }
60
61
  }
61
62
  else {
@@ -99,7 +99,7 @@ class KeyJoin extends Join {
99
99
  right: exprX.value,
100
100
  },
101
101
  };
102
- inStruct.onFieldUsage = exprX.fieldUsage;
102
+ inStruct.fieldUsage = exprX.fieldUsage;
103
103
  return;
104
104
  }
105
105
  else {
@@ -142,7 +142,7 @@ class ExpressionJoin extends Join {
142
142
  return;
143
143
  }
144
144
  inStruct.onExpression = exprX.value;
145
- inStruct.onFieldUsage = exprX.fieldUsage;
145
+ inStruct.fieldUsage = exprX.fieldUsage;
146
146
  }
147
147
  getStructDef(parameterSpace) {
148
148
  var _a;
@@ -63,12 +63,17 @@ const checkCustomErrorMessage = (parser, offendingSymbol, errorCases) => {
63
63
  }
64
64
  }
65
65
  const errReplace = (s) => {
66
- const rs = s
66
+ let rs = s
67
67
  .replace('${currentToken}', currentToken.text || '')
68
68
  .replace('${offendingSymbol}', (offendingSymbol === null || offendingSymbol === void 0 ? void 0 : offendingSymbol.text) || '');
69
69
  try {
70
70
  const previousToken = parser.inputStream.LT(-1);
71
- return rs.replace('${previousToken}', previousToken.text || '');
71
+ rs = rs.replace('${previousToken}', previousToken.text || '');
72
+ const offendingSymbolIndex = offendingSymbol === null || offendingSymbol === void 0 ? void 0 : offendingSymbol.tokenIndex;
73
+ if (offendingSymbolIndex && offendingSymbolIndex > 0) {
74
+ const previousSymbol = parser.inputStream.get(offendingSymbolIndex - 1);
75
+ rs = rs.replace('${previousSymbol}', previousSymbol.text || '');
76
+ }
72
77
  }
73
78
  catch (ex) {
74
79
  // This shouldn't ever occur, but if it does, just leave the untokenized message.
@@ -170,6 +170,51 @@ exports.malloyCustomErrorCases = [
170
170
  with: ['run:', 'query:', 'source:'],
171
171
  },
172
172
  },
173
+ {
174
+ errorMessage: '`count(distinct expression)` deprecated, use `count(expression)` instead.',
175
+ offendingSymbol: MalloyParser_1.MalloyParser.DISTINCT,
176
+ ruleContextOptions: ['fieldExpr'],
177
+ precedingTokenOptions: [[MalloyParser_1.MalloyParser.COUNT], [MalloyParser_1.MalloyParser.OPAREN]],
178
+ },
179
+ {
180
+ errorMessage: "Unexpected type '${offendingSymbol}' in dimension definition. Expected an expression or field reference.",
181
+ offendingSymbolTextOptions: [
182
+ 'string',
183
+ 'number',
184
+ 'int',
185
+ 'integer',
186
+ 'bool',
187
+ 'boolean',
188
+ 'date',
189
+ 'time',
190
+ 'timestamp',
191
+ 'array',
192
+ ],
193
+ ruleContextOptions: ['fieldExpr'],
194
+ precedingTokenOptions: [[MalloyParser_1.MalloyParser.IDENTIFIER], [MalloyParser_1.MalloyParser.IS]],
195
+ },
196
+ // Identify a case where a user is using an open parenthesis following an
197
+ // identifier that does not represent a valid function.
198
+ {
199
+ errorMessage: "Unknown function '${previousSymbol}'. You can find available functions here: https://docs.malloydata.dev/documentation/language/functions",
200
+ offendingSymbol: MalloyParser_1.MalloyParser.OPAREN,
201
+ ruleContextOptions: ['vExpr'],
202
+ precedingTokenOptions: [[MalloyParser_1.MalloyParser.IDENTIFIER]],
203
+ },
204
+ {
205
+ errorMessage: "The 'project:' keyword is no longer supported. Use 'select:' instead.",
206
+ offendingSymbol: MalloyParser_1.MalloyParser.PROJECT,
207
+ },
208
+ {
209
+ errorMessage: "Unsupported keyword 'as'. Use 'is' to name something (ex: `dimension: name is expression`)",
210
+ offendingSymbolTextOptions: ['as'],
211
+ ruleContextOptions: ['isDefine'],
212
+ },
213
+ {
214
+ // Broader catch-all case for the 'as' keyword, including an alternative example.
215
+ errorMessage: "Unsupported keyword 'as'. Use 'is' to name something (ex: `select: new_name is column_name`)",
216
+ offendingSymbolTextOptions: ['as'],
217
+ },
173
218
  ];
174
219
  class MalloyParserErrorListener {
175
220
  constructor(
@@ -19,6 +19,13 @@ export declare function rangeFromContext(sourceInfo: SourceInfo | undefined, pcx
19
19
  * to the line/char positions favored by LSP and VSCode.
20
20
  */
21
21
  export declare function getSourceInfo(code: string): SourceInfo;
22
+ /**
23
+ * Rewrites text that is going to be presented to end users to avoid
24
+ * using terminology that is deprecated or changed.
25
+ *
26
+ * @param text raw text that is being used internally in Malloy
27
+ */
28
+ export declare function modernizeTermsForUserText(text: string): string;
22
29
  export interface ParseInfo {
23
30
  root: ParseTree;
24
31
  tokenStream: CommonTokenStream;
@@ -28,6 +28,7 @@ exports.rangeFromTokens = rangeFromTokens;
28
28
  exports.rangeFromToken = rangeFromToken;
29
29
  exports.rangeFromContext = rangeFromContext;
30
30
  exports.getSourceInfo = getSourceInfo;
31
+ exports.modernizeTermsForUserText = modernizeTermsForUserText;
31
32
  function locationContainsPosition(location, position) {
32
33
  return (location.range.start.line <= position.line &&
33
34
  location.range.end.line >= position.line &&
@@ -112,4 +113,16 @@ function getSourceInfo(code) {
112
113
  }
113
114
  return info;
114
115
  }
116
+ /**
117
+ * Rewrites text that is going to be presented to end users to avoid
118
+ * using terminology that is deprecated or changed.
119
+ *
120
+ * @param text raw text that is being used internally in Malloy
121
+ */
122
+ function modernizeTermsForUserText(text) {
123
+ if (text === 'project') {
124
+ return 'select';
125
+ }
126
+ return text;
127
+ }
115
128
  //# sourceMappingURL=utils.js.map
@@ -26,12 +26,11 @@ exports.logCompositeError = logCompositeError;
26
26
  exports.compileFilterExpression = compileFilterExpression;
27
27
  const malloy_filter_1 = require("@malloydata/malloy-filter");
28
28
  const malloy_types_1 = require("./malloy_types");
29
- const utils_1 = require("./utils");
30
- const utils_2 = require("../lang/utils");
29
+ const utils_1 = require("../lang/utils");
31
30
  function _resolveCompositeSources(path, source, rootFields, nests, fieldUsage,
32
31
  // for resolving nested composites; the list of sources to try
33
32
  sources) {
34
- var _a, _b, _c;
33
+ var _a, _b, _c, _d;
35
34
  // TODO skip all this if the tree doesn't have any composite sources
36
35
  let base = { ...source };
37
36
  let anyComposites = false;
@@ -62,8 +61,9 @@ sources) {
62
61
  fieldNames.add((_a = field.as) !== null && _a !== void 0 ? _a : field.name);
63
62
  }
64
63
  }
64
+ const fieldUsageWithWheres = (_b = mergeFieldUsage(fieldUsage, getFieldUsageFromFilterList(inputSource))) !== null && _b !== void 0 ? _b : [];
65
65
  const fieldsForLookup = [...nonCompositeFields, ...inputSource.fields];
66
- const expanded = expandFieldUsage(fieldUsage, fieldsForLookup);
66
+ const expanded = expandFieldUsage(fieldUsageWithWheres, fieldsForLookup);
67
67
  if (expanded.missingFields.length > 0) {
68
68
  // A lookup failed while expanding, which means this source certainly won't work
69
69
  for (const missingField of expanded.missingFields) {
@@ -96,8 +96,13 @@ sources) {
96
96
  if (inputSource.type === 'composite') {
97
97
  const resolveInner = _resolveCompositeSources(path, inputSource, genRootFields(rootFields, path, fieldsForLookup, false), nests, compositeUsageInThisSource, inputSource.sources);
98
98
  if ('error' in resolveInner) {
99
- // Third point where we abort; if a nested composite failed
100
- abort();
99
+ // Third point where we abort; if a nested composite failed; we don't call abort() because we want to unnest the failures from
100
+ if (resolveInner.error.code === 'no_suitable_composite_source_input') {
101
+ failures.push(...resolveInner.error.data.failures);
102
+ }
103
+ else {
104
+ abort();
105
+ }
101
106
  continue overSources;
102
107
  }
103
108
  base = {
@@ -116,7 +121,7 @@ sources) {
116
121
  ...base,
117
122
  fields,
118
123
  arguments: source.arguments,
119
- filterList: [...((_b = source.filterList) !== null && _b !== void 0 ? _b : []), ...((_c = base.filterList) !== null && _c !== void 0 ? _c : [])],
124
+ filterList: [...((_c = source.filterList) !== null && _c !== void 0 ? _c : []), ...((_d = base.filterList) !== null && _d !== void 0 ? _d : [])],
120
125
  };
121
126
  const joinError = processJoins(path, base, rootFields, nests, expandedCategorized);
122
127
  // Fourth point where we abort: if a join failed
@@ -198,6 +203,7 @@ function onlyCompositeUsage(fieldUsage, fields) {
198
203
  });
199
204
  }
200
205
  function expandFieldUsage(fieldUsage, fields) {
206
+ var _a;
201
207
  const allFieldPathsReferenced = [...fieldUsage];
202
208
  const joinPathsProcessed = [];
203
209
  const missingFields = [];
@@ -217,17 +223,15 @@ function expandFieldUsage(fieldUsage, fields) {
217
223
  continue;
218
224
  }
219
225
  if ((0, malloy_types_1.isAtomic)(def)) {
220
- const fieldUsage = getFieldUsageForField(def);
226
+ const fieldUsage = (_a = def.fieldUsage) !== null && _a !== void 0 ? _a : [];
221
227
  allFieldPathsReferenced.push(...fieldUsageAt(joinedFieldUsage(referenceJoinPath, fieldUsage), reference.at).filter(u1 => !allFieldPathsReferenced.some(u2 => pathEq(u1.path, u2.path))));
222
228
  }
223
229
  if (reference.path.length > 1) {
224
230
  if (!joinPathsProcessed.some(p => pathEq(p, referenceJoinPath))) {
225
231
  joinPathsProcessed.push(referenceJoinPath);
226
232
  const join = lookup(referenceJoinPath, fields);
227
- // Don't want to actually include the name of the join; just the path to the join
228
- const joinJoinPath = referenceJoinPath.slice(0, -1);
229
- const fieldUsage = getFieldUsageForField(join);
230
- allFieldPathsReferenced.push(...fieldUsageAt(joinedFieldUsage(joinJoinPath, fieldUsage), reference.at).filter(u1 => !allFieldPathsReferenced.some(u2 => pathEq(u1.path, u2.path))));
233
+ const joinFieldUsage = getJoinFieldUsage(join, referenceJoinPath);
234
+ allFieldPathsReferenced.push(...fieldUsageAt(joinFieldUsage, reference.at).filter(u1 => !allFieldPathsReferenced.some(u2 => pathEq(u1.path, u2.path))));
231
235
  }
232
236
  }
233
237
  }
@@ -384,14 +388,19 @@ function processJoins(path, base, rootFields, nests, categorizedFieldUsage) {
384
388
  }
385
389
  return { anyComposites, errors };
386
390
  }
387
- function resolveCompositeSources(source, segment, fieldUsage) {
391
+ function getFieldUsageFromFilterList(source) {
388
392
  var _a;
393
+ return ((_a = source.filterList) !== null && _a !== void 0 ? _a : []).flatMap(filter => { var _a; return (_a = filter.fieldUsage) !== null && _a !== void 0 ? _a : []; });
394
+ }
395
+ function resolveCompositeSources(source, segment, fieldUsage) {
396
+ var _a, _b;
389
397
  const sourceExtensions = (0, malloy_types_1.isQuerySegment)(segment)
390
398
  ? (_a = segment.extendSource) !== null && _a !== void 0 ? _a : []
391
399
  : [];
392
400
  const nestLevels = extractNestLevels(segment);
393
401
  const fields = mergeFields(source.fields, sourceExtensions);
394
- const result = _resolveCompositeSources([], source, fields, nestLevels, fieldUsage);
402
+ const fieldUsageWithWheres = (_b = mergeFieldUsage(fieldUsage, getFieldUsageFromFilterList(source))) !== null && _b !== void 0 ? _b : [];
403
+ const result = _resolveCompositeSources([], source, fields, nestLevels, fieldUsageWithWheres);
395
404
  if ('success' in result) {
396
405
  if (result.anyComposites) {
397
406
  return { sourceDef: result.success, error: undefined };
@@ -498,27 +507,6 @@ function isCompositeField(fieldDef) {
498
507
  function getNonCompositeFields(source) {
499
508
  return source.fields.filter(f => !isCompositeField(f));
500
509
  }
501
- function getFieldUsageFromExpr(expr) {
502
- const fieldUsage = [];
503
- for (const node of (0, utils_1.exprWalk)(expr)) {
504
- if (node.node === 'field') {
505
- fieldUsage.push({
506
- path: node.path,
507
- at: node.at,
508
- });
509
- }
510
- }
511
- return fieldUsage;
512
- }
513
- function getFieldUsageForField(field) {
514
- if ((0, malloy_types_1.isAtomic)(field) && field.e) {
515
- return getFieldUsageFromExpr(field.e);
516
- }
517
- else if ((0, malloy_types_1.isJoined)(field) && field.onExpression) {
518
- return getFieldUsageFromExpr(field.onExpression);
519
- }
520
- return [];
521
- }
522
510
  function nestLevelsAt(nests, at) {
523
511
  var _a;
524
512
  if (at === undefined)
@@ -570,7 +558,7 @@ function joinedUngroupings(joinPath, ungroupings) {
570
558
  }));
571
559
  }
572
560
  function extractNestLevels(segment) {
573
- var _a, _b, _c;
561
+ var _a, _b, _c, _d;
574
562
  const fieldsReferencedDirectly = [];
575
563
  const fieldsReferenced = [];
576
564
  const nested = [];
@@ -594,12 +582,13 @@ function extractNestLevels(segment) {
594
582
  nested.push(nestLevelsAt(extractNestLevels(head), head.referencedAt));
595
583
  }
596
584
  else {
597
- fieldsReferenced.push(...getFieldUsageForField(field));
598
- ungroupings.push(...((_a = field.ungroupings) !== null && _a !== void 0 ? _a : []));
599
- requiredGroupBys.push(...((_b = field.requiresGroupBy) !== null && _b !== void 0 ? _b : []));
585
+ const fieldUsage = (_a = field.fieldUsage) !== null && _a !== void 0 ? _a : [];
586
+ fieldsReferenced.push(...fieldUsage);
587
+ ungroupings.push(...((_b = field.ungroupings) !== null && _b !== void 0 ? _b : []));
588
+ requiredGroupBys.push(...((_c = field.requiresGroupBy) !== null && _c !== void 0 ? _c : []));
600
589
  }
601
590
  }
602
- for (const filter of (_c = segment.filterList) !== null && _c !== void 0 ? _c : []) {
591
+ for (const filter of (_d = segment.filterList) !== null && _d !== void 0 ? _d : []) {
603
592
  if (!(0, malloy_types_1.expressionIsScalar)(filter.expressionType))
604
593
  continue;
605
594
  const fields = getSingleValueFilterFields(filter.e);
@@ -677,7 +666,7 @@ function isSingleValueFilterNode(e) {
677
666
  }
678
667
  }
679
668
  function expandRefs(nests, fields) {
680
- var _a, _b, _c;
669
+ var _a, _b, _c, _d;
681
670
  const newNests = [];
682
671
  const requiredGroupBys = [...nests.requiredGroupBys];
683
672
  const allUngroupings = [...nests.ungroupings];
@@ -718,7 +707,7 @@ function expandRefs(nests, fields) {
718
707
  if (def.ungroupings) {
719
708
  allUngroupings.push(...joinedUngroupings(joinPath, ungroupingsAt(def.ungroupings, field.at)));
720
709
  }
721
- const fieldUsage = getFieldUsageForField(def);
710
+ const fieldUsage = (_a = def.fieldUsage) !== null && _a !== void 0 ? _a : [];
722
711
  const moreReferences = fieldUsageAt(joinedFieldUsage(joinPath, fieldUsage), field.at).filter(u1 => !references.some(u2 => pathEq(u1.path, u2.path)));
723
712
  references.push(...moreReferences);
724
713
  }
@@ -726,10 +715,8 @@ function expandRefs(nests, fields) {
726
715
  if (!joinPathsProcessed.some(p => pathEq(p, joinPath))) {
727
716
  joinPathsProcessed.push(joinPath);
728
717
  const join = lookup(joinPath, fields);
729
- // Don't want to actually include the name of the join; just the path to the join
730
- const joinJoinPath = joinPath.slice(0, -1);
731
- const fieldUsage = getFieldUsageForField(join);
732
- references.push(...fieldUsageAt(joinedFieldUsage(joinJoinPath, fieldUsage), field.at).filter(u1 => !references.some(u2 => pathEq(u1.path, u2.path))));
718
+ const joinFieldUsage = getJoinFieldUsage(join, joinPath);
719
+ references.push(...fieldUsageAt(joinFieldUsage, field.at).filter(u1 => !references.some(u2 => pathEq(u1.path, u2.path))));
733
720
  }
734
721
  }
735
722
  }
@@ -740,10 +727,10 @@ function expandRefs(nests, fields) {
740
727
  fieldsReferencedDirectly: [],
741
728
  ungroupings: [],
742
729
  nested: [],
743
- requiredGroupBys: (_a = ungrouping.requiresGroupBy) !== null && _a !== void 0 ? _a : [],
730
+ requiredGroupBys: (_b = ungrouping.requiresGroupBy) !== null && _b !== void 0 ? _b : [],
744
731
  singleValueFilters: [],
745
732
  }, fields);
746
- missingFields.push(...((_b = expanded.missingFields) !== null && _b !== void 0 ? _b : []));
733
+ missingFields.push(...((_c = expanded.missingFields) !== null && _c !== void 0 ? _c : []));
747
734
  for (const field of expanded.result.requiredGroupBys) {
748
735
  if (isUngroupedBy(ungrouping, field.path)) {
749
736
  unsatisfiableGroupBys.push(field);
@@ -753,7 +740,7 @@ function expandRefs(nests, fields) {
753
740
  const nested = [];
754
741
  for (const level of [...nests.nested, ...newNests]) {
755
742
  const expanded = expandRefs(level, fields);
756
- missingFields.push(...((_c = expanded.missingFields) !== null && _c !== void 0 ? _c : []));
743
+ missingFields.push(...((_d = expanded.missingFields) !== null && _d !== void 0 ? _d : []));
757
744
  nested.push(expanded.result);
758
745
  unsatisfiableGroupBys.push(...expanded.result.unsatisfiableGroupBys);
759
746
  }
@@ -768,6 +755,15 @@ function expandRefs(nests, fields) {
768
755
  missingFields: missingFields.length > 0 ? missingFields : undefined,
769
756
  };
770
757
  }
758
+ function getJoinFieldUsage(join, joinPath) {
759
+ var _a, _b;
760
+ return ((_b = mergeFieldUsage(
761
+ // For `fieldUsage` from join `on`, we need the path excluding the join name, since it's
762
+ // already rooted at the parent
763
+ joinedFieldUsage(joinPath.slice(0, -1), (_a = join.fieldUsage) !== null && _a !== void 0 ? _a : []),
764
+ // For `fieldUsage` from join `where`s, we need the path including the join name
765
+ joinedFieldUsage(joinPath, (0, malloy_types_1.isSourceDef)(join) ? getFieldUsageFromFilterList(join) : []))) !== null && _b !== void 0 ? _b : []);
766
+ }
771
767
  function isUngroupedBy(ungrouping, groupedBy) {
772
768
  if (ungrouping.ungroupedFields === '*')
773
769
  return true;
@@ -882,13 +878,14 @@ function logCompositeError(error, logTo) {
882
878
  if (error.code === 'no_suitable_composite_source_input') {
883
879
  const firstFails = error.data.failures.map(failure => failure.issues[0]);
884
880
  const sorted = sortIssuesByReferenceLocation(firstFails);
881
+ const joinPath = error.data.path;
885
882
  const usages = sorted.map(issueFieldUsage);
886
883
  const lastIssue = sorted[sorted.length - 1];
887
884
  const lastUsage = usages[usages.length - 1];
888
885
  const conflictingUsage = firstFails
889
886
  .filter(i => i.type === 'missing-field')
890
887
  .map(i => i.field);
891
- const fConflictingUsage = formatFieldUsages(conflictingUsage);
888
+ const fConflictingUsage = formatFieldUsages(joinedFieldUsage(joinPath, conflictingUsage));
892
889
  const dConflictingUsage = conflictingUsage.length > 0
893
890
  ? `there is no composite input source which defines all of ${fConflictingUsage}`
894
891
  : undefined;
@@ -912,12 +909,12 @@ function logCompositeError(error, logTo) {
912
909
  ? `${joinPlural} ${formatPaths(uniqueFailedJoins)} could not be resolved`
913
910
  : undefined;
914
911
  const dLastIssue = lastUsage
915
- ? `uses field ${formatFieldUsages([lastUsage])}, resulting in`
912
+ ? `uses field ${formatFieldUsages(joinedFieldUsage(joinPath, [lastUsage]))}, resulting in`
916
913
  : 'results in';
917
914
  const dIssues = dConflictingUsageAndMissingGroupBys
918
- ? commaAndList([dConflictingUsageAndMissingGroupBys, dFailedJoins].filter(utils_2.isNotUndefined))
919
- : commaAndList([dConflictingUsage, dMissingGroupBys, dFailedJoins].filter(utils_2.isNotUndefined));
920
- const message = `This operation ${dLastIssue} invalid usage of the composite source, as ${dIssues} (fields required in source: ${formatFieldUsages(error.data.usage)})`;
915
+ ? commaAndList([dConflictingUsageAndMissingGroupBys, dFailedJoins].filter(utils_1.isNotUndefined))
916
+ : commaAndList([dConflictingUsage, dMissingGroupBys, dFailedJoins].filter(utils_1.isNotUndefined));
917
+ const message = `This operation ${dLastIssue} invalid usage of the composite source, as ${dIssues} (fields required in source: ${formatFieldUsages(joinedFieldUsage(joinPath, error.data.usage))})`;
921
918
  logTo.logError('could-not-resolve-composite-source', message, {
922
919
  at: issueLocation(lastIssue),
923
920
  });
@@ -467,7 +467,7 @@ export interface JoinBase {
467
467
  join: JoinType;
468
468
  matrixOperation?: MatrixOperation;
469
469
  onExpression?: Expr;
470
- onFieldUsage?: FieldUsage[];
470
+ fieldUsage?: FieldUsage[];
471
471
  accessModifier?: NonDefaultAccessModifierLabel | undefined;
472
472
  }
473
473
  export type Joinable = CompositeSourceDef | TableSourceDef | SQLSourceDef | QuerySourceDef | RepeatedRecordDef | RecordDef | ArrayDef;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.297";
1
+ export declare const MALLOY_VERSION = "0.0.299";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.297';
5
+ exports.MALLOY_VERSION = '0.0.299';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.297",
3
+ "version": "0.0.299",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -41,9 +41,9 @@
41
41
  "generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
42
42
  },
43
43
  "dependencies": {
44
- "@malloydata/malloy-filter": "0.0.297",
45
- "@malloydata/malloy-interfaces": "0.0.297",
46
- "@malloydata/malloy-tag": "0.0.297",
44
+ "@malloydata/malloy-filter": "0.0.299",
45
+ "@malloydata/malloy-interfaces": "0.0.299",
46
+ "@malloydata/malloy-tag": "0.0.299",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jaro-winkler": "^0.2.8",