@malloydata/malloy 0.0.304 → 0.0.305

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 (74) hide show
  1. package/dist/dialect/dialect.d.ts +1 -1
  2. package/dist/dialect/duckdb/duckdb.d.ts +1 -1
  3. package/dist/dialect/duckdb/duckdb.js +2 -6
  4. package/dist/dialect/mysql/mysql.d.ts +1 -1
  5. package/dist/dialect/mysql/mysql.js +2 -6
  6. package/dist/dialect/postgres/postgres.d.ts +1 -1
  7. package/dist/dialect/postgres/postgres.js +2 -6
  8. package/dist/dialect/snowflake/snowflake.d.ts +1 -1
  9. package/dist/dialect/snowflake/snowflake.js +2 -5
  10. package/dist/dialect/standardsql/standardsql.d.ts +1 -1
  11. package/dist/dialect/standardsql/standardsql.js +2 -6
  12. package/dist/dialect/trino/trino.d.ts +1 -1
  13. package/dist/dialect/trino/trino.js +2 -6
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +2 -3
  16. package/dist/lang/ast/expressions/expr-aggregate-function.js +12 -2
  17. package/dist/lang/ast/expressions/expr-count.js +3 -1
  18. package/dist/lang/ast/expressions/expr-func.js +34 -10
  19. package/dist/lang/ast/expressions/expr-props.js +1 -1
  20. package/dist/lang/ast/expressions/expr-ungroup.js +7 -3
  21. package/dist/lang/ast/expressions/function-ordering.d.ts +19 -5
  22. package/dist/lang/ast/expressions/function-ordering.js +61 -9
  23. package/dist/lang/ast/field-space/include-utils.js +1 -1
  24. package/dist/lang/ast/field-space/index-field-space.js +3 -1
  25. package/dist/lang/ast/field-space/query-spaces.js +20 -11
  26. package/dist/lang/ast/query-builders/index-builder.js +1 -1
  27. package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
  28. package/dist/lang/ast/query-elements/query-arrow.js +14 -4
  29. package/dist/lang/ast/query-elements/query-base.d.ts +1 -0
  30. package/dist/lang/ast/query-elements/query-base.js +14 -4
  31. package/dist/lang/ast/query-elements/query-refine.js +2 -0
  32. package/dist/lang/ast/query-properties/drill.js +1 -1
  33. package/dist/lang/ast/source-properties/join.js +6 -2
  34. package/dist/lang/ast/statements/define-source.js +1 -1
  35. package/dist/lang/ast/types/expr-value.js +1 -1
  36. package/dist/lang/ast/view-elements/reference-view.js +4 -1
  37. package/dist/lang/ast/view-elements/refine-utils.js +1 -1
  38. package/dist/{model/composite_source_utils.d.ts → lang/composite-source-utils.d.ts} +4 -17
  39. package/dist/{model/composite_source_utils.js → lang/composite-source-utils.js} +274 -44
  40. package/dist/lang/test/parse-expects.d.ts +1 -1
  41. package/dist/lang/test/parse-expects.js +6 -2
  42. package/dist/lang/test/test-translator.js +1 -1
  43. package/dist/malloy.js +1 -1
  44. package/dist/model/expression_compiler.d.ts +27 -0
  45. package/dist/model/expression_compiler.js +780 -0
  46. package/dist/model/field_instance.d.ts +108 -0
  47. package/dist/model/field_instance.js +520 -0
  48. package/dist/model/index.d.ts +5 -1
  49. package/dist/model/index.js +25 -4
  50. package/dist/model/join_instance.d.ts +18 -0
  51. package/dist/model/join_instance.js +71 -0
  52. package/dist/model/malloy_types.d.ts +48 -2
  53. package/dist/model/malloy_types.js +39 -1
  54. package/dist/model/query_model.d.ts +2 -0
  55. package/dist/model/query_model.js +7 -0
  56. package/dist/model/query_model_contract.d.ts +32 -0
  57. package/dist/model/query_model_contract.js +7 -0
  58. package/dist/model/query_model_impl.d.ts +30 -0
  59. package/dist/model/query_model_impl.js +266 -0
  60. package/dist/model/query_node.d.ts +132 -0
  61. package/dist/model/query_node.js +638 -0
  62. package/dist/model/query_query.d.ts +86 -0
  63. package/dist/model/query_query.js +1724 -0
  64. package/dist/model/sql_block.js +2 -2
  65. package/dist/model/stage_writer.d.ts +25 -0
  66. package/dist/model/stage_writer.js +120 -0
  67. package/dist/model/utils.d.ts +18 -1
  68. package/dist/model/utils.js +66 -1
  69. package/dist/to_stable.js +3 -4
  70. package/dist/version.d.ts +1 -1
  71. package/dist/version.js +1 -1
  72. package/package.json +4 -4
  73. package/dist/model/malloy_query.d.ts +0 -391
  74. package/dist/model/malloy_query.js +0 -3926
@@ -0,0 +1,18 @@
1
+ import type { QueryStruct } from './query_node';
2
+ import { QueryFieldBoolean } from './query_node';
3
+ import type { JoinRelationship, UniqueKeyRequirement } from './malloy_types';
4
+ import type { DialectFieldList } from '../dialect';
5
+ export declare class JoinInstance {
6
+ queryStruct: QueryStruct;
7
+ alias: string;
8
+ parent: JoinInstance | undefined;
9
+ uniqueKeyRequirement?: UniqueKeyRequirement;
10
+ makeUniqueKey: boolean;
11
+ leafiest: boolean;
12
+ joinFilterConditions?: QueryFieldBoolean[];
13
+ children: JoinInstance[];
14
+ constructor(queryStruct: QueryStruct, alias: string, parent: JoinInstance | undefined);
15
+ parentRelationship(): 'root' | JoinRelationship;
16
+ forceAllSymmetricCalculations(): boolean;
17
+ getDialectFieldList(): DialectFieldList;
18
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.JoinInstance = void 0;
8
+ const query_node_1 = require("./query_node");
9
+ const utils_1 = require("./utils");
10
+ const malloy_types_1 = require("./malloy_types");
11
+ class JoinInstance {
12
+ constructor(queryStruct, alias, parent) {
13
+ this.queryStruct = queryStruct;
14
+ this.alias = alias;
15
+ this.parent = parent;
16
+ this.makeUniqueKey = false;
17
+ this.leafiest = false;
18
+ this.children = [];
19
+ if (parent) {
20
+ parent.children.push(this);
21
+ }
22
+ // convert the filter list into a list of boolean fields so we can
23
+ // generate dependancies and code for them.
24
+ const sd = this.queryStruct.structDef;
25
+ if ((0, malloy_types_1.isSourceDef)(sd) && sd.filterList) {
26
+ this.joinFilterConditions = sd.filterList.map(filter => new query_node_1.QueryFieldBoolean({
27
+ type: 'boolean',
28
+ name: 'ignoreme',
29
+ e: filter.e,
30
+ }, this.queryStruct));
31
+ }
32
+ }
33
+ parentRelationship() {
34
+ if (this.queryStruct.parent === undefined) {
35
+ return 'root';
36
+ }
37
+ const thisStruct = this.queryStruct.structDef;
38
+ if ((0, malloy_types_1.isJoined)(thisStruct)) {
39
+ switch (thisStruct.join) {
40
+ case 'one':
41
+ return 'many_to_one';
42
+ case 'cross':
43
+ return 'many_to_many';
44
+ case 'many':
45
+ return 'one_to_many';
46
+ }
47
+ }
48
+ throw new Error(`Internal error unknown relationship type to parent for ${this.queryStruct.structDef.name}`);
49
+ }
50
+ // For now, we force all symmetric calculations for full and right joins
51
+ // because we need distinct keys for COUNT(xx) operations. Don't really need
52
+ // this for sums. This will produce correct results and we can optimize this
53
+ // at some point..
54
+ forceAllSymmetricCalculations() {
55
+ if (this.queryStruct.parent === undefined) {
56
+ return false;
57
+ }
58
+ const thisStruct = this.queryStruct.structDef;
59
+ if ((0, malloy_types_1.isJoined)(thisStruct)) {
60
+ return (thisStruct.matrixOperation === 'right' ||
61
+ thisStruct.matrixOperation === 'full');
62
+ }
63
+ return false;
64
+ }
65
+ // postgres unnest needs to know the names of the physical fields.
66
+ getDialectFieldList() {
67
+ return (0, utils_1.getDialectFieldList)(this.queryStruct.structDef);
68
+ }
69
+ }
70
+ exports.JoinInstance = JoinInstance;
71
+ //# sourceMappingURL=join_instance.js.map
@@ -426,6 +426,12 @@ export interface BasicArrayDef extends BasicArrayTypeDef, StructDefBase, JoinBas
426
426
  type: 'array';
427
427
  join: 'many';
428
428
  }
429
+ /**
430
+ * Create a clean FieldDef from a TypeDef descendent
431
+ * @param atd Usually a TypeDesc
432
+ * @param name
433
+ * @returns Field with `name` and no type meta data
434
+ */
429
435
  export declare function mkFieldDef(atd: AtomicTypeDef, name: string): AtomicFieldDef;
430
436
  export declare function mkArrayDef(ofType: AtomicTypeDef, name: string): ArrayDef;
431
437
  export interface RecordTypeDef {
@@ -580,7 +586,24 @@ export interface RawSegment extends Filtered {
580
586
  export declare function isRawSegment(pe: PipeSegment): pe is RawSegment;
581
587
  export type IndexFieldDef = RefToField;
582
588
  export type SegmentFieldDef = IndexFieldDef | QueryFieldDef;
583
- export interface IndexSegment extends Filtered {
589
+ /**
590
+ * The compiler needs to know a number of things computed for a query.
591
+ * We've modified the fieldUsage code from composite sources to collect
592
+ * the information needed by the compiler and a query is processed
593
+ * as a final step to append this information.
594
+ *
595
+ * 0) An ordered list list of active joins
596
+ * 1) Each field that is referenced, even indirectly
597
+ * 2) Each join path ending in a count
598
+ * 3) Each join path ending in an assymmetric aggregate
599
+ * 4) Each join path ending in an analytic funtion
600
+ */
601
+ export interface SegmentUsageSummary {
602
+ activeJoins?: FieldUsage[];
603
+ expandedFieldUsage?: FieldUsage[];
604
+ expandedUngroupings?: AggregateUngrouping[];
605
+ }
606
+ export interface IndexSegment extends Filtered, SegmentUsageSummary {
584
607
  type: 'index';
585
608
  indexFields: IndexFieldDef[];
586
609
  limit?: number;
@@ -595,8 +618,11 @@ export declare function isIndexSegment(pe: PipeSegment): pe is IndexSegment;
595
618
  export interface FieldUsage {
596
619
  path: string[];
597
620
  at?: DocumentLocation;
621
+ uniqueKeyRequirement?: UniqueKeyRequirement;
622
+ analyticFunctionUse?: boolean;
598
623
  }
599
- export interface QuerySegment extends Filtered, Ordered {
624
+ export declare function bareFieldUsage(fu: FieldUsage): boolean;
625
+ export interface QuerySegment extends Filtered, Ordered, SegmentUsageSummary {
600
626
  type: 'reduce' | 'project' | 'partial';
601
627
  queryFields: QueryFieldDef[];
602
628
  extendSource?: FieldDef[];
@@ -617,6 +643,8 @@ export interface TurtleDef extends NamedObject, Pipeline {
617
643
  fieldUsage?: FieldUsage[];
618
644
  requiredGroupBys?: string[][];
619
645
  }
646
+ export interface TurtleDefPlusFilters extends TurtleDef, Filtered {
647
+ }
620
648
  interface StructDefBase extends HasLocation, NamedObject {
621
649
  type: string;
622
650
  annotation?: Annotation;
@@ -711,6 +739,9 @@ export interface AggregateUngrouping {
711
739
  ungroupedFields: string[][] | '*';
712
740
  fieldUsage: FieldUsage[];
713
741
  requiresGroupBy?: RequiredGroupBy[];
742
+ exclude: boolean;
743
+ path: string[];
744
+ refFields?: string[];
714
745
  }
715
746
  export type TypeInfo = {
716
747
  expressionType: ExpressionType;
@@ -964,4 +995,19 @@ export declare const TD: {
964
995
  isError: (td: UTD) => td is ErrorTypeDef;
965
996
  eq(x: UTD, y: UTD): boolean;
966
997
  };
998
+ /**
999
+ * Aggregate functions carry this meta data. Used to determine if
1000
+ * a function requires the existence of a unique key. This used
1001
+ * be a pair of types: UniqueKeyUse and UniqueKeyPossibleUse.
1002
+ *
1003
+ * The three states are:
1004
+ *
1005
+ * 1. undefined - not recorded, symmetric MIN/MAX/COUNT_DISTINCT
1006
+ * 2. {isCount: true} - this is a COUNT aggregate
1007
+ * 3. {isCount: false} - this is an asymmetric aggregate, SUM or AVG
1008
+ */
1009
+ export type UniqueKeyRequirement = undefined | {
1010
+ isCount: boolean;
1011
+ };
1012
+ export declare function mergeUniqueKeyRequirement(existing: UniqueKeyRequirement, newInfo: UniqueKeyRequirement): UniqueKeyRequirement;
967
1013
  export {};
@@ -72,6 +72,7 @@ exports.isSamplingPercent = isSamplingPercent;
72
72
  exports.isSamplingEnable = isSamplingEnable;
73
73
  exports.isRawSegment = isRawSegment;
74
74
  exports.isIndexSegment = isIndexSegment;
75
+ exports.bareFieldUsage = bareFieldUsage;
75
76
  exports.isSegmentSQL = isSegmentSQL;
76
77
  exports.sourceBase = sourceBase;
77
78
  exports.isSourceDef = isSourceDef;
@@ -87,6 +88,7 @@ exports.isValueNumber = isValueNumber;
87
88
  exports.isValueBoolean = isValueBoolean;
88
89
  exports.isValueTimestamp = isValueTimestamp;
89
90
  exports.isValueDate = isValueDate;
91
+ exports.mergeUniqueKeyRequirement = mergeUniqueKeyRequirement;
90
92
  function exprHasKids(e) {
91
93
  return 'kids' in e;
92
94
  }
@@ -236,6 +238,12 @@ function isCastType(s) {
236
238
  function fieldIsIntrinsic(f) {
237
239
  return isAtomicFieldType(f.type) && !hasExpression(f);
238
240
  }
241
+ /**
242
+ * Create a clean FieldDef from a TypeDef descendent
243
+ * @param atd Usually a TypeDesc
244
+ * @param name
245
+ * @returns Field with `name` and no type meta data
246
+ */
239
247
  function mkFieldDef(atd, name) {
240
248
  if (isBasicArray(atd)) {
241
249
  return mkArrayDef(atd.elementTypeDef, name);
@@ -248,7 +256,24 @@ function mkFieldDef(atd, name) {
248
256
  const { type, fields } = atd;
249
257
  return { type, fields, join: 'one', name };
250
258
  }
251
- return { ...atd, name };
259
+ const ret = { name, type: atd.type };
260
+ switch (atd.type) {
261
+ case 'sql native':
262
+ return { ...ret, rawType: atd.rawType };
263
+ case 'number': {
264
+ const numberType = atd.numberType;
265
+ return numberType ? { ...ret, numberType } : ret;
266
+ }
267
+ case 'date': {
268
+ const timeframe = atd.timeframe;
269
+ return timeframe ? { name, type: 'date', timeframe } : ret;
270
+ }
271
+ case 'timestamp': {
272
+ const timeframe = atd.timeframe;
273
+ return timeframe ? { name, type: 'timestamp', timeframe } : ret;
274
+ }
275
+ }
276
+ return ret;
252
277
  }
253
278
  function mkArrayDef(ofType, name) {
254
279
  if (ofType.type === 'record') {
@@ -365,6 +390,10 @@ function isRawSegment(pe) {
365
390
  function isIndexSegment(pe) {
366
391
  return pe.type === 'index';
367
392
  }
393
+ function bareFieldUsage(fu) {
394
+ return (fu.uniqueKeyRequirement === undefined &&
395
+ fu.analyticFunctionUse === undefined);
396
+ }
368
397
  function isSegmentSQL(f) {
369
398
  return 'sql' in f;
370
399
  }
@@ -510,5 +539,14 @@ exports.TD = {
510
539
  return x.type === y.type;
511
540
  },
512
541
  };
542
+ function mergeUniqueKeyRequirement(existing, newInfo) {
543
+ if (!existing)
544
+ return newInfo;
545
+ if (!newInfo)
546
+ return existing;
547
+ return {
548
+ isCount: existing.isCount || newInfo.isCount,
549
+ };
550
+ }
513
551
  // clang-format on
514
552
  //# sourceMappingURL=malloy_types.js.map
@@ -0,0 +1,2 @@
1
+ export type { QueryModel, ParentQueryModel } from './query_model_contract';
2
+ export { makeQueryModel, getResultStructDefForQuery } from './query_model_impl';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getResultStructDefForQuery = exports.makeQueryModel = void 0;
4
+ var query_model_impl_1 = require("./query_model_impl");
5
+ Object.defineProperty(exports, "makeQueryModel", { enumerable: true, get: function () { return query_model_impl_1.makeQueryModel; } });
6
+ Object.defineProperty(exports, "getResultStructDefForQuery", { enumerable: true, get: function () { return query_model_impl_1.getResultStructDefForQuery; } });
7
+ //# sourceMappingURL=query_model.js.map
@@ -0,0 +1,32 @@
1
+ import type { Connection } from '../connection/types';
2
+ import type { Dialect } from '../dialect';
3
+ import type { EventStream } from '../runtime_types';
4
+ import type { SourceDef, ModelDef, StructRef, Argument, PrepareResultOptions, CompiledQuery, SearchIndexResult, Query } from './malloy_types';
5
+ import type { QueryStruct } from './query_node';
6
+ import type { StageWriter } from './stage_writer';
7
+ export interface ParentQueryModel {
8
+ model: QueryModel;
9
+ }
10
+ export interface QueryResults {
11
+ lastStageName: string;
12
+ stageWriter: StageWriter;
13
+ structs: SourceDef[];
14
+ malloy: string;
15
+ connectionName: string;
16
+ }
17
+ export interface QueryModel {
18
+ dialect: Dialect;
19
+ modelDef: ModelDef | undefined;
20
+ structs: Map<string, QueryStruct>;
21
+ eventStream?: EventStream;
22
+ loadModelFromDef(modelDef: ModelDef): void;
23
+ getStructByName(name: string): QueryStruct;
24
+ getStructFromRef(structRef: StructRef, sourceArguments: Record<string, Argument> | undefined, prepareResultOptions?: PrepareResultOptions | undefined): QueryStruct;
25
+ loadQuery(query: Query, stageWriter: StageWriter | undefined, prepareResultOptions: PrepareResultOptions | undefined, emitFinalStage: boolean | undefined, isJoinedSubquery: boolean | undefined): QueryResults;
26
+ addDefaultRowLimit(query: Query, defaultRowLimit?: number): {
27
+ query: Query;
28
+ addedDefaultRowLimit?: number;
29
+ };
30
+ compileQuery(query: Query, prepareResultOptions: PrepareResultOptions | undefined, finalize: boolean | undefined): CompiledQuery;
31
+ searchIndex(connection: Connection, explore: string, searchValue: string, limit: number, searchField: string | undefined): Promise<SearchIndexResult[] | undefined>;
32
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=query_model_contract.js.map
@@ -0,0 +1,30 @@
1
+ import type { ModelDef, StructRef, Argument, PrepareResultOptions, Query, SourceDef, SearchIndexResult, CompiledQuery, TurtleDef } from './malloy_types';
2
+ import { StageWriter } from './stage_writer';
3
+ import { type Dialect } from '../dialect';
4
+ import type { EventStream } from '../runtime_types';
5
+ import type { Connection } from '../connection/types';
6
+ import type { ModelRootInterface } from './query_node';
7
+ import { QueryStruct } from './query_node';
8
+ import type { QueryModel, QueryResults } from './query_model_contract';
9
+ export declare function makeQueryModel(modelDef: ModelDef | undefined, eventStream?: EventStream): QueryModel;
10
+ export declare class QueryModelImpl implements QueryModel, ModelRootInterface {
11
+ readonly eventStream?: EventStream | undefined;
12
+ dialect: Dialect;
13
+ modelDef: ModelDef | undefined;
14
+ structs: Map<string, QueryStruct>;
15
+ constructor(modelDef: ModelDef | undefined, eventStream?: EventStream | undefined);
16
+ getFinalOutputStruct(query: Query, options: PrepareResultOptions | undefined): SourceDef | undefined;
17
+ loadModelFromDef(modelDef: ModelDef): void;
18
+ getStructByName(name: string): QueryStruct;
19
+ getStructFromRef(structRef: StructRef, sourceArguments: Record<string, Argument> | undefined, prepareResultOptions?: PrepareResultOptions): QueryStruct;
20
+ loadQuery(query: Query, stageWriter: StageWriter | undefined, prepareResultOptions?: PrepareResultOptions, emitFinalStage?: boolean, isJoinedSubquery?: boolean): QueryResults;
21
+ addDefaultRowLimit(query: Query, defaultRowLimit?: number): {
22
+ query: Query;
23
+ addedDefaultRowLimit?: number;
24
+ };
25
+ compileQuery(query: Query, prepareResultOptions?: PrepareResultOptions, finalize?: boolean): CompiledQuery;
26
+ exploreSearchSQLMap: Map<any, any>;
27
+ searchIndex(connection: Connection, explore: string, searchValue: string, limit?: number, searchField?: string | undefined): Promise<SearchIndexResult[] | undefined>;
28
+ }
29
+ export declare function getResultStructDefForQuery(model: ModelDef, query: Query): SourceDef;
30
+ export declare function getResultStructDefForView(source: SourceDef, view: TurtleDef): SourceDef;
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.QueryModelImpl = void 0;
8
+ exports.makeQueryModel = makeQueryModel;
9
+ exports.getResultStructDefForQuery = getResultStructDefForQuery;
10
+ exports.getResultStructDefForView = getResultStructDefForView;
11
+ const query_query_1 = require("./query_query");
12
+ const malloy_types_1 = require("./malloy_types");
13
+ const stage_writer_1 = require("./stage_writer");
14
+ const dialect_1 = require("../dialect");
15
+ const utils_1 = require("./materialization/utils");
16
+ const query_node_1 = require("./query_node");
17
+ function makeQueryModel(modelDef, eventStream) {
18
+ return new QueryModelImpl(modelDef, eventStream);
19
+ }
20
+ class QueryModelImpl {
21
+ constructor(modelDef, eventStream) {
22
+ this.eventStream = eventStream;
23
+ this.dialect = new dialect_1.StandardSQLDialect();
24
+ // dialect: Dialect = new PostgresDialect();
25
+ this.modelDef = undefined;
26
+ this.structs = new Map();
27
+ this.exploreSearchSQLMap = new Map();
28
+ if (modelDef) {
29
+ this.loadModelFromDef(modelDef);
30
+ }
31
+ }
32
+ // Another circularity breaking method ... call into QueryQuery
33
+ // to find the output shape of a query
34
+ getFinalOutputStruct(query, options) {
35
+ const result = this.loadQuery(query, undefined, options, false, false);
36
+ return result.structs.pop();
37
+ }
38
+ loadModelFromDef(modelDef) {
39
+ this.modelDef = modelDef;
40
+ for (const s of Object.values(this.modelDef.contents)) {
41
+ let qs;
42
+ if ((0, malloy_types_1.isSourceDef)(s)) {
43
+ qs = new query_node_1.QueryStruct(s, undefined, { model: this }, {});
44
+ this.structs.set((0, malloy_types_1.getIdentifier)(s), qs);
45
+ qs.resolveQueryFields((query, options) => this.getFinalOutputStruct(query, options));
46
+ }
47
+ else if (s.type === 'query') {
48
+ /* TODO */
49
+ }
50
+ else {
51
+ throw new Error('Internal Error: Unknown structure type');
52
+ }
53
+ }
54
+ }
55
+ getStructByName(name) {
56
+ const s = this.structs.get(name);
57
+ if (s) {
58
+ return s;
59
+ }
60
+ throw new Error(`Struct ${name} not found in model.`);
61
+ }
62
+ getStructFromRef(structRef, sourceArguments, prepareResultOptions) {
63
+ prepareResultOptions !== null && prepareResultOptions !== void 0 ? prepareResultOptions : (prepareResultOptions = {});
64
+ if (typeof structRef === 'string') {
65
+ const ret = this.getStructByName(structRef);
66
+ if (sourceArguments !== undefined) {
67
+ return new query_node_1.QueryStruct(ret.structDef, sourceArguments, ret.parent ? { struct: ret.parent } : { model: this }, prepareResultOptions);
68
+ }
69
+ return ret;
70
+ }
71
+ return new query_node_1.QueryStruct(structRef, sourceArguments, { model: this }, prepareResultOptions);
72
+ }
73
+ loadQuery(query, stageWriter, prepareResultOptions, emitFinalStage = false, isJoinedSubquery = false) {
74
+ var _a;
75
+ const malloy = '';
76
+ if (!stageWriter) {
77
+ stageWriter = new stage_writer_1.StageWriter(true, undefined);
78
+ }
79
+ const turtleDef = {
80
+ type: 'turtle',
81
+ name: 'ignoreme',
82
+ pipeline: query.pipeline,
83
+ filterList: query.filterList,
84
+ };
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));
87
+ const ret = q.generateSQLFromPipeline(stageWriter);
88
+ if (emitFinalStage && q.parent.dialect.hasFinalStage) {
89
+ // const fieldNames: string[] = [];
90
+ // for (const f of ret.outputStruct.fields) {
91
+ // fieldNames.push(getIdentifier(f));
92
+ // }
93
+ const fieldNames = [];
94
+ for (const f of ret.outputStruct.fields) {
95
+ if ((0, malloy_types_1.isAtomic)(f)) {
96
+ const quoted = q.parent.dialect.sqlMaybeQuoteIdentifier(f.name);
97
+ fieldNames.push(quoted);
98
+ }
99
+ }
100
+ // const fieldNames = getAtomicFields(ret.outputStruct).map(fieldDef =>
101
+ // q.parent.dialect.sqlMaybeQuoteIdentifier(fieldDef.name)
102
+ // );
103
+ ret.lastStageName = stageWriter.addStage(q.parent.dialect.sqlFinalStage(ret.lastStageName, fieldNames));
104
+ }
105
+ return {
106
+ lastStageName: ret.lastStageName,
107
+ malloy,
108
+ stageWriter,
109
+ structs: [ret.outputStruct],
110
+ connectionName: q.parent.connectionName,
111
+ };
112
+ }
113
+ addDefaultRowLimit(query, defaultRowLimit) {
114
+ const nope = { query, addedDefaultRowLimit: undefined };
115
+ if (defaultRowLimit === undefined)
116
+ return nope;
117
+ const lastSegment = query.pipeline[query.pipeline.length - 1];
118
+ if (lastSegment.type === 'raw')
119
+ return nope;
120
+ if (lastSegment.limit !== undefined)
121
+ return nope;
122
+ return {
123
+ query: {
124
+ ...query,
125
+ pipeline: [
126
+ ...query.pipeline.slice(0, -1),
127
+ {
128
+ ...lastSegment,
129
+ limit: defaultRowLimit,
130
+ },
131
+ ],
132
+ },
133
+ addedDefaultRowLimit: defaultRowLimit,
134
+ };
135
+ }
136
+ compileQuery(query, prepareResultOptions, finalize = true) {
137
+ var _a, _b, _c;
138
+ let newModel;
139
+ const addDefaultRowLimit = this.addDefaultRowLimit(query, prepareResultOptions === null || prepareResultOptions === void 0 ? void 0 : prepareResultOptions.defaultRowLimit);
140
+ query = addDefaultRowLimit.query;
141
+ const addedDefaultRowLimit = addDefaultRowLimit.addedDefaultRowLimit;
142
+ const m = newModel || this;
143
+ const ret = m.loadQuery(query, undefined, prepareResultOptions, finalize, false);
144
+ const structRef = (_a = query.compositeResolvedSourceDef) !== null && _a !== void 0 ? _a : query.structRef;
145
+ const sourceExplore = typeof structRef === 'string'
146
+ ? structRef
147
+ : structRef.as || structRef.name;
148
+ const sourceArguments = (_b = query.sourceArguments) !== null && _b !== void 0 ? _b : (typeof structRef === 'string' ? undefined : structRef.arguments);
149
+ // LTNote: I don't understand why this might be here. It should have happened in loadQuery...
150
+ if (finalize && this.dialect.hasFinalStage) {
151
+ ret.lastStageName = ret.stageWriter.addStage(
152
+ // note this will be broken on duckDB waiting on a real fix.
153
+ this.dialect.sqlFinalStage(ret.lastStageName, []));
154
+ }
155
+ return {
156
+ lastStageName: ret.lastStageName,
157
+ malloy: ret.malloy,
158
+ sql: ret.stageWriter.generateSQLStages(),
159
+ dependenciesToMaterialize: ret.stageWriter.dependenciesToMaterialize,
160
+ materialization: (0, utils_1.shouldMaterialize)(query.annotation)
161
+ ? (0, utils_1.buildQueryMaterializationSpec)((_c = query.location) === null || _c === void 0 ? void 0 : _c.url, query.name, prepareResultOptions === null || prepareResultOptions === void 0 ? void 0 : prepareResultOptions.materializedTablePrefix)
162
+ : undefined,
163
+ structs: ret.structs,
164
+ sourceExplore,
165
+ sourceFilters: query.filterList,
166
+ sourceArguments,
167
+ queryName: query.name,
168
+ connectionName: ret.connectionName,
169
+ annotation: query.annotation,
170
+ queryTimezone: ret.structs[0].queryTimezone,
171
+ defaultRowLimitAdded: addedDefaultRowLimit,
172
+ };
173
+ }
174
+ async searchIndex(connection, explore, searchValue, limit = 1000, searchField = undefined) {
175
+ if (!connection.canPersist()) {
176
+ return undefined;
177
+ }
178
+ // make a search index if one isn't modelled.
179
+ const struct = this.getStructByName(explore);
180
+ const d = struct.dialect;
181
+ let indexStar = [];
182
+ for (const [fn, fv] of struct.nameMap) {
183
+ if ((0, query_node_1.isScalarField)(fv) && fv.includeInWildcard()) {
184
+ indexStar.push({ type: 'fieldref', path: [fn] });
185
+ }
186
+ }
187
+ indexStar = indexStar.sort((a, b) => a.path[0].localeCompare(b.path[0]));
188
+ const indexQuery = {
189
+ structRef: explore,
190
+ pipeline: [
191
+ {
192
+ type: 'index',
193
+ indexFields: indexStar,
194
+ sample: d.defaultSampling,
195
+ outputStruct: {
196
+ type: 'query_result',
197
+ name: 'index',
198
+ connection: struct.connectionName,
199
+ dialect: struct.dialect.name,
200
+ fields: [
201
+ { name: 'fieldName', type: 'string' },
202
+ { name: 'fieldPath', type: 'string' },
203
+ { name: 'fieldType', type: 'string' },
204
+ { name: 'weight', type: 'number' },
205
+ { name: 'fieldValue', type: 'string' },
206
+ ],
207
+ },
208
+ },
209
+ ],
210
+ };
211
+ const fieldNameColumn = d.sqlMaybeQuoteIdentifier('fieldName');
212
+ const fieldPathColumn = d.sqlMaybeQuoteIdentifier('fieldPath');
213
+ const fieldValueColumn = d.sqlMaybeQuoteIdentifier('fieldValue');
214
+ const fieldTypeColumn = d.sqlMaybeQuoteIdentifier('fieldType');
215
+ const weightColumn = d.sqlMaybeQuoteIdentifier('weight');
216
+ // if we've compiled the SQL before use it otherwise
217
+ let sqlPDT = this.exploreSearchSQLMap.get(explore);
218
+ if (sqlPDT === undefined) {
219
+ sqlPDT = this.compileQuery(indexQuery, undefined, false).sql;
220
+ this.exploreSearchSQLMap.set(explore, sqlPDT);
221
+ }
222
+ let query = `SELECT
223
+ ${fieldNameColumn},
224
+ ${fieldPathColumn},
225
+ ${fieldValueColumn},
226
+ ${fieldTypeColumn},
227
+ ${weightColumn},
228
+ CASE WHEN lower(${fieldValueColumn}) LIKE lower(${d.sqlLiteralString(searchValue + '%')}) THEN 1 ELSE 0 END as match_first
229
+ FROM ${await connection.manifestTemporaryTable(sqlPDT)}
230
+ WHERE lower(${fieldValueColumn}) LIKE lower(${d.sqlLiteralString('%' + searchValue + '%')}) ${searchField !== undefined
231
+ ? ` AND ${fieldNameColumn} = '` + searchField + "' \n"
232
+ : ''}
233
+ ORDER BY CASE WHEN lower(${fieldValueColumn}) LIKE lower(${d.sqlLiteralString(searchValue + '%')}) THEN 1 ELSE 0 END DESC, ${weightColumn} DESC
234
+ LIMIT ${limit}
235
+ `;
236
+ if (d.hasFinalStage) {
237
+ query = `WITH __stage0 AS(\n${query}\n)\n${d.sqlFinalStage('__stage0', [
238
+ fieldNameColumn,
239
+ fieldPathColumn,
240
+ fieldValueColumn,
241
+ fieldTypeColumn,
242
+ weightColumn,
243
+ 'match_first',
244
+ ])}`;
245
+ }
246
+ const result = await connection.runSQL(query, {
247
+ rowLimit: 1000,
248
+ });
249
+ return result.rows;
250
+ }
251
+ }
252
+ exports.QueryModelImpl = QueryModelImpl;
253
+ function getResultStructDefForQuery(model, query) {
254
+ const queryModel = makeQueryModel(model);
255
+ const compiled = queryModel.compileQuery(query, undefined, true);
256
+ return compiled.structs[compiled.structs.length - 1];
257
+ }
258
+ function getResultStructDefForView(source, view) {
259
+ const qs = new query_node_1.QueryStruct(source, undefined, {
260
+ model: makeQueryModel(undefined),
261
+ }, {});
262
+ const queryQueryQuery = query_query_1.QueryQuery.makeQuery(view, qs, new stage_writer_1.StageWriter(true, undefined), // stage write indicates we want to get a result.
263
+ false, () => undefined);
264
+ return queryQueryQuery.getResultStructDef();
265
+ }
266
+ //# sourceMappingURL=query_model_impl.js.map