@malloydata/malloy 0.0.38-dev230602001052 → 0.0.38-dev230606045241
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/standardsql.js +7 -7
- package/dist/index.d.ts +1 -1
- package/dist/lang/ast/expressions/pick-when.js +14 -13
- package/dist/lang/test/parse.spec.js +11 -0
- package/dist/malloy.d.ts +15 -0
- package/dist/malloy.js +32 -0
- package/dist/runtime_types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -364,13 +364,13 @@ ${(0, utils_1.indent)(sql)}
|
|
|
364
364
|
}
|
|
365
365
|
sqlMeasureTime(from, to, units) {
|
|
366
366
|
const measureMap = {
|
|
367
|
-
microsecond: { use: 'microsecond', ratio: 1 },
|
|
368
|
-
millisecond: { use: 'microsecond', ratio: 1000 },
|
|
369
|
-
second: { use: 'millisecond', ratio: 1000 },
|
|
370
|
-
minute: { use: 'second', ratio: 60 },
|
|
371
|
-
hour: { use: 'minute', ratio: 60 },
|
|
372
|
-
day: { use: 'hour', ratio: 24 },
|
|
373
|
-
week: { use: 'day', ratio: 7 },
|
|
367
|
+
'microsecond': { use: 'microsecond', ratio: 1 },
|
|
368
|
+
'millisecond': { use: 'microsecond', ratio: 1000 },
|
|
369
|
+
'second': { use: 'millisecond', ratio: 1000 },
|
|
370
|
+
'minute': { use: 'second', ratio: 60 },
|
|
371
|
+
'hour': { use: 'minute', ratio: 60 },
|
|
372
|
+
'day': { use: 'hour', ratio: 24 },
|
|
373
|
+
'week': { use: 'day', ratio: 7 },
|
|
374
374
|
};
|
|
375
375
|
let lVal = from.value;
|
|
376
376
|
let rVal = to.value;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { QueryDataRow, Fragment, StructDef, StructRelationship, NamedStructDefs, MalloyQueryData, AtomicFieldType as AtomicFieldTypeInner, DateUnit, ExtractUnit, TimestampUnit, TimeFieldType, QueryData, FieldTypeDef, Expr, DialectFragment, TimeValue, FilterExpression, SQLBlock, FieldDef, FilteredAliasedName, PipeSegment, QueryFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, ModelDef, Query, NamedQuery, NamedModelObject, ExpressionType, DocumentLocation, DocumentRange, DocumentPosition, } from './model';
|
|
1
|
+
export type { QueryDataRow, Fragment, StructDef, StructRelationship, NamedStructDefs, MalloyQueryData, AtomicFieldType as AtomicFieldTypeInner, DateUnit, ExtractUnit, TimestampUnit, TimeFieldType, QueryData, FieldTypeDef, Expr, DialectFragment, TimeValue, FilterExpression, SQLBlock, FieldDef, FilteredAliasedName, PipeSegment, QueryFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, ModelDef, Query, QueryRunStats, NamedQuery, NamedModelObject, ExpressionType, DocumentLocation, DocumentRange, DocumentPosition, } from './model';
|
|
2
2
|
export { Segment, isFilteredAliasedName, flattenQuery, expressionIsCalculation, } from './model';
|
|
3
3
|
export { HighlightType, MalloyTranslator, } from './lang';
|
|
4
4
|
export type { LogMessage, TranslateResponse } from './lang';
|
|
@@ -29,6 +29,9 @@ const fragtype_utils_1 = require("../fragtype-utils");
|
|
|
29
29
|
const expression_def_1 = require("../types/expression-def");
|
|
30
30
|
const malloy_element_1 = require("../types/malloy-element");
|
|
31
31
|
const utils_1 = require("./utils");
|
|
32
|
+
function typeCoalesce(ev1, ev2) {
|
|
33
|
+
return ev1 === undefined || ev1.dataType === 'null' ? ev2 : ev1;
|
|
34
|
+
}
|
|
32
35
|
class Pick extends expression_def_1.ExpressionDef {
|
|
33
36
|
constructor(choices, elsePick) {
|
|
34
37
|
super({ choices });
|
|
@@ -65,21 +68,17 @@ class Pick extends expression_def_1.ExpressionDef {
|
|
|
65
68
|
? choice.pick.getExpression(fs)
|
|
66
69
|
: expr.getExpression(fs);
|
|
67
70
|
anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(whenExpr.expressionType, thenExpr.expressionType));
|
|
68
|
-
if (returnType) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return (0, ast_utils_1.errorFor)('pick when type');
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
returnType = thenExpr;
|
|
71
|
+
if (returnType && !fragtype_utils_1.FT.typeEq(returnType, thenExpr, true)) {
|
|
72
|
+
const whenType = fragtype_utils_1.FT.inspect(thenExpr);
|
|
73
|
+
this.log(`pick type '${whenType}', expected '${returnType.dataType}'`);
|
|
74
|
+
return (0, ast_utils_1.errorFor)('pick when type');
|
|
77
75
|
}
|
|
76
|
+
returnType = typeCoalesce(returnType, thenExpr);
|
|
78
77
|
caseValue.push(' WHEN ', ...whenExpr.value, ' THEN ', ...thenExpr.value);
|
|
79
78
|
}
|
|
80
79
|
const elsePart = this.elsePick || expr;
|
|
81
80
|
const elseVal = elsePart.getExpression(fs);
|
|
82
|
-
returnType
|
|
81
|
+
returnType = typeCoalesce(returnType, elseVal);
|
|
83
82
|
if (!fragtype_utils_1.FT.typeEq(returnType, elseVal, true)) {
|
|
84
83
|
const errSrc = this.elsePick ? 'else' : 'pick default';
|
|
85
84
|
this.log(`${errSrc} type '${fragtype_utils_1.FT.inspect(elseVal)}', expected '${returnType.dataType}'`);
|
|
@@ -112,24 +111,26 @@ class Pick extends expression_def_1.ExpressionDef {
|
|
|
112
111
|
when: c.when.getExpression(fs),
|
|
113
112
|
});
|
|
114
113
|
}
|
|
115
|
-
|
|
114
|
+
let returnType;
|
|
116
115
|
const caseValue = ['CASE'];
|
|
117
|
-
let anyExpressionType =
|
|
116
|
+
let anyExpressionType = 'scalar';
|
|
118
117
|
for (const aChoice of choiceValues) {
|
|
119
118
|
if (!fragtype_utils_1.FT.typeEq(aChoice.when, fragtype_utils_1.FT.boolT)) {
|
|
120
119
|
this.log(`when expression must be boolean, not '${fragtype_utils_1.FT.inspect(aChoice.when)}`);
|
|
121
120
|
return (0, ast_utils_1.errorFor)('pick when type');
|
|
122
121
|
}
|
|
123
|
-
if (!fragtype_utils_1.FT.typeEq(returnType, aChoice.pick, true)) {
|
|
122
|
+
if (returnType && !fragtype_utils_1.FT.typeEq(returnType, aChoice.pick, true)) {
|
|
124
123
|
const whenType = fragtype_utils_1.FT.inspect(aChoice.pick);
|
|
125
124
|
this.log(`pick type '${whenType}', expected '${returnType.dataType}'`);
|
|
126
125
|
return (0, ast_utils_1.errorFor)('pick value type');
|
|
127
126
|
}
|
|
127
|
+
returnType = typeCoalesce(returnType, aChoice.pick);
|
|
128
128
|
anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, (0, malloy_types_1.maxExpressionType)(aChoice.pick.expressionType, aChoice.when.expressionType));
|
|
129
129
|
caseValue.push(' WHEN ', ...aChoice.when.value, ' THEN ', ...aChoice.pick.value);
|
|
130
130
|
}
|
|
131
131
|
const defVal = this.elsePick.getExpression(fs);
|
|
132
132
|
anyExpressionType = (0, malloy_types_1.maxExpressionType)(anyExpressionType, defVal.expressionType);
|
|
133
|
+
returnType = typeCoalesce(returnType, defVal);
|
|
133
134
|
if (!fragtype_utils_1.FT.typeEq(returnType, defVal, true)) {
|
|
134
135
|
this.elsePick.log(`else type '${fragtype_utils_1.FT.inspect(defVal)}', expected '${returnType.dataType}'`);
|
|
135
136
|
return (0, ast_utils_1.errorFor)('pick value type mismatch');
|
|
@@ -37,6 +37,14 @@ function exprOK(s) {
|
|
|
37
37
|
return undefined;
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
function exprType(s, t) {
|
|
41
|
+
return () => {
|
|
42
|
+
const expr = new test_translator_1.BetaExpression(s);
|
|
43
|
+
expect(expr).modelParsed();
|
|
44
|
+
expect(expr.generated().dataType).toBe(t);
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
40
48
|
function modelOK(s) {
|
|
41
49
|
return () => {
|
|
42
50
|
const m = new test_translator_1.TestTranslator(s);
|
|
@@ -720,6 +728,9 @@ describe('expressions', () => {
|
|
|
720
728
|
test('filtering', exprOK(`
|
|
721
729
|
astr ? pick 'missing value' when NULL
|
|
722
730
|
`));
|
|
731
|
+
test('null branch with else', exprType("astr ? pick null when = '42' else 3", 'number'));
|
|
732
|
+
test('null branch no else', exprType("astr ? pick null when = '42'", 'string'));
|
|
733
|
+
test('null branch no apply', exprType('pick null when 1 = 1 else 3', 'number'));
|
|
723
734
|
test('tiering', exprOK(`
|
|
724
735
|
ai ?
|
|
725
736
|
pick 1 when < 10
|
package/dist/malloy.d.ts
CHANGED
|
@@ -121,6 +121,14 @@ export declare class Malloy {
|
|
|
121
121
|
sqlStruct: SQLBlockStructDef;
|
|
122
122
|
options?: RunSQLOptions;
|
|
123
123
|
}): AsyncIterableIterator<DataRecord>;
|
|
124
|
+
static estimateQueryCost(params: {
|
|
125
|
+
connections: LookupConnection<Connection>;
|
|
126
|
+
preparedResult: PreparedResult;
|
|
127
|
+
}): Promise<QueryRunStats>;
|
|
128
|
+
static estimateQueryCost(params: {
|
|
129
|
+
connections: LookupConnection<Connection>;
|
|
130
|
+
sqlStruct: SQLBlockStructDef;
|
|
131
|
+
}): Promise<QueryRunStats>;
|
|
124
132
|
}
|
|
125
133
|
/**
|
|
126
134
|
* A Malloy error, which may contain log messages produced during compilation.
|
|
@@ -930,6 +938,12 @@ export declare class QueryMaterializer extends FluentState<PreparedQuery> {
|
|
|
930
938
|
* @return A promise of the `PreparedQuery`.
|
|
931
939
|
*/
|
|
932
940
|
getPreparedQuery(): Promise<PreparedQuery>;
|
|
941
|
+
/**
|
|
942
|
+
* Estimates the cost of this loaded `Query`.
|
|
943
|
+
*
|
|
944
|
+
* @return The estimated cost of running this loaded query.
|
|
945
|
+
*/
|
|
946
|
+
estimateQueryCost(): Promise<QueryRunStats>;
|
|
933
947
|
}
|
|
934
948
|
/**
|
|
935
949
|
* An object representing the task of loading a `PreparedResult`, capable of
|
|
@@ -986,6 +1000,7 @@ export declare class SQLBlockMaterializer extends FluentState<SQLBlockStructDef>
|
|
|
986
1000
|
* @return A promise to the SQL string.
|
|
987
1001
|
*/
|
|
988
1002
|
getSQL(): Promise<string>;
|
|
1003
|
+
estimateQueryCost(): Promise<QueryRunStats>;
|
|
989
1004
|
}
|
|
990
1005
|
/**
|
|
991
1006
|
* An object representing the task of loading an `Explore`, capable of
|
package/dist/malloy.js
CHANGED
|
@@ -281,6 +281,23 @@ class Malloy {
|
|
|
281
281
|
index += 1;
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
+
static async estimateQueryCost({ connections, preparedResult, sqlStruct, }) {
|
|
285
|
+
const sqlBlock = sqlStruct === null || sqlStruct === void 0 ? void 0 : sqlStruct.structSource.sqlBlock;
|
|
286
|
+
if (!connections) {
|
|
287
|
+
throw new Error('Internal Error: Connection or LookupConnection<Connection> must be provided.');
|
|
288
|
+
}
|
|
289
|
+
const connectionName = (sqlBlock === null || sqlBlock === void 0 ? void 0 : sqlBlock.connection) || (preparedResult === null || preparedResult === void 0 ? void 0 : preparedResult.connectionName);
|
|
290
|
+
const connection = await connections.lookupConnection(connectionName);
|
|
291
|
+
if (sqlBlock) {
|
|
292
|
+
return await connection.estimateQueryCost(sqlBlock === null || sqlBlock === void 0 ? void 0 : sqlBlock.selectStr);
|
|
293
|
+
}
|
|
294
|
+
else if (preparedResult) {
|
|
295
|
+
return await connection.estimateQueryCost(preparedResult === null || preparedResult === void 0 ? void 0 : preparedResult.sql);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
throw new Error('Internal error: sqlStruct or preparedResult must be provided.');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
284
301
|
}
|
|
285
302
|
exports.Malloy = Malloy;
|
|
286
303
|
/**
|
|
@@ -1878,6 +1895,16 @@ class QueryMaterializer extends FluentState {
|
|
|
1878
1895
|
getPreparedQuery() {
|
|
1879
1896
|
return this.materialize();
|
|
1880
1897
|
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Estimates the cost of this loaded `Query`.
|
|
1900
|
+
*
|
|
1901
|
+
* @return The estimated cost of running this loaded query.
|
|
1902
|
+
*/
|
|
1903
|
+
async estimateQueryCost() {
|
|
1904
|
+
const connections = this.runtime.connections;
|
|
1905
|
+
const preparedResult = await this.getPreparedResult();
|
|
1906
|
+
return Malloy.estimateQueryCost({ connections, preparedResult });
|
|
1907
|
+
}
|
|
1881
1908
|
}
|
|
1882
1909
|
exports.QueryMaterializer = QueryMaterializer;
|
|
1883
1910
|
/**
|
|
@@ -1967,6 +1994,11 @@ class SQLBlockMaterializer extends FluentState {
|
|
|
1967
1994
|
const sqlStruct = await this.getSQLBlock();
|
|
1968
1995
|
return sqlStruct.structSource.sqlBlock.selectStr;
|
|
1969
1996
|
}
|
|
1997
|
+
async estimateQueryCost() {
|
|
1998
|
+
const connections = this.runtime.connections;
|
|
1999
|
+
const sqlStruct = await this.getSQLBlock();
|
|
2000
|
+
return Malloy.estimateQueryCost({ connections, sqlStruct });
|
|
2001
|
+
}
|
|
1970
2002
|
}
|
|
1971
2003
|
exports.SQLBlockMaterializer = SQLBlockMaterializer;
|
|
1972
2004
|
/**
|
package/dist/runtime_types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RunSQLOptions } from './run_sql_options';
|
|
2
|
-
import { MalloyQueryData, QueryDataRow, SQLBlock, StructDef } from './model/malloy_types';
|
|
2
|
+
import { MalloyQueryData, QueryDataRow, QueryRunStats, SQLBlock, StructDef } from './model/malloy_types';
|
|
3
3
|
/**
|
|
4
4
|
* The contents of a Malloy query document.
|
|
5
5
|
*/
|
|
@@ -77,6 +77,7 @@ export interface Connection extends InfoConnection {
|
|
|
77
77
|
canPersist(): this is PersistSQLResults;
|
|
78
78
|
canStream(): this is StreamingConnection;
|
|
79
79
|
close(): Promise<void>;
|
|
80
|
+
estimateQueryCost(sqlCommand: string): Promise<QueryRunStats>;
|
|
80
81
|
}
|
|
81
82
|
export interface TestableConnection extends Connection {
|
|
82
83
|
test(): Promise<void>;
|