@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
@@ -78,6 +78,7 @@ import { JoinWithContext } from "./MalloyParser";
78
78
  import { JoinOnContext } from "./MalloyParser";
79
79
  import { SQIDContext } from "./MalloyParser";
80
80
  import { SQParensContext } from "./MalloyParser";
81
+ import { SQComposeContext } from "./MalloyParser";
81
82
  import { SQRefinedQueryContext } from "./MalloyParser";
82
83
  import { SQArrowContext } from "./MalloyParser";
83
84
  import { SQExtendedSourceContext } from "./MalloyParser";
@@ -1177,6 +1178,18 @@ export interface MalloyParserListener extends ParseTreeListener {
1177
1178
  * @param ctx the parse tree
1178
1179
  */
1179
1180
  exitSQParens?: (ctx: SQParensContext) => void;
1181
+ /**
1182
+ * Enter a parse tree produced by the `SQCompose`
1183
+ * labeled alternative in `MalloyParser.sqExpr`.
1184
+ * @param ctx the parse tree
1185
+ */
1186
+ enterSQCompose?: (ctx: SQComposeContext) => void;
1187
+ /**
1188
+ * Exit a parse tree produced by the `SQCompose`
1189
+ * labeled alternative in `MalloyParser.sqExpr`.
1190
+ * @param ctx the parse tree
1191
+ */
1192
+ exitSQCompose?: (ctx: SQComposeContext) => void;
1180
1193
  /**
1181
1194
  * Enter a parse tree produced by the `SQRefinedQuery`
1182
1195
  * labeled alternative in `MalloyParser.sqExpr`.
@@ -78,6 +78,7 @@ import { JoinWithContext } from "./MalloyParser";
78
78
  import { JoinOnContext } from "./MalloyParser";
79
79
  import { SQIDContext } from "./MalloyParser";
80
80
  import { SQParensContext } from "./MalloyParser";
81
+ import { SQComposeContext } from "./MalloyParser";
81
82
  import { SQRefinedQueryContext } from "./MalloyParser";
82
83
  import { SQArrowContext } from "./MalloyParser";
83
84
  import { SQExtendedSourceContext } from "./MalloyParser";
@@ -785,6 +786,13 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
785
786
  * @return the visitor result
786
787
  */
787
788
  visitSQParens?: (ctx: SQParensContext) => Result;
789
+ /**
790
+ * Visit a parse tree produced by the `SQCompose`
791
+ * labeled alternative in `MalloyParser.sqExpr`.
792
+ * @param ctx the parse tree
793
+ * @return the visitor result
794
+ */
795
+ visitSQCompose?: (ctx: SQComposeContext) => Result;
788
796
  /**
789
797
  * Visit a parse tree produced by the `SQRefinedQuery`
790
798
  * labeled alternative in `MalloyParser.sqExpr`.
@@ -212,6 +212,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
212
212
  protected getSqExpr(cx: parse.SqExprContext): ast.SourceQueryElement;
213
213
  visitSQExtendedSource(pcx: parse.SQExtendedSourceContext): ast.SQExtend;
214
214
  visitSQParens(pcx: parse.SQParensContext): ast.SourceQueryElement;
215
+ visitSQCompose(pcx: parse.SQComposeContext): ast.SQCompose;
215
216
  visitSQArrow(pcx: parse.SQArrowContext): ast.SQArrow;
216
217
  getVExpr(pcx: ParserRuleContext): ast.View;
217
218
  visitSegField(pcx: parse.SegFieldContext): ast.ReferenceView;
@@ -1280,6 +1280,11 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1280
1280
  const sqExpr = this.getSqExpr(pcx.sqExpr());
1281
1281
  return this.astAt(sqExpr, pcx);
1282
1282
  }
1283
+ visitSQCompose(pcx) {
1284
+ const sources = pcx.sqExpr().map(sqExpr => this.getSqExpr(sqExpr));
1285
+ this.inExperiment('composite_sources', pcx);
1286
+ return this.astAt(new ast.SQCompose(sources), pcx);
1287
+ }
1283
1288
  visitSQArrow(pcx) {
1284
1289
  const applyTo = this.getSqExpr(pcx.sqExpr());
1285
1290
  const headCx = pcx.segExpr();
@@ -1,4 +1,4 @@
1
- import { DocumentLocation, ExpressionValueType } from '../model/malloy_types';
1
+ import { CompositeFieldUsage, DocumentLocation, ExpressionValueType } from '../model/malloy_types';
2
2
  import { EventStream } from '../runtime_types';
3
3
  export type LogSeverity = 'error' | 'warn' | 'debug';
4
4
  /**
@@ -156,6 +156,15 @@ type MessageParameterTypes = {
156
156
  'field-list-edit-not-found': string;
157
157
  'unexpected-element-type': string;
158
158
  'field-not-found': string;
159
+ 'invalid-composite-source-input': string;
160
+ 'invalid-composite-field-usage': {
161
+ newUsage: CompositeFieldUsage;
162
+ allUsage: CompositeFieldUsage;
163
+ };
164
+ 'empty-composite-source': string;
165
+ 'unnecessary-composite-source': string;
166
+ 'composite-source-atomic-fields-only': string;
167
+ 'composite-source-connection-mismatch': string;
159
168
  'invalid-property-access-in-field-reference': string;
160
169
  'parameter-default-does-not-match-declared-type': string;
161
170
  'parameter-null-default-without-declared-type': string;
@@ -23,6 +23,7 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.makeLogMessage = exports.MESSAGE_FORMATTERS = exports.BaseMessageLogger = void 0;
26
+ const composite_source_utils_1 = require("../model/composite_source_utils");
26
27
  class BaseMessageLogger {
27
28
  constructor(eventStream) {
28
29
  this.eventStream = eventStream;
@@ -94,6 +95,12 @@ exports.MESSAGE_FORMATTERS = {
94
95
  'case-else-type-does-not-match': e => `Case else type ${e.elseType} does not match return type ${e.returnType}`,
95
96
  'case-when-must-be-boolean': e => `Case when expression must be boolean, not ${e.whenType}`,
96
97
  'case-when-type-does-not-match': e => `Case when type ${e.whenType} does not match value type ${e.valueType}`,
98
+ 'invalid-composite-field-usage': e => {
99
+ const formattedNewCompositeUsage = (0, composite_source_utils_1.formatCompositeFieldUsages)(e.newUsage);
100
+ const formattedAllCompositeUsage = (0, composite_source_utils_1.formatCompositeFieldUsages)(e.allUsage);
101
+ const pluralUse = (0, composite_source_utils_1.compositeFieldUsageIsPlural)(e.newUsage) ? 's' : '';
102
+ return `This operation uses composite field${pluralUse} ${formattedNewCompositeUsage}, resulting in invalid usage of the composite source, as there is no composite input source which defines all of ${formattedAllCompositeUsage}`;
103
+ },
97
104
  };
98
105
  function makeLogMessage(code, parameters, options) {
99
106
  var _a, _b, _c, _d, _e;
@@ -0,0 +1 @@
1
+ import './parse-expects';
@@ -0,0 +1,155 @@
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
+ const test_translator_1 = require("./test-translator");
10
+ require("./parse-expects");
11
+ const composite_source_utils_1 = require("../../model/composite_source_utils");
12
+ function addPathToCompositeUsage(path, compositeUsage) {
13
+ var _a;
14
+ if (path.length === 0)
15
+ throw new Error('empty path');
16
+ if (path.length === 1) {
17
+ return {
18
+ fields: [...compositeUsage.fields, path[0]],
19
+ joinedUsage: compositeUsage.joinedUsage,
20
+ };
21
+ }
22
+ else {
23
+ return {
24
+ fields: compositeUsage.fields,
25
+ joinedUsage: {
26
+ ...compositeUsage.joinedUsage,
27
+ [path[0]]: addPathToCompositeUsage(path.slice(1), (_a = compositeUsage.joinedUsage[path[0]]) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)()),
28
+ },
29
+ };
30
+ }
31
+ }
32
+ function paths(paths) {
33
+ let cu = (0, composite_source_utils_1.emptyCompositeFieldUsage)();
34
+ for (const path of paths) {
35
+ cu = addPathToCompositeUsage(path, cu);
36
+ }
37
+ return cu;
38
+ }
39
+ describe('composite sources', () => {
40
+ describe('composite field usage', () => {
41
+ const m = (0, test_translator_1.model) `
42
+ ##! experimental.composite_sources
43
+ source: x is compose(ab, ab) extend {
44
+ dimension: aif is ai + af
45
+ }
46
+
47
+ source: y is compose(ab, ab) extend {
48
+ join_one: x on 1 = 1
49
+ }
50
+ `;
51
+ beforeAll(() => {
52
+ m.translator.translate();
53
+ });
54
+ test('looked up value', () => {
55
+ const mexpr = (0, test_translator_1.makeExprFunc)(m.translator.modelDef, 'y');
56
+ expect(mexpr `ai`).hasCompositeUsage(paths([['ai']]));
57
+ });
58
+ test('multiple values', () => {
59
+ const mexpr = (0, test_translator_1.makeExprFunc)(m.translator.modelDef, 'y');
60
+ expect(mexpr `ai + af`).hasCompositeUsage(paths([['ai'], ['af']]));
61
+ });
62
+ test('value plus constant', () => {
63
+ const mexpr = (0, test_translator_1.makeExprFunc)(m.translator.modelDef, 'y');
64
+ expect(mexpr `ai + 1`).hasCompositeUsage(paths([['ai']]));
65
+ });
66
+ test('join usage', () => {
67
+ const mexpr = (0, test_translator_1.makeExprFunc)(m.translator.modelDef, 'y');
68
+ expect(mexpr `x.ai + 1`).hasCompositeUsage(paths([['x', 'ai']]));
69
+ });
70
+ test('join usage complex', () => {
71
+ const mexpr = (0, test_translator_1.makeExprFunc)(m.translator.modelDef, 'y');
72
+ expect(mexpr `x.aif`).hasCompositeUsage(paths([
73
+ ['x', 'ai'],
74
+ ['x', 'af'],
75
+ ]));
76
+ });
77
+ });
78
+ describe('composite source resolution and validation', () => {
79
+ test('compose fails on group_by that is relevant', () => {
80
+ expect(`
81
+ ##! experimental.composite_sources
82
+ run: compose(
83
+ a extend { dimension: one is 1, two is 2 },
84
+ a extend { dimension: one is 1, three is 3 }
85
+ ) -> {
86
+ group_by: one
87
+ group_by: three
88
+ group_by: ${'two'}
89
+ }
90
+ `).toLog((0, test_translator_1.errorMessage)('This operation uses composite field `two`, resulting in invalid usage of the composite source, as there is no composite input source which defines all of `one`, `three`, `two`'));
91
+ });
92
+ test('compose fails on filter that is relevant', () => {
93
+ expect(`
94
+ ##! experimental.composite_sources
95
+ run: compose(
96
+ a extend { dimension: one is 1, two is 2 },
97
+ a extend { dimension: one is 1, three is 3 }
98
+ ) -> {
99
+ group_by: one
100
+ group_by: three
101
+ where: ${'two = 2'}
102
+ }
103
+ `).toLog((0, test_translator_1.errorMessage)('This operation uses composite field `two`, resulting in invalid usage of the composite source, as there is no composite input source which defines all of `one`, `three`, `two`'));
104
+ });
105
+ test('compose fails in case where second field has overlap with first', () => {
106
+ expect(`
107
+ ##! experimental.composite_sources
108
+ run: compose(
109
+ a extend { dimension: one is 1 },
110
+ a extend { dimension: two is 3 }
111
+ ) -> {
112
+ group_by: one
113
+ group_by: ${'three is one + two'}
114
+ }
115
+ `).toLog((0, test_translator_1.errorMessage)('This operation uses composite field `two`, resulting in invalid usage of the composite source, as there is no composite input source which defines all of `one`, `two`'));
116
+ });
117
+ test('compose resolution succeeds nested', () => {
118
+ expect(`
119
+ ##! experimental.composite_sources
120
+ run: compose(
121
+ compose(
122
+ a extend { dimension: one is 1, two is 2 },
123
+ a extend { dimension: one is 1, three is 3 }
124
+ ),
125
+ a extend { dimension: one is 1, two is 2, three is 3 }
126
+ ) -> {
127
+ group_by: one, two ${'three'}
128
+ }
129
+ `).toTranslate();
130
+ });
131
+ test('good composite field usage works', () => expect(`
132
+ ##! experimental.composite_sources
133
+ run: compose(a, a extend { dimension: one is 1 }) -> { group_by: one }
134
+ `).toTranslate());
135
+ test.skip('index on composite fails', () => expect(`
136
+ ##! experimental.composite_sources
137
+ run: compose(a extend { dimension: two is 2 }, a extend { dimension: one is 1 }) -> { index: * }
138
+ `).toLog((0, test_translator_1.errorMessage)('Cannot index on a composite source')));
139
+ test('raw run of composite source fails', () => expect(`
140
+ ##! experimental.composite_sources
141
+ run: compose(a extend { dimension: two is 2 }, a extend { dimension: one is 1 })
142
+ `).toLog((0, test_translator_1.errorMessage)('Cannot run this object as a query')));
143
+ test('composite source with parameter', () => {
144
+ expect(`
145
+ ##! experimental { composite_sources parameters }
146
+ source: foo(param is 1) is compose(
147
+ a extend { dimension: x is param },
148
+ a extend { dimension: y is param + 1 }
149
+ )
150
+ run: foo(param is 2) -> { group_by: y }
151
+ `).toTranslate();
152
+ });
153
+ });
154
+ });
155
+ //# sourceMappingURL=composite-field-usage.spec.js.map
@@ -1,4 +1,4 @@
1
- import { DocumentLocation } from '../../model';
1
+ import { CompositeFieldUsage, DocumentLocation } from '../../model';
2
2
  import { LogSeverity } from '../parse-log';
3
3
  type MessageProblemSpec = {
4
4
  severity: LogSeverity;
@@ -45,6 +45,7 @@ declare global {
45
45
  * Warnings are ignored, so need to be checked seperately
46
46
  */
47
47
  compilesTo(exprString: string): R;
48
+ hasCompositeUsage(compositeUsage: CompositeFieldUsage): R;
48
49
  }
49
50
  }
50
51
  }
@@ -276,6 +276,42 @@ expect.extend({
276
276
  const msg = pass ? `Matched: ${rcvExpr}` : this.utils.diff(expr, rcvExpr);
277
277
  return { pass, message: () => `${msg}` };
278
278
  },
279
+ hasCompositeUsage: function (tx, compositeFieldUsage) {
280
+ let bx;
281
+ if (typeof tx === 'string') {
282
+ bx = new test_translator_1.BetaExpression(tx);
283
+ }
284
+ else {
285
+ const x = xlator(tx);
286
+ if (x instanceof test_translator_1.BetaExpression) {
287
+ bx = x;
288
+ }
289
+ else {
290
+ return {
291
+ pass: false,
292
+ message: () => 'Must pass expr`EXPRESSION` to expect(EXPRSSION).compilesTo()',
293
+ };
294
+ }
295
+ }
296
+ bx.compile();
297
+ // Only report errors, callers will need to test for warnings
298
+ if (bx.logger.hasErrors()) {
299
+ return {
300
+ message: () => `Translation problems:\n${bx.prettyErrors()}`,
301
+ pass: false,
302
+ };
303
+ }
304
+ const badRefs = checkForNeededs(bx);
305
+ if (!badRefs.pass) {
306
+ return badRefs;
307
+ }
308
+ const actual = bx.generated().compositeFieldUsage;
309
+ const pass = this.equals(actual, compositeFieldUsage);
310
+ const msg = pass
311
+ ? `Matched: ${actual}`
312
+ : this.utils.diff(compositeFieldUsage, actual);
313
+ return { pass, message: () => `${msg}` };
314
+ },
279
315
  });
280
316
  function problemSpecSummary(s) {
281
317
  return `${s.severity} '${'message' in s ? s.message : s.code}' ${s.data !== undefined ? (0, test_translator_1.pretty)(s.data) : ''}`;
@@ -316,5 +316,14 @@ describe('source:', () => {
316
316
  const ad = (0, test_translator_1.getFieldDef)(hasDate, 'ad');
317
317
  expect(ad).toMatchObject({ name: 'ad', type: 'date' });
318
318
  });
319
+ describe('composite sources', () => {
320
+ test('basic composite source', () => {
321
+ expect(`
322
+ ##! experimental.composite_sources
323
+ source: x is compose(a, a extend { dimension: foo is 1 })
324
+ run: x -> { select: foo }
325
+ `).toTranslate();
326
+ });
327
+ });
319
328
  });
320
329
  //# sourceMappingURL=source.spec.js.map
@@ -45,8 +45,9 @@ export declare class TestTranslator extends MalloyTranslator {
45
45
  getQuery(queryName: string | number): Query | undefined;
46
46
  }
47
47
  export declare class BetaExpression extends TestTranslator {
48
+ readonly sourceName: string;
48
49
  private compiled?;
49
- constructor(src: string);
50
+ constructor(src: string, model?: ModelDef, sourceName?: string);
50
51
  private testFS;
51
52
  compile(): void;
52
53
  generated(): ExprValue;
@@ -72,6 +73,7 @@ export declare function makeModelFunc(options: {
72
73
  prefix?: string;
73
74
  wrap?: (code: string) => string;
74
75
  }): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator<TestTranslator>;
76
+ export declare function makeExprFunc(model: ModelDef, sourceName: string): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator<TestTranslator>;
75
77
  export declare function markSource(unmarked: TemplateStringsArray, ...marked: string[]): MarkedSource;
76
78
  export declare function getSelectOneStruct(sqlBlock: SQLSentence): SQLSourceDef;
77
79
  export declare function error<T extends MessageCode>(code: T, data?: MessageParameterType<T>): {
@@ -23,7 +23,7 @@
23
23
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
  */
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.warningMessage = exports.errorMessage = exports.warning = exports.error = exports.getSelectOneStruct = exports.markSource = exports.makeModelFunc = exports.model = exports.expr = exports.getJoinField = exports.getQueryField = exports.getQueryFieldDef = exports.getFieldDef = exports.getModelQuery = exports.getExplore = exports.BetaExpression = exports.TestTranslator = exports.TestChildTranslator = exports.aTableDef = exports.pretty = void 0;
26
+ exports.warningMessage = exports.errorMessage = exports.warning = exports.error = exports.getSelectOneStruct = exports.markSource = exports.makeExprFunc = exports.makeModelFunc = exports.model = exports.expr = exports.getJoinField = exports.getQueryField = exports.getQueryFieldDef = exports.getFieldDef = exports.getModelQuery = exports.getExplore = exports.BetaExpression = exports.TestTranslator = exports.TestChildTranslator = exports.aTableDef = exports.pretty = void 0;
27
27
  const util_1 = require("util");
28
28
  const malloy_types_1 = require("../../model/malloy_types");
29
29
  const ast_1 = require("../ast");
@@ -386,11 +386,12 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
386
386
  exports.TestTranslator = TestTranslator;
387
387
  TestTranslator.inspectCompile = false;
388
388
  class BetaExpression extends TestTranslator {
389
- constructor(src) {
390
- super(src, null, null, 'debugExpr');
389
+ constructor(src, model, sourceName = 'ab') {
390
+ super(src, null, null, 'debugExpr', model);
391
+ this.sourceName = sourceName;
391
392
  }
392
393
  testFS() {
393
- const aStruct = this.internalModel.contents['ab'];
394
+ const aStruct = this.internalModel.contents[this.sourceName];
394
395
  if ((0, malloy_types_1.isSourceDef)(aStruct)) {
395
396
  const tstFS = new static_space_1.StaticSourceSpace(aStruct);
396
397
  return tstFS;
@@ -498,6 +499,16 @@ function makeModelFunc(options) {
498
499
  };
499
500
  }
500
501
  exports.makeModelFunc = makeModelFunc;
502
+ function makeExprFunc(model, sourceName) {
503
+ return function expr(unmarked, ...marked) {
504
+ const ms = markSource(unmarked, ...marked);
505
+ return {
506
+ ...ms,
507
+ translator: new BetaExpression(ms.code, model, sourceName),
508
+ };
509
+ };
510
+ }
511
+ exports.makeExprFunc = makeExprFunc;
501
512
  function markSource(unmarked, ...marked) {
502
513
  let code = '';
503
514
  const locations = [];
@@ -1,2 +1,3 @@
1
1
  import { DocumentLocation, DocumentPosition } from '../model/malloy_types';
2
2
  export declare function locationContainsPosition(location: DocumentLocation, position: DocumentPosition): boolean;
3
+ export declare function isNotUndefined<T>(value: T | undefined): value is T;
@@ -22,7 +22,7 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.locationContainsPosition = void 0;
25
+ exports.isNotUndefined = exports.locationContainsPosition = void 0;
26
26
  function locationContainsPosition(location, position) {
27
27
  return (location.range.start.line <= position.line &&
28
28
  location.range.end.line >= position.line &&
@@ -32,4 +32,8 @@ function locationContainsPosition(location, position) {
32
32
  position.character <= location.range.end.character));
33
33
  }
34
34
  exports.locationContainsPosition = locationContainsPosition;
35
+ function isNotUndefined(value) {
36
+ return value !== undefined;
37
+ }
38
+ exports.isNotUndefined = isNotUndefined;
35
39
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1,65 @@
1
+ import { CompositeFieldUsage, SourceDef } from './malloy_types';
2
+ type CompositeError = {
3
+ code: 'not_a_composite_source';
4
+ data: {
5
+ path: string[];
6
+ };
7
+ } | {
8
+ code: 'composite_source_not_defined';
9
+ data: {
10
+ path: string[];
11
+ };
12
+ } | {
13
+ code: 'composite_source_not_a_join';
14
+ data: {
15
+ path: string[];
16
+ };
17
+ } | {
18
+ code: 'composite_source_is_not_joinable';
19
+ data: {
20
+ path: string[];
21
+ };
22
+ } | {
23
+ code: 'no_suitable_composite_source_input';
24
+ data: {
25
+ path: string[];
26
+ fields: string[];
27
+ };
28
+ };
29
+ type SingleNarrowedCompositeFieldResolution = {
30
+ source: SourceDef;
31
+ nested?: SingleNarrowedCompositeFieldResolution | undefined;
32
+ }[];
33
+ interface NarrowedCompositeFieldResolution {
34
+ source: SingleNarrowedCompositeFieldResolution | undefined;
35
+ joined: {
36
+ [name: string]: NarrowedCompositeFieldResolution;
37
+ };
38
+ }
39
+ export declare function emptyNarrowedCompositeFieldResolution(): NarrowedCompositeFieldResolution;
40
+ export declare function narrowCompositeFieldResolution(source: SourceDef, compositeFieldUsage: CompositeFieldUsage, narrowedCompositeFieldResolution: NarrowedCompositeFieldResolution): {
41
+ narrowedCompositeFieldResolution: NarrowedCompositeFieldResolution;
42
+ error: undefined;
43
+ } | {
44
+ error: CompositeError;
45
+ narrowedCompositeFieldResolution: undefined;
46
+ };
47
+ export declare function resolveCompositeSources(source: SourceDef, compositeFieldUsage: CompositeFieldUsage): {
48
+ sourceDef: SourceDef;
49
+ error: undefined;
50
+ } | {
51
+ error: CompositeError;
52
+ sourceDef: undefined;
53
+ };
54
+ export declare function compositeFieldUsagePaths(compositeFieldUsage: CompositeFieldUsage): string[][];
55
+ export declare function formatCompositeFieldUsages(compositeFieldUsage: CompositeFieldUsage): string;
56
+ export declare function isEmptyCompositeFieldUsage(compositeFieldUsage: CompositeFieldUsage): boolean;
57
+ export declare function compositeFieldUsageIsPlural(compositeFieldUsage: CompositeFieldUsage): boolean;
58
+ export declare function formatCompositeFieldUsage(compositeFieldUsage: string[]): string;
59
+ export declare function unique<T>(values: T[]): T[];
60
+ export declare function mergeCompositeFieldUsage(...usages: (CompositeFieldUsage | undefined)[]): CompositeFieldUsage;
61
+ export declare function emptyCompositeFieldUsage(): CompositeFieldUsage;
62
+ export declare function compositeFieldUsageDifference(a: CompositeFieldUsage, b: CompositeFieldUsage): CompositeFieldUsage;
63
+ export declare function joinedCompositeFieldUsage(joinPath: string[], compositeFieldUsage: CompositeFieldUsage): CompositeFieldUsage;
64
+ export declare function compositeFieldUsageJoinPaths(compositeFieldUsage: CompositeFieldUsage): string[][];
65
+ export {};