@malloydata/malloy 0.0.215 → 0.0.216-dev241118202522

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 (72) hide show
  1. package/dist/dialect/functions/util.d.ts +8 -8
  2. package/dist/dialect/functions/util.js +15 -7
  3. package/dist/lang/ast/ast-utils.js +2 -0
  4. package/dist/lang/ast/expressions/expr-aggregate-function.js +1 -0
  5. package/dist/lang/ast/expressions/expr-compare.js +7 -14
  6. package/dist/lang/ast/expressions/expr-count-distinct.js +1 -0
  7. package/dist/lang/ast/expressions/expr-count.js +3 -0
  8. package/dist/lang/ast/expressions/expr-func.js +3 -0
  9. package/dist/lang/ast/expressions/expr-id-reference.js +10 -1
  10. package/dist/lang/ast/expressions/expr-now.js +2 -0
  11. package/dist/lang/ast/expressions/expr-ungroup.js +1 -0
  12. package/dist/lang/ast/field-space/dynamic-space.d.ts +1 -3
  13. package/dist/lang/ast/field-space/dynamic-space.js +11 -15
  14. package/dist/lang/ast/field-space/query-spaces.d.ts +19 -0
  15. package/dist/lang/ast/field-space/query-spaces.js +104 -12
  16. package/dist/lang/ast/field-space/reference-field.js +7 -1
  17. package/dist/lang/ast/field-space/refined-space.d.ts +1 -0
  18. package/dist/lang/ast/field-space/refined-space.js +9 -6
  19. package/dist/lang/ast/field-space/struct-space-field-base.js +4 -0
  20. package/dist/lang/ast/index.d.ts +1 -0
  21. package/dist/lang/ast/index.js +1 -0
  22. package/dist/lang/ast/query-builders/index-builder.js +1 -1
  23. package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -1
  24. package/dist/lang/ast/query-builders/reduce-builder.js +9 -5
  25. package/dist/lang/ast/query-elements/query-base.js +16 -3
  26. package/dist/lang/ast/query-items/field-declaration.js +3 -0
  27. package/dist/lang/ast/query-properties/filters.d.ts +3 -0
  28. package/dist/lang/ast/query-properties/filters.js +42 -26
  29. package/dist/lang/ast/query-properties/nest.d.ts +1 -0
  30. package/dist/lang/ast/query-properties/nest.js +5 -1
  31. package/dist/lang/ast/source-elements/composite-source.d.ts +16 -0
  32. package/dist/lang/ast/source-elements/composite-source.js +75 -0
  33. package/dist/lang/ast/source-elements/source.d.ts +2 -2
  34. package/dist/lang/ast/source-properties/join.js +2 -0
  35. package/dist/lang/ast/source-query-elements/sq-compose.d.ts +13 -0
  36. package/dist/lang/ast/source-query-elements/sq-compose.js +48 -0
  37. package/dist/lang/ast/typedesc-utils.js +7 -1
  38. package/dist/lang/ast/types/expr-value.js +4 -0
  39. package/dist/lang/ast/types/expression-def.js +4 -5
  40. package/dist/lang/ast/types/query-builder.d.ts +2 -1
  41. package/dist/lang/ast/types/space-field.js +14 -1
  42. package/dist/lang/ast/types/space-param.js +3 -0
  43. package/dist/lang/ast/view-elements/reference-view.js +1 -0
  44. package/dist/lang/ast/view-elements/refine-utils.js +2 -0
  45. package/dist/lang/lib/Malloy/MalloyLexer.d.ts +113 -112
  46. package/dist/lang/lib/Malloy/MalloyLexer.js +1149 -1143
  47. package/dist/lang/lib/Malloy/MalloyParser.d.ts +126 -112
  48. package/dist/lang/lib/Malloy/MalloyParser.js +1380 -1282
  49. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +13 -0
  50. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +8 -0
  51. package/dist/lang/malloy-to-ast.d.ts +1 -0
  52. package/dist/lang/malloy-to-ast.js +5 -0
  53. package/dist/lang/parse-log.d.ts +10 -1
  54. package/dist/lang/parse-log.js +7 -0
  55. package/dist/lang/test/composite-field-usage.spec.d.ts +1 -0
  56. package/dist/lang/test/composite-field-usage.spec.js +155 -0
  57. package/dist/lang/test/parse-expects.d.ts +2 -1
  58. package/dist/lang/test/parse-expects.js +36 -0
  59. package/dist/lang/test/source.spec.js +9 -0
  60. package/dist/lang/test/test-translator.d.ts +3 -1
  61. package/dist/lang/test/test-translator.js +15 -4
  62. package/dist/lang/utils.d.ts +1 -0
  63. package/dist/lang/utils.js +5 -1
  64. package/dist/model/composite_source_utils.d.ts +65 -0
  65. package/dist/model/composite_source_utils.js +279 -0
  66. package/dist/model/malloy_query.d.ts +3 -3
  67. package/dist/model/malloy_query.js +13 -6
  68. package/dist/model/malloy_types.d.ts +19 -2
  69. package/dist/model/malloy_types.js +15 -3
  70. package/dist/version.d.ts +1 -1
  71. package/dist/version.js +1 -1
  72. package/package.json +1 -1
@@ -46,6 +46,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.StructSpaceFieldBase = void 0;
49
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
49
50
  const malloy_types_1 = require("../../../model/malloy_types");
50
51
  const TDU = __importStar(require("../typedesc-utils"));
51
52
  const space_field_1 = require("../types/space-field");
@@ -65,17 +66,20 @@ class StructSpaceFieldBase extends space_field_1.SpaceField {
65
66
  };
66
67
  }
67
68
  typeDesc() {
69
+ var _a, _b;
68
70
  if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
69
71
  return {
70
72
  type: this.structDef.type,
71
73
  evalSpace: 'input',
72
74
  expressionType: 'scalar',
75
+ compositeFieldUsage: (_a = this.structDef.onCompositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
73
76
  };
74
77
  }
75
78
  return {
76
79
  ...TDU.atomicDef(this.structDef),
77
80
  evalSpace: 'input',
78
81
  expressionType: 'scalar',
82
+ compositeFieldUsage: (_b = this.structDef.onCompositeFieldUsage) !== null && _b !== void 0 ? _b : (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
79
83
  };
80
84
  }
81
85
  }
@@ -9,6 +9,7 @@ export * from './source-query-elements/sq-refine';
9
9
  export * from './source-query-elements/sq-source';
10
10
  export * from './source-query-elements/sq-reference';
11
11
  export * from './source-query-elements/sq-extend';
12
+ export * from './source-query-elements/sq-compose';
12
13
  export * from './source-properties/field-list-edit';
13
14
  export * from './source-properties/primary-key';
14
15
  export * from './source-properties/renames';
@@ -47,6 +47,7 @@ __exportStar(require("./source-query-elements/sq-refine"), exports);
47
47
  __exportStar(require("./source-query-elements/sq-source"), exports);
48
48
  __exportStar(require("./source-query-elements/sq-reference"), exports);
49
49
  __exportStar(require("./source-query-elements/sq-extend"), exports);
50
+ __exportStar(require("./source-query-elements/sq-compose"), exports);
50
51
  __exportStar(require("./source-properties/field-list-edit"), exports);
51
52
  __exportStar(require("./source-properties/primary-key"), exports);
52
53
  __exportStar(require("./source-properties/renames"), exports);
@@ -40,7 +40,7 @@ class IndexBuilder {
40
40
  }
41
41
  execute(qp) {
42
42
  if (qp instanceof filters_1.Filter) {
43
- this.filters.push(...qp.getFilterList(this.inputFS));
43
+ qp.queryExecute(this);
44
44
  }
45
45
  else if (qp instanceof limit_1.Limit) {
46
46
  if (this.limit) {
@@ -1,4 +1,4 @@
1
- import { FilterCondition, PipeSegment, QuerySegment } from '../../../model/malloy_types';
1
+ import { CompositeFieldUsage, FilterCondition, PipeSegment, QuerySegment } from '../../../model/malloy_types';
2
2
  import { SourceFieldSpace } from '../types/field-space';
3
3
  import { Ordering } from '../query-properties/ordering';
4
4
  import { Top } from '../query-properties/top';
@@ -17,6 +17,7 @@ export declare abstract class QuerySegmentBuilder implements QueryBuilder {
17
17
  filters: FilterCondition[];
18
18
  execute(qp: QueryProperty): void;
19
19
  abstract finalize(fromSeg: PipeSegment | undefined): PipeSegment;
20
+ get compositeFieldUsage(): CompositeFieldUsage;
20
21
  refineFrom(from: PipeSegment | undefined, to: QuerySegment): void;
21
22
  }
22
23
  export declare class ReduceBuilder extends QuerySegmentBuilder implements QueryBuilder {
@@ -25,12 +25,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.ReduceBuilder = exports.QuerySegmentBuilder = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
27
  const error_factory_1 = require("../error-factory");
28
- const filters_1 = require("../query-properties/filters");
29
28
  const limit_1 = require("../query-properties/limit");
30
29
  const ordering_1 = require("../query-properties/ordering");
31
30
  const top_1 = require("../query-properties/top");
32
31
  const query_spaces_1 = require("../field-space/query-spaces");
33
32
  const definition_list_1 = require("../types/definition-list");
33
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
34
34
  class QuerySegmentBuilder {
35
35
  constructor() {
36
36
  this.alwaysJoins = [];
@@ -44,10 +44,6 @@ class QuerySegmentBuilder {
44
44
  if (qp instanceof definition_list_1.DefinitionList) {
45
45
  this.resultFS.pushFields(...qp.list);
46
46
  }
47
- else if (qp instanceof filters_1.Filter) {
48
- const filterFS = qp.havingClause ? this.resultFS : this.inputFS;
49
- this.filters.push(...qp.getFilterList(filterFS));
50
- }
51
47
  else if (qp instanceof top_1.Top) {
52
48
  if (this.limit) {
53
49
  qp.logError('limit-already-specified', 'Query operation already limited');
@@ -81,7 +77,11 @@ class QuerySegmentBuilder {
81
77
  }
82
78
  }
83
79
  }
80
+ get compositeFieldUsage() {
81
+ return this.resultFS.compositeFieldUsage;
82
+ }
84
83
  refineFrom(from, to) {
84
+ var _a;
85
85
  if (from && from.type !== 'index' && from.type !== 'raw') {
86
86
  if (!this.order) {
87
87
  if (from.orderBy) {
@@ -117,6 +117,10 @@ class QuerySegmentBuilder {
117
117
  if (this.alwaysJoins.length > 0) {
118
118
  to.alwaysJoins = [...this.alwaysJoins];
119
119
  }
120
+ const fromCompositeFieldUsage = from && (0, malloy_types_1.isQuerySegment)(from)
121
+ ? (_a = from.compositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)()
122
+ : (0, composite_source_utils_1.emptyCompositeFieldUsage)();
123
+ to.compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(fromCompositeFieldUsage, this.compositeFieldUsage);
120
124
  }
121
125
  }
122
126
  exports.QuerySegmentBuilder = QuerySegmentBuilder;
@@ -23,14 +23,27 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.QueryBase = void 0;
26
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
27
+ const malloy_types_1 = require("../../../model/malloy_types");
26
28
  const query_utils_1 = require("../query-utils");
27
29
  const malloy_element_1 = require("../types/malloy-element");
28
30
  class QueryBase extends malloy_element_1.MalloyElement {
29
31
  query() {
30
- const q = this.queryComp(true).query;
32
+ const { inputStruct, query } = this.queryComp(true);
33
+ // TODO add an error if a raw/index query is done against a composite source
34
+ let compositeResolvedSourceDef = undefined;
35
+ if (query.pipeline[0] && (0, malloy_types_1.isQuerySegment)(query.pipeline[0])) {
36
+ const compositeFieldUsage = query.pipeline[0].compositeFieldUsage;
37
+ if (compositeFieldUsage !== undefined &&
38
+ !(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(compositeFieldUsage)) {
39
+ const resolved = (0, composite_source_utils_1.resolveCompositeSources)(inputStruct, compositeFieldUsage);
40
+ compositeResolvedSourceDef = resolved.sourceDef;
41
+ }
42
+ }
31
43
  return {
32
- ...q,
33
- pipeline: (0, query_utils_1.detectAndRemovePartialStages)(q.pipeline, this),
44
+ ...query,
45
+ compositeResolvedSourceDef,
46
+ pipeline: (0, query_utils_1.detectAndRemovePartialStages)(query.pipeline, this),
34
47
  };
35
48
  }
36
49
  }
@@ -112,6 +112,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
112
112
  type: retType,
113
113
  location: this.location,
114
114
  e: exprValue.value,
115
+ compositeFieldUsage: exprValue.compositeFieldUsage,
115
116
  };
116
117
  if ((0, granular_result_1.isGranularResult)(exprValue)) {
117
118
  timeRet.timeframe = exprValue.timeframe;
@@ -129,6 +130,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
129
130
  name: exprName,
130
131
  location: this.location,
131
132
  e: exprValue.value,
133
+ compositeFieldUsage: exprValue.compositeFieldUsage,
132
134
  };
133
135
  break;
134
136
  }
@@ -141,6 +143,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
141
143
  join: 'one',
142
144
  fields,
143
145
  e: exprValue.value,
146
+ compositeFieldUsage: exprValue.compositeFieldUsage,
144
147
  dialect: exprFS.dialectName(),
145
148
  };
146
149
  break;
@@ -2,6 +2,7 @@ import { FilterCondition } from '../../../model/malloy_types';
2
2
  import { ExpressionDef } from '../types/expression-def';
3
3
  import { FieldSpace } from '../types/field-space';
4
4
  import { ListOf, MalloyElement } from '../types/malloy-element';
5
+ import { QueryBuilder } from '../types/query-builder';
5
6
  import { LegalRefinementStage, QueryPropertyInterface } from '../types/query-property-interface';
6
7
  export declare class FilterElement extends MalloyElement {
7
8
  readonly expr: ExpressionDef;
@@ -16,5 +17,7 @@ export declare class Filter extends ListOf<FilterElement> implements QueryProper
16
17
  forceQueryClass: undefined;
17
18
  queryRefinementStage: LegalRefinementStage;
18
19
  set having(isHaving: boolean);
20
+ protected checkedFilterCondition(fs: FieldSpace, filter: FilterElement): FilterCondition | undefined;
19
21
  getFilterList(fs: FieldSpace): FilterCondition[];
22
+ queryExecute(executeFor: QueryBuilder): void;
20
23
  }
@@ -24,6 +24,7 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.Filter = exports.FilterElement = void 0;
26
26
  const malloy_types_1 = require("../../../model/malloy_types");
27
+ const utils_1 = require("../../utils");
27
28
  const malloy_element_1 = require("../types/malloy-element");
28
29
  const query_property_interface_1 = require("../types/query-property-interface");
29
30
  class FilterElement extends malloy_element_1.MalloyElement {
@@ -42,6 +43,7 @@ class FilterElement extends malloy_element_1.MalloyElement {
42
43
  code: this.exprSrc,
43
44
  e: { node: 'false' },
44
45
  expressionType: 'scalar',
46
+ compositeFieldUsage: exprVal.compositeFieldUsage,
45
47
  };
46
48
  }
47
49
  const exprCond = {
@@ -49,6 +51,7 @@ class FilterElement extends malloy_element_1.MalloyElement {
49
51
  code: this.exprSrc,
50
52
  e: exprVal.value,
51
53
  expressionType: exprVal.expressionType,
54
+ compositeFieldUsage: exprVal.compositeFieldUsage,
52
55
  };
53
56
  return exprCond;
54
57
  }
@@ -68,36 +71,49 @@ class Filter extends malloy_element_1.ListOf {
68
71
  ? query_property_interface_1.LegalRefinementStage.Tail
69
72
  : query_property_interface_1.LegalRefinementStage.Head;
70
73
  }
71
- getFilterList(fs) {
72
- const checked = [];
73
- for (const oneElement of this.list) {
74
- const fExpr = oneElement.filterCondition(fs);
75
- // mtoy todo is having we never set then queryRefinementStage might be wrong
76
- // ... calculations and aggregations must go last
77
- // Aggregates are ALSO checked at SQL generation time, but checking
78
- // here allows better reflection of errors back to user.
79
- if (this.havingClause !== undefined) {
80
- const isAggregate = (0, malloy_types_1.expressionIsAggregate)(fExpr.expressionType);
81
- const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(fExpr.expressionType);
82
- if (this.havingClause) {
83
- if (isAnalytic) {
84
- oneElement.logError('analytic-in-having', 'Analytic expressions are not allowed in `having:`');
85
- continue;
86
- }
74
+ checkedFilterCondition(fs, filter) {
75
+ const fExpr = filter.filterCondition(fs);
76
+ // mtoy todo is having we never set then queryRefinementStage might be wrong
77
+ // ... calculations and aggregations must go last
78
+ // Aggregates are ALSO checked at SQL generation time, but checking
79
+ // here allows better reflection of errors back to user.
80
+ if (this.havingClause !== undefined) {
81
+ const isAggregate = (0, malloy_types_1.expressionIsAggregate)(fExpr.expressionType);
82
+ const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(fExpr.expressionType);
83
+ if (this.havingClause) {
84
+ if (isAnalytic) {
85
+ filter.logError('analytic-in-having', 'Analytic expressions are not allowed in `having:`');
86
+ return;
87
+ }
88
+ }
89
+ else {
90
+ if (isAnalytic) {
91
+ filter.logError('analytic-in-where', 'Analytic expressions are not allowed in `where:`');
92
+ return;
87
93
  }
88
- else {
89
- if (isAnalytic) {
90
- oneElement.logError('analytic-in-where', 'Analytic expressions are not allowed in `where:`');
91
- continue;
92
- }
93
- else if (isAggregate) {
94
- oneElement.logError('aggregate-in-where', 'Aggregate expressions are not allowed in `where:`; use `having:`');
95
- }
94
+ else if (isAggregate) {
95
+ filter.logError('aggregate-in-where', 'Aggregate expressions are not allowed in `where:`; use `having:`');
96
96
  }
97
97
  }
98
- checked.push(fExpr);
99
98
  }
100
- return checked;
99
+ return fExpr;
100
+ }
101
+ getFilterList(fs) {
102
+ return this.list
103
+ .map(filter => this.checkedFilterCondition(fs, filter))
104
+ .filter(utils_1.isNotUndefined);
105
+ }
106
+ queryExecute(executeFor) {
107
+ const filterFS = this.havingClause
108
+ ? executeFor.resultFS
109
+ : executeFor.inputFS;
110
+ for (const filter of this.list) {
111
+ const fExpr = this.checkedFilterCondition(filterFS, filter);
112
+ if (fExpr !== undefined) {
113
+ executeFor.filters.push(fExpr);
114
+ executeFor.resultFS.addCompositeFieldUserFromFilter(fExpr, filter);
115
+ }
116
+ }
101
117
  }
102
118
  }
103
119
  exports.Filter = Filter;
@@ -7,6 +7,7 @@ export declare class NestFieldDeclaration extends ViewFieldDeclaration implement
7
7
  elementType: string;
8
8
  queryRefinementStage: LegalRefinementStage;
9
9
  forceQueryClass: QueryClass;
10
+ turtleDef: model.TurtleDef | undefined;
10
11
  queryExecute(executeFor: QueryBuilder): void;
11
12
  getFieldDef(fs: FieldSpace): model.TurtleDef;
12
13
  }
@@ -32,21 +32,25 @@ class NestFieldDeclaration extends view_field_declaration_1.ViewFieldDeclaration
32
32
  this.elementType = 'nest-field-declaration';
33
33
  this.queryRefinementStage = query_property_interface_1.LegalRefinementStage.Single;
34
34
  this.forceQueryClass = query_property_interface_1.QueryClass.Grouping;
35
+ this.turtleDef = undefined;
35
36
  }
36
37
  queryExecute(executeFor) {
37
38
  executeFor.resultFS.pushFields(this);
38
39
  }
39
40
  getFieldDef(fs) {
41
+ if (this.turtleDef)
42
+ return this.turtleDef;
40
43
  if (fs.isQueryFieldSpace()) {
41
44
  const { pipeline, annotation } = this.view.pipelineComp(fs, fs.outputSpace());
42
45
  const checkedPipeline = (0, query_utils_1.detectAndRemovePartialStages)(pipeline, this);
43
- return {
46
+ this.turtleDef = {
44
47
  type: 'turtle',
45
48
  name: this.name,
46
49
  pipeline: checkedPipeline,
47
50
  annotation: { ...this.note, inherits: annotation },
48
51
  location: this.location,
49
52
  };
53
+ return this.turtleDef;
50
54
  }
51
55
  throw this.internalError('Unexpected namespace for nest');
52
56
  }
@@ -0,0 +1,16 @@
1
+ import { Annotation, SourceDef } from '../../../model/malloy_types';
2
+ import { HasParameter } from '../parameters/has-parameter';
3
+ import { Source } from './source';
4
+ import { ParameterSpace } from '../field-space/parameter-space';
5
+ /**
6
+ * A Source that is a virtual union of the fields of other sources, choosing
7
+ * the first source that has all the fields at query time.
8
+ */
9
+ export declare class CompositeSource extends Source {
10
+ readonly sources: Source[];
11
+ elementType: string;
12
+ currentAnnotation?: Annotation;
13
+ constructor(sources: Source[]);
14
+ getSourceDef(parameterSpace: ParameterSpace | undefined): SourceDef;
15
+ withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined): SourceDef;
16
+ }
@@ -0,0 +1,75 @@
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.CompositeSource = void 0;
10
+ const malloy_types_1 = require("../../../model/malloy_types");
11
+ const source_1 = require("./source");
12
+ /**
13
+ * A Source that is a virtual union of the fields of other sources, choosing
14
+ * the first source that has all the fields at query time.
15
+ */
16
+ class CompositeSource extends source_1.Source {
17
+ constructor(sources) {
18
+ super({ sources });
19
+ this.sources = sources;
20
+ this.elementType = 'compositeSource';
21
+ }
22
+ getSourceDef(parameterSpace) {
23
+ return this.withParameters(parameterSpace, []);
24
+ }
25
+ withParameters(parameterSpace, pList) {
26
+ const sourceDefs = this.sources.map(source => source.withParameters(parameterSpace, pList));
27
+ const connection = sourceDefs[0].connection;
28
+ const dialect = sourceDefs[0].dialect;
29
+ const name = 'composite_source';
30
+ const fields = [];
31
+ const fieldNames = new Set();
32
+ this.sources.forEach((source, index) => {
33
+ var _a;
34
+ const sourceDef = sourceDefs[index];
35
+ // Check that connections all match; don't bother checking dialect, since it will
36
+ // match if the connection matches.
37
+ if (sourceDef.connection !== connection) {
38
+ source.logError('composite-source-connection-mismatch', `All sources in a composite source must share the same connection; connection \`${sourceDef.connection}\` differs from previous connection \`${connection}\``);
39
+ }
40
+ for (const field of sourceDef.fields) {
41
+ if (!(0, malloy_types_1.isAtomic)(field)) {
42
+ source.logWarning('composite-source-atomic-fields-only', `Only atomic fields are supported in composite sources; field \`${field.name}\` is not atomic and will be ignored`);
43
+ continue;
44
+ }
45
+ const fieldName = (_a = field.as) !== null && _a !== void 0 ? _a : field.name;
46
+ if (!fieldNames.has(fieldName)) {
47
+ fieldNames.add(fieldName);
48
+ const compositeField = {
49
+ ...field,
50
+ name: fieldName,
51
+ as: undefined,
52
+ e: { node: 'compositeField' },
53
+ compositeFieldUsage: { fields: [fieldName], joinedUsage: {} },
54
+ code: this.code,
55
+ location: this.codeLocation,
56
+ };
57
+ fields.push(compositeField);
58
+ }
59
+ }
60
+ });
61
+ return {
62
+ type: 'composite',
63
+ // TODO Use sourceRefs rather than sourceDefs when possible to avoid potential
64
+ // explosion of source defs...
65
+ sources: sourceDefs,
66
+ connection,
67
+ fields,
68
+ dialect,
69
+ name,
70
+ parameters: sourceDefs[0].parameters,
71
+ };
72
+ }
73
+ }
74
+ exports.CompositeSource = CompositeSource;
75
+ //# sourceMappingURL=composite-source.js.map
@@ -1,4 +1,4 @@
1
- import { InvokedStructRef, Parameter, SourceDef, StructDef } from '../../../model/malloy_types';
1
+ import { InvokedStructRef, Parameter, SourceDef } from '../../../model/malloy_types';
2
2
  import { MalloyElement } from '../types/malloy-element';
3
3
  import { HasParameter } from '../parameters/has-parameter';
4
4
  import { ParameterSpace } from '../field-space/parameter-space';
@@ -10,5 +10,5 @@ export declare abstract class Source extends MalloyElement {
10
10
  abstract getSourceDef(parameterSpace: ParameterSpace | undefined): SourceDef;
11
11
  structRef(parameterSpace: ParameterSpace | undefined): InvokedStructRef;
12
12
  protected packParameters(pList: HasParameter[] | undefined): Record<string, Parameter> | undefined;
13
- withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined): StructDef;
13
+ withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined): SourceDef;
14
14
  }
@@ -95,6 +95,7 @@ class KeyJoin extends Join {
95
95
  right: exprX.value,
96
96
  },
97
97
  };
98
+ inStruct.onCompositeFieldUsage = exprX.compositeFieldUsage;
98
99
  return;
99
100
  }
100
101
  else {
@@ -137,6 +138,7 @@ class ExpressionJoin extends Join {
137
138
  return;
138
139
  }
139
140
  inStruct.onExpression = exprX.value;
141
+ inStruct.onCompositeFieldUsage = exprX.compositeFieldUsage;
140
142
  }
141
143
  structDef(parameterSpace) {
142
144
  var _a;
@@ -0,0 +1,13 @@
1
+ import { CompositeSource } from '../source-elements/composite-source';
2
+ import { SourceQueryElement } from './source-query-element';
3
+ /**
4
+ * e.g. `compose(source_a, source_b)`
5
+ */
6
+ export declare class SQCompose extends SourceQueryElement {
7
+ readonly sources: SourceQueryElement[];
8
+ elementType: string;
9
+ asSource?: CompositeSource;
10
+ constructor(sources: SourceQueryElement[]);
11
+ getSource(): CompositeSource | undefined;
12
+ isSource(): boolean;
13
+ }
@@ -0,0 +1,48 @@
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.SQCompose = void 0;
10
+ const composite_source_1 = require("../source-elements/composite-source");
11
+ const source_query_element_1 = require("./source-query-element");
12
+ /**
13
+ * e.g. `compose(source_a, source_b)`
14
+ */
15
+ class SQCompose extends source_query_element_1.SourceQueryElement {
16
+ constructor(sources) {
17
+ super({ sources });
18
+ this.sources = sources;
19
+ this.elementType = 'sq-compose';
20
+ }
21
+ getSource() {
22
+ if (this.asSource) {
23
+ return this.asSource;
24
+ }
25
+ const sources = this.sources.map(s => s.getSource());
26
+ if (sources.length === 0) {
27
+ this.sqLog('empty-composite-source', 'Composite source must have at least one input source');
28
+ return undefined;
29
+ }
30
+ else if (sources.length === 1) {
31
+ this.sqLog('unnecessary-composite-source', 'A composite source with one input is equivalent to that input', { severity: 'warn' });
32
+ }
33
+ if (hasNoUndefined(sources)) {
34
+ this.asSource = new composite_source_1.CompositeSource(sources);
35
+ this.has({ asSource: this.asSource });
36
+ return this.asSource;
37
+ }
38
+ this.sqLog('invalid-composite-source-input', 'All composite source inputs must be valid sources');
39
+ }
40
+ isSource() {
41
+ return true;
42
+ }
43
+ }
44
+ exports.SQCompose = SQCompose;
45
+ function hasNoUndefined(arr) {
46
+ return arr.every(s => s !== undefined);
47
+ }
48
+ //# sourceMappingURL=sq-compose.js.map
@@ -24,12 +24,18 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.atomicDef = exports.inspect = exports.typeEq = exports.typeIn = exports.eq = exports.any = exports.anyAtomicT = exports.aggregateBoolT = exports.viewT = exports.errorT = exports.boolT = exports.timestampT = exports.dateT = exports.stringT = exports.numberT = exports.nullT = void 0;
26
26
  const model_1 = require("../../model");
27
+ const composite_source_utils_1 = require("../../model/composite_source_utils");
27
28
  function mkTypeDesc(
28
29
  // The problem is that record and array, as currently defined, require a dialect
29
30
  // which isn't available. In retrospect the dialect shouldn't be in the type,
30
31
  // it should only be in the field, which I wil do eventually.
31
32
  dataType, expressionType = 'scalar', evalSpace = 'constant') {
32
- return { type: dataType, expressionType, evalSpace };
33
+ return {
34
+ type: dataType,
35
+ expressionType,
36
+ evalSpace,
37
+ compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
38
+ };
33
39
  }
34
40
  exports.nullT = mkTypeDesc('null');
35
41
  exports.numberT = mkTypeDesc('number');
@@ -24,12 +24,14 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.literalTimeResult = exports.literalExprValue = exports.computedErrorExprValue = exports.computedTimeResult = exports.computedExprValue = void 0;
26
26
  const model_1 = require("../../../model");
27
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
27
28
  function computedExprValue({ value, dataType, from, }) {
28
29
  return {
29
30
  ...dataType,
30
31
  value,
31
32
  expressionType: (0, model_1.maxOfExpressionTypes)(from.map(e => e.expressionType)),
32
33
  evalSpace: (0, model_1.mergeEvalSpaces)(...from.map(e => e.evalSpace)),
34
+ compositeFieldUsage: (0, composite_source_utils_1.mergeCompositeFieldUsage)(...from.map(e => e.compositeFieldUsage)),
33
35
  };
34
36
  }
35
37
  exports.computedExprValue = computedExprValue;
@@ -40,6 +42,7 @@ function computedTimeResult({ value, dataType, from, timeframe, }) {
40
42
  expressionType: xv.expressionType,
41
43
  evalSpace: xv.evalSpace,
42
44
  value: xv.value,
45
+ compositeFieldUsage: (0, composite_source_utils_1.mergeCompositeFieldUsage)(...from.map(e => e.compositeFieldUsage)),
43
46
  };
44
47
  if (timeframe) {
45
48
  y.timeframe = timeframe;
@@ -67,6 +70,7 @@ function literalTimeResult({ value, dataType, timeframe, }) {
67
70
  expressionType: xv.expressionType,
68
71
  evalSpace: xv.evalSpace,
69
72
  value: xv.value,
73
+ compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
70
74
  };
71
75
  if (timeframe) {
72
76
  y.timeframe = timeframe;
@@ -200,12 +200,11 @@ function getMorphicValue(mv, mt) {
200
200
  return mv;
201
201
  }
202
202
  if (mv.morphic && mv.morphic[mt]) {
203
- return {
204
- type: mt,
203
+ return (0, expr_value_1.computedExprValue)({
204
+ dataType: { type: mt },
205
205
  value: mv.morphic[mt],
206
- expressionType: mv.expressionType,
207
- evalSpace: mv.evalSpace,
208
- };
206
+ from: [mv],
207
+ });
209
208
  }
210
209
  }
211
210
  exports.getMorphicValue = getMorphicValue;
@@ -1,8 +1,9 @@
1
- import { PipeSegment } from '../../../model/malloy_types';
1
+ import { FilterCondition, PipeSegment } from '../../../model/malloy_types';
2
2
  import { QueryProperty } from './query-property';
3
3
  import { QueryInputSpace } from '../field-space/query-input-space';
4
4
  import { QueryOperationSpace } from '../field-space/query-spaces';
5
5
  export interface QueryBuilder {
6
+ filters: FilterCondition[];
6
7
  type: 'grouping' | 'index' | 'project';
7
8
  inputFS: QueryInputSpace;
8
9
  resultFS: QueryOperationSpace;
@@ -24,14 +24,27 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.SpaceField = void 0;
26
26
  const space_entry_1 = require("./space-entry");
27
+ const composite_source_utils_1 = require("../../../model/composite_source_utils");
27
28
  class SpaceField extends space_entry_1.SpaceEntry {
28
29
  constructor() {
29
30
  super(...arguments);
30
31
  this.refType = 'field';
31
32
  }
32
33
  fieldTypeFromFieldDef(def) {
34
+ var _a, _b, _c;
33
35
  const expressionType = def.expressionType || 'scalar';
34
- const ref = { ...def, expressionType, evalSpace: 'input' };
36
+ const ref = {
37
+ ...def,
38
+ expressionType,
39
+ evalSpace: 'input',
40
+ compositeFieldUsage:
41
+ // Use the composite field usage in the def if it exists, otherwise, if the
42
+ // field has an e whic is a composite field, then the composite field usage
43
+ // should be just the name of the field.
44
+ (_a = def.compositeFieldUsage) !== null && _a !== void 0 ? _a : (((_b = def.e) === null || _b === void 0 ? void 0 : _b.node) === 'compositeField'
45
+ ? { fields: [(_c = def.as) !== null && _c !== void 0 ? _c : def.name], joinedUsage: {} }
46
+ : (0, composite_source_utils_1.emptyCompositeFieldUsage)()),
47
+ };
35
48
  return ref;
36
49
  }
37
50
  getQueryFieldDef(_fs) {