@malloydata/malloy 0.0.310 → 0.0.312

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.
@@ -124,7 +124,7 @@ import { AccessModifierListContext } from "./MalloyParser";
124
124
  import { DefMeasuresContext } from "./MalloyParser";
125
125
  import { DefDimensionsContext } from "./MalloyParser";
126
126
  import { RenameListContext } from "./MalloyParser";
127
- import { ExploreRenameDefContext } from "./MalloyParser";
127
+ import { RenameEntryContext } from "./MalloyParser";
128
128
  import { DefListContext } from "./MalloyParser";
129
129
  import { FieldDefContext } from "./MalloyParser";
130
130
  import { FieldNameDefContext } from "./MalloyParser";
@@ -1666,15 +1666,15 @@ export interface MalloyParserListener extends ParseTreeListener {
1666
1666
  */
1667
1667
  exitRenameList?: (ctx: RenameListContext) => void;
1668
1668
  /**
1669
- * Enter a parse tree produced by `MalloyParser.exploreRenameDef`.
1669
+ * Enter a parse tree produced by `MalloyParser.renameEntry`.
1670
1670
  * @param ctx the parse tree
1671
1671
  */
1672
- enterExploreRenameDef?: (ctx: ExploreRenameDefContext) => void;
1672
+ enterRenameEntry?: (ctx: RenameEntryContext) => void;
1673
1673
  /**
1674
- * Exit a parse tree produced by `MalloyParser.exploreRenameDef`.
1674
+ * Exit a parse tree produced by `MalloyParser.renameEntry`.
1675
1675
  * @param ctx the parse tree
1676
1676
  */
1677
- exitExploreRenameDef?: (ctx: ExploreRenameDefContext) => void;
1677
+ exitRenameEntry?: (ctx: RenameEntryContext) => void;
1678
1678
  /**
1679
1679
  * Enter a parse tree produced by `MalloyParser.defList`.
1680
1680
  * @param ctx the parse tree
@@ -124,7 +124,7 @@ import { AccessModifierListContext } from "./MalloyParser";
124
124
  import { DefMeasuresContext } from "./MalloyParser";
125
125
  import { DefDimensionsContext } from "./MalloyParser";
126
126
  import { RenameListContext } from "./MalloyParser";
127
- import { ExploreRenameDefContext } from "./MalloyParser";
127
+ import { RenameEntryContext } from "./MalloyParser";
128
128
  import { DefListContext } from "./MalloyParser";
129
129
  import { FieldDefContext } from "./MalloyParser";
130
130
  import { FieldNameDefContext } from "./MalloyParser";
@@ -1085,11 +1085,11 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
1085
1085
  */
1086
1086
  visitRenameList?: (ctx: RenameListContext) => Result;
1087
1087
  /**
1088
- * Visit a parse tree produced by `MalloyParser.exploreRenameDef`.
1088
+ * Visit a parse tree produced by `MalloyParser.renameEntry`.
1089
1089
  * @param ctx the parse tree
1090
1090
  * @return the visitor result
1091
1091
  */
1092
- visitExploreRenameDef?: (ctx: ExploreRenameDefContext) => Result;
1092
+ visitRenameEntry?: (ctx: RenameEntryContext) => Result;
1093
1093
  /**
1094
1094
  * Visit a parse tree produced by `MalloyParser.defList`.
1095
1095
  * @param ctx the parse tree
@@ -112,7 +112,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
112
112
  getAccessLabelProp(pcx: parse.AccessLabelPropContext | undefined): AccessModifierLabel | undefined;
113
113
  visitDefMeasures(pcx: parse.DefMeasuresContext): ast.Measures;
114
114
  visitQueryExtend(pcx: parse.QueryExtendContext): ast.ExtendBlock;
115
- visitExploreRenameDef(pcx: parse.ExploreRenameDefContext): ast.RenameField;
115
+ visitRenameEntry(pcx: parse.RenameEntryContext): ast.RenameField;
116
116
  visitDefExploreRename(pcx: parse.DefExploreRenameContext): ast.Renames;
117
117
  visitFilterClauseList(pcx: parse.FilterClauseListContext): ast.Filter;
118
118
  visitDrillClauseList(pcx: parse.FilterClauseListContext): ast.Drill;
@@ -526,17 +526,21 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
526
526
  const el = new ast.ExtendBlock(extensions);
527
527
  return this.astAt(el, pcx);
528
528
  }
529
- visitExploreRenameDef(pcx) {
529
+ visitRenameEntry(pcx) {
530
530
  const newName = pcx.fieldName(0);
531
531
  const oldName = pcx.fieldName(1);
532
532
  const rename = new ast.RenameField((0, parse_utils_1.getId)(newName), this.getFieldName(oldName));
533
+ const notes = this.getNotes(pcx.tags()).concat(this.getIsNotes(pcx.isDefine()));
534
+ rename.extendNote({ notes });
533
535
  return this.astAt(rename, pcx);
534
536
  }
535
537
  visitDefExploreRename(pcx) {
536
538
  const accessLabel = this.getAccessLabel(pcx.accessLabel());
537
- const rcxs = pcx.renameList().exploreRenameDef();
538
- const renames = rcxs.map(rcx => this.visitExploreRenameDef(rcx));
539
+ const rcxs = pcx.renameList().renameEntry();
540
+ const renames = rcxs.map(rcx => this.visitRenameEntry(rcx));
539
541
  const stmt = new ast.Renames(renames, accessLabel);
542
+ const blockNotes = this.getNotes(pcx.tags());
543
+ stmt.extendNote({ blockNotes });
540
544
  return this.astAt(stmt, pcx);
541
545
  }
542
546
  visitFilterClauseList(pcx) {
@@ -202,7 +202,7 @@ class DocumentSymbolWalker {
202
202
  parent.children.push(symbol);
203
203
  }
204
204
  }
205
- enterExploreRenameDef(pcx) {
205
+ enterRenameEntry(pcx) {
206
206
  const symbol = {
207
207
  range: this.translator.rangeFromContext(pcx),
208
208
  name: pcx.fieldName()[0].text,
package/dist/malloy.d.ts CHANGED
@@ -757,6 +757,7 @@ export declare class ExploreField extends Explore {
757
757
  isAtomicField(): this is AtomicField;
758
758
  get parentExplore(): Explore;
759
759
  get sourceClasses(): string[];
760
+ get queryTimezone(): string | undefined;
760
761
  }
761
762
  type Connectionable = {
762
763
  connection: Connection;
package/dist/malloy.js CHANGED
@@ -1715,6 +1715,14 @@ class ExploreField extends Explore {
1715
1715
  const sourceField = this.structDef.name || this.structDef.as;
1716
1716
  return sourceField ? [sourceField] : [];
1717
1717
  }
1718
+ get queryTimezone() {
1719
+ // For ExploreField, check the structDef directly first
1720
+ if ((0, model_1.isRecordOrRepeatedRecord)(this._structDef)) {
1721
+ return this._structDef.queryTimezone;
1722
+ }
1723
+ // Fall back to the parent implementation
1724
+ return super.queryTimezone;
1725
+ }
1718
1726
  }
1719
1727
  exports.ExploreField = ExploreField;
1720
1728
  /**
@@ -55,6 +55,9 @@ export declare class FieldInstanceResult implements FieldInstance {
55
55
  * Information about the query containing this result set. Invented
56
56
  * to pass on timezone information, but maybe more things will
57
57
  * eventually go in here.
58
+ *
59
+ * For nested queries, this walks up the FieldInstanceResult parent chain
60
+ * to find the most specific (innermost) query timezone that applies.
58
61
  * @returns QueryInfo
59
62
  */
60
63
  getQueryInfo(): QueryInfo;
@@ -117,6 +117,9 @@ class FieldInstanceResult {
117
117
  * Information about the query containing this result set. Invented
118
118
  * to pass on timezone information, but maybe more things will
119
119
  * eventually go in here.
120
+ *
121
+ * For nested queries, this walks up the FieldInstanceResult parent chain
122
+ * to find the most specific (innermost) query timezone that applies.
120
123
  * @returns QueryInfo
121
124
  */
122
125
  getQueryInfo() {
@@ -127,6 +130,9 @@ class FieldInstanceResult {
127
130
  return { queryTimezone };
128
131
  }
129
132
  }
133
+ if (this.parent) {
134
+ return this.parent.getQueryInfo();
135
+ }
130
136
  return {};
131
137
  }
132
138
  addField(as, field, usage, drillExpression) {
@@ -73,10 +73,12 @@ exports.FilterCompilers = {
73
73
  case '>':
74
74
  case '<':
75
75
  case '>=':
76
- case '<=':
76
+ case '<=': {
77
+ const op = nc.not ? invertCompare(nc.operator) : nc.operator;
77
78
  return nc.values
78
- .map(v => `${x} ${nc.operator} ${v}`)
79
+ .map(v => `${x} ${op} ${v}`)
79
80
  .join(nc.not ? ' AND ' : ' OR ');
81
+ }
80
82
  case 'range': {
81
83
  let startOp = nc.startOperator;
82
84
  let endOp = nc.endOperator;
@@ -103,14 +105,16 @@ exports.FilterCompilers = {
103
105
  },
104
106
  booleanCompile(bc, x, _d) {
105
107
  switch (bc.operator) {
108
+ case 'true':
109
+ return bc.not ? `NOT COALESCE(${x}, false)` : `COALESCE(${x}, false)`;
106
110
  case 'false':
107
- return `${x} = false`;
111
+ return bc.not
112
+ ? `COALESCE(${x} != false, true)`
113
+ : `COALESCE(${x} = false, false)`;
108
114
  case 'false_or_null':
109
- return `${x} IS NULL OR ${x} = false`;
115
+ return bc.not ? `COALESCE(${x}, false)` : `NOT COALESCE(${x}, false)`;
110
116
  case 'null':
111
117
  return bc.not ? `${x} IS NOT NULL` : `${x} IS NULL`;
112
- case 'true':
113
- return x;
114
118
  }
115
119
  },
116
120
  stringCompile(sc, x, d) {
@@ -166,7 +170,7 @@ exports.FilterCompilers = {
166
170
  }
167
171
  case 'or': {
168
172
  const clauses = sc.members.map(c => exports.FilterCompilers.stringCompile(c, x, d));
169
- return clauses.join(' AND ');
173
+ return clauses.join(' OR ');
170
174
  }
171
175
  case ',': {
172
176
  /*
@@ -441,6 +441,7 @@ export interface RecordTypeDef {
441
441
  export interface RecordDef extends RecordTypeDef, StructDefBase, JoinBase, FieldBase {
442
442
  type: 'record';
443
443
  join: 'one';
444
+ queryTimezone?: string;
444
445
  }
445
446
  export interface RecordElementTypeDef {
446
447
  type: 'record_element';
@@ -453,11 +454,13 @@ export interface RepeatedRecordTypeDef {
453
454
  export interface RepeatedRecordDef extends RepeatedRecordTypeDef, StructDefBase, JoinBase, FieldBase {
454
455
  type: 'array';
455
456
  join: 'many';
457
+ queryTimezone?: string;
456
458
  }
457
459
  export type ArrayTypeDef = BasicArrayTypeDef | RepeatedRecordTypeDef;
458
460
  export type ArrayDef = BasicArrayDef | RepeatedRecordDef;
459
461
  export declare function isRepeatedRecordFunctionParam(paramT: FunctionParameterTypeDef): paramT is RepeatedRecordFunctionParameterTypeDef;
460
462
  export declare function isRepeatedRecord(fd: FieldDef | QueryFieldDef | StructDef | AtomicTypeDef): fd is RepeatedRecordTypeDef;
463
+ export declare function isRecordOrRepeatedRecord(fd: FieldDef | StructDef): fd is RecordDef | RepeatedRecordDef;
461
464
  export declare function isBasicArray(td: AtomicTypeDef | FieldDef | QueryFieldDef | StructDef): td is BasicArrayTypeDef;
462
465
  export interface ErrorTypeDef {
463
466
  type: 'error';
@@ -975,6 +978,7 @@ export interface PrepareResultOptions {
975
978
  replaceMaterializedReferences?: boolean;
976
979
  materializedTablePrefix?: string;
977
980
  defaultRowLimit?: number;
981
+ isPartialQuery?: boolean;
978
982
  }
979
983
  type UTD = AtomicTypeDef | TypedDef | FunctionParameterTypeDef | FunctionReturnTypeDef | undefined;
980
984
  /**
@@ -52,6 +52,7 @@ exports.mkFieldDef = mkFieldDef;
52
52
  exports.mkArrayDef = mkArrayDef;
53
53
  exports.isRepeatedRecordFunctionParam = isRepeatedRecordFunctionParam;
54
54
  exports.isRepeatedRecord = isRepeatedRecord;
55
+ exports.isRecordOrRepeatedRecord = isRecordOrRepeatedRecord;
55
56
  exports.isBasicArray = isBasicArray;
56
57
  exports.isMatrixOperation = isMatrixOperation;
57
58
  exports.isJoinable = isJoinable;
@@ -303,6 +304,12 @@ function isRepeatedRecordFunctionParam(paramT) {
303
304
  function isRepeatedRecord(fd) {
304
305
  return fd.type === 'array' && fd.elementTypeDef.type === 'record_element';
305
306
  }
307
+ function isRecordOrRepeatedRecord(fd) {
308
+ return (fd.type === 'record' ||
309
+ (fd.type === 'array' &&
310
+ 'elementTypeDef' in fd &&
311
+ fd.elementTypeDef.type === 'record_element'));
312
+ }
306
313
  function isBasicArray(td) {
307
314
  return td.type === 'array' && td.elementTypeDef.type !== 'record_element';
308
315
  }
@@ -73,8 +73,14 @@ class QueryModelImpl {
73
73
  loadQuery(query, stageWriter, prepareResultOptions, emitFinalStage = false, isJoinedSubquery = false) {
74
74
  var _a;
75
75
  const malloy = '';
76
+ const structRef = (_a = query.compositeResolvedSourceDef) !== null && _a !== void 0 ? _a : query.structRef;
77
+ const queryStruct = this.getStructFromRef(structRef, query.sourceArguments, prepareResultOptions);
78
+ // If this query is being written as part of a SQL block don't use CTE (WITH ...)
79
+ const noCTE = prepareResultOptions &&
80
+ prepareResultOptions.isPartialQuery &&
81
+ queryStruct.dialect.name !== 'postgres'; // postgres does weird stuff with final stages that won't work here.
76
82
  if (!stageWriter) {
77
- stageWriter = new stage_writer_1.StageWriter(true, undefined);
83
+ stageWriter = new stage_writer_1.StageWriter(!noCTE, undefined);
78
84
  }
79
85
  const turtleDef = {
80
86
  type: 'turtle',
@@ -82,8 +88,7 @@ class QueryModelImpl {
82
88
  pipeline: query.pipeline,
83
89
  filterList: query.filterList,
84
90
  };
85
- const structRef = (_a = query.compositeResolvedSourceDef) !== null && _a !== void 0 ? _a : query.structRef;
86
- const q = query_query_1.QueryQuery.makeQuery(turtleDef, this.getStructFromRef(structRef, query.sourceArguments, prepareResultOptions), stageWriter, isJoinedSubquery, (name) => this.structs.get(name));
91
+ const q = query_query_1.QueryQuery.makeQuery(turtleDef, queryStruct, stageWriter, isJoinedSubquery, (name) => this.structs.get(name));
87
92
  const ret = q.generateSQLFromPipeline(stageWriter);
88
93
  if (emitFinalStage && q.parent.dialect.hasFinalStage) {
89
94
  // const fieldNames: string[] = [];
@@ -102,6 +107,7 @@ class QueryModelImpl {
102
107
  // );
103
108
  ret.lastStageName = stageWriter.addStage(q.parent.dialect.sqlFinalStage(ret.lastStageName, fieldNames));
104
109
  }
110
+ // console.log('---', stageWriter.combineStages(true).sql, '---');
105
111
  return {
106
112
  lastStageName: ret.lastStageName,
107
113
  malloy,
@@ -388,24 +388,37 @@ class QueryQuery extends query_node_1.QueryField {
388
388
  const resultMetadata = this.getResultMetadata(fi);
389
389
  if (fi instanceof field_instance_1.FieldInstanceResult) {
390
390
  const { structDef, repeatedResultType } = this.generateTurtlePipelineSQL(fi, new stage_writer_1.StageWriter(true, undefined), '<nosource>');
391
+ // Get the timezone from the nested query
392
+ const nestedQueryInfo = fi.getQueryInfo();
393
+ const queryTimezone = nestedQueryInfo.queryTimezone;
391
394
  if (repeatedResultType === 'nested') {
392
395
  const multiLineNest = {
393
- ...structDef,
394
396
  type: 'array',
395
397
  elementTypeDef: { type: 'record_element' },
396
398
  join: 'many',
397
399
  name,
400
+ fields: structDef.fields,
401
+ ...(structDef.annotation && { annotation: structDef.annotation }),
402
+ ...(structDef.modelAnnotation && {
403
+ modelAnnotation: structDef.modelAnnotation,
404
+ }),
398
405
  resultMetadata,
406
+ ...(queryTimezone && { queryTimezone }),
399
407
  };
400
408
  fields.push(multiLineNest);
401
409
  }
402
410
  else {
403
411
  const oneLineNest = {
404
- ...structDef,
405
412
  type: 'record',
406
413
  join: 'one',
407
414
  name,
415
+ fields: structDef.fields,
416
+ ...(structDef.annotation && { annotation: structDef.annotation }),
417
+ ...(structDef.modelAnnotation && {
418
+ modelAnnotation: structDef.modelAnnotation,
419
+ }),
408
420
  resultMetadata,
421
+ ...(queryTimezone && { queryTimezone }),
409
422
  };
410
423
  fields.push(oneLineNest);
411
424
  }
@@ -46,8 +46,10 @@ function compileSQLInterpolation(select, connection, partialModel) {
46
46
  }
47
47
  const compiledSql = queryModel.compileQuery(segment, {
48
48
  defaultRowLimit: undefined,
49
+ isPartialQuery: true,
49
50
  }, false).sql;
50
51
  selectStr += parenAlready ? compiledSql : `(${compiledSql})`;
52
+ // console.log(selectStr);
51
53
  parenAlready = false;
52
54
  }
53
55
  }
@@ -3,12 +3,15 @@ import type { QueryToMaterialize, StructDef, Query } from './malloy_types';
3
3
  export declare class StageWriter {
4
4
  parent: StageWriter | undefined;
5
5
  withs: string[];
6
+ stageNames: string[];
6
7
  udfs: string[];
7
8
  pdts: string[];
8
9
  dependenciesToMaterialize: Record<string, QueryToMaterialize>;
9
10
  stagePrefix: string;
10
11
  useCTE: boolean;
12
+ stageNumber: number;
11
13
  constructor(useCTE: boolean | undefined, parent: StageWriter | undefined);
14
+ private nextName;
12
15
  getName(id: number): string;
13
16
  root(): StageWriter;
14
17
  addStage(sql: string): string;
@@ -11,14 +11,20 @@ class StageWriter {
11
11
  constructor(useCTE = true, parent) {
12
12
  this.parent = parent;
13
13
  this.withs = [];
14
+ this.stageNames = [];
14
15
  this.udfs = [];
15
16
  this.pdts = [];
16
17
  this.dependenciesToMaterialize = {};
17
18
  this.stagePrefix = '__stage';
19
+ this.stageNumber = 0;
18
20
  this.useCTE = useCTE;
19
21
  }
22
+ nextName() {
23
+ const stageName = `${this.stagePrefix}${this.root().stageNumber++}`;
24
+ return stageName;
25
+ }
20
26
  getName(id) {
21
- return `${this.stagePrefix}${id}`;
27
+ return this.stageNames[id];
22
28
  }
23
29
  root() {
24
30
  if (this.parent === undefined) {
@@ -31,7 +37,9 @@ class StageWriter {
31
37
  addStage(sql) {
32
38
  if (this.useCTE) {
33
39
  this.withs.push(sql);
34
- return this.getName(this.withs.length - 1);
40
+ const stageName = this.nextName();
41
+ this.stageNames.push(stageName);
42
+ return stageName;
35
43
  }
36
44
  else {
37
45
  this.withs[0] = sql;
@@ -102,7 +110,7 @@ class StageWriter {
102
110
  }
103
111
  const udfs = this.udfs.join('\n');
104
112
  const pdts = this.pdts.join('\n');
105
- const sql = this.combineStages(false).sql;
113
+ const sql = this.useCTE ? this.combineStages(false).sql : '';
106
114
  return udfs + pdts + sql + this.withs[lastStageNum];
107
115
  }
108
116
  generateCoorelatedSubQuery(dialect, structDef) {
package/dist/to_stable.js CHANGED
@@ -213,9 +213,17 @@ function convertFieldInfos(source, fields) {
213
213
  const resultMetadataAnnotation = field.resultMetadata
214
214
  ? getResultMetadataAnnotation(field, field.resultMetadata)
215
215
  : undefined;
216
+ // Check if this field has queryTimezone information (for RecordDef/RepeatedRecordDef)
217
+ let timezoneAnnotation;
218
+ if ((0, model_1.isRecordOrRepeatedRecord)(field) && field.queryTimezone) {
219
+ const timezoneTag = malloy_tag_1.Tag.withPrefix('#(malloy) ');
220
+ timezoneTag.set(['query_timezone'], field.queryTimezone);
221
+ timezoneAnnotation = { value: timezoneTag.toString() };
222
+ }
216
223
  const fieldAnnotations = [
217
224
  ...(annotations !== null && annotations !== void 0 ? annotations : []),
218
225
  ...(resultMetadataAnnotation ? [resultMetadataAnnotation] : []),
226
+ ...(timezoneAnnotation ? [timezoneAnnotation] : []),
219
227
  ];
220
228
  const fieldInfo = {
221
229
  kind: aggregate ? 'measure' : 'dimension',
@@ -343,6 +351,11 @@ function getResultStructMetadataAnnotation(field, resultMetadata) {
343
351
  }
344
352
  hasAny = true;
345
353
  }
354
+ // Include queryTimezone if present on the field
355
+ if (field.queryTimezone) {
356
+ tag.set(['query_timezone'], field.queryTimezone);
357
+ hasAny = true;
358
+ }
346
359
  return hasAny
347
360
  ? {
348
361
  value: tag.toString(),
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.310";
1
+ export declare const MALLOY_VERSION = "0.0.312";
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.310';
5
+ exports.MALLOY_VERSION = '0.0.312';
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.310",
3
+ "version": "0.0.312",
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.310",
45
- "@malloydata/malloy-interfaces": "0.0.310",
46
- "@malloydata/malloy-tag": "0.0.310",
44
+ "@malloydata/malloy-filter": "0.0.312",
45
+ "@malloydata/malloy-interfaces": "0.0.312",
46
+ "@malloydata/malloy-tag": "0.0.312",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jaro-winkler": "^0.2.8",