@malloydata/malloy 0.0.141-dev240410194001 → 0.0.141
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 +4 -3
- package/dist/dialect/dialect.js +2 -0
- package/dist/dialect/duckdb/duckdb.d.ts +3 -3
- package/dist/dialect/duckdb/duckdb.js +6 -6
- package/dist/dialect/trino/trino.d.ts +3 -2
- package/dist/dialect/trino/trino.js +10 -5
- package/dist/model/malloy_query.js +35 -21
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DialectFragment, Expr, ExtractUnit, Sampling,
|
|
1
|
+
import { DialectFragment, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../model/malloy_types';
|
|
2
2
|
import { DialectFunctionOverloadDef } from './functions';
|
|
3
3
|
type DialectFieldTypes = string | 'struct';
|
|
4
4
|
interface DialectField {
|
|
@@ -52,6 +52,7 @@ export declare abstract class Dialect {
|
|
|
52
52
|
readsNestedData: boolean;
|
|
53
53
|
orderByClause: OrderByClauseType;
|
|
54
54
|
nullMatchesFunctionSignature: boolean;
|
|
55
|
+
supportsSelectReplace: boolean;
|
|
55
56
|
abstract getGlobalFunctionDef(name: string): DialectFunctionOverloadDef[] | undefined;
|
|
56
57
|
abstract quoteTablePath(tablePath: string): string;
|
|
57
58
|
abstract sqlGroupSetTable(groupSetCount: number): string;
|
|
@@ -66,9 +67,9 @@ export declare abstract class Dialect {
|
|
|
66
67
|
abstract sqlFieldReference(alias: string, fieldName: string, fieldType: string, isNested: boolean, isArray: boolean): string;
|
|
67
68
|
abstract sqlUnnestPipelineHead(isSingleton: boolean, sourceSQLExpression: string): string;
|
|
68
69
|
abstract sqlCreateFunction(id: string, funcText: string): string;
|
|
69
|
-
abstract sqlCreateFunctionCombineLastStage(lastStageName: string,
|
|
70
|
+
abstract sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList): string;
|
|
70
71
|
abstract sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
71
|
-
abstract sqlSelectAliasAsStruct(alias: string,
|
|
72
|
+
abstract sqlSelectAliasAsStruct(alias: string, fieldList: DialectFieldList): string;
|
|
72
73
|
sqlFinalStage(_lastStageName: string, _fields: string[]): string;
|
|
73
74
|
sqlDateToString(sqlDateExp: string): string;
|
|
74
75
|
abstract sqlMaybeQuoteIdentifier(identifier: string): string;
|
package/dist/dialect/dialect.js
CHANGED
|
@@ -72,6 +72,8 @@ class Dialect {
|
|
|
72
72
|
this.orderByClause = 'ordinal';
|
|
73
73
|
// null will match in a function signature
|
|
74
74
|
this.nullMatchesFunctionSignature = true;
|
|
75
|
+
// support select * replace(...)
|
|
76
|
+
this.supportsSelectReplace = true;
|
|
75
77
|
}
|
|
76
78
|
sqlFinalStage(_lastStageName, _fields) {
|
|
77
79
|
throw new Error('Dialect has no final Stage but called Anyway');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DateUnit, Expr, ExtractUnit, Sampling,
|
|
1
|
+
import { DateUnit, Expr, ExtractUnit, Sampling, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
|
|
2
2
|
import { DialectFunctionOverloadDef } from '../functions';
|
|
3
3
|
import { Dialect, DialectFieldList, QueryInfo } from '../dialect';
|
|
4
4
|
export declare class DuckDBDialect extends Dialect {
|
|
@@ -35,8 +35,8 @@ export declare class DuckDBDialect extends Dialect {
|
|
|
35
35
|
sqlFieldReference(alias: string, fieldName: string, _fieldType: string, _isNested: boolean, isArray: boolean): string;
|
|
36
36
|
sqlUnnestPipelineHead(isSingleton: boolean, sourceSQLExpression: string): string;
|
|
37
37
|
sqlCreateFunction(id: string, funcText: string): string;
|
|
38
|
-
sqlCreateFunctionCombineLastStage(lastStageName: string,
|
|
39
|
-
sqlSelectAliasAsStruct(alias: string,
|
|
38
|
+
sqlCreateFunctionCombineLastStage(lastStageName: string, dialectFieldList: DialectFieldList): string;
|
|
39
|
+
sqlSelectAliasAsStruct(alias: string, dialectFieldList: DialectFieldList): string;
|
|
40
40
|
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
41
41
|
sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
|
|
42
42
|
sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
|
|
@@ -177,14 +177,14 @@ class DuckDBDialect extends dialect_1.Dialect {
|
|
|
177
177
|
sqlCreateFunction(id, funcText) {
|
|
178
178
|
return `DROP MACRO IF EXISTS ${id}; \n${hackSplitComment}\n CREATE MACRO ${id}(_param) AS (\n${(0, utils_1.indent)(funcText)}\n);\n${hackSplitComment}\n`;
|
|
179
179
|
}
|
|
180
|
-
sqlCreateFunctionCombineLastStage(lastStageName,
|
|
181
|
-
return `SELECT LIST(STRUCT_PACK(${
|
|
182
|
-
.map(
|
|
180
|
+
sqlCreateFunctionCombineLastStage(lastStageName, dialectFieldList) {
|
|
181
|
+
return `SELECT LIST(STRUCT_PACK(${dialectFieldList
|
|
182
|
+
.map(d => this.sqlMaybeQuoteIdentifier(d.sqlOutputName))
|
|
183
183
|
.join(',')})) FROM ${lastStageName}\n`;
|
|
184
184
|
}
|
|
185
|
-
sqlSelectAliasAsStruct(alias,
|
|
186
|
-
return `STRUCT_PACK(${
|
|
187
|
-
.map(
|
|
185
|
+
sqlSelectAliasAsStruct(alias, dialectFieldList) {
|
|
186
|
+
return `STRUCT_PACK(${dialectFieldList
|
|
187
|
+
.map(d => `${alias}.${d.sqlOutputName}`)
|
|
188
188
|
.join(', ')})`;
|
|
189
189
|
}
|
|
190
190
|
// TODO
|
|
@@ -23,6 +23,7 @@ export declare class TrinoDialect extends Dialect {
|
|
|
23
23
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
24
24
|
orderByClause: OrderByClauseType;
|
|
25
25
|
nullMatchesFunctionSignature: boolean;
|
|
26
|
+
supportsSelectReplace: boolean;
|
|
26
27
|
quoteTablePath(tablePath: string): string;
|
|
27
28
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
28
29
|
dialectExpr(qi: QueryInfo, df: DialectFragment): Expr;
|
|
@@ -39,8 +40,8 @@ export declare class TrinoDialect extends Dialect {
|
|
|
39
40
|
sqlUnnestPipelineHead(isSingleton: boolean, sourceSQLExpression: string): string;
|
|
40
41
|
sqlCreateFunction(id: string, funcText: string): string;
|
|
41
42
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
42
|
-
sqlCreateFunctionCombineLastStage(lastStageName: string): string;
|
|
43
|
-
sqlSelectAliasAsStruct(alias: string): string;
|
|
43
|
+
sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList): string;
|
|
44
|
+
sqlSelectAliasAsStruct(alias: string, fieldList: any): string;
|
|
44
45
|
keywords: string[];
|
|
45
46
|
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
46
47
|
sqlNow(): Expr;
|
|
@@ -77,6 +77,7 @@ class TrinoDialect extends dialect_1.Dialect {
|
|
|
77
77
|
this.cantPartitionWindowFunctionsOnExpressions = false;
|
|
78
78
|
this.orderByClause = 'output_name';
|
|
79
79
|
this.nullMatchesFunctionSignature = false;
|
|
80
|
+
this.supportsSelectReplace = false;
|
|
80
81
|
// TODO(figutierrez): update.
|
|
81
82
|
this.keywords = `
|
|
82
83
|
ALL
|
|
@@ -279,7 +280,7 @@ class TrinoDialect extends dialect_1.Dialect {
|
|
|
279
280
|
sqlUnnestPipelineHead(isSingleton, sourceSQLExpression) {
|
|
280
281
|
let p = sourceSQLExpression;
|
|
281
282
|
if (isSingleton) {
|
|
282
|
-
p = `[${p}]`;
|
|
283
|
+
p = `ARRAY[${p}]`;
|
|
283
284
|
}
|
|
284
285
|
return `UNNEST(${p})`;
|
|
285
286
|
}
|
|
@@ -297,11 +298,15 @@ ${(0, utils_1.indent)(sql)}
|
|
|
297
298
|
);
|
|
298
299
|
`;
|
|
299
300
|
}
|
|
300
|
-
sqlCreateFunctionCombineLastStage(lastStageName) {
|
|
301
|
-
|
|
301
|
+
sqlCreateFunctionCombineLastStage(lastStageName, fieldList) {
|
|
302
|
+
const fields = fieldList.map(f => f.sqlExpression).join(', ');
|
|
303
|
+
const definitions = this.buildTypeExpression(fieldList);
|
|
304
|
+
return `SELECT ARRAY_AGG(CAST(ROW(${fields}) as ROW(${definitions}))) FROM ${lastStageName}\n`;
|
|
302
305
|
}
|
|
303
|
-
sqlSelectAliasAsStruct(alias) {
|
|
304
|
-
|
|
306
|
+
sqlSelectAliasAsStruct(alias, fieldList) {
|
|
307
|
+
const fields = fieldList.map(f => f.sqlExpression).join(', ');
|
|
308
|
+
const definitions = this.buildTypeExpression(fieldList);
|
|
309
|
+
return `CAST(ROW(${fields}) as ROW(${definitions})`;
|
|
305
310
|
}
|
|
306
311
|
sqlMaybeQuoteIdentifier(identifier) {
|
|
307
312
|
return '"' + identifier + '"';
|
|
@@ -37,6 +37,18 @@ function generateSQLStringLiteral(sourceString) {
|
|
|
37
37
|
function identifierNormalize(s) {
|
|
38
38
|
return s.replace(/[^a-zA-Z0-9_]/g, '_o_');
|
|
39
39
|
}
|
|
40
|
+
function getDialectFieldList(structDef) {
|
|
41
|
+
const dialectFieldList = [];
|
|
42
|
+
for (const f of structDef.fields.filter(malloy_types_1.isPhysical)) {
|
|
43
|
+
dialectFieldList.push({
|
|
44
|
+
type: f.type,
|
|
45
|
+
sqlExpression: (0, malloy_types_1.getIdentifier)(f),
|
|
46
|
+
rawName: (0, malloy_types_1.getIdentifier)(f),
|
|
47
|
+
sqlOutputName: (0, malloy_types_1.getIdentifier)(f),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return dialectFieldList;
|
|
51
|
+
}
|
|
40
52
|
class UniqueKeyUse extends Set {
|
|
41
53
|
add_use(k) {
|
|
42
54
|
if (k !== undefined) {
|
|
@@ -86,7 +98,7 @@ class StageWriter {
|
|
|
86
98
|
if (lastStageName === undefined) {
|
|
87
99
|
throw new Error('Internal Error: no stage to combine');
|
|
88
100
|
}
|
|
89
|
-
sql += dialect.sqlCreateFunctionCombineLastStage(lastStageName, structDef);
|
|
101
|
+
sql += dialect.sqlCreateFunctionCombineLastStage(lastStageName, getDialectFieldList(structDef));
|
|
90
102
|
const id = `${dialect.udfPrefix}${this.root().udfs.length}`;
|
|
91
103
|
sql = dialect.sqlCreateFunction(id, sql);
|
|
92
104
|
this.root().udfs.push(sql);
|
|
@@ -131,11 +143,11 @@ class StageWriter {
|
|
|
131
143
|
}
|
|
132
144
|
generateCoorelatedSubQuery(dialect, structDef) {
|
|
133
145
|
if (!this.useCTE) {
|
|
134
|
-
return dialect.sqlCreateFunctionCombineLastStage(`(${this.withs[0]})`, structDef);
|
|
146
|
+
return dialect.sqlCreateFunctionCombineLastStage(`(${this.withs[0]})`, getDialectFieldList(structDef));
|
|
135
147
|
}
|
|
136
148
|
else {
|
|
137
149
|
return (this.combineStages(true).sql +
|
|
138
|
-
dialect.sqlCreateFunctionCombineLastStage(this.getName(this.withs.length - 1), structDef));
|
|
150
|
+
dialect.sqlCreateFunctionCombineLastStage(this.getName(this.withs.length - 1), getDialectFieldList(structDef)));
|
|
139
151
|
}
|
|
140
152
|
}
|
|
141
153
|
}
|
|
@@ -1421,16 +1433,7 @@ class JoinInstance {
|
|
|
1421
1433
|
}
|
|
1422
1434
|
// postgres unnest needs to know the names of the physical fields.
|
|
1423
1435
|
getDialectFieldList() {
|
|
1424
|
-
|
|
1425
|
-
for (const f of this.queryStruct.fieldDef.fields.filter(malloy_types_1.isPhysical)) {
|
|
1426
|
-
dialectFieldList.push({
|
|
1427
|
-
type: f.type,
|
|
1428
|
-
sqlExpression: (0, malloy_types_1.getIdentifier)(f),
|
|
1429
|
-
rawName: (0, malloy_types_1.getIdentifier)(f),
|
|
1430
|
-
sqlOutputName: (0, malloy_types_1.getIdentifier)(f),
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
1433
|
-
return dialectFieldList;
|
|
1436
|
+
return getDialectFieldList(this.queryStruct.fieldDef);
|
|
1434
1437
|
}
|
|
1435
1438
|
}
|
|
1436
1439
|
/** nested query */
|
|
@@ -1996,8 +1999,7 @@ class QueryQuery extends QueryField {
|
|
|
1996
1999
|
let joins = '';
|
|
1997
2000
|
for (const childJoin of ji.children) {
|
|
1998
2001
|
joins += this.generateSQLJoinBlock(stageWriter, childJoin);
|
|
1999
|
-
|
|
2000
|
-
select += `, ${this.parent.dialect.sqlSelectAliasAsStruct(childJoin.alias, physicalFields)} AS ${childJoin.alias}`;
|
|
2002
|
+
select += `, ${this.parent.dialect.sqlSelectAliasAsStruct(childJoin.alias, getDialectFieldList(childJoin.queryStruct.fieldDef))} AS ${childJoin.alias}`;
|
|
2001
2003
|
}
|
|
2002
2004
|
select += `\nFROM ${structSQL} AS ${ji.alias}\n${joins}\nWHERE ${conditions === null || conditions === void 0 ? void 0 : conditions.join(' AND ')}\n`;
|
|
2003
2005
|
s += `${matrixOperation} JOIN (\n${(0, utils_1.indent)(select)}) AS ${ji.alias}\n ON ${onCondition}\n`;
|
|
@@ -2170,12 +2172,24 @@ class QueryQuery extends QueryField {
|
|
|
2170
2172
|
if (outputPipelinedSQL.length === 0) {
|
|
2171
2173
|
return lastStageName;
|
|
2172
2174
|
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2175
|
+
let retSQL;
|
|
2176
|
+
if (this.parent.dialect.supportsSelectReplace) {
|
|
2177
|
+
const pipelinesSQL = outputPipelinedSQL
|
|
2178
|
+
.map(o => `${o.pipelineSQL} as ${o.sqlFieldName}`)
|
|
2179
|
+
.join(',\n');
|
|
2180
|
+
retSQL = `SELECT * replace (${pipelinesSQL}) FROM ${lastStageName}
|
|
2181
|
+
`;
|
|
2182
|
+
}
|
|
2183
|
+
else {
|
|
2184
|
+
const pipelinesSQL = outputPipelinedSQL
|
|
2185
|
+
.map(o => `${o.pipelineSQL} as ${o.sqlFieldName}`)
|
|
2186
|
+
.join(',\n');
|
|
2187
|
+
const outputFields = outputPipelinedSQL.map(f => f.sqlFieldName);
|
|
2188
|
+
const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.sqlMaybeQuoteIdentifier(f));
|
|
2189
|
+
const fields = allFields.filter(f => outputFields.indexOf(f) === -1);
|
|
2190
|
+
retSQL = `SELECT ${fields.length > 0 ? fields.join(', ') + ',' : ''} ${pipelinesSQL} FROM ${lastStageName}`;
|
|
2191
|
+
}
|
|
2192
|
+
return stageWriter.addStage(retSQL);
|
|
2179
2193
|
}
|
|
2180
2194
|
generateStage0Fields(resultSet, output, stageWriter) {
|
|
2181
2195
|
const scalarFields = [];
|