@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.
@@ -1,4 +1,4 @@
1
- import { DialectFragment, Expr, ExtractUnit, Sampling, StructDef, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../model/malloy_types';
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, structDef: StructDef): string;
70
+ abstract sqlCreateFunctionCombineLastStage(lastStageName: string, fieldList: DialectFieldList): string;
70
71
  abstract sqlCreateTableAsSelect(tableName: string, sql: string): string;
71
- abstract sqlSelectAliasAsStruct(alias: string, physicalFieldNames: string[]): 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;
@@ -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, StructDef, TimeFieldType, TimeValue, TimestampUnit, TypecastFragment, FieldAtomicTypeDef } from '../../model/malloy_types';
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, structDef: StructDef): string;
39
- sqlSelectAliasAsStruct(alias: string, physicalFieldNames: string[]): 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, structDef) {
181
- return `SELECT LIST(STRUCT_PACK(${structDef.fields
182
- .map(fieldDef => this.sqlMaybeQuoteIdentifier((0, malloy_types_1.getIdentifier)(fieldDef)))
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, physicalFieldNames) {
186
- return `STRUCT_PACK(${physicalFieldNames
187
- .map(name => `${alias}.${name}`)
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
- return `SELECT ARRAY((SELECT AS STRUCT * FROM ${lastStageName}))\n`;
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
- return `(SELECT AS STRUCT ${alias}.*)`;
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
- const dialectFieldList = [];
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
- const physicalFields = (0, malloy_types_1.getPhysicalFields)(childJoin.queryStruct.fieldDef).map(fieldDef => this.parent.dialect.sqlMaybeQuoteIdentifier(fieldDef.name));
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
- const pipelinesSQL = outputPipelinedSQL
2174
- .map(o => `${o.pipelineSQL} as ${o.sqlFieldName}
2175
- `)
2176
- .join(',\n');
2177
- return stageWriter.addStage(`SELECT * replace (${pipelinesSQL}) FROM ${lastStageName}
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 = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.141-dev240410194001",
3
+ "version": "0.0.141",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",