@malloydata/malloy 0.0.294 → 0.0.296

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.
@@ -21,13 +21,13 @@ exports.fieldUsageJoinPaths = fieldUsageJoinPaths;
21
21
  exports.checkRequiredGroupBys = checkRequiredGroupBys;
22
22
  exports.pathEq = pathEq;
23
23
  exports.pathBegins = pathBegins;
24
- exports.sortFieldUsageByReferenceLocation = sortFieldUsageByReferenceLocation;
25
24
  exports.hasCompositesAnywhere = hasCompositesAnywhere;
26
25
  exports.logCompositeError = logCompositeError;
27
26
  exports.compileFilterExpression = compileFilterExpression;
28
27
  const malloy_filter_1 = require("@malloydata/malloy-filter");
29
28
  const malloy_types_1 = require("./malloy_types");
30
29
  const utils_1 = require("./utils");
30
+ const utils_2 = require("../lang/utils");
31
31
  function _resolveCompositeSources(path, source, rootFields, nests, fieldUsage,
32
32
  // for resolving nested composites; the list of sources to try
33
33
  sources) {
@@ -403,27 +403,40 @@ function resolveCompositeSources(source, segment, fieldUsage) {
403
403
  function fieldUsagePaths(fieldUsage) {
404
404
  return fieldUsage.map(u => u.path);
405
405
  }
406
- function formatFieldUsages(fieldUsage) {
406
+ function dedupPaths(paths) {
407
407
  const deduped = [];
408
- for (const usage of fieldUsage) {
409
- if (!deduped.some(p => pathEq(p, usage.path))) {
410
- deduped.push(usage.path);
408
+ for (const path of paths) {
409
+ if (!deduped.some(p => pathEq(p, path))) {
410
+ deduped.push(path);
411
411
  }
412
412
  }
413
+ return deduped;
414
+ }
415
+ function formatPaths(paths, combinator = 'and') {
416
+ const deduped = dedupPaths(paths);
413
417
  const formattedUsages = deduped.map(fieldUsage => formatFieldUsage(fieldUsage));
414
- if (formattedUsages.length === 0) {
418
+ return commaAndList(formattedUsages, combinator);
419
+ }
420
+ function formatRequiredGroupings(requiredGroupings) {
421
+ return formatPaths(requiredGroupings.map(g => g.path), 'and/or');
422
+ }
423
+ function commaAndList(strs, combinator = 'and') {
424
+ if (strs.length === 0) {
415
425
  return '';
416
426
  }
417
- else if (formattedUsages.length === 1) {
418
- return formattedUsages[0];
427
+ else if (strs.length === 1) {
428
+ return strs[0];
419
429
  }
420
- else if (formattedUsages.length === 2) {
421
- return `${formattedUsages[0]} and ${formattedUsages[1]}`;
430
+ else if (strs.length === 2) {
431
+ return `${strs[0]} ${combinator} ${strs[1]}`;
422
432
  }
423
433
  else {
424
- return `${formattedUsages.slice(0, -1).join(', ')}, and ${formattedUsages[formattedUsages.length - 1]}`;
434
+ return `${strs.slice(0, -1).join(', ')}, ${combinator} ${strs[strs.length - 1]}`;
425
435
  }
426
436
  }
437
+ function formatFieldUsages(fieldUsage) {
438
+ return formatPaths(fieldUsage.map(u => u.path));
439
+ }
427
440
  function countFieldUsage(fieldUsage) {
428
441
  const paths = [];
429
442
  for (const usage of fieldUsage) {
@@ -529,6 +542,7 @@ function requiredGroupBysAt(requiredGroupBys, at) {
529
542
  return requiredGroupBys;
530
543
  return requiredGroupBys === null || requiredGroupBys === void 0 ? void 0 : requiredGroupBys.map(r => ({
531
544
  ...r,
545
+ fieldUsage: r.fieldUsage ? fieldUsageAt([r.fieldUsage], at)[0] : undefined,
532
546
  at,
533
547
  }));
534
548
  }
@@ -698,7 +712,7 @@ function expandRefs(nests, fields) {
698
712
  missingFields.push(field);
699
713
  continue;
700
714
  }
701
- requiredGroupBys.push({ path, at: field.at });
715
+ requiredGroupBys.push({ path, at: field.at, fieldUsage: field });
702
716
  }
703
717
  }
704
718
  if (def.ungroupings) {
@@ -827,8 +841,21 @@ function compareLocations(a, b) {
827
841
  return 1;
828
842
  return 0;
829
843
  }
830
- function sortFieldUsageByReferenceLocation(usage) {
831
- return usage.sort((a, b) => compareLocations(a.at, b.at));
844
+ function issueLocation(issue) {
845
+ if (issue.type === 'missing-field') {
846
+ return issue.field.at;
847
+ }
848
+ else if (issue.type === 'missing-required-group-by') {
849
+ return issue.requiredGroupBy.at;
850
+ }
851
+ else {
852
+ return issue.firstUsage.at;
853
+ }
854
+ }
855
+ function sortIssuesByReferenceLocation(issues) {
856
+ return issues.sort((a, b) => {
857
+ return compareLocations(issueLocation(a), issueLocation(b));
858
+ });
832
859
  }
833
860
  function hasCompositesAnywhere(source) {
834
861
  if (source.type === 'composite')
@@ -840,55 +867,60 @@ function hasCompositesAnywhere(source) {
840
867
  }
841
868
  return false;
842
869
  }
870
+ function issueFieldUsage(issue) {
871
+ if (issue.type === 'missing-field') {
872
+ return issue.field;
873
+ }
874
+ else if (issue.type === 'missing-required-group-by') {
875
+ return issue.requiredGroupBy.fieldUsage;
876
+ }
877
+ else {
878
+ return undefined;
879
+ }
880
+ }
843
881
  function logCompositeError(error, logTo) {
844
882
  if (error.code === 'no_suitable_composite_source_input') {
845
- if (error.data.failures.length > 0 &&
846
- error.data.failures.every(failure => {
847
- return (failure.issues.length > 0 &&
848
- failure.issues.every(issue => issue.type === 'missing-field'));
849
- })) {
850
- const firstFails = error.data.failures.map(failure => {
851
- if (failure.issues[0].type !== 'missing-field')
852
- throw new Error('Programmer error');
853
- return failure.issues[0].field;
854
- });
855
- const sorted = sortFieldUsageByReferenceLocation(firstFails);
856
- const lastUsage = sorted[sorted.length - 1];
857
- logTo.logError('invalid-composite-field-usage', {
858
- newUsage: [lastUsage],
859
- conflictingUsage: sorted,
860
- allUsage: error.data.usage,
861
- }, {
862
- at: lastUsage.at,
863
- });
864
- }
865
- else {
866
- for (let i = 0; i < error.data.failures.length; i++) {
867
- const failure = error.data.failures[i];
868
- const sourceName = failure.source.as
869
- ? ` (\`${failure.source.as}\`)`
870
- : '';
871
- const join = error.data.path.length === 0
872
- ? ''
873
- : `join ${error.data.path.join('.')} of `;
874
- const source = `${join}composed source #${i + 1}${sourceName}`;
875
- const requiredFields = `\nFields required in source: ${formatFieldUsages(error.data.usage)}`;
876
- for (const issue of failure.issues) {
877
- if (issue.type === 'missing-field') {
878
- const fieldRef = `\`${issue.field.path.join('.')}\``;
879
- logTo.logError('could-not-resolve-composite-source', `Could not resolve composite source: missing field ${fieldRef} in ${source}${requiredFields}`, { at: issue.field.at });
880
- }
881
- else if (issue.type === 'missing-required-group-by') {
882
- const fieldRef = `\`${issue.requiredGroupBy.path.join('.')}\``;
883
- logTo.logError('could-not-resolve-composite-source', `Could not resolve composite source: missing group by or single value filter of ${fieldRef} as required in ${source}${requiredFields}`, { at: issue.requiredGroupBy.at });
884
- }
885
- else {
886
- const joinRef = `\`${issue.path.join('.')}\``;
887
- logTo.logError('could-not-resolve-composite-source', `Could not resolve composite source: join ${joinRef} could not be resolved in ${source}${requiredFields}`, { at: issue.firstUsage.at });
888
- }
889
- }
890
- }
891
- }
883
+ const firstFails = error.data.failures.map(failure => failure.issues[0]);
884
+ const sorted = sortIssuesByReferenceLocation(firstFails);
885
+ const usages = sorted.map(issueFieldUsage);
886
+ const lastIssue = sorted[sorted.length - 1];
887
+ const lastUsage = usages[usages.length - 1];
888
+ const conflictingUsage = firstFails
889
+ .filter(i => i.type === 'missing-field')
890
+ .map(i => i.field);
891
+ const fConflictingUsage = formatFieldUsages(conflictingUsage);
892
+ const dConflictingUsage = conflictingUsage.length > 0
893
+ ? `there is no composite input source which defines all of ${fConflictingUsage}`
894
+ : undefined;
895
+ const missingGroupBys = firstFails
896
+ .filter(i => i.type === 'missing-required-group-by')
897
+ .map(i => i.requiredGroupBy);
898
+ const fMissingGroupBys = formatRequiredGroupings(missingGroupBys);
899
+ const dGrouping = 'required group by or single value filter';
900
+ const dMissingGroupBys = missingGroupBys.length > 0
901
+ ? `there is a missing ${dGrouping} of ${fMissingGroupBys}`
902
+ : undefined;
903
+ const dConflictingUsageAndMissingGroupBys = conflictingUsage.length > 0 && missingGroupBys.length > 0
904
+ ? `there is no composite input source which defines ${fConflictingUsage} without having an unsatisfied ${dGrouping} on ${fMissingGroupBys}`
905
+ : undefined;
906
+ const failedJoins = firstFails
907
+ .filter(i => i.type === 'join-failed')
908
+ .map(i => i.path);
909
+ const uniqueFailedJoins = dedupPaths(failedJoins);
910
+ const joinPlural = uniqueFailedJoins.length > 1 ? 'joins' : 'join';
911
+ const dFailedJoins = failedJoins.length > 0
912
+ ? `${joinPlural} ${formatPaths(uniqueFailedJoins)} could not be resolved`
913
+ : undefined;
914
+ const dLastIssue = lastUsage
915
+ ? `uses field ${formatFieldUsages([lastUsage])}, resulting in`
916
+ : 'results in';
917
+ 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)})`;
921
+ logTo.logError('could-not-resolve-composite-source', message, {
922
+ at: issueLocation(lastIssue),
923
+ });
892
924
  }
893
925
  else {
894
926
  logTo.logError('could-not-resolve-composite-source', 'Could not resolve composite source');
@@ -1,3 +1,4 @@
1
+ import type * as Malloy from '@malloydata/malloy-interfaces';
1
2
  import type { QueryInfo, Dialect, DialectFieldList } from '../dialect';
2
3
  import type { AggregateFunctionType, CompiledQuery, Expr, FieldDef, Filtered, FunctionOverloadDef, FunctionParameterDef, JoinRelationship, ModelDef, OrderBy, OutputFieldNode, ParameterNode, PipeSegment, Query, QueryFieldDef, QuerySegment, RefToField, ResultMetadataDef, ResultStructMetadataDef, SearchIndexResult, SegmentFieldDef, StructDef, StructRef, TurtleDef, FunctionOrderBy, Argument, AggregateExpr, FilterCondition, GenericSQLExpr, FieldnameNode, FunctionCallNode, UngroupNode, SourceReferenceNode, SpreadExpr, FilteredExpr, SourceDef, BooleanFieldDef, QueryResultDef, QueryToMaterialize, PrepareResultOptions, CaseExpr, BasicAtomicDef, AtomicFieldDef, FilterMatchExpr } from './malloy_types';
3
4
  import type { Connection } from '../connection/types';
@@ -126,11 +127,12 @@ declare class FieldInstanceField implements FieldInstance {
126
127
  f: QueryField;
127
128
  fieldUsage: FieldUsage;
128
129
  parent: FieldInstanceResult;
130
+ readonly drillExpression: Malloy.Expression | undefined;
129
131
  type: FieldInstanceType;
130
132
  additionalGroupSets: number[];
131
133
  analyticalSQL: string | undefined;
132
134
  partitionSQL: string | undefined;
133
- constructor(f: QueryField, fieldUsage: FieldUsage, parent: FieldInstanceResult);
135
+ constructor(f: QueryField, fieldUsage: FieldUsage, parent: FieldInstanceResult, drillExpression: Malloy.Expression | undefined);
134
136
  root(): FieldInstanceResultRoot;
135
137
  getSQL(): string;
136
138
  getAnalyticalSQL(forPartition: boolean): string;
@@ -161,7 +163,7 @@ declare class FieldInstanceResult implements FieldInstance {
161
163
  * @returns QueryInfo
162
164
  */
163
165
  getQueryInfo(): QueryInfo;
164
- addField(as: string, field: QueryField, usage: FieldUsage): void;
166
+ addField(as: string, field: QueryField, usage: FieldUsage, drillExpression: Malloy.Expression | undefined): void;
165
167
  parentGroupSet(): number;
166
168
  add(name: string, f: FieldInstance): void;
167
169
  hasField(name: string): boolean;
@@ -259,6 +261,7 @@ declare class QueryQuery extends QueryField {
259
261
  addDependantExpr(resultStruct: FieldInstanceResult, context: QueryStruct, e: Expr, joinStack: string[]): void;
260
262
  addDependancies(resultStruct: FieldInstanceResult, field: QueryField): void;
261
263
  getSegmentFields(resultStruct: FieldInstanceResult): SegmentFieldDef[];
264
+ private getDrillExpression;
262
265
  expandFields(resultStruct: FieldInstanceResult): void;
263
266
  expandFilters(resultStruct: FieldInstanceResult): void;
264
267
  generateSQLFilters(resultStruct: FieldInstanceResult, which: 'where' | 'having'): AndChain;
@@ -1,8 +1,4 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryModel = exports.Segment = void 0;
4
- exports.getResultStructDefForView = getResultStructDefForView;
5
- exports.getResultStructDefForQuery = getResultStructDefForQuery;
6
2
  /*
7
3
  * Copyright 2023 Google LLC
8
4
  *
@@ -25,6 +21,10 @@ exports.getResultStructDefForQuery = getResultStructDefForQuery;
25
21
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
23
  */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.QueryModel = exports.Segment = void 0;
26
+ exports.getResultStructDefForView = getResultStructDefForView;
27
+ exports.getResultStructDefForQuery = getResultStructDefForQuery;
28
28
  const uuid_1 = require("uuid");
29
29
  const dialect_1 = require("../dialect");
30
30
  const standardsql_1 = require("../dialect/standardsql/standardsql");
@@ -1124,10 +1124,11 @@ function sqlSumDistinct(dialect, sqlExp, sqlDistintKey) {
1124
1124
  return ret;
1125
1125
  }
1126
1126
  class FieldInstanceField {
1127
- constructor(f, fieldUsage, parent) {
1127
+ constructor(f, fieldUsage, parent, drillExpression) {
1128
1128
  this.f = f;
1129
1129
  this.fieldUsage = fieldUsage;
1130
1130
  this.parent = parent;
1131
+ this.drillExpression = drillExpression;
1131
1132
  this.type = 'field';
1132
1133
  this.additionalGroupSets = [];
1133
1134
  }
@@ -1186,7 +1187,7 @@ class FieldInstanceResult {
1186
1187
  }
1187
1188
  return {};
1188
1189
  }
1189
- addField(as, field, usage) {
1190
+ addField(as, field, usage, drillExpression) {
1190
1191
  const fi = this.allFields.get(as);
1191
1192
  if (fi) {
1192
1193
  if (fi.type === 'query') {
@@ -1203,7 +1204,7 @@ class FieldInstanceResult {
1203
1204
  }
1204
1205
  }
1205
1206
  }
1206
- this.add(as, new FieldInstanceField(field, usage, this));
1207
+ this.add(as, new FieldInstanceField(field, usage, this, drillExpression));
1207
1208
  }
1208
1209
  parentGroupSet() {
1209
1210
  if (this.parent) {
@@ -1828,10 +1829,16 @@ class QueryQuery extends QueryField {
1828
1829
  ? fs.queryFields
1829
1830
  : [];
1830
1831
  }
1832
+ getDrillExpression(f) {
1833
+ if ((0, malloy_types_1.isAtomic)(f) || f.type === 'fieldref')
1834
+ return f.drillExpression;
1835
+ return undefined;
1836
+ }
1831
1837
  expandFields(resultStruct) {
1832
1838
  let resultIndex = 1;
1833
1839
  for (const f of this.getSegmentFields(resultStruct)) {
1834
1840
  const { as, field } = this.expandField(f);
1841
+ const drillExpression = this.getDrillExpression(f);
1835
1842
  if (field instanceof QueryQuery) {
1836
1843
  if (this.firstSegment.type === 'project') {
1837
1844
  throw new Error(`Nested views cannot be used in select - '${field.fieldDef.name}'`);
@@ -1844,7 +1851,7 @@ class QueryQuery extends QueryField {
1844
1851
  resultStruct.addField(as, field, {
1845
1852
  resultIndex,
1846
1853
  type: 'result',
1847
- });
1854
+ }, drillExpression);
1848
1855
  this.addDependancies(resultStruct, field);
1849
1856
  if (isBasicAggregate(field)) {
1850
1857
  if (this.firstSegment.type === 'project') {
@@ -1859,7 +1866,7 @@ class QueryQuery extends QueryField {
1859
1866
  resultStruct.addField(as, field, {
1860
1867
  resultIndex,
1861
1868
  type: 'result',
1862
- });
1869
+ }, drillExpression);
1863
1870
  }
1864
1871
  // else if (
1865
1872
  // this.firstSegment.type === "project" &&
@@ -1950,11 +1957,13 @@ class QueryQuery extends QueryField {
1950
1957
  : undefined;
1951
1958
  const sourceClasses = [sourceField];
1952
1959
  const referenceId = fi.f.referenceId;
1960
+ const drillExpression = fi.drillExpression;
1953
1961
  const base = {
1954
1962
  sourceField,
1955
1963
  sourceExpression,
1956
1964
  sourceClasses,
1957
1965
  referenceId,
1966
+ drillExpression,
1958
1967
  };
1959
1968
  if (isBasicCalculation(fi.f)) {
1960
1969
  filterList = fi.f.getFilterList();
@@ -2020,7 +2029,6 @@ class QueryQuery extends QueryField {
2020
2029
  join: 'many',
2021
2030
  name,
2022
2031
  resultMetadata,
2023
- drillView: fi.turtleDef.drillView,
2024
2032
  };
2025
2033
  fields.push(multiLineNest);
2026
2034
  }
@@ -2031,7 +2039,6 @@ class QueryQuery extends QueryField {
2031
2039
  join: 'one',
2032
2040
  name,
2033
2041
  resultMetadata,
2034
- drillView: fi.turtleDef.drillView,
2035
2042
  };
2036
2043
  fields.push(oneLineNest);
2037
2044
  }
@@ -2060,12 +2067,10 @@ class QueryQuery extends QueryField {
2060
2067
  }
2061
2068
  const location = fOut.location;
2062
2069
  const annotation = fOut.annotation;
2063
- const drillView = (0, malloy_types_1.isAtomic)(fOut) || (0, malloy_types_1.isTurtle)(fOut) ? fOut.drillView : undefined;
2064
2070
  const common = {
2065
2071
  resultMetadata,
2066
2072
  location,
2067
2073
  annotation,
2068
- drillView,
2069
2074
  };
2070
2075
  // build out the result fields...
2071
2076
  switch (fOut.type) {
@@ -2835,7 +2840,6 @@ class QueryQuery extends QueryField {
2835
2840
  type: 'turtle',
2836
2841
  name: 'starthere',
2837
2842
  pipeline,
2838
- drillView: fi.turtleDef.drillView,
2839
2843
  };
2840
2844
  const inputStruct = {
2841
2845
  type: 'nest_source',
@@ -2942,11 +2946,12 @@ class QueryQueryIndexStage extends QueryQuery {
2942
2946
  this.maxGroupSet = groupIndex;
2943
2947
  for (const f of this.firstSegment.indexFields) {
2944
2948
  const { as, field } = this.expandField(f);
2945
- this.indexPaths[as] = f.path;
2949
+ const referencePath = f.path;
2950
+ this.indexPaths[as] = referencePath;
2946
2951
  resultStruct.addField(as, field, {
2947
2952
  resultIndex,
2948
2953
  type: 'result',
2949
- });
2954
+ }, undefined);
2950
2955
  if (field instanceof QueryAtomicField) {
2951
2956
  this.addDependancies(resultStruct, field);
2952
2957
  }
@@ -2958,7 +2963,7 @@ class QueryQueryIndexStage extends QueryQuery {
2958
2963
  resultStruct.addField(measure, f, {
2959
2964
  resultIndex,
2960
2965
  type: 'result',
2961
- });
2966
+ }, undefined);
2962
2967
  this.addDependancies(resultStruct, f);
2963
2968
  }
2964
2969
  this.expandFilters(resultStruct);
@@ -3615,20 +3620,20 @@ class QueryStruct {
3615
3620
  return field;
3616
3621
  }
3617
3622
  getQueryFieldReference(f) {
3618
- const { path, annotation, drillView } = f;
3623
+ const { path, annotation, drillExpression } = f;
3619
3624
  const field = this.getFieldByName(path);
3620
- if (annotation || drillView) {
3625
+ if (annotation || drillExpression) {
3621
3626
  if (field.parent === undefined) {
3622
3627
  throw new Error('Inconcievable, field reference to orphaned query field');
3623
3628
  }
3624
3629
  // Made a field object from the source, but the annotations were computed by the compiler
3625
3630
  // when it generated the reference, and has both the source and reference annotations included.
3626
3631
  if (field instanceof QueryFieldStruct) {
3627
- const newDef = { ...field.fieldDef, annotation, drillView };
3632
+ const newDef = { ...field.fieldDef, annotation, drillExpression };
3628
3633
  return new QueryFieldStruct(newDef, undefined, field.parent, {}, field.referenceId);
3629
3634
  }
3630
3635
  else {
3631
- const newDef = { ...field.fieldDef, annotation, drillView };
3636
+ const newDef = { ...field.fieldDef, annotation, drillExpression };
3632
3637
  return field.parent.makeQueryField(newDef, field.referenceId);
3633
3638
  }
3634
3639
  }
@@ -3683,7 +3688,6 @@ class QueryStruct {
3683
3688
  pipeline,
3684
3689
  annotation,
3685
3690
  location: turtleDef.location,
3686
- drillView: turtleDef.drillView,
3687
3691
  };
3688
3692
  return flatTurtleDef;
3689
3693
  }
@@ -1,4 +1,4 @@
1
- import type { Filter } from '@malloydata/malloy-interfaces';
1
+ import type * as Malloy from '@malloydata/malloy-interfaces';
2
2
  /**
3
3
  * Field computations are compiled into an expression tree of "Expr"
4
4
  * type nodes. Each node is one of these three interfaces. The
@@ -60,8 +60,8 @@ export interface FilterCondition extends ExprE {
60
60
  code: string;
61
61
  expressionType: ExpressionType;
62
62
  fieldUsage?: FieldUsage[];
63
- drillView?: string;
64
- stableFilter?: Filter;
63
+ filterView?: string;
64
+ stableFilter?: Malloy.Filter;
65
65
  isSourceFilter?: boolean;
66
66
  }
67
67
  export interface FilteredExpr extends ExprWithKids {
@@ -265,6 +265,7 @@ export interface Expression {
265
265
  fieldUsage?: FieldUsage[];
266
266
  expressionType?: ExpressionType;
267
267
  code?: string;
268
+ drillExpression?: Malloy.Expression;
268
269
  }
269
270
  type ConstantExpr = Expr;
270
271
  interface ParameterInfo {
@@ -343,6 +344,7 @@ export interface ResultMetadataDef {
343
344
  filterList?: FilterCondition[];
344
345
  fieldKind: 'measure' | 'dimension' | 'struct';
345
346
  referenceId?: string;
347
+ drillExpression?: Malloy.Expression | undefined;
346
348
  drillable?: boolean;
347
349
  }
348
350
  export interface Ordered {
@@ -389,7 +391,7 @@ export interface FieldBase extends NamedObject, Expression, ResultMetadata {
389
391
  accessModifier?: NonDefaultAccessModifierLabel | undefined;
390
392
  requiresGroupBy?: RequiredGroupBy[];
391
393
  ungroupings?: AggregateUngrouping[];
392
- drillView?: string;
394
+ drillExpression?: Malloy.Expression | undefined;
393
395
  }
394
396
  export declare function fieldIsIntrinsic(f: FieldDef): f is AtomicFieldDef;
395
397
  export interface StringTypeDef {
@@ -610,7 +612,6 @@ export interface TurtleDef extends NamedObject, Pipeline {
610
612
  accessModifier?: NonDefaultAccessModifierLabel | undefined;
611
613
  fieldUsage?: FieldUsage[];
612
614
  requiredGroupBys?: string[][];
613
- drillView?: string;
614
615
  }
615
616
  interface StructDefBase extends HasLocation, NamedObject {
616
617
  type: string;
@@ -684,6 +685,7 @@ export type ExpressionValueType = AtomicFieldType | NonAtomicType;
684
685
  export type ExpressionValueTypeDef = AtomicTypeDef | NonAtomicTypeDef;
685
686
  export type BasicExpressionType = Exclude<ExpressionValueType, JoinElementType | 'turtle'>;
686
687
  export interface RequiredGroupBy {
688
+ fieldUsage?: FieldUsage;
687
689
  at?: DocumentLocation;
688
690
  path: string[];
689
691
  }
@@ -799,7 +801,7 @@ export interface RefToField {
799
801
  path: string[];
800
802
  annotation?: Annotation;
801
803
  at?: DocumentLocation;
802
- drillView?: string;
804
+ drillExpression?: Malloy.Expression | undefined;
803
805
  }
804
806
  export type QueryFieldDef = AtomicFieldDef | TurtleDef | RefToField;
805
807
  export type TypedDef = AtomicTypeDef | JoinFieldDef | TurtleDef | RefToField | StructDef;
@@ -1,4 +1,4 @@
1
- import type * as Malloy from '@malloydata/malloy-interfaces';
1
+ import * as Malloy from '@malloydata/malloy-interfaces';
2
2
  import type { FieldDef, ModelDef, ResultStructMetadataDef, SourceDef } from './model';
3
3
  import { Tag } from '@malloydata/malloy-tag';
4
4
  export declare function sourceDefToSourceInfo(sourceDef: SourceDef): Malloy.SourceInfo;
@@ -6,3 +6,15 @@ export declare function modelDefToModelInfo(modelDef: ModelDef): Malloy.ModelInf
6
6
  export declare function convertFieldInfos(source: SourceDef, fields: FieldDef[]): Malloy.FieldInfo[];
7
7
  export declare function writeLiteralToTag(tag: Tag, path: (string | number)[], literal: Malloy.LiteralValue): void;
8
8
  export declare function getResultStructMetadataAnnotation(field: SourceDef, resultMetadata: ResultStructMetadataDef): Malloy.Annotation | undefined;
9
+ /**
10
+ * Writes a Malloy interface object to a tag at a given path.
11
+ *
12
+ * E.g. `writeMalloyObjectToTag(tag, ['expr'], 'Expression', {kind: 'field_reference', name: 'carrier'})`
13
+ *
14
+ * produces the tag `#(malloy) expr { kind = field_reference name = carrier }`
15
+ */
16
+ export declare function writeMalloyObjectToTag(tag: Tag, path: (string | number)[], obj: unknown, type: string): void;
17
+ /**
18
+ * Extracts a Malloy interface object from a tag at a given path; the inverse of `writeMalloyObjectToTag`.
19
+ */
20
+ export declare function extractMalloyObjectFromTag(tag: Tag, type: string): unknown;