@malloydata/malloy 0.0.335 → 0.0.337
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 +201 -0
- package/dist/api/foundation/compile.js +429 -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/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/connection/registry.d.ts +73 -0
- package/dist/connection/registry.js +106 -0
- package/dist/connection/types.d.ts +5 -15
- 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 +9 -4
- package/dist/index.js +37 -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
|
@@ -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;
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.StageWriter = void 0;
|
|
8
|
-
const utils_1 = require("./
|
|
9
|
-
const utils_2 = require("./utils");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
10
9
|
class StageWriter {
|
|
11
10
|
constructor(useCTE = true, parent) {
|
|
12
11
|
this.parent = parent;
|
|
@@ -14,7 +13,6 @@ class StageWriter {
|
|
|
14
13
|
this.stageNames = [];
|
|
15
14
|
this.udfs = [];
|
|
16
15
|
this.pdts = [];
|
|
17
|
-
this.dependenciesToMaterialize = {};
|
|
18
16
|
this.stagePrefix = '__stage';
|
|
19
17
|
this.stageNumber = 0;
|
|
20
18
|
this.useCTE = useCTE;
|
|
@@ -43,7 +41,7 @@ class StageWriter {
|
|
|
43
41
|
}
|
|
44
42
|
else {
|
|
45
43
|
this.withs[0] = sql;
|
|
46
|
-
return (0,
|
|
44
|
+
return (0, utils_1.indent)(`\n(${sql})\n`);
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
addUDF(stageWriter, dialect, structDef) {
|
|
@@ -53,31 +51,15 @@ class StageWriter {
|
|
|
53
51
|
if (lastStageName === undefined) {
|
|
54
52
|
throw new Error('Internal Error: no stage to combine');
|
|
55
53
|
}
|
|
56
|
-
sql += dialect.sqlCreateFunctionCombineLastStage(lastStageName, (0,
|
|
54
|
+
sql += dialect.sqlCreateFunctionCombineLastStage(lastStageName, (0, utils_1.getDialectFieldList)(structDef), (_a = structDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.orderBy);
|
|
57
55
|
const id = `${dialect.udfPrefix}${this.root().udfs.length}`;
|
|
58
56
|
sql = dialect.sqlCreateFunction(id, sql);
|
|
59
57
|
this.root().udfs.push(sql);
|
|
60
58
|
return id;
|
|
61
59
|
}
|
|
62
|
-
addMaterializedQuery(fieldName, query, materializatedTablePrefix) {
|
|
63
|
-
var _a;
|
|
64
|
-
const name = query.name;
|
|
65
|
-
if (!name) {
|
|
66
|
-
throw new Error(`Source ${fieldName} on a unnamed query that is tagged as materialize, only named queries can be materialized.`);
|
|
67
|
-
}
|
|
68
|
-
const path = (_a = query.location) === null || _a === void 0 ? void 0 : _a.url;
|
|
69
|
-
if (!path) {
|
|
70
|
-
throw new Error(`Trying to materialize query ${name}, but its path is not set.`);
|
|
71
|
-
}
|
|
72
|
-
// Creating an object that should uniquely identify a query within a Malloy model repo.
|
|
73
|
-
const queryMaterializationSpec = (0, utils_1.buildQueryMaterializationSpec)(path, name, materializatedTablePrefix);
|
|
74
|
-
this.root().dependenciesToMaterialize[queryMaterializationSpec.id] =
|
|
75
|
-
queryMaterializationSpec;
|
|
76
|
-
return queryMaterializationSpec.id;
|
|
77
|
-
}
|
|
78
60
|
addPDT(baseName, dialect) {
|
|
79
61
|
const sql = this.combineStages(false).sql + this.withs[this.withs.length - 1];
|
|
80
|
-
const name = baseName + (0,
|
|
62
|
+
const name = baseName + (0, utils_1.generateHash)(sql);
|
|
81
63
|
const tableName = `scratch.${name}`;
|
|
82
64
|
this.root().pdts.push(dialect.sqlCreateTableAsSelect(tableName, sql));
|
|
83
65
|
return tableName;
|
|
@@ -97,7 +79,7 @@ class StageWriter {
|
|
|
97
79
|
if (sql === undefined) {
|
|
98
80
|
throw new Error(`Expected sql WITH to be present for stage ${lastStageName}.`);
|
|
99
81
|
}
|
|
100
|
-
w += `${prefix}${lastStageName} AS (\n${(0,
|
|
82
|
+
w += `${prefix}${lastStageName} AS (\n${(0, utils_1.indent)(sql)})\n`;
|
|
101
83
|
prefix = ', ';
|
|
102
84
|
}
|
|
103
85
|
return { sql: w, lastStageName };
|
|
@@ -116,11 +98,11 @@ class StageWriter {
|
|
|
116
98
|
generateCoorelatedSubQuery(dialect, structDef) {
|
|
117
99
|
var _a, _b;
|
|
118
100
|
if (!this.useCTE) {
|
|
119
|
-
return dialect.sqlCreateFunctionCombineLastStage(`(${this.withs[0]})`, (0,
|
|
101
|
+
return dialect.sqlCreateFunctionCombineLastStage(`(${this.withs[0]})`, (0, utils_1.getDialectFieldList)(structDef), (_a = structDef.resultMetadata) === null || _a === void 0 ? void 0 : _a.orderBy);
|
|
120
102
|
}
|
|
121
103
|
else {
|
|
122
104
|
return (this.combineStages(true).sql +
|
|
123
|
-
dialect.sqlCreateFunctionCombineLastStage(this.getName(this.withs.length - 1), (0,
|
|
105
|
+
dialect.sqlCreateFunctionCombineLastStage(this.getName(this.withs.length - 1), (0, utils_1.getDialectFieldList)(structDef), (_b = structDef.resultMetadata) === null || _b === void 0 ? void 0 : _b.orderBy));
|
|
124
106
|
}
|
|
125
107
|
}
|
|
126
108
|
}
|
package/dist/model/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Expr, GenericSQLExpr, StructDef } from './malloy_types';
|
|
1
|
+
import type { Expr, GenericSQLExpr, ModelDef, StructDef } from './malloy_types';
|
|
2
2
|
import type { DialectFieldList } from '../dialect';
|
|
3
3
|
/** simple indent function */
|
|
4
4
|
export declare function indent(s: string): string;
|
|
@@ -22,6 +22,20 @@ export declare class AndChain {
|
|
|
22
22
|
sql(whereOrHaving?: 'where' | 'having'): string;
|
|
23
23
|
}
|
|
24
24
|
export declare function generateHash(input: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Compute a digest for lookup/identity purposes (not cryptographic).
|
|
27
|
+
*
|
|
28
|
+
* Uses blueimp-md5 for these reasons:
|
|
29
|
+
* - Works in both Node.js and browsers (no native crypto dependency)
|
|
30
|
+
* - Synchronous API (unlike Web Crypto which is async)
|
|
31
|
+
* - Well-maintained by Sebastian Tschan (blueimp), a known maintainer
|
|
32
|
+
* - High adoption (~1.7M weekly downloads)
|
|
33
|
+
* - MD5 is fast and produces short hex strings - perfect for cache keys
|
|
34
|
+
*
|
|
35
|
+
* Takes variable string arguments and combines them in a collision-resistant
|
|
36
|
+
* way by including the length of each string (similar to pathToKey pattern).
|
|
37
|
+
*/
|
|
38
|
+
export declare function makeDigest(...parts: string[]): string;
|
|
25
39
|
export declare function joinWith<T>(els: T[][], sep: T): T[];
|
|
26
40
|
export declare function range(start: number, end: number): number[];
|
|
27
41
|
export declare function exprKids(eNode: Expr): IterableIterator<Expr>;
|
|
@@ -49,3 +63,8 @@ export declare class GenerateState {
|
|
|
49
63
|
withApply(s: string): GenerateState;
|
|
50
64
|
withTotal(groupSet: number): GenerateState;
|
|
51
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Create an empty ModelDef with the given name.
|
|
68
|
+
* Use this factory to ensure all required fields are present.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mkModelDef(name: string): ModelDef;
|
package/dist/model/utils.js
CHANGED
|
@@ -21,11 +21,15 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
25
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
|
+
};
|
|
24
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
28
|
exports.GenerateState = exports.AndChain = void 0;
|
|
26
29
|
exports.indent = indent;
|
|
27
30
|
exports.generateSQLStringLiteral = generateSQLStringLiteral;
|
|
28
31
|
exports.generateHash = generateHash;
|
|
32
|
+
exports.makeDigest = makeDigest;
|
|
29
33
|
exports.joinWith = joinWith;
|
|
30
34
|
exports.range = range;
|
|
31
35
|
exports.exprKids = exprKids;
|
|
@@ -36,7 +40,9 @@ exports.getDialectFieldList = getDialectFieldList;
|
|
|
36
40
|
exports.pathToKey = pathToKey;
|
|
37
41
|
exports.groupingKey = groupingKey;
|
|
38
42
|
exports.caseGroup = caseGroup;
|
|
43
|
+
exports.mkModelDef = mkModelDef;
|
|
39
44
|
const uuid_1 = require("uuid");
|
|
45
|
+
const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
|
|
40
46
|
const malloy_types_1 = require("./malloy_types");
|
|
41
47
|
/** simple indent function */
|
|
42
48
|
function indent(s) {
|
|
@@ -108,6 +114,26 @@ function generateHash(input) {
|
|
|
108
114
|
const MALLOY_UUID = '76c17e9d-f3ce-5f2d-bfde-98ad3d2a37f6';
|
|
109
115
|
return (0, uuid_1.v5)(input, MALLOY_UUID);
|
|
110
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Compute a digest for lookup/identity purposes (not cryptographic).
|
|
119
|
+
*
|
|
120
|
+
* Uses blueimp-md5 for these reasons:
|
|
121
|
+
* - Works in both Node.js and browsers (no native crypto dependency)
|
|
122
|
+
* - Synchronous API (unlike Web Crypto which is async)
|
|
123
|
+
* - Well-maintained by Sebastian Tschan (blueimp), a known maintainer
|
|
124
|
+
* - High adoption (~1.7M weekly downloads)
|
|
125
|
+
* - MD5 is fast and produces short hex strings - perfect for cache keys
|
|
126
|
+
*
|
|
127
|
+
* Takes variable string arguments and combines them in a collision-resistant
|
|
128
|
+
* way by including the length of each string (similar to pathToKey pattern).
|
|
129
|
+
*/
|
|
130
|
+
function makeDigest(...parts) {
|
|
131
|
+
// Combine parts with length prefix to avoid collisions
|
|
132
|
+
// e.g., ("ab", "c") vs ("a", "bc") both concat to "abc"
|
|
133
|
+
// but with lengths: "2:ab/1:c" vs "1:a/2:bc"
|
|
134
|
+
const combined = parts.map(p => `${p.length}:${p}`).join('/');
|
|
135
|
+
return (0, blueimp_md5_1.default)(combined);
|
|
136
|
+
}
|
|
111
137
|
function joinWith(els, sep) {
|
|
112
138
|
const result = [];
|
|
113
139
|
for (let i = 0; i < els.length; i++) {
|
|
@@ -260,4 +286,18 @@ class GenerateState {
|
|
|
260
286
|
}
|
|
261
287
|
}
|
|
262
288
|
exports.GenerateState = GenerateState;
|
|
289
|
+
/**
|
|
290
|
+
* Create an empty ModelDef with the given name.
|
|
291
|
+
* Use this factory to ensure all required fields are present.
|
|
292
|
+
*/
|
|
293
|
+
function mkModelDef(name) {
|
|
294
|
+
return {
|
|
295
|
+
name,
|
|
296
|
+
exports: [],
|
|
297
|
+
contents: {},
|
|
298
|
+
sourceRegistry: {},
|
|
299
|
+
queryList: [],
|
|
300
|
+
dependencies: {},
|
|
301
|
+
};
|
|
302
|
+
}
|
|
263
303
|
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TagParseSpec, MalloyTagParse } from './annotation';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for objects that have Malloy tag annotations.
|
|
4
|
+
* This is part of the runtime API - objects returned from the Malloy
|
|
5
|
+
* runtime implement this interface to expose their tag metadata.
|
|
6
|
+
*/
|
|
7
|
+
export interface Taggable {
|
|
8
|
+
tagParse: (spec?: TagParseSpec) => MalloyTagParse;
|
|
9
|
+
getTaglines: (prefix?: RegExp) => string[];
|
|
10
|
+
}
|
package/dist/taggable.js
ADDED
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.337";
|
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.
|
|
5
|
+
exports.MALLOY_VERSION = '0.0.337';
|
|
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.
|
|
3
|
+
"version": "0.0.337",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -45,11 +45,12 @@
|
|
|
45
45
|
"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"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@malloydata/malloy-filter": "0.0.
|
|
49
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
50
|
-
"@malloydata/malloy-tag": "0.0.
|
|
48
|
+
"@malloydata/malloy-filter": "0.0.337",
|
|
49
|
+
"@malloydata/malloy-interfaces": "0.0.337",
|
|
50
|
+
"@malloydata/malloy-tag": "0.0.337",
|
|
51
51
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
52
52
|
"assert": "^2.0.0",
|
|
53
|
+
"blueimp-md5": "^2.19.0",
|
|
53
54
|
"jaro-winkler": "^0.2.8",
|
|
54
55
|
"jest-diff": "^29.6.2",
|
|
55
56
|
"lodash": "^4.17.20",
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
"uuid": "^8.3.2"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
61
|
+
"@types/blueimp-md5": "^2.18.2",
|
|
60
62
|
"@types/jaro-winkler": "^0.2.3",
|
|
61
63
|
"@types/lodash": "^4.14.165",
|
|
62
64
|
"@types/luxon": "^3.5.0",
|