@malloydata/malloy 0.0.203-dev241021134413 → 0.0.203-dev241022191525

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 (37) hide show
  1. package/dist/dialect/dialect.d.ts +11 -0
  2. package/dist/dialect/dialect.js +27 -0
  3. package/dist/dialect/duckdb/duckdb.js +2 -2
  4. package/dist/dialect/mysql/mysql.js +12 -15
  5. package/dist/dialect/pg_impl.js +7 -9
  6. package/dist/dialect/snowflake/snowflake.js +12 -17
  7. package/dist/dialect/standardsql/standardsql.js +13 -16
  8. package/dist/dialect/trino/trino.js +9 -12
  9. package/dist/lang/ast/expressions/expr-granular-time.js +1 -1
  10. package/dist/lang/ast/expressions/expr-record-literal.d.ts +1 -1
  11. package/dist/lang/ast/expressions/expr-record-literal.js +28 -25
  12. package/dist/lang/ast/expressions/expr-time-extract.js +3 -3
  13. package/dist/lang/ast/expressions/expr-time.js +2 -2
  14. package/dist/lang/ast/expressions/for-range.js +1 -1
  15. package/dist/lang/ast/expressions/time-literal.js +1 -1
  16. package/dist/lang/ast/query-builders/index-builder.d.ts +1 -0
  17. package/dist/lang/ast/query-builders/index-builder.js +4 -0
  18. package/dist/lang/ast/query-builders/reduce-builder.d.ts +1 -0
  19. package/dist/lang/ast/query-builders/reduce-builder.js +4 -0
  20. package/dist/lang/ast/source-properties/join.js +1 -0
  21. package/dist/lang/ast/time-utils.d.ts +1 -3
  22. package/dist/lang/ast/time-utils.js +24 -34
  23. package/dist/lang/ast/types/expression-def.js +2 -2
  24. package/dist/lang/ast/types/query-builder.d.ts +1 -0
  25. package/dist/lang/lib/Malloy/MalloyParser.d.ts +49 -14
  26. package/dist/lang/lib/Malloy/MalloyParser.js +1784 -1538
  27. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +48 -11
  28. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +30 -7
  29. package/dist/lang/malloy-to-ast.d.ts +4 -1
  30. package/dist/lang/malloy-to-ast.js +21 -32
  31. package/dist/lang/test/query.spec.js +7 -2
  32. package/dist/lang/test/test-translator.js +1 -1
  33. package/dist/model/malloy_query.d.ts +1 -0
  34. package/dist/model/malloy_query.js +15 -1
  35. package/dist/model/malloy_types.d.ts +43 -14
  36. package/dist/model/malloy_types.js +83 -2
  37. package/package.json +1 -1
@@ -24,6 +24,8 @@ import { TableMethodContext } from "./MalloyParser";
24
24
  import { NestDefContext } from "./MalloyParser";
25
25
  import { ExprFieldPathContext } from "./MalloyParser";
26
26
  import { ExprLiteralContext } from "./MalloyParser";
27
+ import { ExprArrayLiteralContext } from "./MalloyParser";
28
+ import { ExprLiteralRecordContext } from "./MalloyParser";
27
29
  import { ExprFieldPropsContext } from "./MalloyParser";
28
30
  import { ExprDurationContext } from "./MalloyParser";
29
31
  import { ExprTimeTruncContext } from "./MalloyParser";
@@ -215,10 +217,11 @@ import { CollectionMemberContext } from "./MalloyParser";
215
217
  import { FieldPathContext } from "./MalloyParser";
216
218
  import { JoinNameContext } from "./MalloyParser";
217
219
  import { FieldNameContext } from "./MalloyParser";
218
- import { JustExprContext } from "./MalloyParser";
219
220
  import { SqlExploreNameRefContext } from "./MalloyParser";
220
221
  import { NameSQLBlockContext } from "./MalloyParser";
221
222
  import { ConnectionNameContext } from "./MalloyParser";
223
+ import { DebugExprContext } from "./MalloyParser";
224
+ import { DebugPartialContext } from "./MalloyParser";
222
225
  import { ExperimentalStatementForTestingContext } from "./MalloyParser";
223
226
  /**
224
227
  * This interface defines a complete listener for a parse tree produced by
@@ -525,6 +528,30 @@ export interface MalloyParserListener extends ParseTreeListener {
525
528
  * @param ctx the parse tree
526
529
  */
527
530
  exitExprLiteral?: (ctx: ExprLiteralContext) => void;
531
+ /**
532
+ * Enter a parse tree produced by the `exprArrayLiteral`
533
+ * labeled alternative in `MalloyParser.fieldExpr`.
534
+ * @param ctx the parse tree
535
+ */
536
+ enterExprArrayLiteral?: (ctx: ExprArrayLiteralContext) => void;
537
+ /**
538
+ * Exit a parse tree produced by the `exprArrayLiteral`
539
+ * labeled alternative in `MalloyParser.fieldExpr`.
540
+ * @param ctx the parse tree
541
+ */
542
+ exitExprArrayLiteral?: (ctx: ExprArrayLiteralContext) => void;
543
+ /**
544
+ * Enter a parse tree produced by the `exprLiteralRecord`
545
+ * labeled alternative in `MalloyParser.fieldExpr`.
546
+ * @param ctx the parse tree
547
+ */
548
+ enterExprLiteralRecord?: (ctx: ExprLiteralRecordContext) => void;
549
+ /**
550
+ * Exit a parse tree produced by the `exprLiteralRecord`
551
+ * labeled alternative in `MalloyParser.fieldExpr`.
552
+ * @param ctx the parse tree
553
+ */
554
+ exitExprLiteralRecord?: (ctx: ExprLiteralRecordContext) => void;
528
555
  /**
529
556
  * Enter a parse tree produced by the `exprFieldProps`
530
557
  * labeled alternative in `MalloyParser.fieldExpr`.
@@ -2549,16 +2576,6 @@ export interface MalloyParserListener extends ParseTreeListener {
2549
2576
  * @param ctx the parse tree
2550
2577
  */
2551
2578
  exitFieldName?: (ctx: FieldNameContext) => void;
2552
- /**
2553
- * Enter a parse tree produced by `MalloyParser.justExpr`.
2554
- * @param ctx the parse tree
2555
- */
2556
- enterJustExpr?: (ctx: JustExprContext) => void;
2557
- /**
2558
- * Exit a parse tree produced by `MalloyParser.justExpr`.
2559
- * @param ctx the parse tree
2560
- */
2561
- exitJustExpr?: (ctx: JustExprContext) => void;
2562
2579
  /**
2563
2580
  * Enter a parse tree produced by `MalloyParser.sqlExploreNameRef`.
2564
2581
  * @param ctx the parse tree
@@ -2589,6 +2606,26 @@ export interface MalloyParserListener extends ParseTreeListener {
2589
2606
  * @param ctx the parse tree
2590
2607
  */
2591
2608
  exitConnectionName?: (ctx: ConnectionNameContext) => void;
2609
+ /**
2610
+ * Enter a parse tree produced by `MalloyParser.debugExpr`.
2611
+ * @param ctx the parse tree
2612
+ */
2613
+ enterDebugExpr?: (ctx: DebugExprContext) => void;
2614
+ /**
2615
+ * Exit a parse tree produced by `MalloyParser.debugExpr`.
2616
+ * @param ctx the parse tree
2617
+ */
2618
+ exitDebugExpr?: (ctx: DebugExprContext) => void;
2619
+ /**
2620
+ * Enter a parse tree produced by `MalloyParser.debugPartial`.
2621
+ * @param ctx the parse tree
2622
+ */
2623
+ enterDebugPartial?: (ctx: DebugPartialContext) => void;
2624
+ /**
2625
+ * Exit a parse tree produced by `MalloyParser.debugPartial`.
2626
+ * @param ctx the parse tree
2627
+ */
2628
+ exitDebugPartial?: (ctx: DebugPartialContext) => void;
2592
2629
  /**
2593
2630
  * Enter a parse tree produced by `MalloyParser.experimentalStatementForTesting`.
2594
2631
  * @param ctx the parse tree
@@ -24,6 +24,8 @@ import { TableMethodContext } from "./MalloyParser";
24
24
  import { NestDefContext } from "./MalloyParser";
25
25
  import { ExprFieldPathContext } from "./MalloyParser";
26
26
  import { ExprLiteralContext } from "./MalloyParser";
27
+ import { ExprArrayLiteralContext } from "./MalloyParser";
28
+ import { ExprLiteralRecordContext } from "./MalloyParser";
27
29
  import { ExprFieldPropsContext } from "./MalloyParser";
28
30
  import { ExprDurationContext } from "./MalloyParser";
29
31
  import { ExprTimeTruncContext } from "./MalloyParser";
@@ -215,10 +217,11 @@ import { CollectionMemberContext } from "./MalloyParser";
215
217
  import { FieldPathContext } from "./MalloyParser";
216
218
  import { JoinNameContext } from "./MalloyParser";
217
219
  import { FieldNameContext } from "./MalloyParser";
218
- import { JustExprContext } from "./MalloyParser";
219
220
  import { SqlExploreNameRefContext } from "./MalloyParser";
220
221
  import { NameSQLBlockContext } from "./MalloyParser";
221
222
  import { ConnectionNameContext } from "./MalloyParser";
223
+ import { DebugExprContext } from "./MalloyParser";
224
+ import { DebugPartialContext } from "./MalloyParser";
222
225
  import { ExperimentalStatementForTestingContext } from "./MalloyParser";
223
226
  /**
224
227
  * This interface defines a complete generic visitor for a parse tree produced
@@ -403,6 +406,20 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
403
406
  * @return the visitor result
404
407
  */
405
408
  visitExprLiteral?: (ctx: ExprLiteralContext) => Result;
409
+ /**
410
+ * Visit a parse tree produced by the `exprArrayLiteral`
411
+ * labeled alternative in `MalloyParser.fieldExpr`.
412
+ * @param ctx the parse tree
413
+ * @return the visitor result
414
+ */
415
+ visitExprArrayLiteral?: (ctx: ExprArrayLiteralContext) => Result;
416
+ /**
417
+ * Visit a parse tree produced by the `exprLiteralRecord`
418
+ * labeled alternative in `MalloyParser.fieldExpr`.
419
+ * @param ctx the parse tree
420
+ * @return the visitor result
421
+ */
422
+ visitExprLiteralRecord?: (ctx: ExprLiteralRecordContext) => Result;
406
423
  /**
407
424
  * Visit a parse tree produced by the `exprFieldProps`
408
425
  * labeled alternative in `MalloyParser.fieldExpr`.
@@ -1606,12 +1623,6 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
1606
1623
  * @return the visitor result
1607
1624
  */
1608
1625
  visitFieldName?: (ctx: FieldNameContext) => Result;
1609
- /**
1610
- * Visit a parse tree produced by `MalloyParser.justExpr`.
1611
- * @param ctx the parse tree
1612
- * @return the visitor result
1613
- */
1614
- visitJustExpr?: (ctx: JustExprContext) => Result;
1615
1626
  /**
1616
1627
  * Visit a parse tree produced by `MalloyParser.sqlExploreNameRef`.
1617
1628
  * @param ctx the parse tree
@@ -1630,6 +1641,18 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
1630
1641
  * @return the visitor result
1631
1642
  */
1632
1643
  visitConnectionName?: (ctx: ConnectionNameContext) => Result;
1644
+ /**
1645
+ * Visit a parse tree produced by `MalloyParser.debugExpr`.
1646
+ * @param ctx the parse tree
1647
+ * @return the visitor result
1648
+ */
1649
+ visitDebugExpr?: (ctx: DebugExprContext) => Result;
1650
+ /**
1651
+ * Visit a parse tree produced by `MalloyParser.debugPartial`.
1652
+ * @param ctx the parse tree
1653
+ * @return the visitor result
1654
+ */
1655
+ visitDebugPartial?: (ctx: DebugPartialContext) => Result;
1633
1656
  /**
1634
1657
  * Visit a parse tree produced by `MalloyParser.experimentalStatementForTesting`.
1635
1658
  * @param ctx the parse tree
@@ -200,7 +200,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
200
200
  visitLiteralQuarter(pcx: parse.LiteralQuarterContext): ast.ExpressionDef;
201
201
  visitLiteralYear(pcx: parse.LiteralYearContext): ast.ExpressionDef;
202
202
  visitImportStatement(pcx: parse.ImportStatementContext): ast.ImportStatement;
203
- visitJustExpr(pcx: parse.JustExprContext): ast.ExpressionDef;
203
+ visitDebugExpr(pcx: parse.DebugExprContext): ast.ExpressionDef;
204
204
  visitSampleStatement(pcx: parse.SampleStatementContext): ast.SampleProperty;
205
205
  visitDocAnnotations(pcx: parse.DocAnnotationsContext): ast.ModelAnnotation;
206
206
  visitIgnoredObjectAnnotations(pcx: parse.IgnoredObjectAnnotationsContext): IgnoredElement;
@@ -224,6 +224,9 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
224
224
  visitSQTable(pcx: parse.SQTableContext): ast.SQSource | ErrorNode;
225
225
  visitSQSQL(pcx: parse.SQSQLContext): ast.SQSource;
226
226
  visitExperimentalStatementForTesting(pcx: parse.ExperimentalStatementForTestingContext): ast.ExperimentalExperiment;
227
+ visitRecordRef(pcx: parse.RecordRefContext): ast.RecordElement;
228
+ visitRecordExpr(pcx: parse.RecordExprContext): ast.RecordElement;
229
+ visitExprLiteralRecord(pcx: parse.ExprLiteralRecordContext): ast.RecordLiteral;
227
230
  visitExprWarnLike(pcx: parse.ExprWarnLikeContext): ast.ExprCompare;
228
231
  visitExprWarnNullCmp(pcx: parse.ExprWarnNullCmpContext): ast.ExprCompare;
229
232
  visitExprWarnIn(pcx: parse.ExprWarnInContext): ast.ExprLegacyIn;
@@ -419,9 +419,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
419
419
  return { joinAs, joinFrom: new ast.SQReference(joinAs), notes: [] };
420
420
  }
421
421
  visitQueryJoinStatement(pcx) {
422
- const result = this.astAt(this.visit(pcx.joinStatement()), pcx);
423
- this.m4advisory(pcx, 'join-statement-in-view', 'Joins in queries are deprecated, move into an `extend:` block.');
424
- return result;
422
+ return this.astAt(this.visit(pcx.joinStatement()), pcx);
425
423
  }
426
424
  visitJoinOn(pcx) {
427
425
  var _a;
@@ -1203,7 +1201,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1203
1201
  }
1204
1202
  return importStmt;
1205
1203
  }
1206
- visitJustExpr(pcx) {
1204
+ visitDebugExpr(pcx) {
1207
1205
  return this.getFieldExpr(pcx.fieldExpr());
1208
1206
  }
1209
1207
  visitSampleStatement(pcx) {
@@ -1336,34 +1334,25 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1336
1334
  this.inExperiment('compilerTestExperimentParse', pcx);
1337
1335
  return this.astAt(new ast.ExperimentalExperiment('compilerTestExperimentTranslate'), pcx);
1338
1336
  }
1339
- // visitRecordRef(pcx: parse.RecordRefContext) {
1340
- // const pathCx = pcx.fieldPath();
1341
- // const tailEl = pathCx.fieldName().at(-1);
1342
- // if (tailEl) {
1343
- // const elementKey = getId(tailEl);
1344
- // const idRef = new ast.ExprIdReference(
1345
- // this.getFieldPath(pathCx, ast.ExpressionFieldReference)
1346
- // );
1347
- // return new ast.RecordElement(elementKey, idRef);
1348
- // }
1349
- // throw this.internalError(
1350
- // pathCx,
1351
- // 'IMPOSSIBLY A PATH CONTAINED ZERO ELEMENTS'
1352
- // );
1353
- // }
1354
- // visitRecordExpr(pcx: parse.RecordExprContext) {
1355
- // const elementKey = getId(pcx.recordKey());
1356
- // const elementVal = this.getFieldExpr(pcx.fieldExpr());
1357
- // return new ast.RecordElement(elementKey, elementVal);
1358
- // }
1359
- // visitExprLiteralRecord(pcx: parse.ExprLiteralRecordContext) {
1360
- // const els = this.only<ast.RecordElement>(
1361
- // pcx.recordElement().map(elCx => this.astAt(this.visit(elCx), elCx)),
1362
- // visited => visited instanceof ast.RecordElement && visited,
1363
- // 'a key value pair'
1364
- // );
1365
- // return new ast.RecordLiteral(els);
1366
- // }
1337
+ visitRecordRef(pcx) {
1338
+ const pathCx = pcx.fieldPath();
1339
+ const tailEl = pathCx.fieldName().at(-1);
1340
+ if (tailEl) {
1341
+ const elementKey = (0, parse_utils_1.getId)(tailEl);
1342
+ const idRef = new ast.ExprIdReference(this.getFieldPath(pathCx, ast.ExpressionFieldReference));
1343
+ return new ast.RecordElement(elementKey, idRef);
1344
+ }
1345
+ throw this.internalError(pathCx, 'IMPOSSIBLY A PATH CONTAINED ZERO ELEMENTS');
1346
+ }
1347
+ visitRecordExpr(pcx) {
1348
+ const elementKey = (0, parse_utils_1.getId)(pcx.recordKey());
1349
+ const elementVal = this.getFieldExpr(pcx.fieldExpr());
1350
+ return new ast.RecordElement(elementKey, elementVal);
1351
+ }
1352
+ visitExprLiteralRecord(pcx) {
1353
+ const els = this.only(pcx.recordElement().map(elCx => this.astAt(this.visit(elCx), elCx)), visited => visited instanceof ast.RecordElement && visited, 'a key value pair');
1354
+ return new ast.RecordLiteral(els);
1355
+ }
1367
1356
  visitExprWarnLike(pcx) {
1368
1357
  let op = '~';
1369
1358
  const left = pcx.fieldExpr(0);
@@ -923,8 +923,13 @@ describe('query:', () => {
923
923
  source: a2 is a extend { ${'declare: x is 1'} }`).toLog((0, test_translator_1.warningMessage)('`declare:` is deprecated; use `dimension:` or `measure:` inside a source or `extend:` block'));
924
924
  });
925
925
  test('joins in query', () => {
926
- expect((0, test_translator_1.markSource) `##! m4warnings=warn
927
- run: a -> { ${'join_one: b on true'}; ${'join_many: c is b on true'}; ${'join_cross: d is b on true'}; group_by: b.astr }`).toLog((0, test_translator_1.warningMessage)('Joins in queries are deprecated, move into an `extend:` block.'), (0, test_translator_1.warningMessage)('Joins in queries are deprecated, move into an `extend:` block.'), (0, test_translator_1.warningMessage)('Joins in queries are deprecated, move into an `extend:` block.'));
926
+ expect((0, test_translator_1.markSource) `
927
+ run: a -> {
928
+ join_one: b on true
929
+ join_many: c is b on true
930
+ join_cross: d is b on true
931
+ group_by: b.astr
932
+ }`).toTranslate();
928
933
  });
929
934
  });
930
935
  test('refine query with extended source', () => {
@@ -387,7 +387,7 @@ exports.TestTranslator = TestTranslator;
387
387
  TestTranslator.inspectCompile = false;
388
388
  class BetaExpression extends TestTranslator {
389
389
  constructor(src) {
390
- super(src, null, null, 'justExpr');
390
+ super(src, null, null, 'debugExpr');
391
391
  }
392
392
  testFS() {
393
393
  const aStruct = this.internalModel.contents['ab'];
@@ -264,6 +264,7 @@ declare class QueryQuery extends QueryField {
264
264
  expandFilters(resultStruct: FieldInstanceResult): void;
265
265
  generateSQLFilters(resultStruct: FieldInstanceResult, which: 'where' | 'having'): AndChain;
266
266
  prepare(_stageWriter: StageWriter | undefined): void;
267
+ addAlwaysJoins(rootResult: FieldInstanceResultRoot): void;
267
268
  getResultMetadata(fi: FieldInstance): ResultStructMetadataDef | ResultMetadataDef | undefined;
268
269
  /** returns a fields and primary key of a struct for this query */
269
270
  getResultStructDef(resultStruct?: FieldInstanceResult, isRoot?: boolean): SourceDef;
@@ -965,7 +965,7 @@ class QueryFieldDate extends QueryAtomicField {
965
965
  else {
966
966
  const truncated = {
967
967
  node: 'trunc',
968
- e: { ...this.getExpr(), dataType: 'date' },
968
+ e: (0, malloy_types_1.mkTemporal)(this.getExpr(), 'date'),
969
969
  units: fd.timeframe,
970
970
  };
971
971
  return this.exprToSQL(resultSet, this.parent, truncated);
@@ -1802,10 +1802,24 @@ class QueryQuery extends QueryField {
1802
1802
  this.expandFields(this.rootResult);
1803
1803
  this.rootResult.addStructToJoin(this.parent, this, undefined, []);
1804
1804
  this.rootResult.findJoins(this);
1805
+ this.addAlwaysJoins(this.rootResult);
1805
1806
  this.rootResult.calculateSymmetricAggregates();
1806
1807
  this.prepared = true;
1807
1808
  }
1808
1809
  }
1810
+ addAlwaysJoins(rootResult) {
1811
+ var _a;
1812
+ const stage = this.fieldDef.pipeline[0];
1813
+ if (stage.type !== 'raw') {
1814
+ const alwaysJoins = (_a = stage.alwaysJoins) !== null && _a !== void 0 ? _a : [];
1815
+ for (const joinName of alwaysJoins) {
1816
+ const qs = this.parent.getChildByName(joinName);
1817
+ if (qs instanceof QueryStruct) {
1818
+ rootResult.addStructToJoin(qs, this, undefined, []);
1819
+ }
1820
+ }
1821
+ }
1822
+ }
1809
1823
  // get the source fieldname and filters associated with the field (so we can drill later)
1810
1824
  getResultMetadata(fi) {
1811
1825
  if (fi instanceof FieldInstanceField) {
@@ -8,7 +8,7 @@
8
8
  */
9
9
  export interface ExprLeaf {
10
10
  node: string;
11
- dataType?: AtomicFieldType;
11
+ typeDef?: AtomicTypeDef;
12
12
  sql?: string;
13
13
  }
14
14
  export interface ExprE extends ExprLeaf {
@@ -24,11 +24,11 @@ export type AnyExpr = ExprE | ExprOptionalE | ExprWithKids | ExprLeaf;
24
24
  export declare function exprHasKids(e: AnyExpr): e is ExprWithKids;
25
25
  export declare function exprHasE(e: AnyExpr): e is ExprE;
26
26
  export declare function exprIsLeaf(e: AnyExpr): boolean;
27
- export type Expr = BinaryExpr | UnaryExpr | FunctionCallNode | OutputFieldNode | FilterCondition | FilteredExpr | AggregateExpr | EmptyExpr | UngroupNode | FunctionParameterNode | SpreadExpr | AggregateOrderByNode | AggregateLimitNode | FieldnameNode | SourceReferenceNode | ParameterNode | NowNode | MeasureTimeExpr | TimeDeltaExpr | TimeTruncExpr | TimeExtractExpr | TypecastExpr | RegexMatchExpr | RegexLiteralNode | TimeLiteralNode | StringLiteralNode | NumberLiteralNode | BooleanLiteralNode | RecordLiteralNode | ArrayLiteralNode | FunctionOrderBy | GenericSQLExpr | NullNode | CaseExpr | InCompareExpr | ErrorNode;
28
- interface HasDataType {
29
- dataType: AtomicFieldType;
27
+ export type Expr = BinaryExpr | UnaryExpr | FunctionCallNode | OutputFieldNode | FilterCondition | FilteredExpr | AggregateExpr | EmptyExpr | UngroupNode | FunctionParameterNode | SpreadExpr | AggregateOrderByNode | AggregateLimitNode | FieldnameNode | SourceReferenceNode | ParameterNode | NowNode | MeasureTimeExpr | TimeExtractExpr | TimeDeltaExpr | TimeTruncExpr | TimeLiteralNode | TypecastExpr | RegexMatchExpr | RegexLiteralNode | StringLiteralNode | NumberLiteralNode | BooleanLiteralNode | RecordLiteralNode | ArrayLiteralNode | FunctionOrderBy | GenericSQLExpr | NullNode | CaseExpr | InCompareExpr | ErrorNode;
28
+ interface HasTypeDef {
29
+ typeDef: AtomicTypeDef;
30
30
  }
31
- export type TypedExpr = Expr & HasDataType;
31
+ export type TypedExpr = Expr & HasTypeDef;
32
32
  export type BinaryOperator = '+' | '-' | '*' | '%' | '/' | 'and' | 'or' | '=' | '!=' | '>' | '<' | '>=' | '<=' | 'coalesce' | 'like' | '!like';
33
33
  export interface BinaryExpr extends ExprWithKids {
34
34
  node: BinaryOperator;
@@ -118,9 +118,10 @@ export interface NowNode extends ExprLeaf {
118
118
  node: 'now';
119
119
  }
120
120
  interface HasTimeValue {
121
- dataType: TemporalFieldType;
121
+ typeDef: TemporalTypeDef;
122
122
  }
123
123
  type TimeExpr = Expr & HasTimeValue;
124
+ export declare function mkTemporal(e: Expr, timeType: TemporalTypeDef | TemporalFieldType): TimeExpr;
124
125
  export interface MeasureTimeExpr extends ExprWithKids {
125
126
  node: 'timeDiff';
126
127
  units: TimestampUnit;
@@ -148,15 +149,22 @@ export interface TimeExtractExpr extends ExprE {
148
149
  e: TimeExpr;
149
150
  units: ExtractUnit;
150
151
  }
151
- export interface TypecastExpr extends ExprE {
152
+ export interface MalloyTypecastExpr extends ExprE {
152
153
  node: 'cast';
153
154
  safe: boolean;
154
155
  e: Expr;
155
- dstType: CastType | {
156
- raw: string;
157
- };
158
- srcType?: AtomicFieldType;
156
+ dstType: LeafAtomicTypeDef;
157
+ srcType?: LeafAtomicTypeDef;
158
+ }
159
+ interface RawTypeCastExpr extends ExprE {
160
+ node: 'cast';
161
+ safe: boolean;
162
+ e: Expr;
163
+ dstSQLType: string;
164
+ srcType?: LeafAtomicTypeDef;
159
165
  }
166
+ export type TypecastExpr = MalloyTypecastExpr | RawTypeCastExpr;
167
+ export declare function isRawCast(te: TypecastExpr): te is RawTypeCastExpr;
160
168
  export interface RegexMatchExpr extends ExprWithKids {
161
169
  node: 'regexpMatch';
162
170
  kids: {
@@ -167,7 +175,7 @@ export interface RegexMatchExpr extends ExprWithKids {
167
175
  export interface TimeLiteralNode extends ExprLeaf {
168
176
  node: 'timeLiteral';
169
177
  literal: string;
170
- dataType: TemporalFieldType;
178
+ typeDef: TemporalTypeDef;
171
179
  timezone?: string;
172
180
  }
173
181
  export interface StringLiteralNode extends ExprLeaf {
@@ -194,7 +202,7 @@ export interface ArrayLiteralNode extends ExprWithKids {
194
202
  kids: {
195
203
  values: Expr[];
196
204
  };
197
- dataType: AtomicFieldType;
205
+ typeDef: ArrayTypeDef;
198
206
  }
199
207
  export interface ErrorNode extends ExprLeaf {
200
208
  node: 'error';
@@ -531,6 +539,7 @@ export interface IndexSegment extends Filtered {
531
539
  limit?: number;
532
540
  weightMeasure?: string;
533
541
  sample?: Sampling;
542
+ alwaysJoins?: string[];
534
543
  }
535
544
  export declare function isIndexSegment(pe: PipeSegment): pe is IndexSegment;
536
545
  export interface QuerySegment extends Filtered {
@@ -541,6 +550,7 @@ export interface QuerySegment extends Filtered {
541
550
  by?: By;
542
551
  orderBy?: OrderBy[];
543
552
  queryTimezone?: string;
553
+ alwaysJoins?: string[];
544
554
  }
545
555
  export interface TurtleDef extends NamedObject, Pipeline {
546
556
  type: 'turtle';
@@ -658,7 +668,7 @@ export type LeafAtomicTypeDef = StringTypeDef | TemporalTypeDef | NumberTypeDef
658
668
  export type AtomicTypeDef = LeafAtomicTypeDef | ArrayTypeDef | RecordTypeDef;
659
669
  export type LeafAtomicDef = LeafAtomicTypeDef & FieldAtomicBase;
660
670
  export type AtomicFieldDef = AtomicTypeDef & FieldAtomicBase;
661
- export declare function isLeafAtomic(fd: FieldDef | QueryFieldDef): fd is LeafAtomicDef;
671
+ export declare function isLeafAtomic(fd: FieldDef | QueryFieldDef | AtomicTypeDef): fd is LeafAtomicDef;
662
672
  export type FieldDef = AtomicFieldDef | JoinFieldDef | TurtleDef;
663
673
  export interface RefToField {
664
674
  type: 'fieldref';
@@ -779,4 +789,23 @@ export interface PrepareResultOptions {
779
789
  replaceMaterializedReferences?: boolean;
780
790
  materializedTablePrefix?: string;
781
791
  }
792
+ type UTD = AtomicTypeDef | undefined;
793
+ export declare const TD: {
794
+ isA: (td: UTD, ...tList: string[]) => boolean | undefined;
795
+ notA: (td: UTD, ...tList: string[]) => boolean | undefined;
796
+ isString: (td: UTD) => td is StringTypeDef;
797
+ isNumber: (td: UTD) => td is NumberTypeDef;
798
+ isBoolean: (td: UTD) => td is BooleanTypeDef;
799
+ isJSON: (td: UTD) => td is JSONTypeDef;
800
+ isSQL: (td: UTD) => td is NativeUnsupportedTypeDef;
801
+ isDate: (td: UTD) => td is DateTypeDef;
802
+ isTimestamp: (td: UTD) => td is TimestampTypeDef;
803
+ isError: (td: UTD) => td is ErrorTypeDef;
804
+ eq: (x: UTD, y: UTD) => boolean;
805
+ timestamp: () => TimestampTypeDef;
806
+ date: () => DateTypeDef;
807
+ string: () => StringTypeDef;
808
+ number: () => NumberTypeDef;
809
+ error: () => ErrorTypeDef;
810
+ };
782
811
  export {};
@@ -22,8 +22,8 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.mergeEvalSpaces = exports.isLiteral = exports.isScalarArray = exports.isBaseTable = exports.isSourceDef = exports.sourceBase = exports.isSegmentSQL = exports.isIndexSegment = exports.isRawSegment = exports.isSamplingEnable = exports.isSamplingPercent = exports.isSamplingRows = exports.isQuerySegment = exports.isProjectSegment = exports.isPartialSegment = exports.isReduceSegment = exports.structHasErrors = exports.segmentHasErrors = exports.refIsStructDef = exports.isByExpression = exports.isByName = exports.ValueType = exports.isExtractUnit = exports.isTimestampUnit = exports.isDateUnit = exports.isJoinedSource = exports.isJoined = exports.isJoinable = exports.isMatrixOperation = exports.isRepeatedRecord = exports.arrayEachFields = exports.fieldIsIntrinsic = exports.isCastType = exports.isAtomicFieldType = exports.isTemporalField = exports.hasExpression = exports.maxOfExpressionTypes = exports.maxExpressionType = exports.isExpressionTypeLEQ = exports.expressionIsAnalytic = exports.expressionIsCalculation = exports.expressionInvolvesAggregate = exports.expressionIsUngroupedAggregate = exports.expressionIsAggregate = exports.expressionIsScalar = exports.paramHasValue = exports.isAsymmetricExpr = exports.exprIsLeaf = exports.exprHasE = exports.exprHasKids = void 0;
26
- exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.getAtomicFields = exports.isAtomic = exports.isTurtleDef = exports.getIdentifier = exports.isLeafAtomic = void 0;
25
+ exports.isScalarArray = exports.isBaseTable = exports.isSourceDef = exports.sourceBase = exports.isSegmentSQL = exports.isIndexSegment = exports.isRawSegment = exports.isSamplingEnable = exports.isSamplingPercent = exports.isSamplingRows = exports.isQuerySegment = exports.isProjectSegment = exports.isPartialSegment = exports.isReduceSegment = exports.structHasErrors = exports.segmentHasErrors = exports.refIsStructDef = exports.isByExpression = exports.isByName = exports.ValueType = exports.isExtractUnit = exports.isTimestampUnit = exports.isDateUnit = exports.isJoinedSource = exports.isJoined = exports.isJoinable = exports.isMatrixOperation = exports.isRepeatedRecord = exports.arrayEachFields = exports.fieldIsIntrinsic = exports.isCastType = exports.isAtomicFieldType = exports.isTemporalField = exports.hasExpression = exports.maxOfExpressionTypes = exports.maxExpressionType = exports.isExpressionTypeLEQ = exports.expressionIsAnalytic = exports.expressionIsCalculation = exports.expressionInvolvesAggregate = exports.expressionIsUngroupedAggregate = exports.expressionIsAggregate = exports.expressionIsScalar = exports.paramHasValue = exports.isRawCast = exports.mkTemporal = exports.isAsymmetricExpr = exports.exprIsLeaf = exports.exprHasE = exports.exprHasKids = void 0;
26
+ exports.TD = exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.getAtomicFields = exports.isAtomic = exports.isTurtleDef = exports.getIdentifier = exports.isLeafAtomic = exports.mergeEvalSpaces = exports.isLiteral = void 0;
27
27
  function exprHasKids(e) {
28
28
  return 'kids' in e;
29
29
  }
@@ -41,6 +41,33 @@ function isAsymmetricExpr(f) {
41
41
  ['sum', 'avg', 'count', 'distinct'].includes(f.function));
42
42
  }
43
43
  exports.isAsymmetricExpr = isAsymmetricExpr;
44
+ /**
45
+ * Return true if this node can be turned into a temporal node by simply
46
+ * appending a time type to the typedef. The type systsem makes this hard
47
+ * because while it is theoretically possible to pass an array typed Expr,
48
+ * the reality is that type checking will stop this from ever happening.
49
+ *
50
+ * The list here is the list of Expr types which have a fixed typeDef,
51
+ * which are not of time type.
52
+ *
53
+ * If !canMakeTemporal then mkTemporal is going to return something
54
+ * which will probably error at SQL generation time, so don't do that.
55
+ */
56
+ function canMakeTemporal(e) {
57
+ return e.node !== 'arrayLiteral' && e.node !== 'recordLiteral';
58
+ }
59
+ function mkTemporal(e, timeType) {
60
+ const ttd = typeof timeType === 'string' ? { type: timeType } : timeType;
61
+ if (canMakeTemporal(e)) {
62
+ return { ...e, typeDef: { ...ttd } };
63
+ }
64
+ return e;
65
+ }
66
+ exports.mkTemporal = mkTemporal;
67
+ function isRawCast(te) {
68
+ return 'dstSQLType' in te;
69
+ }
70
+ exports.isRawCast = isRawCast;
44
71
  function paramHasValue(p) {
45
72
  return p.value !== null;
46
73
  }
@@ -369,5 +396,59 @@ function isValueDate(value, field) {
369
396
  return field.type === 'date';
370
397
  }
371
398
  exports.isValueDate = isValueDate;
399
+ exports.TD = {
400
+ isA: (td, ...tList) => td && tList.includes(td.type),
401
+ notA: (td, ...tList) => td && !tList.includes(td.type),
402
+ isString: (td) => td !== undefined && td.type === 'string',
403
+ isNumber: (td) => td !== undefined && td.type === 'number',
404
+ isBoolean: (td) => td !== undefined && td.type === 'boolean',
405
+ isJSON: (td) => td !== undefined && td.type === 'json',
406
+ isSQL: (td) => td !== undefined && td.type === 'sql native',
407
+ isDate: (td) => td !== undefined && td.type === 'date',
408
+ isTimestamp: (td) => td !== undefined && td.type === 'timestamp',
409
+ isError: (td) => td !== undefined && td.type === 'error',
410
+ eq: function (x, y) {
411
+ if (x === undefined || y === undefined) {
412
+ return false;
413
+ }
414
+ function checkFields(a, b) {
415
+ const aSchema = {};
416
+ for (const aEnt of a['fields'] || []) {
417
+ if (aEnt.name) {
418
+ aSchema[aEnt.name] = aEnt;
419
+ }
420
+ else {
421
+ return false;
422
+ }
423
+ }
424
+ for (const bEnt of b['fields'] || []) {
425
+ if (!exports.TD.eq(aSchema[bEnt.name], bEnt)) {
426
+ return false;
427
+ }
428
+ }
429
+ return true;
430
+ }
431
+ if (x.type === 'array' && y.type === 'array') {
432
+ if (x.elementTypeDef.type !== y.elementTypeDef.type) {
433
+ return false;
434
+ }
435
+ if (x.elementTypeDef.type !== 'record_element' && // Both are equal, but to make this
436
+ y.elementTypeDef.type !== 'record_element' // typecheck, we need the && clause.
437
+ ) {
438
+ return exports.TD.eq(x.elementTypeDef, y.elementTypeDef);
439
+ }
440
+ return checkFields(x, y);
441
+ }
442
+ else if (x.type === 'record' && y.type === 'record') {
443
+ return checkFields(x, y);
444
+ }
445
+ return x.type === y.type;
446
+ },
447
+ timestamp: () => ({ type: 'timestamp' }),
448
+ date: () => ({ type: 'date' }),
449
+ string: () => ({ type: 'string' }),
450
+ number: () => ({ type: 'number', numberType: 'float' }),
451
+ error: () => ({ type: 'error' }),
452
+ };
372
453
  // clang-format on
373
454
  //# sourceMappingURL=malloy_types.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.203-dev241021134413",
3
+ "version": "0.0.203-dev241022191525",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",