@malloydata/malloy 0.0.335 → 0.0.336
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.
- package/CONTEXT.md +4 -3
- package/MALLOY_API.md +129 -0
- package/dist/annotation.d.ts +0 -2
- package/dist/annotation.js +29 -23
- package/dist/api/asynchronous.d.ts +1 -1
- package/dist/api/foundation/cache.d.ts +32 -0
- package/dist/api/foundation/cache.js +92 -0
- package/dist/api/foundation/compile.d.ts +175 -0
- package/dist/api/foundation/compile.js +391 -0
- package/dist/api/foundation/core.d.ts +493 -0
- package/dist/api/foundation/core.js +1247 -0
- package/dist/api/foundation/document.d.ts +167 -0
- package/dist/api/foundation/document.js +206 -0
- package/dist/api/foundation/index.d.ts +10 -0
- package/dist/api/foundation/index.js +77 -0
- package/dist/api/foundation/readers.d.ts +53 -0
- package/dist/api/foundation/readers.js +134 -0
- package/dist/api/foundation/result.d.ts +185 -0
- package/dist/api/foundation/result.js +704 -0
- package/dist/api/foundation/runtime.d.ts +361 -0
- package/dist/api/foundation/runtime.js +733 -0
- package/dist/api/foundation/types.d.ts +54 -0
- package/dist/api/foundation/types.js +7 -0
- package/dist/api/foundation/writers.d.ts +42 -0
- package/dist/api/foundation/writers.js +230 -0
- package/dist/api/util.d.ts +1 -1
- package/dist/connection/base_connection.d.ts +5 -0
- package/dist/connection/types.d.ts +5 -0
- package/dist/dialect/duckdb/duckdb.js +2 -1
- package/dist/dialect/snowflake/snowflake.js +7 -1
- package/dist/dialect/trino/trino.js +7 -2
- package/dist/index.d.ts +6 -3
- package/dist/index.js +30 -26
- package/dist/lang/ast/error-factory.js +3 -5
- package/dist/lang/ast/source-elements/query-source.js +2 -7
- package/dist/lang/ast/source-elements/refined-source.js +11 -1
- package/dist/lang/ast/source-elements/sql-source.d.ts +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +18 -3
- package/dist/lang/ast/sql-elements/sql-string.d.ts +2 -2
- package/dist/lang/ast/sql-elements/sql-string.js +18 -1
- package/dist/lang/ast/statements/define-source.js +7 -2
- package/dist/lang/ast/statements/import-statement.js +53 -21
- package/dist/lang/ast/types/document-compile-result.d.ts +1 -0
- package/dist/lang/ast/types/malloy-element.d.ts +3 -1
- package/dist/lang/ast/types/malloy-element.js +23 -7
- package/dist/lang/malloy-to-ast.d.ts +1 -1
- package/dist/lang/malloy-to-ast.js +1 -1
- package/dist/lang/parse-malloy.d.ts +3 -2
- package/dist/lang/parse-malloy.js +14 -25
- package/dist/lang/test/test-translator.js +1 -0
- package/dist/lang/translate-response.d.ts +1 -0
- package/dist/model/constant_expression_compiler.js +6 -7
- package/dist/model/index.d.ts +3 -1
- package/dist/model/index.js +15 -9
- package/dist/model/malloy_types.d.ts +89 -15
- package/dist/model/malloy_types.js +12 -0
- package/dist/model/persist_utils.d.ts +47 -0
- package/dist/model/persist_utils.js +257 -0
- package/dist/model/query_model_impl.d.ts +2 -4
- package/dist/model/query_model_impl.js +5 -13
- package/dist/model/query_node.d.ts +1 -2
- package/dist/model/query_node.js +3 -13
- package/dist/model/query_query.d.ts +17 -1
- package/dist/model/query_query.js +81 -36
- package/dist/model/source_def_utils.d.ts +50 -0
- package/dist/model/source_def_utils.js +154 -0
- package/dist/model/sql_block.d.ts +5 -1
- package/dist/model/sql_block.js +29 -4
- package/dist/model/sql_compiled.d.ts +29 -0
- package/dist/model/sql_compiled.js +102 -0
- package/dist/model/stage_writer.d.ts +1 -3
- package/dist/model/stage_writer.js +7 -25
- package/dist/model/utils.d.ts +20 -1
- package/dist/model/utils.js +40 -0
- package/dist/run_sql_options.d.ts +0 -1
- package/dist/taggable.d.ts +10 -0
- package/dist/taggable.js +7 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -4
- package/dist/malloy.d.ts +0 -1365
- package/dist/malloy.js +0 -3421
- package/dist/model/materialization/utils.d.ts +0 -3
- package/dist/model/materialization/utils.js +0 -41
|
@@ -11,7 +11,8 @@ const utils_1 = require("./utils");
|
|
|
11
11
|
const query_node_1 = require("./query_node");
|
|
12
12
|
const stage_writer_1 = require("./stage_writer");
|
|
13
13
|
const field_instance_1 = require("./field_instance");
|
|
14
|
-
const
|
|
14
|
+
const sql_compiled_1 = require("./sql_compiled");
|
|
15
|
+
const source_def_utils_1 = require("./source_def_utils");
|
|
15
16
|
function pathToCol(path) {
|
|
16
17
|
return path.map(el => encodeURIComponent(el)).join('/');
|
|
17
18
|
}
|
|
@@ -51,7 +52,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
51
52
|
parent = new query_node_1.QueryStruct({
|
|
52
53
|
...sourceDef,
|
|
53
54
|
fields: [...sourceDef.fields, ...firstStage.extendSource],
|
|
54
|
-
}, parentStruct.sourceArguments, parent.parent ? { struct: parent } : { model: parent.
|
|
55
|
+
}, parentStruct.sourceArguments, parent.parent ? { struct: parent } : { model: parent.getModel() }, parent.prepareResultOptions);
|
|
55
56
|
turtleWithFilters = {
|
|
56
57
|
...turtleWithFilters,
|
|
57
58
|
pipeline: [
|
|
@@ -514,7 +515,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
514
515
|
return outputStruct;
|
|
515
516
|
}
|
|
516
517
|
getStructSourceSQL(qs, stageWriter) {
|
|
517
|
-
var _a, _b
|
|
518
|
+
var _a, _b;
|
|
518
519
|
switch (qs.structDef.type) {
|
|
519
520
|
case 'table':
|
|
520
521
|
return this.parent.dialect.quoteTablePath(qs.structDef.tablePath);
|
|
@@ -525,47 +526,86 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
525
526
|
case 'finalize':
|
|
526
527
|
return qs.structDef.name;
|
|
527
528
|
case 'sql_select':
|
|
528
|
-
return `(${qs.structDef.
|
|
529
|
+
return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_a = qs.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, path => this.parent.dialect.quoteTablePath(path), (query, opts) => {
|
|
530
|
+
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
531
|
+
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
532
|
+
return ret.sql;
|
|
533
|
+
})})`;
|
|
529
534
|
case 'nest_source':
|
|
530
535
|
return qs.structDef.pipeSQL;
|
|
531
536
|
case 'query_source': {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const structRef = (_c = query.compositeResolvedSourceDef) !== null && _c !== void 0 ? _c : query.structRef;
|
|
548
|
-
let sourceStruct;
|
|
549
|
-
if (typeof structRef === 'string') {
|
|
550
|
-
const struct = this.structRefToQueryStruct(structRef);
|
|
551
|
-
if (!struct) {
|
|
552
|
-
throw new Error(`Unexpected reference to an undefined source '${structRef}'`);
|
|
537
|
+
const { buildManifest, connectionDigests, strictPersist } = (_b = qs.prepareResultOptions) !== null && _b !== void 0 ? _b : {};
|
|
538
|
+
// Check manifest for this source
|
|
539
|
+
if (buildManifest && connectionDigests) {
|
|
540
|
+
const connDigest = connectionDigests[qs.structDef.connection];
|
|
541
|
+
if (connDigest) {
|
|
542
|
+
// Compile with empty opts to get manifest-ignorant SQL for BuildID
|
|
543
|
+
const fullRet = this.compileQueryToStages(qs.structDef.query, {}, undefined, false);
|
|
544
|
+
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, fullRet.sql);
|
|
545
|
+
const entry = buildManifest.buildEntries[buildId];
|
|
546
|
+
if (entry) {
|
|
547
|
+
// Found in manifest - use persisted table
|
|
548
|
+
return this.parent.dialect.quoteTablePath(entry.tableName);
|
|
549
|
+
}
|
|
550
|
+
if (strictPersist) {
|
|
551
|
+
throw new Error(`Persist source '${qs.structDef.sourceID}' not found in manifest (buildId: ${buildId})`);
|
|
553
552
|
}
|
|
554
|
-
sourceStruct = struct;
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
sourceStruct = new query_node_1.QueryStruct(structRef, query.sourceArguments, { model: this.parent.getModel() }, qs.prepareResultOptions);
|
|
558
553
|
}
|
|
559
|
-
const q = QueryQuery.makeQuery(turtleDef, sourceStruct, stageWriter, qs.parent !== undefined, // isJoinedSubquery
|
|
560
|
-
this.structRefToQueryStruct);
|
|
561
|
-
const ret = q.generateSQLFromPipeline(stageWriter);
|
|
562
|
-
return ret.lastStageName;
|
|
563
554
|
}
|
|
555
|
+
// Not in manifest - compile normally
|
|
556
|
+
const ret = this.compileQueryToStages(qs.structDef.query, qs.prepareResultOptions, stageWriter, qs.parent !== undefined);
|
|
557
|
+
return ret.lastStageName;
|
|
564
558
|
}
|
|
565
559
|
default:
|
|
566
560
|
throw new Error(`Cannot create SQL StageWriter from '${(0, malloy_types_1.getIdentifier)(qs.structDef)}' type '${qs.structDef.type}`);
|
|
567
561
|
}
|
|
568
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Compile a Query into SQL stages. Used by both query_source compilation
|
|
565
|
+
* and getCompiledSQL for interpolated sources.
|
|
566
|
+
*
|
|
567
|
+
* @param query The query to compile
|
|
568
|
+
* @param prepareResultOptions Options including manifest for substitution
|
|
569
|
+
* @param stageWriter If provided, stages are added to this writer and lastStageName is returned.
|
|
570
|
+
* If undefined, a new isolated writer is created and full SQL is returned.
|
|
571
|
+
* @param isJoinedSubquery Whether this is a joined subquery
|
|
572
|
+
* @returns { lastStageName, stageWriter, sql } - sql is only set if stageWriter was undefined
|
|
573
|
+
*/
|
|
574
|
+
compileQueryToStages(query, prepareResultOptions, stageWriter, isJoinedSubquery) {
|
|
575
|
+
var _a;
|
|
576
|
+
const turtleDef = {
|
|
577
|
+
type: 'turtle',
|
|
578
|
+
name: 'ignoreme',
|
|
579
|
+
pipeline: query.pipeline,
|
|
580
|
+
filterList: query.filterList,
|
|
581
|
+
};
|
|
582
|
+
const structRef = (_a = query.compositeResolvedSourceDef) !== null && _a !== void 0 ? _a : query.structRef;
|
|
583
|
+
let sourceStruct;
|
|
584
|
+
if (typeof structRef === 'string') {
|
|
585
|
+
const struct = this.structRefToQueryStruct(structRef);
|
|
586
|
+
if (!struct) {
|
|
587
|
+
throw new Error(`Unexpected reference to an undefined source '${structRef}'`);
|
|
588
|
+
}
|
|
589
|
+
sourceStruct = struct;
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
sourceStruct = new query_node_1.QueryStruct(structRef, query.sourceArguments, { model: this.parent.getModel() }, prepareResultOptions);
|
|
593
|
+
}
|
|
594
|
+
// Create isolated stageWriter if none provided
|
|
595
|
+
const isolated = stageWriter === undefined;
|
|
596
|
+
// When isPartialQuery is set (e.g., SQL interpolation), don't use CTEs
|
|
597
|
+
// for dialects that don't support them in subqueries
|
|
598
|
+
const noCTE = prepareResultOptions.isPartialQuery &&
|
|
599
|
+
!sourceStruct.dialect.supportsCTEinCoorelatedSubQueries;
|
|
600
|
+
const writer = stageWriter !== null && stageWriter !== void 0 ? stageWriter : new stage_writer_1.StageWriter(!noCTE, undefined);
|
|
601
|
+
const q = QueryQuery.makeQuery(turtleDef, sourceStruct, writer, isJoinedSubquery, this.structRefToQueryStruct);
|
|
602
|
+
const ret = q.generateSQLFromPipeline(writer);
|
|
603
|
+
return {
|
|
604
|
+
lastStageName: ret.lastStageName,
|
|
605
|
+
stageWriter: writer,
|
|
606
|
+
sql: isolated ? writer.generateSQLStages() : undefined,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
569
609
|
generateSQLJoinBlock(stageWriter, ji, depth) {
|
|
570
610
|
var _a;
|
|
571
611
|
let s = '';
|
|
@@ -1490,10 +1530,10 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
1490
1530
|
};
|
|
1491
1531
|
pipeline.shift();
|
|
1492
1532
|
for (const transform of pipeline) {
|
|
1493
|
-
const
|
|
1533
|
+
const parentArg = this.parent.parent
|
|
1494
1534
|
? { struct: this.parent.parent }
|
|
1495
1535
|
: { model: this.parent.getModel() };
|
|
1496
|
-
const s = new query_node_1.QueryStruct(structDef, undefined,
|
|
1536
|
+
const s = new query_node_1.QueryStruct(structDef, undefined, parentArg, this.parent.prepareResultOptions);
|
|
1497
1537
|
const q = QueryQuery.makeQuery({ type: 'turtle', name: '~computeLastStage~', pipeline: [transform] }, s, stageWriter, this.isJoinedSubquery, this.structRefToQueryStruct);
|
|
1498
1538
|
q.prepare(stageWriter);
|
|
1499
1539
|
lastStageName = q.generateSQL(stageWriter);
|
|
@@ -1727,10 +1767,15 @@ class QueryQueryProject extends QueryQuery {
|
|
|
1727
1767
|
}
|
|
1728
1768
|
class QueryQueryRaw extends QueryQuery {
|
|
1729
1769
|
generateSQL(stageWriter) {
|
|
1770
|
+
var _a;
|
|
1730
1771
|
if (this.parent.structDef.type !== 'sql_select') {
|
|
1731
1772
|
throw new Error('Invalid struct for QueryQueryRaw, currently only supports SQL');
|
|
1732
1773
|
}
|
|
1733
|
-
return stageWriter.addStage(this.parent.structDef.
|
|
1774
|
+
return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, path => this.parent.dialect.quoteTablePath(path), (query, opts) => {
|
|
1775
|
+
// Compile query to isolated SQL (not into parent's stageWriter)
|
|
1776
|
+
const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
|
|
1777
|
+
return ret.sql;
|
|
1778
|
+
}));
|
|
1734
1779
|
}
|
|
1735
1780
|
prepare() {
|
|
1736
1781
|
// Do nothing!
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SourceDef Utilities for Persistence
|
|
3
|
+
*
|
|
4
|
+
* Key invariant: sourceID is ONLY assigned in DefineSource when a source
|
|
5
|
+
* gets a name. Factory functions explicitly copy only the fields they need,
|
|
6
|
+
* never using spread, to prevent accidental propagation of sourceID/extends.
|
|
7
|
+
*
|
|
8
|
+
* The `extends` property is set by callers when processing extend blocks.
|
|
9
|
+
*/
|
|
10
|
+
import type { BuildID, FieldDef, ModelDef, PersistableSourceDef, Query, QuerySourceDef, SourceDef, SourceID, SourceRegistryEntry, SourceRegistryValue, SQLPhraseSegment, SQLSourceDef, TableSourceDef } from './malloy_types';
|
|
11
|
+
export declare function mkSourceID(name: string, url: string | undefined): SourceID;
|
|
12
|
+
/**
|
|
13
|
+
* Create a BuildID from connection digest and SQL.
|
|
14
|
+
* BuildID is a hash that uniquely identifies a build artifact.
|
|
15
|
+
*/
|
|
16
|
+
export declare function mkBuildID(connectionDigest: string, sql: string): BuildID;
|
|
17
|
+
/**
|
|
18
|
+
* Create a QuerySourceDef from query compilation output.
|
|
19
|
+
* Explicitly copies SourceDefBase fields - no spread.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mkQuerySourceDef(base: SourceDef, query: Query, name: string): QuerySourceDef;
|
|
22
|
+
/**
|
|
23
|
+
* Create an SQLSourceDef from schema lookup result.
|
|
24
|
+
* Explicitly copies SourceDefBase fields - no spread.
|
|
25
|
+
*/
|
|
26
|
+
export declare function mkSQLSourceDef(base: SourceDef, selectStr: string, selectSegments?: SQLPhraseSegment[]): SQLSourceDef;
|
|
27
|
+
/**
|
|
28
|
+
* Create a TableSourceDef. All fields specified, no base to copy from.
|
|
29
|
+
*/
|
|
30
|
+
export declare function mkTableSourceDef(name: string, connection: string, tablePath: string, dialect: string, fields: FieldDef[]): TableSourceDef;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve a sourceID to a SourceDef using the sourceRegistry.
|
|
33
|
+
*
|
|
34
|
+
* @param modelDef The model definition containing the registry
|
|
35
|
+
* @param sourceID The sourceID to resolve
|
|
36
|
+
* @returns The SourceDef if found, undefined otherwise
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveSourceID(modelDef: ModelDef, sourceID: SourceID): PersistableSourceDef | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Add an entry to the sourceRegistry.
|
|
41
|
+
*
|
|
42
|
+
* @param registry The sourceRegistry to modify (from ModelDef or Document)
|
|
43
|
+
* @param sourceID The sourceID to register
|
|
44
|
+
* @param entry Either a SourceRegistryReference (for namespace sources) or a PersistableSourceDef (for hidden deps)
|
|
45
|
+
*/
|
|
46
|
+
export declare function registerSource(registry: Record<SourceID, SourceRegistryValue>, sourceID: SourceID, entry: SourceRegistryEntry): void;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a sourceID is already in the registry.
|
|
49
|
+
*/
|
|
50
|
+
export declare function hasSourceRegistryEntry(modelDef: ModelDef, sourceID: SourceID): boolean;
|
|
@@ -0,0 +1,154 @@
|
|
|
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.mkSourceID = mkSourceID;
|
|
8
|
+
exports.mkBuildID = mkBuildID;
|
|
9
|
+
exports.mkQuerySourceDef = mkQuerySourceDef;
|
|
10
|
+
exports.mkSQLSourceDef = mkSQLSourceDef;
|
|
11
|
+
exports.mkTableSourceDef = mkTableSourceDef;
|
|
12
|
+
exports.resolveSourceID = resolveSourceID;
|
|
13
|
+
exports.registerSource = registerSource;
|
|
14
|
+
exports.hasSourceRegistryEntry = hasSourceRegistryEntry;
|
|
15
|
+
const utils_1 = require("./utils");
|
|
16
|
+
const malloy_types_1 = require("./malloy_types");
|
|
17
|
+
function mkSourceID(name, url) {
|
|
18
|
+
return `${name}@${url !== null && url !== void 0 ? url : 'unknown'}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a BuildID from connection digest and SQL.
|
|
22
|
+
* BuildID is a hash that uniquely identifies a build artifact.
|
|
23
|
+
*/
|
|
24
|
+
function mkBuildID(connectionDigest, sql) {
|
|
25
|
+
return (0, utils_1.makeDigest)(connectionDigest, sql);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a QuerySourceDef from query compilation output.
|
|
29
|
+
* Explicitly copies SourceDefBase fields - no spread.
|
|
30
|
+
*/
|
|
31
|
+
function mkQuerySourceDef(base, query, name) {
|
|
32
|
+
return {
|
|
33
|
+
// Type discriminant
|
|
34
|
+
type: 'query_source',
|
|
35
|
+
// QuerySourceDef-specific
|
|
36
|
+
query,
|
|
37
|
+
// NamedObject
|
|
38
|
+
name,
|
|
39
|
+
as: base.as,
|
|
40
|
+
// HasLocation
|
|
41
|
+
location: base.location,
|
|
42
|
+
// StructDefBase
|
|
43
|
+
annotation: base.annotation,
|
|
44
|
+
modelAnnotation: base.modelAnnotation,
|
|
45
|
+
fields: base.fields,
|
|
46
|
+
// Filtered
|
|
47
|
+
filterList: base.filterList,
|
|
48
|
+
// ResultStructMetadata
|
|
49
|
+
resultMetadata: base.resultMetadata,
|
|
50
|
+
// SourceDefBase
|
|
51
|
+
arguments: query.sourceArguments,
|
|
52
|
+
parameters: base.parameters,
|
|
53
|
+
queryTimezone: base.queryTimezone,
|
|
54
|
+
connection: base.connection,
|
|
55
|
+
primaryKey: base.primaryKey,
|
|
56
|
+
dialect: base.dialect,
|
|
57
|
+
partitionComposite: base.partitionComposite,
|
|
58
|
+
errorFactory: base.errorFactory,
|
|
59
|
+
// PersistableSourceProperties - explicitly NOT copied
|
|
60
|
+
// sourceID: undefined,
|
|
61
|
+
// extends: undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create an SQLSourceDef from schema lookup result.
|
|
66
|
+
* Explicitly copies SourceDefBase fields - no spread.
|
|
67
|
+
*/
|
|
68
|
+
function mkSQLSourceDef(base, selectStr, selectSegments) {
|
|
69
|
+
return {
|
|
70
|
+
// Type discriminant
|
|
71
|
+
type: 'sql_select',
|
|
72
|
+
// SQLSourceDef-specific
|
|
73
|
+
selectStr,
|
|
74
|
+
selectSegments,
|
|
75
|
+
// NamedObject
|
|
76
|
+
name: base.name,
|
|
77
|
+
as: base.as,
|
|
78
|
+
// HasLocation
|
|
79
|
+
location: base.location,
|
|
80
|
+
// StructDefBase
|
|
81
|
+
annotation: base.annotation,
|
|
82
|
+
modelAnnotation: base.modelAnnotation,
|
|
83
|
+
fields: base.fields,
|
|
84
|
+
// Filtered
|
|
85
|
+
filterList: base.filterList,
|
|
86
|
+
// ResultStructMetadata
|
|
87
|
+
resultMetadata: base.resultMetadata,
|
|
88
|
+
// SourceDefBase
|
|
89
|
+
arguments: base.arguments,
|
|
90
|
+
parameters: base.parameters,
|
|
91
|
+
queryTimezone: base.queryTimezone,
|
|
92
|
+
connection: base.connection,
|
|
93
|
+
primaryKey: base.primaryKey,
|
|
94
|
+
dialect: base.dialect,
|
|
95
|
+
partitionComposite: base.partitionComposite,
|
|
96
|
+
errorFactory: base.errorFactory,
|
|
97
|
+
// PersistableSourceProperties - explicitly NOT copied
|
|
98
|
+
// sourceID: undefined,
|
|
99
|
+
// extends: undefined,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a TableSourceDef. All fields specified, no base to copy from.
|
|
104
|
+
*/
|
|
105
|
+
function mkTableSourceDef(name, connection, tablePath, dialect, fields) {
|
|
106
|
+
return {
|
|
107
|
+
type: 'table',
|
|
108
|
+
name,
|
|
109
|
+
connection,
|
|
110
|
+
tablePath,
|
|
111
|
+
dialect,
|
|
112
|
+
fields,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// =============================================================================
|
|
116
|
+
// Source Registry Utilities
|
|
117
|
+
// =============================================================================
|
|
118
|
+
/**
|
|
119
|
+
* Resolve a sourceID to a SourceDef using the sourceRegistry.
|
|
120
|
+
*
|
|
121
|
+
* @param modelDef The model definition containing the registry
|
|
122
|
+
* @param sourceID The sourceID to resolve
|
|
123
|
+
* @returns The SourceDef if found, undefined otherwise
|
|
124
|
+
*/
|
|
125
|
+
function resolveSourceID(modelDef, sourceID) {
|
|
126
|
+
const value = modelDef.sourceRegistry[sourceID];
|
|
127
|
+
if (!value)
|
|
128
|
+
return undefined;
|
|
129
|
+
if ((0, malloy_types_1.isSourceRegistryReference)(value.entry)) {
|
|
130
|
+
const obj = modelDef.contents[value.entry.name];
|
|
131
|
+
return obj && (0, malloy_types_1.isSourceDef)(obj) && (0, malloy_types_1.isPersistableSourceDef)(obj)
|
|
132
|
+
? obj
|
|
133
|
+
: undefined;
|
|
134
|
+
}
|
|
135
|
+
// It's a PersistableSourceDef
|
|
136
|
+
return value.entry;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Add an entry to the sourceRegistry.
|
|
140
|
+
*
|
|
141
|
+
* @param registry The sourceRegistry to modify (from ModelDef or Document)
|
|
142
|
+
* @param sourceID The sourceID to register
|
|
143
|
+
* @param entry Either a SourceRegistryReference (for namespace sources) or a PersistableSourceDef (for hidden deps)
|
|
144
|
+
*/
|
|
145
|
+
function registerSource(registry, sourceID, entry) {
|
|
146
|
+
registry[sourceID] = { entry };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if a sourceID is already in the registry.
|
|
150
|
+
*/
|
|
151
|
+
function hasSourceRegistryEntry(modelDef, sourceID) {
|
|
152
|
+
return sourceID in modelDef.sourceRegistry;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=source_def_utils.js.map
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { SQLSourceRequest } from '../lang/translate-response';
|
|
2
2
|
import type { SQLPhraseSegment, ModelDef } from './malloy_types';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The translator needs to know the output schema of an SQLSourceDef
|
|
5
|
+
* this will prepare an SQL string suitable to answer that question.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getSourceRequest(select: SQLPhraseSegment[], connection: string, partialModel: ModelDef | undefined): SQLSourceRequest;
|
|
4
8
|
export declare function sqlKey(connectionName: string, sql: string): string;
|
package/dist/model/sql_block.js
CHANGED
|
@@ -22,12 +22,16 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
25
|
+
exports.getSourceRequest = getSourceRequest;
|
|
26
26
|
exports.sqlKey = sqlKey;
|
|
27
27
|
const query_model_1 = require("./query_model");
|
|
28
28
|
const malloy_types_1 = require("./malloy_types");
|
|
29
29
|
const utils_1 = require("./utils");
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The translator needs to know the output schema of an SQLSourceDef
|
|
32
|
+
* this will prepare an SQL string suitable to answer that question.
|
|
33
|
+
*/
|
|
34
|
+
function getSourceRequest(select, connection, partialModel) {
|
|
31
35
|
let queryModel = undefined;
|
|
32
36
|
let selectStr = '';
|
|
33
37
|
let parenAlready = false;
|
|
@@ -36,8 +40,30 @@ function compileSQLInterpolation(select, connection, partialModel) {
|
|
|
36
40
|
selectStr += segment.sql;
|
|
37
41
|
parenAlready = segment.sql.match(/\(\s*$/) !== null;
|
|
38
42
|
}
|
|
43
|
+
else if ((0, malloy_types_1.isSegmentSource)(segment)) {
|
|
44
|
+
// PersistableSourceDef (sql_select or query_source)
|
|
45
|
+
let compiledSql;
|
|
46
|
+
if (segment.type === 'sql_select') {
|
|
47
|
+
compiledSql = segment.selectStr;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// query_source - compile the inner query
|
|
51
|
+
if (!queryModel) {
|
|
52
|
+
if (!partialModel) {
|
|
53
|
+
throw new Error('Internal error: Partial model missing when compiling SQL block');
|
|
54
|
+
}
|
|
55
|
+
queryModel = (0, query_model_1.makeQueryModel)(partialModel);
|
|
56
|
+
}
|
|
57
|
+
compiledSql = queryModel.compileQuery(segment.query, {
|
|
58
|
+
defaultRowLimit: undefined,
|
|
59
|
+
isPartialQuery: true,
|
|
60
|
+
}, false).sql;
|
|
61
|
+
}
|
|
62
|
+
selectStr += parenAlready ? compiledSql : `(${compiledSql})`;
|
|
63
|
+
parenAlready = false;
|
|
64
|
+
}
|
|
39
65
|
else {
|
|
40
|
-
//
|
|
66
|
+
// Query segment
|
|
41
67
|
if (!queryModel) {
|
|
42
68
|
if (!partialModel) {
|
|
43
69
|
throw new Error('Internal error: Partial model missing when compiling SQL block');
|
|
@@ -49,7 +75,6 @@ function compileSQLInterpolation(select, connection, partialModel) {
|
|
|
49
75
|
isPartialQuery: true,
|
|
50
76
|
}, false).sql;
|
|
51
77
|
selectStr += parenAlready ? compiledSql : `(${compiledSql})`;
|
|
52
|
-
// console.log(selectStr);
|
|
53
78
|
parenAlready = false;
|
|
54
79
|
}
|
|
55
80
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PrepareResultOptions, SQLSourceDef, PersistableSourceDef, Query } from './malloy_types';
|
|
2
|
+
/**
|
|
3
|
+
* Callback type for compiling a Query to SQL.
|
|
4
|
+
* opts is optional - omit for "full SQL" (BuildID computation),
|
|
5
|
+
* provide for "run SQL" (with manifest substitution).
|
|
6
|
+
*/
|
|
7
|
+
export type CompileQueryCallback = (query: Query, opts?: PrepareResultOptions) => string;
|
|
8
|
+
/**
|
|
9
|
+
* Compile a SQLSourceDef to its final SQL string.
|
|
10
|
+
*
|
|
11
|
+
* If the source has selectSegments (interpolated persistent sources), each segment
|
|
12
|
+
* is expanded by looking up in the manifest or compiling inline.
|
|
13
|
+
*
|
|
14
|
+
* @param src The SQLSourceDef to compile
|
|
15
|
+
* @param opts PrepareResultOptions with buildManifest and connectionDigests
|
|
16
|
+
* @param quoteTablePath Dialect function to safely quote a table path
|
|
17
|
+
* @param compileQuery Callback to compile a Query to SQL
|
|
18
|
+
*/
|
|
19
|
+
export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOptions, quoteTablePath: (path: string) => string, compileQuery: CompileQueryCallback): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get the SQL for a PersistableSourceDef.
|
|
22
|
+
*
|
|
23
|
+
* @param source The persistable source to compile
|
|
24
|
+
* @param quoteTablePath Dialect function to quote table paths
|
|
25
|
+
* @param compileQuery Callback to compile a Query to SQL
|
|
26
|
+
* @param opts Optional - if provided with manifest, nested sources may be substituted.
|
|
27
|
+
* Omit for "full SQL" (e.g., when computing BuildID).
|
|
28
|
+
*/
|
|
29
|
+
export declare function getSourceSQL(source: PersistableSourceDef, quoteTablePath: (path: string) => string, compileQuery: CompileQueryCallback, opts?: PrepareResultOptions): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
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.getCompiledSQL = getCompiledSQL;
|
|
8
|
+
exports.getSourceSQL = getSourceSQL;
|
|
9
|
+
const malloy_types_1 = require("./malloy_types");
|
|
10
|
+
const source_def_utils_1 = require("./source_def_utils");
|
|
11
|
+
/**
|
|
12
|
+
* Compile a SQLSourceDef to its final SQL string.
|
|
13
|
+
*
|
|
14
|
+
* If the source has selectSegments (interpolated persistent sources), each segment
|
|
15
|
+
* is expanded by looking up in the manifest or compiling inline.
|
|
16
|
+
*
|
|
17
|
+
* @param src The SQLSourceDef to compile
|
|
18
|
+
* @param opts PrepareResultOptions with buildManifest and connectionDigests
|
|
19
|
+
* @param quoteTablePath Dialect function to safely quote a table path
|
|
20
|
+
* @param compileQuery Callback to compile a Query to SQL
|
|
21
|
+
*/
|
|
22
|
+
function getCompiledSQL(src, opts, quoteTablePath, compileQuery) {
|
|
23
|
+
// If no segments, just return the pre-computed selectStr
|
|
24
|
+
if (!src.selectSegments || src.selectSegments.length === 0) {
|
|
25
|
+
return src.selectStr;
|
|
26
|
+
}
|
|
27
|
+
// Expand each segment
|
|
28
|
+
const parts = [];
|
|
29
|
+
for (const segment of src.selectSegments) {
|
|
30
|
+
parts.push(expandSegment(segment, opts, quoteTablePath, compileQuery));
|
|
31
|
+
}
|
|
32
|
+
return parts.join('');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Expand a single SQLPhraseSegment to SQL.
|
|
36
|
+
*/
|
|
37
|
+
function expandSegment(segment, opts, quoteTablePath, compileQuery) {
|
|
38
|
+
// Plain SQL string
|
|
39
|
+
if ((0, malloy_types_1.isSegmentSQL)(segment)) {
|
|
40
|
+
return segment.sql;
|
|
41
|
+
}
|
|
42
|
+
// PersistableSourceDef (sql_select or query_source)
|
|
43
|
+
if ((0, malloy_types_1.isSegmentSource)(segment)) {
|
|
44
|
+
return expandPersistableSource(segment, opts, quoteTablePath, compileQuery);
|
|
45
|
+
}
|
|
46
|
+
// Query segment
|
|
47
|
+
return expandQuery(segment, opts, quoteTablePath, compileQuery);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Expand a PersistableSourceDef, checking manifest for pre-built table.
|
|
51
|
+
* Always returns a subquery form: (SELECT * FROM table) or (inline SQL)
|
|
52
|
+
*/
|
|
53
|
+
function expandPersistableSource(source, opts, quoteTablePath, compileQuery) {
|
|
54
|
+
const { buildManifest, connectionDigests, strictPersist } = opts;
|
|
55
|
+
// Try manifest lookup if we have the required info
|
|
56
|
+
if (buildManifest && connectionDigests) {
|
|
57
|
+
const connDigest = connectionDigests[source.connection];
|
|
58
|
+
if (connDigest) {
|
|
59
|
+
// Get the SQL for this source to compute BuildID (no opts = full SQL)
|
|
60
|
+
const sql = getSourceSQL(source, quoteTablePath, compileQuery);
|
|
61
|
+
const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, sql);
|
|
62
|
+
const entry = buildManifest.buildEntries[buildId];
|
|
63
|
+
if (entry) {
|
|
64
|
+
// Found in manifest - substitute with subquery from persisted table
|
|
65
|
+
return `(SELECT * FROM ${quoteTablePath(entry.tableName)})`;
|
|
66
|
+
}
|
|
67
|
+
// Not in manifest
|
|
68
|
+
if (strictPersist) {
|
|
69
|
+
throw new Error(`Persist source '${source.sourceID}' not found in manifest (buildId: ${buildId})`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// No manifest or not found - expand inline as subquery
|
|
74
|
+
const sql = getSourceSQL(source, quoteTablePath, compileQuery, opts);
|
|
75
|
+
return `(${sql})`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Expand a Query segment.
|
|
79
|
+
*/
|
|
80
|
+
function expandQuery(query, opts, _quoteTablePath, compileQuery) {
|
|
81
|
+
// Set isPartialQuery so CTEs aren't used (they can't be nested in subqueries)
|
|
82
|
+
const sql = compileQuery(query, { ...opts, isPartialQuery: true });
|
|
83
|
+
return `(${sql})`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the SQL for a PersistableSourceDef.
|
|
87
|
+
*
|
|
88
|
+
* @param source The persistable source to compile
|
|
89
|
+
* @param quoteTablePath Dialect function to quote table paths
|
|
90
|
+
* @param compileQuery Callback to compile a Query to SQL
|
|
91
|
+
* @param opts Optional - if provided with manifest, nested sources may be substituted.
|
|
92
|
+
* Omit for "full SQL" (e.g., when computing BuildID).
|
|
93
|
+
*/
|
|
94
|
+
function getSourceSQL(source, quoteTablePath, compileQuery, opts) {
|
|
95
|
+
if (source.type === 'sql_select') {
|
|
96
|
+
// Recursive call for nested sql_select
|
|
97
|
+
return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {}, quoteTablePath, compileQuery);
|
|
98
|
+
}
|
|
99
|
+
// query_source - compile the inner query
|
|
100
|
+
return compileQuery(source.query, opts);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=sql_compiled.js.map
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { Dialect } from '../dialect';
|
|
2
|
-
import type {
|
|
2
|
+
import type { StructDef } from './malloy_types';
|
|
3
3
|
export declare class StageWriter {
|
|
4
4
|
parent: StageWriter | undefined;
|
|
5
5
|
withs: string[];
|
|
6
6
|
stageNames: string[];
|
|
7
7
|
udfs: string[];
|
|
8
8
|
pdts: string[];
|
|
9
|
-
dependenciesToMaterialize: Record<string, QueryToMaterialize>;
|
|
10
9
|
stagePrefix: string;
|
|
11
10
|
useCTE: boolean;
|
|
12
11
|
stageNumber: number;
|
|
@@ -16,7 +15,6 @@ export declare class StageWriter {
|
|
|
16
15
|
root(): StageWriter;
|
|
17
16
|
addStage(sql: string): string;
|
|
18
17
|
addUDF(stageWriter: StageWriter, dialect: Dialect, structDef: StructDef): string;
|
|
19
|
-
addMaterializedQuery(fieldName: string, query: Query, materializatedTablePrefix?: string): string;
|
|
20
18
|
addPDT(baseName: string, dialect: Dialect): string;
|
|
21
19
|
combineStages(includeLastStage: boolean): {
|
|
22
20
|
sql: string;
|