@malloydata/malloy 0.0.295 → 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.
@@ -211,6 +211,106 @@ const string_reverse = {
211
211
  returns: 'string',
212
212
  impl: { sql: 'REVERSE(CAST(${str} AS VARCHAR))' },
213
213
  };
214
+ const set_agg = {
215
+ generic: { 'T': ['any'] },
216
+ takes: { 'value': { dimension: T } },
217
+ returns: { measure: { array: T } },
218
+ impl: { function: 'SET_AGG' },
219
+ isSymmetric: true,
220
+ };
221
+ const set_union = {
222
+ generic: { 'T': ['any'] },
223
+ takes: { x: { array: T } },
224
+ returns: { measure: { array: T } },
225
+ impl: { function: 'SET_UNION' },
226
+ };
227
+ const hll_accumulate_moving = {
228
+ preceding: {
229
+ takes: {
230
+ 'value': { dimension: T },
231
+ 'preceding': { literal: 'number' },
232
+ },
233
+ returns: { calculation: { sql_native: 'hyperloglog' } },
234
+ generic: {
235
+ 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
236
+ },
237
+ impl: {
238
+ function: 'APPROX_SET',
239
+ needsWindowOrderBy: true,
240
+ between: { preceding: 'preceding', following: 0 },
241
+ },
242
+ },
243
+ following: {
244
+ takes: {
245
+ 'value': { dimension: T },
246
+ 'preceding': { literal: 'number' },
247
+ 'following': { literal: 'number' },
248
+ },
249
+ returns: { calculation: { sql_native: 'hyperloglog' } },
250
+ generic: {
251
+ 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
252
+ },
253
+ impl: {
254
+ function: 'APPROX_SET',
255
+ needsWindowOrderBy: true,
256
+ between: { preceding: 'preceding', following: 'following' },
257
+ },
258
+ },
259
+ };
260
+ const hll_combine_moving = {
261
+ preceding: {
262
+ takes: {
263
+ 'value': { sql_native: 'hyperloglog' },
264
+ 'preceding': { literal: 'number' },
265
+ },
266
+ returns: { calculation: { sql_native: 'hyperloglog' } },
267
+ impl: {
268
+ function: 'MERGE',
269
+ needsWindowOrderBy: true,
270
+ between: { preceding: 'preceding', following: 0 },
271
+ },
272
+ },
273
+ following: {
274
+ takes: {
275
+ 'value': { sql_native: 'hyperloglog' },
276
+ 'preceding': { literal: 'number' },
277
+ 'following': { literal: 'number' },
278
+ },
279
+ returns: { calculation: { sql_native: 'hyperloglog' } },
280
+ impl: {
281
+ function: 'MERGE',
282
+ needsWindowOrderBy: true,
283
+ between: { preceding: 'preceding', following: 'following' },
284
+ },
285
+ },
286
+ };
287
+ const hll_estimate_moving = {
288
+ preceding: {
289
+ takes: {
290
+ 'value': { sql_native: 'hyperloglog' },
291
+ 'preceding': { literal: 'number' },
292
+ },
293
+ returns: { calculation: 'number' },
294
+ impl: {
295
+ function: 'CARDINALITY',
296
+ needsWindowOrderBy: true,
297
+ between: { preceding: 'preceding', following: 0 },
298
+ },
299
+ },
300
+ following: {
301
+ takes: {
302
+ 'value': { sql_native: 'hyperloglog' },
303
+ 'preceding': { literal: 'number' },
304
+ 'following': { literal: 'number' },
305
+ },
306
+ returns: { calculation: 'number' },
307
+ impl: {
308
+ function: 'CARDINALITY',
309
+ needsWindowOrderBy: true,
310
+ between: { preceding: 'preceding', following: 'following' },
311
+ },
312
+ },
313
+ };
214
314
  /**
215
315
  * This map is for functions which exist in both Presto and Trino.
216
316
  * If you are adding functions which only exist in Presto, put them in
@@ -223,6 +323,10 @@ exports.TRINO_DIALECT_FUNCTIONS = {
223
323
  // string functions
224
324
  reverse: string_reverse,
225
325
  // aggregate functions
326
+ max_by,
327
+ min_by,
328
+ string_agg,
329
+ string_agg_distinct,
226
330
  // TODO: Approx percentile can be called with a third argument; we probably
227
331
  // want to implement that at some point
228
332
  // In Presto, this is an "error" parameter between 0 and 1
@@ -284,10 +388,9 @@ exports.TRINO_DIALECT_FUNCTIONS = {
284
388
  returns: { dimension: { sql_native: 'hyperloglog' } },
285
389
  impl: { sql: 'CAST(${value} AS HyperLogLog)' },
286
390
  },
287
- max_by,
288
- min_by,
289
- string_agg,
290
- string_agg_distinct,
391
+ hll_accumulate_moving,
392
+ hll_combine_moving,
393
+ hll_estimate_moving,
291
394
  ...(0, util_1.def)('variance', { 'n': 'number' }, { measure: 'number' }),
292
395
  // scalar functions
293
396
  ...(0, util_1.def)('bitwise_and', { 'val1': 'number', 'val2': 'number' }, 'number'),
@@ -315,6 +418,8 @@ exports.TRINO_DIALECT_FUNCTIONS = {
315
418
  array_agg_distinct,
316
419
  array_join,
317
420
  sequence,
421
+ set_agg,
422
+ set_union,
318
423
  ...(0, util_1.def)('array_distinct', { 'x': { array: T } }, { array: T }),
319
424
  ...(0, util_1.def)('array_except', { 'x': { array: T }, 'y': { array: T } }, { array: T }),
320
425
  ...(0, util_1.def)('array_intersect', { 'x': { array: T }, 'y': { array: T } }, { array: T }),
@@ -402,5 +507,38 @@ exports.PRESTO_DIALECT_FUNCTIONS = {
402
507
  impl: { sql: 'APPROX_SET(${value}, 0.0040625)' },
403
508
  },
404
509
  },
510
+ hll_accumulate_moving: {
511
+ preceding: {
512
+ takes: {
513
+ 'value': { dimension: T },
514
+ 'preceding': { literal: 'number' },
515
+ },
516
+ returns: { calculation: { sql_native: 'hyperloglog' } },
517
+ generic: {
518
+ 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
519
+ },
520
+ impl: {
521
+ sql: 'APPROX_SET(${value}, 0.0040625)',
522
+ needsWindowOrderBy: true,
523
+ between: { preceding: 'preceding', following: 0 },
524
+ },
525
+ },
526
+ following: {
527
+ takes: {
528
+ 'value': { dimension: T },
529
+ 'preceding': { literal: 'number' },
530
+ 'following': { literal: 'number' },
531
+ },
532
+ returns: { calculation: { sql_native: 'hyperloglog' } },
533
+ generic: {
534
+ 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
535
+ },
536
+ impl: {
537
+ sql: 'APPROX_SET(${value}, 0.0040625)',
538
+ needsWindowOrderBy: true,
539
+ between: { preceding: 'preceding', following: 'following' },
540
+ },
541
+ },
542
+ },
405
543
  };
406
544
  //# sourceMappingURL=dialect_functions.js.map
@@ -133,17 +133,17 @@ class ReferenceField extends space_field_1.SpaceField {
133
133
  if (refTo) {
134
134
  const joinPath = this.fieldRef.list.slice(0, -1).map(x => x.refString);
135
135
  const typeDesc = refTo.typeDesc();
136
+ const usage = {
137
+ path: this.fieldRef.path,
138
+ at: this.fieldRef.location,
139
+ };
136
140
  this.memoTypeDesc = {
137
141
  ...typeDesc,
138
- fieldUsage: [
139
- {
140
- path: this.fieldRef.path,
141
- at: this.fieldRef.location,
142
- },
143
- ],
142
+ fieldUsage: [usage],
144
143
  requiresGroupBy: (_a = typeDesc.requiresGroupBy) === null || _a === void 0 ? void 0 : _a.map(gb => ({
145
144
  ...gb,
146
145
  path: [...joinPath, ...gb.path],
146
+ fieldUsage: usage,
147
147
  })),
148
148
  };
149
149
  return this.memoTypeDesc;
@@ -1,4 +1,4 @@
1
- import type { FieldUsage, DocumentLocation, ExpressionValueType } from '../model/malloy_types';
1
+ import type { DocumentLocation, ExpressionValueType } from '../model/malloy_types';
2
2
  import type { EventStream } from '../runtime_types';
3
3
  export type LogSeverity = 'error' | 'warn' | 'debug';
4
4
  /**
@@ -159,11 +159,6 @@ type MessageParameterTypes = {
159
159
  'field-not-found': string;
160
160
  'composite-field-type-mismatch': string;
161
161
  'invalid-composite-source-input': string;
162
- 'invalid-composite-field-usage': {
163
- newUsage: FieldUsage[];
164
- allUsage: FieldUsage[];
165
- conflictingUsage: FieldUsage[];
166
- };
167
162
  'could-not-resolve-composite-source': string;
168
163
  'empty-composite-source': string;
169
164
  'unnecessary-composite-source': string;
@@ -24,7 +24,6 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.MESSAGE_FORMATTERS = exports.BaseMessageLogger = void 0;
26
26
  exports.makeLogMessage = makeLogMessage;
27
- const composite_source_utils_1 = require("../model/composite_source_utils");
28
27
  class BaseMessageLogger {
29
28
  constructor(eventStream) {
30
29
  this.eventStream = eventStream;
@@ -96,13 +95,6 @@ exports.MESSAGE_FORMATTERS = {
96
95
  'case-else-type-does-not-match': e => `Case else type ${e.elseType} does not match return type ${e.returnType}`,
97
96
  'case-when-must-be-boolean': e => `Case when expression must be boolean, not ${e.whenType}`,
98
97
  'case-when-type-does-not-match': e => `Case when type ${e.whenType} does not match value type ${e.valueType}`,
99
- 'invalid-composite-field-usage': e => {
100
- const formattedNewCompositeUsage = (0, composite_source_utils_1.formatFieldUsages)(e.newUsage);
101
- const formattedConflictingCompositeUsage = (0, composite_source_utils_1.formatFieldUsages)(e.conflictingUsage);
102
- const formattedAllCompositeUsage = (0, composite_source_utils_1.formatFieldUsages)(e.allUsage);
103
- const pluralUse = (0, composite_source_utils_1.fieldUsageIsPlural)(e.newUsage) ? 's' : '';
104
- return `This operation uses field${pluralUse} ${formattedNewCompositeUsage}, resulting in invalid usage of the composite source, as there is no composite input source which defines all of ${formattedConflictingCompositeUsage}\nFields required in source: ${formattedAllCompositeUsage}`;
105
- },
106
98
  };
107
99
  function makeLogMessage(code, parameters, options) {
108
100
  var _a, _b, _c, _d, _e;
@@ -84,7 +84,6 @@ export declare function fieldUsageJoinPaths(fieldUsage: FieldUsage[]): string[][
84
84
  export declare function checkRequiredGroupBys(compositeResolvedSourceDef: SourceDef, segment: PipeSegment): RequiredGroupBy[];
85
85
  export declare function pathEq(a: string[], b: string[]): boolean;
86
86
  export declare function pathBegins(path: string[], prefix: string[]): boolean;
87
- export declare function sortFieldUsageByReferenceLocation(usage: FieldUsage[]): FieldUsage[];
88
87
  export declare function hasCompositesAnywhere(source: StructDef): boolean;
89
88
  export declare function logCompositeError(error: CompositeError, logTo: MalloyElement): void;
90
89
  export declare function compileFilterExpression(ft: string, fexpr: Expr): {
@@ -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');
@@ -685,6 +685,7 @@ export type ExpressionValueType = AtomicFieldType | NonAtomicType;
685
685
  export type ExpressionValueTypeDef = AtomicTypeDef | NonAtomicTypeDef;
686
686
  export type BasicExpressionType = Exclude<ExpressionValueType, JoinElementType | 'turtle'>;
687
687
  export interface RequiredGroupBy {
688
+ fieldUsage?: FieldUsage;
688
689
  at?: DocumentLocation;
689
690
  path: string[];
690
691
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.295";
1
+ export declare const MALLOY_VERSION = "0.0.296";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.295';
5
+ exports.MALLOY_VERSION = '0.0.296';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.295",
3
+ "version": "0.0.296",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -41,9 +41,9 @@
41
41
  "generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
42
42
  },
43
43
  "dependencies": {
44
- "@malloydata/malloy-filter": "0.0.295",
45
- "@malloydata/malloy-interfaces": "0.0.295",
46
- "@malloydata/malloy-tag": "0.0.295",
44
+ "@malloydata/malloy-filter": "0.0.296",
45
+ "@malloydata/malloy-interfaces": "0.0.296",
46
+ "@malloydata/malloy-tag": "0.0.296",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jaro-winkler": "^0.2.8",