@malloydata/malloy 0.0.221-dev241209191943 → 0.0.221-dev241211195814

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.
@@ -23,6 +23,7 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.IndexFieldSpace = void 0;
26
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
26
27
  const malloy_types_1 = require("../../../model/malloy_types");
27
28
  const field_references_1 = require("../query-items/field-references");
28
29
  const space_field_1 = require("../types/space-field");
@@ -52,15 +53,20 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
52
53
  this.logError('refinement-of-index-segment', 'index query operations cannot be refined');
53
54
  return { type: 'index', indexFields: [] };
54
55
  }
56
+ let compositeFieldUsage = (0, composite_source_utils_1.emptyCompositeFieldUsage)();
57
+ let narrowedCompositeFieldResolution = (0, composite_source_utils_1.emptyNarrowedCompositeFieldResolution)();
55
58
  const indexFields = [];
59
+ const source = this.inputSpace().structDef();
56
60
  for (const [name, field] of this.entries()) {
57
61
  if (field instanceof space_field_1.SpaceField) {
58
- const wildPath = this.expandedWild[name];
59
- if (wildPath) {
60
- indexFields.push({ type: 'fieldref', path: wildPath });
61
- continue;
62
+ let nextCompositeFieldUsage = undefined;
63
+ let logTo = undefined;
64
+ const wild = this.expandedWild[name];
65
+ if (wild) {
66
+ indexFields.push({ type: 'fieldref', path: wild.path });
67
+ nextCompositeFieldUsage = wild.entry.typeDesc().compositeFieldUsage;
62
68
  }
63
- if (field instanceof reference_field_1.ReferenceField) {
69
+ else if (field instanceof reference_field_1.ReferenceField) {
64
70
  // attempt to cause a type check
65
71
  const fieldRef = field.fieldRef;
66
72
  const check = fieldRef.getField(this.exprSpace);
@@ -69,10 +75,18 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
69
75
  }
70
76
  else {
71
77
  indexFields.push(fieldRef.refToField);
78
+ nextCompositeFieldUsage =
79
+ check.found.typeDesc().compositeFieldUsage;
80
+ logTo = fieldRef;
72
81
  }
73
82
  }
83
+ const next = this.applyNextCompositeFieldUsage(source, compositeFieldUsage, narrowedCompositeFieldResolution, nextCompositeFieldUsage, logTo);
84
+ compositeFieldUsage = next.compositeFieldUsage;
85
+ narrowedCompositeFieldResolution =
86
+ next.narrowedCompositeFieldResolution;
74
87
  }
75
88
  }
89
+ this._compositeFieldUsage = compositeFieldUsage;
76
90
  return { type: 'index', indexFields };
77
91
  }
78
92
  addRefineFromFields(_refineThis) { }
@@ -115,7 +129,7 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
115
129
  name,
116
130
  ]);
117
131
  if (this.entry(indexName)) {
118
- const conflict = (_a = this.expandedWild[indexName]) === null || _a === void 0 ? void 0 : _a.join('.');
132
+ const conflict = (_a = this.expandedWild[indexName].path) === null || _a === void 0 ? void 0 : _a.join('.');
119
133
  wild.logError('name-conflict-in-wildcard-expansion', `Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
120
134
  }
121
135
  else {
@@ -125,7 +139,10 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
125
139
  (0, malloy_types_1.expressionIsScalar)(eTypeDesc.expressionType) &&
126
140
  (dialect === undefined || !dialect.ignoreInProject(name))) {
127
141
  expandEntries.push({ name: indexName, entry });
128
- this.expandedWild[indexName] = joinPath.concat(name);
142
+ this.expandedWild[indexName] = {
143
+ path: joinPath.concat(name),
144
+ entry,
145
+ };
129
146
  }
130
147
  }
131
148
  }
@@ -8,6 +8,7 @@ import { LookupResult } from '../types/lookup-result';
8
8
  import { QueryInputSpace } from './query-input-space';
9
9
  import { SpaceEntry } from '../types/space-entry';
10
10
  import { LogMessageOptions, MessageCode, MessageParameterType } from '../../parse-log';
11
+ import { NarrowedCompositeFieldResolution } from '../../../model/composite_source_utils';
11
12
  /**
12
13
  * The output space of a query operation. It is not named "QueryOutputSpace"
13
14
  * because this is the namespace of the Query which is a layer of an output and
@@ -20,7 +21,10 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
20
21
  readonly astEl: MalloyElement;
21
22
  protected exprSpace: QueryInputSpace;
22
23
  abstract readonly segmentType: 'reduce' | 'project' | 'index';
23
- expandedWild: Record<string, string[]>;
24
+ expandedWild: Record<string, {
25
+ path: string[];
26
+ entry: SpaceEntry;
27
+ }>;
24
28
  compositeFieldUsers: ({
25
29
  type: 'filter';
26
30
  filter: model.FilterCondition;
@@ -44,6 +48,10 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
44
48
  protected getCompositeFieldUsageIncludingJoinOns(compositeFieldUsage: model.CompositeFieldUsage): model.CompositeFieldUsage;
45
49
  addCompositeFieldUserFromFilter(filter: model.FilterCondition, logTo: MalloyElement): void;
46
50
  newEntry(name: string, logTo: MalloyElement, entry: SpaceEntry): void;
51
+ protected applyNextCompositeFieldUsage(source: model.SourceDef, compositeFieldUsage: model.CompositeFieldUsage, narrowedCompositeFieldResolution: NarrowedCompositeFieldResolution, nextCompositeFieldUsage: model.CompositeFieldUsage | undefined, logTo: MalloyElement | undefined): {
52
+ compositeFieldUsage: model.CompositeFieldUsage;
53
+ narrowedCompositeFieldResolution: NarrowedCompositeFieldResolution;
54
+ };
47
55
  }
48
56
  export declare abstract class QuerySpace extends QueryOperationSpace {
49
57
  addRefineFromFields(refineThis: model.PipeSegment): void;
@@ -77,7 +77,8 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
77
77
  this.astEl = astEl;
78
78
  this.expandedWild = {};
79
79
  this.compositeFieldUsers = [];
80
- // Composite field usage is not computed until `queryFieldDefs` is called; if anyone
80
+ // Composite field usage is not computed until `queryFieldDefs` is called
81
+ // (or `getPipeSegment` for index segments); if anyone
81
82
  // tries to access it before that, they'll get an error
82
83
  this._compositeFieldUsage = undefined;
83
84
  this.exprSpace = new query_input_space_1.QueryInputSpace(queryInputSpace.structDef(), this);
@@ -131,7 +132,7 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
131
132
  continue;
132
133
  }
133
134
  if (this.entry(name)) {
134
- const conflict = (_a = this.expandedWild[name]) === null || _a === void 0 ? void 0 : _a.join('.');
135
+ const conflict = (_a = this.expandedWild[name]) === null || _a === void 0 ? void 0 : _a.path.join('.');
135
136
  wild.logError('name-conflict-in-wildcard-expansion', `Cannot expand '${name}' in '${wild.refString}' because a field with that name already exists${conflict ? ` (conflicts with ${conflict})` : ''}`);
136
137
  }
137
138
  else {
@@ -140,7 +141,10 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
140
141
  model.expressionIsScalar(eType.expressionType) &&
141
142
  (dialect === undefined || !dialect.ignoreInProject(name))) {
142
143
  expandEntries.push({ name, entry });
143
- this.expandedWild[name] = joinPath.concat(name);
144
+ this.expandedWild[name] = {
145
+ path: joinPath.concat(name),
146
+ entry,
147
+ };
144
148
  }
145
149
  }
146
150
  }
@@ -163,7 +167,7 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
163
167
  var _a;
164
168
  const reference = joinPath.map(n => new field_space_1.FieldName(n));
165
169
  this.astEl.has({ reference });
166
- const lookup = this.queryInputSpace.lookup(reference);
170
+ const lookup = this.exprSpace.lookup(reference);
167
171
  // Should always be found...
168
172
  if (lookup.found && lookup.found instanceof struct_space_field_base_1.StructSpaceFieldBase) {
169
173
  return ((_a = lookup.found.fieldDef().onCompositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)());
@@ -189,6 +193,26 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
189
193
  }
190
194
  super.newEntry(name, logTo, entry);
191
195
  }
196
+ applyNextCompositeFieldUsage(source, compositeFieldUsage, narrowedCompositeFieldResolution, nextCompositeFieldUsage, logTo) {
197
+ if (nextCompositeFieldUsage) {
198
+ const newCompositeFieldUsage = this.getCompositeFieldUsageIncludingJoinOns((0, composite_source_utils_1.compositeFieldUsageDifference)(nextCompositeFieldUsage, compositeFieldUsage));
199
+ compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(compositeFieldUsage, newCompositeFieldUsage);
200
+ if (!(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(newCompositeFieldUsage)) {
201
+ const result = (0, composite_source_utils_1.narrowCompositeFieldResolution)(source, compositeFieldUsage, narrowedCompositeFieldResolution);
202
+ if (result.error) {
203
+ (logTo !== null && logTo !== void 0 ? logTo : this).logError('invalid-composite-field-usage', {
204
+ newUsage: newCompositeFieldUsage,
205
+ allUsage: compositeFieldUsage,
206
+ });
207
+ }
208
+ else {
209
+ narrowedCompositeFieldResolution =
210
+ result.narrowedCompositeFieldResolution;
211
+ }
212
+ }
213
+ }
214
+ return { compositeFieldUsage, narrowedCompositeFieldResolution };
215
+ }
192
216
  }
193
217
  exports.QueryOperationSpace = QueryOperationSpace;
194
218
  // Project and Reduce or "QuerySegments" are built from a QuerySpace
@@ -252,57 +276,38 @@ class QuerySpace extends QueryOperationSpace {
252
276
  const { name, field } = user;
253
277
  const wildPath = this.expandedWild[name];
254
278
  if (wildPath) {
255
- fields.push({ type: 'fieldref', path: wildPath });
256
- continue;
279
+ fields.push({ type: 'fieldref', path: wildPath.path });
280
+ nextCompositeFieldUsage =
281
+ wildPath.entry.typeDesc().compositeFieldUsage;
257
282
  }
258
- // TODO handle wildcards for composite sources
259
- const fieldQueryDef = field.getQueryFieldDef(this.exprSpace);
260
- if (fieldQueryDef) {
261
- const typeDesc = field.typeDesc();
262
- nextCompositeFieldUsage = typeDesc.compositeFieldUsage;
263
- // Filter out fields whose type is 'error', which means that a totally bad field
264
- // isn't sent to the compiler, where it will wig out.
265
- // TODO Figure out how to make errors generated by `canContain` go in the right place,
266
- // maybe by adding a logable element to SpaceFields.
267
- if (typeDesc &&
268
- typeDesc.type !== 'error' &&
269
- this.canContain(typeDesc) &&
270
- !isEmptyNest(fieldQueryDef)) {
271
- fields.push(fieldQueryDef);
272
- }
273
- }
274
- // TODO I removed the error here because during calculation of the refinement space,
275
- // (see creation of a QuerySpace) we add references to all the fields from
276
- // the refinement, but they don't have definitions. So in the case where we
277
- // don't have a field def, we "know" that that field is already in the query,
278
- // and we don't need to worry about actually adding it. Previously, this was also true for
279
- // project statements, where we added "*" as a field and also all the individual
280
- // fields, but the individual fields didn't have field defs.
281
- }
282
- if (nextCompositeFieldUsage) {
283
- const newCompositeFieldUsage = this.getCompositeFieldUsageIncludingJoinOns((0, composite_source_utils_1.compositeFieldUsageDifference)(nextCompositeFieldUsage, compositeFieldUsage));
284
- compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(compositeFieldUsage, newCompositeFieldUsage);
285
- if (!(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(newCompositeFieldUsage)) {
286
- const result = (0, composite_source_utils_1.narrowCompositeFieldResolution)(source, compositeFieldUsage, narrowedCompositeFieldResolution);
287
- if (result.error) {
288
- if (user.logTo) {
289
- user.logTo.logError('invalid-composite-field-usage', {
290
- newUsage: newCompositeFieldUsage,
291
- allUsage: compositeFieldUsage,
292
- });
293
- }
294
- else {
295
- // This should not happen; logTo should only be not set for a field from a refinement,
296
- // which should never fail the composite resolution
297
- throw new Error('Unexpected invalid composite field resolution');
283
+ else {
284
+ const fieldQueryDef = field.getQueryFieldDef(this.exprSpace);
285
+ if (fieldQueryDef) {
286
+ const typeDesc = field.typeDesc();
287
+ nextCompositeFieldUsage = typeDesc.compositeFieldUsage;
288
+ // Filter out fields whose type is 'error', which means that a totally bad field
289
+ // isn't sent to the compiler, where it will wig out.
290
+ // TODO Figure out how to make errors generated by `canContain` go in the right place,
291
+ // maybe by adding a logable element to SpaceFields.
292
+ if (typeDesc &&
293
+ typeDesc.type !== 'error' &&
294
+ this.canContain(typeDesc) &&
295
+ !isEmptyNest(fieldQueryDef)) {
296
+ fields.push(fieldQueryDef);
298
297
  }
299
298
  }
300
- else {
301
- narrowedCompositeFieldResolution =
302
- result.narrowedCompositeFieldResolution;
303
- }
299
+ // TODO I removed the error here because during calculation of the refinement space,
300
+ // (see creation of a QuerySpace) we add references to all the fields from
301
+ // the refinement, but they don't have definitions. So in the case where we
302
+ // don't have a field def, we "know" that that field is already in the query,
303
+ // and we don't need to worry about actually adding it. Previously, this was also true for
304
+ // project statements, where we added "*" as a field and also all the individual
305
+ // fields, but the individual fields didn't have field defs.
304
306
  }
305
307
  }
308
+ const next = this.applyNextCompositeFieldUsage(source, compositeFieldUsage, narrowedCompositeFieldResolution, nextCompositeFieldUsage, user.logTo);
309
+ compositeFieldUsage = next.compositeFieldUsage;
310
+ narrowedCompositeFieldResolution = next.narrowedCompositeFieldResolution;
306
311
  }
307
312
  this._compositeFieldUsage = compositeFieldUsage;
308
313
  return fields;
@@ -1,4 +1,4 @@
1
- import { FilterCondition, PipeSegment, Sampling } from '../../../model/malloy_types';
1
+ import { CompositeFieldUsage, FilterCondition, PipeSegment, Sampling } from '../../../model/malloy_types';
2
2
  import { FieldName, SourceFieldSpace } from '../types/field-space';
3
3
  import { Limit } from '../query-properties/limit';
4
4
  import { IndexFieldSpace } from '../field-space/index-field-space';
@@ -18,5 +18,6 @@ export declare class IndexBuilder implements QueryBuilder {
18
18
  readonly type = "index";
19
19
  constructor(inputFS: SourceFieldSpace, refineThis: PipeSegment | undefined, isNestIn: QueryOperationSpace | undefined, astEl: MalloyElement);
20
20
  execute(qp: QueryProperty): void;
21
+ get compositeFieldUsage(): CompositeFieldUsage;
21
22
  finalize(from: PipeSegment | undefined): PipeSegment;
22
23
  }
@@ -30,6 +30,7 @@ const indexing_1 = require("../query-properties/indexing");
30
30
  const limit_1 = require("../query-properties/limit");
31
31
  const sampling_1 = require("../query-properties/sampling");
32
32
  const index_field_space_1 = require("../field-space/index-field-space");
33
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
33
34
  class IndexBuilder {
34
35
  constructor(inputFS, refineThis, isNestIn, astEl) {
35
36
  this.filters = [];
@@ -64,7 +65,11 @@ class IndexBuilder {
64
65
  qp.logError('illegal-operation-for-index', 'Not legal in an index query operation');
65
66
  }
66
67
  }
68
+ get compositeFieldUsage() {
69
+ return this.resultFS.compositeFieldUsage;
70
+ }
67
71
  finalize(from) {
72
+ var _a;
68
73
  if (from && !(0, malloy_types_1.isIndexSegment)(from) && !(0, malloy_types_1.isPartialSegment)(from)) {
69
74
  this.resultFS.logError('refinement-of-index-segment', `Can't refine index with ${from.type}`);
70
75
  return error_factory_1.ErrorFactory.indexSegment;
@@ -95,6 +100,10 @@ class IndexBuilder {
95
100
  if (this.alwaysJoins.length > 0) {
96
101
  indexSegment.alwaysJoins = [...this.alwaysJoins];
97
102
  }
103
+ const fromCompositeFieldUsage = from && from.type === 'index'
104
+ ? (_a = from.compositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)()
105
+ : (0, composite_source_utils_1.emptyCompositeFieldUsage)();
106
+ indexSegment.compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(fromCompositeFieldUsage, this.compositeFieldUsage);
98
107
  return indexSegment;
99
108
  }
100
109
  }
@@ -31,9 +31,10 @@ class QueryBase extends malloy_element_1.MalloyElement {
31
31
  query() {
32
32
  var _a;
33
33
  const { inputStruct, query } = this.queryComp(true);
34
- // TODO add an error if a raw/index query is done against a composite source
34
+ // TODO add an error if a raw query is done against a composite source
35
35
  let compositeResolvedSourceDef = undefined;
36
- if (query.pipeline[0] && (0, malloy_types_1.isQuerySegment)(query.pipeline[0])) {
36
+ if (query.pipeline[0] &&
37
+ ((0, malloy_types_1.isQuerySegment)(query.pipeline[0]) || (0, malloy_types_1.isIndexSegment)(query.pipeline[0]))) {
37
38
  const compositeFieldUsage = (_a = query.pipeline[0].compositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)();
38
39
  if (!(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(compositeFieldUsage) ||
39
40
  inputStruct.type === 'composite') {
@@ -137,10 +137,15 @@ describe('composite sources', () => {
137
137
  ##! experimental.composite_sources
138
138
  run: compose(a, a extend { dimension: one is 1 }) -> { group_by: one }
139
139
  `).toTranslate());
140
- test.skip('index on composite fails', () => expect(`
140
+ test('index on composite translates', () => expect(`
141
141
  ##! experimental.composite_sources
142
- run: compose(a extend { dimension: two is 2 }, a extend { dimension: one is 1 }) -> { index: * }
143
- `).toLog((0, test_translator_1.errorMessage)('Cannot index on a composite source')));
142
+ source: x is compose(
143
+ a extend { except: ai },
144
+ a
145
+ )
146
+ run: x -> { index: ai }
147
+ run: x -> { index: * }
148
+ `).toTranslate());
144
149
  test('raw run of composite source fails', () => expect(`
145
150
  ##! experimental.composite_sources
146
151
  run: compose(a extend { dimension: two is 2 }, a extend { dimension: one is 1 })
@@ -30,7 +30,7 @@ type SingleNarrowedCompositeFieldResolution = {
30
30
  source: SourceDef;
31
31
  nested?: SingleNarrowedCompositeFieldResolution | undefined;
32
32
  }[];
33
- interface NarrowedCompositeFieldResolution {
33
+ export interface NarrowedCompositeFieldResolution {
34
34
  source: SingleNarrowedCompositeFieldResolution | undefined;
35
35
  joined: {
36
36
  [name: string]: NarrowedCompositeFieldResolution;
@@ -10,11 +10,11 @@ exports.compositeFieldUsageJoinPaths = exports.joinedCompositeFieldUsage = expor
10
10
  const utils_1 = require("../lang/utils");
11
11
  const malloy_types_1 = require("./malloy_types");
12
12
  function _resolveCompositeSources(path, source, compositeFieldUsage, narrowedCompositeFieldResolution = undefined) {
13
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
13
+ var _a, _b, _c, _d, _e, _f, _g;
14
14
  let base = { ...source };
15
15
  let narrowedSources = undefined;
16
16
  const nonCompositeFields = getNonCompositeFields(source);
17
- if (compositeFieldUsage.fields.length > 0) {
17
+ if (compositeFieldUsage.fields.length > 0 || source.type === 'composite') {
18
18
  if (source.type === 'composite') {
19
19
  let found = false;
20
20
  // The narrowed source list is either the one given when this function was called,
@@ -86,18 +86,10 @@ function _resolveCompositeSources(path, source, compositeFieldUsage, narrowedCom
86
86
  return { error: { code: 'not_a_composite_source', data: { path } } };
87
87
  }
88
88
  }
89
- else if (source.type === 'composite') {
90
- const first = source.sources[0];
91
- base = {
92
- ...first,
93
- fields: [...nonCompositeFields, ...base.fields],
94
- filterList: [...((_e = source.filterList) !== null && _e !== void 0 ? _e : []), ...((_f = first.filterList) !== null && _f !== void 0 ? _f : [])],
95
- };
96
- }
97
89
  const fieldsByName = {};
98
- const narrowedJoinedSources = (_g = narrowedCompositeFieldResolution === null || narrowedCompositeFieldResolution === void 0 ? void 0 : narrowedCompositeFieldResolution.joined) !== null && _g !== void 0 ? _g : {};
90
+ const narrowedJoinedSources = (_e = narrowedCompositeFieldResolution === null || narrowedCompositeFieldResolution === void 0 ? void 0 : narrowedCompositeFieldResolution.joined) !== null && _e !== void 0 ? _e : {};
99
91
  for (const field of base.fields) {
100
- fieldsByName[(_h = field.as) !== null && _h !== void 0 ? _h : field.name] = field;
92
+ fieldsByName[(_f = field.as) !== null && _f !== void 0 ? _f : field.name] = field;
101
93
  }
102
94
  for (const [joinName, joinedUsage] of Object.entries(compositeFieldUsage.joinedUsage)) {
103
95
  const join = fieldsByName[joinName];
@@ -127,7 +119,7 @@ function _resolveCompositeSources(path, source, compositeFieldUsage, narrowedCom
127
119
  fieldsByName[joinName] = {
128
120
  ...resolved.success,
129
121
  join: join.join,
130
- as: (_j = join.as) !== null && _j !== void 0 ? _j : join.name,
122
+ as: (_g = join.as) !== null && _g !== void 0 ? _g : join.name,
131
123
  onExpression: join.onExpression,
132
124
  };
133
125
  narrowedJoinedSources[joinName] = resolved.narrowedCompositeFieldResolution;
@@ -233,14 +225,12 @@ function arrayDifference(a, b) {
233
225
  function compositeFieldUsageDifference(a, b) {
234
226
  return {
235
227
  fields: arrayDifference(a.fields, b.fields),
236
- joinedUsage: Object.fromEntries(Object.entries(a.joinedUsage)
237
- .map(([joinName, joinedUsage]) => [
228
+ joinedUsage: Object.fromEntries(Object.entries(a.joinedUsage).map(([joinName, joinedUsage]) => [
238
229
  joinName,
239
230
  joinName in b.joinedUsage
240
231
  ? compositeFieldUsageDifference(joinedUsage, b.joinedUsage[joinName])
241
232
  : joinedUsage,
242
- ])
243
- .filter(([_, joinedUsage]) => countCompositeFieldUsage(joinedUsage) > 0)),
233
+ ])),
244
234
  };
245
235
  }
246
236
  exports.compositeFieldUsageDifference = compositeFieldUsageDifference;
@@ -546,6 +546,7 @@ export interface IndexSegment extends Filtered {
546
546
  weightMeasure?: string;
547
547
  sample?: Sampling;
548
548
  alwaysJoins?: string[];
549
+ compositeFieldUsage?: CompositeFieldUsage;
549
550
  }
550
551
  export declare function isIndexSegment(pe: PipeSegment): pe is IndexSegment;
551
552
  export interface CompositeFieldUsage {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.221-dev241209191943",
3
+ "version": "0.0.221-dev241211195814",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",