@malloydata/malloy 0.0.146 → 0.0.147-dev240521202508
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/dist/dialect/dialect.d.ts +1 -0
- package/dist/dialect/duckdb/duckdb.d.ts +1 -0
- package/dist/dialect/duckdb/duckdb.js +1 -0
- package/dist/dialect/postgres/postgres.d.ts +1 -0
- package/dist/dialect/postgres/postgres.js +1 -0
- package/dist/dialect/snowflake/snowflake.d.ts +1 -0
- package/dist/dialect/snowflake/snowflake.js +1 -0
- package/dist/dialect/standardsql/standardsql.d.ts +1 -0
- package/dist/dialect/standardsql/standardsql.js +1 -0
- package/dist/dialect/trino/trino.d.ts +1 -0
- package/dist/dialect/trino/trino.js +1 -0
- package/dist/lang/ast/source-elements/named-source.js +4 -0
- package/dist/lang/ast/source-elements/sql-source.js +3 -0
- package/dist/lang/ast/source-elements/table-source.js +3 -2
- package/dist/lang/ast/types/malloy-element.d.ts +7 -0
- package/dist/lang/ast/types/malloy-element.js +19 -0
- package/dist/lang/parse-malloy.d.ts +4 -0
- package/dist/lang/parse-malloy.js +27 -0
- package/dist/lang/test/sql-block.spec.js +2 -2
- package/dist/lang/test/test-translator.d.ts +1 -0
- package/dist/lang/test/test-translator.js +1 -0
- package/dist/malloy.d.ts +2 -0
- package/dist/malloy.js +28 -0
- package/package.json +1 -1
|
@@ -46,6 +46,7 @@ export declare abstract class Dialect {
|
|
|
46
46
|
abstract supportsQualify: boolean;
|
|
47
47
|
abstract supportsSafeCast: boolean;
|
|
48
48
|
abstract supportsNesting: boolean;
|
|
49
|
+
abstract experimental: boolean;
|
|
49
50
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
50
51
|
supportsPipelinesInViews: boolean;
|
|
51
52
|
supportsArraysInData: boolean;
|
|
@@ -3,6 +3,7 @@ import { DialectFunctionOverloadDef } from '../functions';
|
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class DuckDBDialect extends Dialect {
|
|
5
5
|
name: string;
|
|
6
|
+
experimental: boolean;
|
|
6
7
|
defaultNumberType: string;
|
|
7
8
|
defaultDecimalType: string;
|
|
8
9
|
hasFinalStage: boolean;
|
|
@@ -21,6 +21,7 @@ export declare class PostgresDialect extends Dialect {
|
|
|
21
21
|
supportsQualify: boolean;
|
|
22
22
|
globalFunctions: import("../functions/function_map").FunctionMap;
|
|
23
23
|
supportsNesting: boolean;
|
|
24
|
+
experimental: boolean;
|
|
24
25
|
readsNestedData: boolean;
|
|
25
26
|
quoteTablePath(tablePath: string): string;
|
|
26
27
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
@@ -93,6 +93,7 @@ class PostgresDialect extends dialect_1.Dialect {
|
|
|
93
93
|
this.supportsQualify = false;
|
|
94
94
|
this.globalFunctions = functions_1.POSTGRES_FUNCTIONS;
|
|
95
95
|
this.supportsNesting = true;
|
|
96
|
+
this.experimental = false;
|
|
96
97
|
this.readsNestedData = false;
|
|
97
98
|
}
|
|
98
99
|
quoteTablePath(tablePath) {
|
|
@@ -3,6 +3,7 @@ import { DialectFunctionOverloadDef } from '../functions';
|
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class SnowflakeDialect extends Dialect {
|
|
5
5
|
name: string;
|
|
6
|
+
experimental: boolean;
|
|
6
7
|
defaultNumberType: string;
|
|
7
8
|
defaultDecimalType: string;
|
|
8
9
|
udfPrefix: string;
|
|
@@ -3,6 +3,7 @@ import { DialectFunctionOverloadDef } from '../functions';
|
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class StandardSQLDialect extends Dialect {
|
|
5
5
|
name: string;
|
|
6
|
+
experimental: boolean;
|
|
6
7
|
defaultNumberType: string;
|
|
7
8
|
defaultDecimalType: string;
|
|
8
9
|
udfPrefix: string;
|
|
@@ -77,6 +77,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
77
77
|
constructor() {
|
|
78
78
|
super(...arguments);
|
|
79
79
|
this.name = 'standardsql';
|
|
80
|
+
this.experimental = false;
|
|
80
81
|
this.defaultNumberType = 'FLOAT64';
|
|
81
82
|
this.defaultDecimalType = 'NUMERIC';
|
|
82
83
|
this.udfPrefix = '__udf';
|
|
@@ -3,6 +3,7 @@ import { DialectFunctionOverloadDef } from '../functions';
|
|
|
3
3
|
import { Dialect, DialectFieldList, OrderByClauseType, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class TrinoDialect extends Dialect {
|
|
5
5
|
name: string;
|
|
6
|
+
experimental: boolean;
|
|
6
7
|
defaultNumberType: string;
|
|
7
8
|
defaultDecimalType: string;
|
|
8
9
|
udfPrefix: string;
|
|
@@ -66,6 +66,7 @@ class NamedSource extends source_1.Source {
|
|
|
66
66
|
return this.refName;
|
|
67
67
|
}
|
|
68
68
|
modelStruct() {
|
|
69
|
+
var _a;
|
|
69
70
|
const modelEnt = this.modelEntry(this.ref);
|
|
70
71
|
const entry = modelEnt === null || modelEnt === void 0 ? void 0 : modelEnt.entry;
|
|
71
72
|
if (!entry) {
|
|
@@ -89,6 +90,9 @@ class NamedSource extends source_1.Source {
|
|
|
89
90
|
this.log(`Must use 'from_sql()' for sql source '${this.refName}'`);
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
93
|
+
else {
|
|
94
|
+
(_a = this.document()) === null || _a === void 0 ? void 0 : _a.checkExperimentalDialect(this, entry.dialect);
|
|
95
|
+
}
|
|
92
96
|
return { ...entry };
|
|
93
97
|
}
|
|
94
98
|
structDef() {
|
|
@@ -82,6 +82,9 @@ class SQLSource extends source_1.Source {
|
|
|
82
82
|
partialModel: this.select.containsQueries ? doc.modelDef() : undefined,
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
+
else if (lookup.status === 'present') {
|
|
86
|
+
doc.checkExperimentalDialect(this, lookup.value.dialect);
|
|
87
|
+
}
|
|
85
88
|
}
|
|
86
89
|
structDef() {
|
|
87
90
|
var _a;
|
|
@@ -28,7 +28,7 @@ const source_1 = require("./source");
|
|
|
28
28
|
const error_factory_1 = require("../error-factory");
|
|
29
29
|
class TableSource extends source_1.Source {
|
|
30
30
|
structDef() {
|
|
31
|
-
var _a, _b;
|
|
31
|
+
var _a, _b, _c;
|
|
32
32
|
const info = this.getTableInfo();
|
|
33
33
|
if (info === undefined) {
|
|
34
34
|
return error_factory_1.ErrorFactory.structDef;
|
|
@@ -39,6 +39,7 @@ class TableSource extends source_1.Source {
|
|
|
39
39
|
let msg = `Schema read failure for table '${tablePath}' for connection '${connectionName}'`;
|
|
40
40
|
if (tableDefEntry) {
|
|
41
41
|
if (tableDefEntry.status === 'present') {
|
|
42
|
+
(_b = this.document()) === null || _b === void 0 ? void 0 : _b.checkExperimentalDialect(this, tableDefEntry.value.dialect);
|
|
42
43
|
tableDefEntry.value.location = this.location;
|
|
43
44
|
tableDefEntry.value.fields.forEach(field => {
|
|
44
45
|
field.location = this.location;
|
|
@@ -51,7 +52,7 @@ class TableSource extends source_1.Source {
|
|
|
51
52
|
})),
|
|
52
53
|
location: this.location,
|
|
53
54
|
};
|
|
54
|
-
(
|
|
55
|
+
(_c = this.document()) === null || _c === void 0 ? void 0 : _c.rememberToAddModelAnnotations(ret);
|
|
55
56
|
return ret;
|
|
56
57
|
}
|
|
57
58
|
if (tableDefEntry.status === 'error') {
|
|
@@ -133,5 +133,12 @@ export declare class Document extends MalloyElement implements NameSpace {
|
|
|
133
133
|
defineSQL(sql: SQLBlockStructDef, name?: string): boolean;
|
|
134
134
|
getEntry(str: string): ModelEntry;
|
|
135
135
|
setEntry(str: string, ent: ModelEntry): void;
|
|
136
|
+
/**
|
|
137
|
+
* Return an error message if this dialect is the first reference to this particular
|
|
138
|
+
* dialect, and the dialect is marked as experimental, and we are not running tests.
|
|
139
|
+
* @param dialect The dialect name
|
|
140
|
+
* @returns The error message or undefined
|
|
141
|
+
*/
|
|
142
|
+
checkExperimentalDialect(me: MalloyElement, dialect: string): void;
|
|
136
143
|
}
|
|
137
144
|
export {};
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.Document = exports.DocStatementList = exports.ListOf = exports.isDocStatementOrDocStatementList = exports.isDocStatement = exports.ExperimentalExperiment = exports.ModelEntryReference = exports.Unimplemented = exports.MalloyElement = void 0;
|
|
26
|
+
const dialect_1 = require("../../../dialect");
|
|
26
27
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
28
|
const tags_1 = require("../../../tags");
|
|
28
29
|
const global_name_space_1 = require("./global-name-space");
|
|
@@ -546,8 +547,26 @@ class Document extends MalloyElement {
|
|
|
546
547
|
if (this.globalNameSpace.getEntry(str) !== undefined) {
|
|
547
548
|
this.log(`Cannot redefine '${str}', which is in global namespace`);
|
|
548
549
|
}
|
|
550
|
+
if (ent.entry.type === 'struct') {
|
|
551
|
+
this.checkExperimentalDialect(this, ent.entry.dialect);
|
|
552
|
+
}
|
|
549
553
|
this.documentModel[str] = ent;
|
|
550
554
|
}
|
|
555
|
+
/**
|
|
556
|
+
* Return an error message if this dialect is the first reference to this particular
|
|
557
|
+
* dialect, and the dialect is marked as experimental, and we are not running tests.
|
|
558
|
+
* @param dialect The dialect name
|
|
559
|
+
* @returns The error message or undefined
|
|
560
|
+
*/
|
|
561
|
+
checkExperimentalDialect(me, dialect) {
|
|
562
|
+
const t = this.translator();
|
|
563
|
+
if (t &&
|
|
564
|
+
t.firstReferenceToDialect(dialect) &&
|
|
565
|
+
(0, dialect_1.getDialect)(dialect).experimental &&
|
|
566
|
+
!t.experimentalDialectEnabled(dialect)) {
|
|
567
|
+
me.log(`Requires compiler flag '##! experimental.dialect.${dialect}'`, 'error');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
551
570
|
}
|
|
552
571
|
exports.Document = Document;
|
|
553
572
|
//# sourceMappingURL=malloy-element.js.map
|
|
@@ -156,6 +156,10 @@ export declare abstract class MalloyTranslation {
|
|
|
156
156
|
rangeFromContext(pcx: ParserRuleContext): DocumentRange;
|
|
157
157
|
rangeFromTokens(startToken: Token, stopToken: Token): DocumentRange;
|
|
158
158
|
rangeFromToken(token: Token): DocumentRange;
|
|
159
|
+
private dialectAlreadyChecked;
|
|
160
|
+
firstReferenceToDialect(dialect: string): boolean;
|
|
161
|
+
allDialectsEnabled: boolean;
|
|
162
|
+
experimentalDialectEnabled(dialect: string): boolean;
|
|
159
163
|
}
|
|
160
164
|
export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
161
165
|
readonly root: MalloyTranslator;
|
|
@@ -519,6 +519,18 @@ class MalloyTranslation {
|
|
|
519
519
|
this.sqlBlocks = [];
|
|
520
520
|
this.imports = [];
|
|
521
521
|
this.compilerFlags = new tags_1.Tag();
|
|
522
|
+
/*
|
|
523
|
+
Experimental dialect support, not confident this is how this should work.
|
|
524
|
+
|
|
525
|
+
To prevent cascading errors, each translator will only warn once about use of an experimental dialect.
|
|
526
|
+
|
|
527
|
+
To enable tests to run without having to enabled experimental dialects, there is a hook here for
|
|
528
|
+
the owner of a Translator object to decide if we check the experimental flag.
|
|
529
|
+
|
|
530
|
+
Not sure where the logic for this needs to go, this is just my first guess
|
|
531
|
+
*/
|
|
532
|
+
this.dialectAlreadyChecked = {};
|
|
533
|
+
this.allDialectsEnabled = false;
|
|
522
534
|
this.childTranslators = new Map();
|
|
523
535
|
this.modelDef = {
|
|
524
536
|
name: sourceURL,
|
|
@@ -748,6 +760,21 @@ class MalloyTranslation {
|
|
|
748
760
|
rangeFromToken(token) {
|
|
749
761
|
return this.rangeFromTokens(token, token);
|
|
750
762
|
}
|
|
763
|
+
firstReferenceToDialect(dialect) {
|
|
764
|
+
if (this.dialectAlreadyChecked[dialect]) {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
this.dialectAlreadyChecked[dialect] = true;
|
|
768
|
+
return true;
|
|
769
|
+
}
|
|
770
|
+
experimentalDialectEnabled(dialect) {
|
|
771
|
+
if (this.allDialectsEnabled) {
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
const experimental = this.compilerFlags.tag('experimental');
|
|
775
|
+
return (experimental !== undefined &&
|
|
776
|
+
(experimental.bare() || experimental.has('dialect', dialect)));
|
|
777
|
+
}
|
|
751
778
|
}
|
|
752
779
|
exports.MalloyTranslation = MalloyTranslation;
|
|
753
780
|
class MalloyChildTranslator extends MalloyTranslation {
|
|
@@ -28,7 +28,7 @@ const sql_block_1 = require("../../model/sql_block");
|
|
|
28
28
|
const test_translator_1 = require("./test-translator");
|
|
29
29
|
require("./parse-expects");
|
|
30
30
|
const parse_malloy_1 = require("../parse-malloy");
|
|
31
|
-
describe('sql
|
|
31
|
+
describe('connection sql()', () => {
|
|
32
32
|
const selStmt = 'SELECT * FROM aTable';
|
|
33
33
|
function makeSchemaResponse(sql) {
|
|
34
34
|
const cname = sql.connection || 'bigquery';
|
|
@@ -142,7 +142,7 @@ describe('sql blocks in malloy', () => {
|
|
|
142
142
|
const model = new test_translator_1.TestTranslator(`
|
|
143
143
|
source: sql_block is aConnection.sql("""${selStmt}""")
|
|
144
144
|
source: malloy_source is sql_block extend { primary_key: ai }
|
|
145
|
-
`);
|
|
145
|
+
`);
|
|
146
146
|
const sql = (0, sql_block_1.makeSQLBlock)([{ sql: selStmt }], 'aConnection');
|
|
147
147
|
model.update({ compileSQL: { [sql.name]: makeSchemaResponse(sql) } });
|
|
148
148
|
expect(model).toTranslate();
|
|
@@ -26,6 +26,7 @@ export declare class TestChildTranslator extends MalloyChildTranslator {
|
|
|
26
26
|
}
|
|
27
27
|
export declare class TestTranslator extends MalloyTranslator {
|
|
28
28
|
readonly testSrc: string;
|
|
29
|
+
allDialectsEnabled: boolean;
|
|
29
30
|
testRoot?: TestRoot;
|
|
30
31
|
internalModel: ModelDef;
|
|
31
32
|
constructor(testSrc: string, importBaseURL?: string | null, rootRule?: string, internalModel?: ModelDef);
|
|
@@ -207,6 +207,7 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
207
207
|
constructor(testSrc, importBaseURL = null, rootRule = 'malloyDocument', internalModel) {
|
|
208
208
|
super(testURI, importBaseURL);
|
|
209
209
|
this.testSrc = testSrc;
|
|
210
|
+
this.allDialectsEnabled = true;
|
|
210
211
|
/*
|
|
211
212
|
* All test source files can assume that an import of this
|
|
212
213
|
* model has already happened.
|
package/dist/malloy.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface Loggable {
|
|
|
14
14
|
}
|
|
15
15
|
export interface ParseOptions {
|
|
16
16
|
importBaseURL?: URL;
|
|
17
|
+
testEnvironment?: boolean;
|
|
17
18
|
}
|
|
18
19
|
export interface CompileOptions {
|
|
19
20
|
refreshSchemaCache?: boolean | number;
|
|
@@ -690,6 +691,7 @@ export declare class ExploreField extends Explore {
|
|
|
690
691
|
* An environment for compiling and running Malloy queries.
|
|
691
692
|
*/
|
|
692
693
|
export declare class Runtime {
|
|
694
|
+
isTestRuntime: boolean;
|
|
693
695
|
private _urlReader;
|
|
694
696
|
private _connections;
|
|
695
697
|
constructor(runtime: LookupConnection<Connection> & URLReader);
|
package/dist/malloy.js
CHANGED
|
@@ -50,6 +50,9 @@ class Malloy {
|
|
|
50
50
|
const translator = new lang_1.MalloyTranslator(url.toString(), importBaseURL.toString(), {
|
|
51
51
|
urls: { [url.toString()]: source },
|
|
52
52
|
});
|
|
53
|
+
if (options === null || options === void 0 ? void 0 : options.testEnvironment) {
|
|
54
|
+
translator.allDialectsEnabled = true;
|
|
55
|
+
}
|
|
53
56
|
return new Parse(translator);
|
|
54
57
|
}
|
|
55
58
|
static parse({ url, urlReader, source, options, }) {
|
|
@@ -1490,6 +1493,7 @@ exports.ExploreField = ExploreField;
|
|
|
1490
1493
|
*/
|
|
1491
1494
|
class Runtime {
|
|
1492
1495
|
constructor(...args) {
|
|
1496
|
+
this.isTestRuntime = false;
|
|
1493
1497
|
let urlReader;
|
|
1494
1498
|
let connections;
|
|
1495
1499
|
for (const arg of args) {
|
|
@@ -1535,6 +1539,14 @@ class Runtime {
|
|
|
1535
1539
|
*/
|
|
1536
1540
|
loadModel(source, options) {
|
|
1537
1541
|
const { refreshSchemaCache, noThrowOnError } = options || {};
|
|
1542
|
+
if (this.isTestRuntime) {
|
|
1543
|
+
if (options === undefined) {
|
|
1544
|
+
options = { testEnvironment: true };
|
|
1545
|
+
}
|
|
1546
|
+
else {
|
|
1547
|
+
options = { ...options, testEnvironment: true };
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1538
1550
|
return new ModelMaterializer(this, async () => {
|
|
1539
1551
|
const parse = source instanceof URL
|
|
1540
1552
|
? await Malloy.parse({
|
|
@@ -1811,6 +1823,14 @@ class ModelMaterializer extends FluentState {
|
|
|
1811
1823
|
return this.makeQueryMaterializer(async () => {
|
|
1812
1824
|
const urlReader = this.runtime.urlReader;
|
|
1813
1825
|
const connections = this.runtime.connections;
|
|
1826
|
+
if (this.runtime.isTestRuntime) {
|
|
1827
|
+
if (options === undefined) {
|
|
1828
|
+
options = { testEnvironment: true };
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
options = { ...options, testEnvironment: true };
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1814
1834
|
const parse = query instanceof URL
|
|
1815
1835
|
? await Malloy.parse({
|
|
1816
1836
|
url: query,
|
|
@@ -1841,6 +1861,14 @@ class ModelMaterializer extends FluentState {
|
|
|
1841
1861
|
* or loading further related objects.
|
|
1842
1862
|
*/
|
|
1843
1863
|
extendModel(query, options) {
|
|
1864
|
+
if (this.runtime.isTestRuntime) {
|
|
1865
|
+
if (options === undefined) {
|
|
1866
|
+
options = { testEnvironment: true };
|
|
1867
|
+
}
|
|
1868
|
+
else {
|
|
1869
|
+
options = { ...options, testEnvironment: true };
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1844
1872
|
return new ModelMaterializer(this.runtime, async () => {
|
|
1845
1873
|
const urlReader = this.runtime.urlReader;
|
|
1846
1874
|
const connections = this.runtime.connections;
|