@malloydata/malloy 0.0.307 → 0.0.309
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/postgres/postgres.d.ts +3 -2
- package/dist/dialect/postgres/postgres.js +42 -8
- package/dist/model/expression_compiler.js +8 -9
- package/dist/model/field_instance.js +0 -12
- package/dist/model/filter_compilers.d.ts +1 -0
- package/dist/model/filter_compilers.js +29 -39
- package/dist/model/query_node.d.ts +10 -2
- package/dist/model/query_node.js +5 -5
- package/dist/model/query_query.d.ts +9 -1
- package/dist/model/query_query.js +26 -28
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Sampling, AtomicTypeDef, TimeDeltaExpr, TypecastExpr, MeasureTimeExpr, BasicAtomicTypeDef, RecordLiteralNode, ArrayLiteralNode } from '../../model/malloy_types';
|
|
1
|
+
import type { Sampling, AtomicTypeDef, TimeDeltaExpr, TypecastExpr, MeasureTimeExpr, BasicAtomicTypeDef, RecordLiteralNode, ArrayLiteralNode, TimeExtractExpr } from '../../model/malloy_types';
|
|
2
2
|
import type { DialectFunctionOverloadDef } from '../functions';
|
|
3
|
-
import type
|
|
3
|
+
import { type DialectFieldList, type FieldReferenceType, type QueryInfo } from '../dialect';
|
|
4
4
|
import { PostgresBase } from '../pg_impl';
|
|
5
5
|
export declare class PostgresDialect extends PostgresBase {
|
|
6
6
|
name: string;
|
|
@@ -66,4 +66,5 @@ export declare class PostgresDialect extends PostgresBase {
|
|
|
66
66
|
validateTypeName(sqlType: string): boolean;
|
|
67
67
|
sqlLiteralRecord(lit: RecordLiteralNode): string;
|
|
68
68
|
sqlLiteralArray(lit: ArrayLiteralNode): string;
|
|
69
|
+
sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
|
|
69
70
|
}
|
|
@@ -26,6 +26,7 @@ exports.PostgresDialect = void 0;
|
|
|
26
26
|
const utils_1 = require("../../model/utils");
|
|
27
27
|
const malloy_types_1 = require("../../model/malloy_types");
|
|
28
28
|
const functions_1 = require("../functions");
|
|
29
|
+
const dialect_1 = require("../dialect");
|
|
29
30
|
const pg_impl_1 = require("../pg_impl");
|
|
30
31
|
const dialect_functions_1 = require("./dialect_functions");
|
|
31
32
|
const function_overrides_1 = require("./function_overrides");
|
|
@@ -80,7 +81,7 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
80
81
|
this.udfPrefix = 'pg_temp.__udf';
|
|
81
82
|
this.hasFinalStage = true;
|
|
82
83
|
this.divisionIsInteger = true;
|
|
83
|
-
this.supportsSumDistinctFunction =
|
|
84
|
+
this.supportsSumDistinctFunction = true;
|
|
84
85
|
this.unnestWithNumbers = false;
|
|
85
86
|
this.defaultSampling = { rows: 50000 };
|
|
86
87
|
this.supportUnnestArrayAgg = true;
|
|
@@ -242,14 +243,33 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
242
243
|
}
|
|
243
244
|
throw new Error(`Unknown or unhandled postgres time unit: ${df.units}`);
|
|
244
245
|
}
|
|
246
|
+
// This looks like a partial implementation of a method similar to how DuckDB
|
|
247
|
+
// does symmetric aggregates, which was abandoned. Leaving it in here for now
|
|
248
|
+
// in case the original author wants to pick it up again.
|
|
249
|
+
// sqlSumDistinct(key: string, value: string, funcName: string): string {
|
|
250
|
+
// // return `sum_distinct(list({key:${key}, val: ${value}}))`;
|
|
251
|
+
// return `(
|
|
252
|
+
// SELECT ${funcName}((a::json->>'f2')::DOUBLE PRECISION) as value
|
|
253
|
+
// FROM (
|
|
254
|
+
// SELECT UNNEST(array_agg(distinct row_to_json(row(${key},${value}))::text)) a
|
|
255
|
+
// ) a
|
|
256
|
+
// )`;
|
|
257
|
+
// }
|
|
245
258
|
sqlSumDistinct(key, value, funcName) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
259
|
+
const hashKey = this.sqlSumDistinctHashedKey(key);
|
|
260
|
+
// PostgreSQL requires CAST to NUMERIC before ROUND, which is different
|
|
261
|
+
// than the generic implementation of sqlSumDistinct, but is OK in
|
|
262
|
+
// PostgreSQL because NUMERIC has arbitrary precision.
|
|
263
|
+
const roundedValue = `ROUND(CAST(COALESCE(${value}, 0) AS NUMERIC), 9)`;
|
|
264
|
+
const sumSQL = `SUM(DISTINCT ${roundedValue} + ${hashKey}) - SUM(DISTINCT ${hashKey})`;
|
|
265
|
+
const ret = `CAST(${sumSQL} AS DOUBLE PRECISION)`;
|
|
266
|
+
if (funcName === 'SUM') {
|
|
267
|
+
return ret;
|
|
268
|
+
}
|
|
269
|
+
else if (funcName === 'AVG') {
|
|
270
|
+
return `(${ret})/NULLIF(COUNT(DISTINCT CASE WHEN ${value} IS NOT NULL THEN ${key} END), 0)`;
|
|
271
|
+
}
|
|
272
|
+
throw new Error(`Unknown Symmetric Aggregate function ${funcName}`);
|
|
253
273
|
}
|
|
254
274
|
// TODO this does not preserve the types of the arguments, meaning we have to hack
|
|
255
275
|
// around this in the definitions of functions that use this to cast back to the correct
|
|
@@ -339,6 +359,20 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
339
359
|
const array = lit.kids.values.map(val => val.sql);
|
|
340
360
|
return 'JSONB_BUILD_ARRAY(' + array.join(',') + ')';
|
|
341
361
|
}
|
|
362
|
+
sqlTimeExtractExpr(qi, from) {
|
|
363
|
+
const units = pg_impl_1.timeExtractMap[from.units] || from.units;
|
|
364
|
+
let extractFrom = from.e.sql;
|
|
365
|
+
if (malloy_types_1.TD.isTimestamp(from.e.typeDef)) {
|
|
366
|
+
const tz = (0, dialect_1.qtz)(qi);
|
|
367
|
+
if (tz) {
|
|
368
|
+
extractFrom = `(${extractFrom}::TIMESTAMPTZ AT TIME ZONE '${tz}')`;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// PostgreSQL before 14 returns a double precision for EXTRACT, cast to integer
|
|
372
|
+
// since it is common to pass an extraction to mod ( like in fitler expressions )
|
|
373
|
+
const extracted = `EXTRACT(${units} FROM ${extractFrom})::integer`;
|
|
374
|
+
return from.units === 'day_of_week' ? `(${extracted}+1)` : `(${extracted})`;
|
|
375
|
+
}
|
|
342
376
|
}
|
|
343
377
|
exports.PostgresDialect = PostgresDialect;
|
|
344
378
|
//# sourceMappingURL=postgres.js.map
|
|
@@ -33,16 +33,15 @@ function sqlSumDistinct(dialect, sqlExp, sqlDistintKey) {
|
|
|
33
33
|
const precision = 9;
|
|
34
34
|
const uniqueInt = dialect.sqlSumDistinctHashedKey(sqlDistintKey);
|
|
35
35
|
const multiplier = 10 ** (precision - NUMERIC_DECIMAL_PRECISION);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
-
|
|
43
|
-
SUM(DISTINCT ${uniqueInt})
|
|
36
|
+
// Ensure value is numeric and handle nulls
|
|
37
|
+
const safeValue = `CAST(COALESCE(${sqlExp}, 0) AS ${dialect.defaultDecimalType})`;
|
|
38
|
+
// Scale and round to eliminate floating point differences
|
|
39
|
+
const roundedValue = `ROUND(${safeValue}*${multiplier}, ${NUMERIC_DECIMAL_PRECISION})`;
|
|
40
|
+
const sumSQL = `(
|
|
41
|
+
SUM(DISTINCT ${roundedValue} + ${uniqueInt})
|
|
42
|
+
- SUM(DISTINCT ${uniqueInt})
|
|
44
43
|
)`;
|
|
45
|
-
let ret = `(${sumSQL}
|
|
44
|
+
let ret = `(${sumSQL}/${multiplier})`;
|
|
46
45
|
ret = `CAST(${ret} AS ${dialect.defaultNumberType})`;
|
|
47
46
|
return ret;
|
|
48
47
|
}
|
|
@@ -47,18 +47,6 @@ class FieldInstanceField {
|
|
|
47
47
|
if ((0, malloy_types_1.hasExpression)(this.f.fieldDef)) {
|
|
48
48
|
return FieldInstanceField.exprCompiler(this.parent, this.f.parent, this.f.fieldDef.e);
|
|
49
49
|
}
|
|
50
|
-
// Walk the tree and compute record aliases if needed
|
|
51
|
-
for (let ancestor = this.f.parent; ancestor !== undefined; ancestor = ancestor.parent) {
|
|
52
|
-
if (ancestor.structDef.type === 'record' &&
|
|
53
|
-
(0, malloy_types_1.hasExpression)(ancestor.structDef) &&
|
|
54
|
-
ancestor.recordAlias === undefined) {
|
|
55
|
-
if (!ancestor.parent) {
|
|
56
|
-
throw new Error('Inconceivable record ancestor with expression but no parent');
|
|
57
|
-
}
|
|
58
|
-
const aliasValue = FieldInstanceField.exprCompiler(this.parent, ancestor.parent, ancestor.structDef.e);
|
|
59
|
-
ancestor.informOfAliasValue(aliasValue);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
50
|
return sqlFullChildReference(this.f.parent, this.f.fieldDef.name, this.f.parent.structDef.type === 'record'
|
|
63
51
|
? {
|
|
64
52
|
result: this.parent,
|
|
@@ -521,51 +521,20 @@ class TemporalFilterCompiler {
|
|
|
521
521
|
return this.lastUnit(m.units);
|
|
522
522
|
case 'next':
|
|
523
523
|
return this.nextUnit(m.units);
|
|
524
|
+
case 'sunday':
|
|
525
|
+
return this.weekdayMoment(1, m.which);
|
|
524
526
|
case 'monday':
|
|
527
|
+
return this.weekdayMoment(2, m.which);
|
|
525
528
|
case 'tuesday':
|
|
529
|
+
return this.weekdayMoment(3, m.which);
|
|
526
530
|
case 'wednesday':
|
|
531
|
+
return this.weekdayMoment(4, m.which);
|
|
527
532
|
case 'thursday':
|
|
533
|
+
return this.weekdayMoment(5, m.which);
|
|
528
534
|
case 'friday':
|
|
535
|
+
return this.weekdayMoment(6, m.which);
|
|
529
536
|
case 'saturday':
|
|
530
|
-
|
|
531
|
-
const destDay = [
|
|
532
|
-
'sunday',
|
|
533
|
-
'monday',
|
|
534
|
-
'tuesday',
|
|
535
|
-
'wednesday',
|
|
536
|
-
'thursday',
|
|
537
|
-
'friday',
|
|
538
|
-
'saturday',
|
|
539
|
-
].indexOf(m.moment);
|
|
540
|
-
const dow = this.dayofWeek(this.nowExpr()).sql;
|
|
541
|
-
if (m.which === 'next') {
|
|
542
|
-
const nForwards = `${this.mod7(`${destDay}-(${dow}-1)+6`)}+1`;
|
|
543
|
-
const begin = this.delta(this.thisUnit('day').begin, '+', nForwards, 'day');
|
|
544
|
-
const end = this.delta(this.thisUnit('day').begin, '+', `${nForwards}+1`, 'day');
|
|
545
|
-
// console.log(
|
|
546
|
-
// `SELECT ${
|
|
547
|
-
// this.nowExpr().sql
|
|
548
|
-
// } as now,\n ${destDay} as destDay,\n ${dow} as dow,\n ${nForwards} as nForwards,\n ${
|
|
549
|
-
// begin.sql
|
|
550
|
-
// } as begin,\n ${end.sql} as end`
|
|
551
|
-
// );
|
|
552
|
-
return { begin, end: end.sql };
|
|
553
|
-
}
|
|
554
|
-
// dacks back = mod((daw0 - dst) + 6, 7) + 1;
|
|
555
|
-
// dacks back = mod(((daw - 1) - dst) + 6, 7) + 1;
|
|
556
|
-
// dacks back = mod(((daw) - dst) + 7, 7) + 1;
|
|
557
|
-
const nBack = `${this.mod7(`(${dow}-1)-${destDay}+6`)}+1`;
|
|
558
|
-
const begin = this.delta(this.thisUnit('day').begin, '-', nBack, 'day');
|
|
559
|
-
const end = this.delta(this.thisUnit('day').begin, '-', `(${nBack})-1`, 'day');
|
|
560
|
-
// console.log(
|
|
561
|
-
// `SELECT ${
|
|
562
|
-
// this.nowExpr().sql
|
|
563
|
-
// } as now,\n ${destDay} as destDay,\n ${dow} as dow,\n ${nBack} as nBack,\n ${
|
|
564
|
-
// begin.sql
|
|
565
|
-
// } as begin,\n ${end.sql} as end`
|
|
566
|
-
// );
|
|
567
|
-
return { begin, end: end.sql };
|
|
568
|
-
}
|
|
537
|
+
return this.weekdayMoment(7, m.which);
|
|
569
538
|
}
|
|
570
539
|
}
|
|
571
540
|
isIn(notIn, begin, end) {
|
|
@@ -581,6 +550,27 @@ class TemporalFilterCompiler {
|
|
|
581
550
|
end = this.time(end);
|
|
582
551
|
return `${this.expr} ${begOp} ${begin} ${joinOp} ${this.expr} ${endOp} ${end}`;
|
|
583
552
|
}
|
|
553
|
+
weekdayMoment(destDay, which) {
|
|
554
|
+
const direction = which || 'last';
|
|
555
|
+
const dow = this.dayofWeek(this.nowExpr());
|
|
556
|
+
const todayBegin = this.thisUnit('day').begin;
|
|
557
|
+
// destDay comes in as 1-7 (Malloy format), convert to 0-6
|
|
558
|
+
const destDayZeroBased = destDay - 1;
|
|
559
|
+
// dow is 1-7, convert to 0-6 for the arithmetic
|
|
560
|
+
const dowZeroBased = `(${dow.sql}-1)`;
|
|
561
|
+
let daysOffset;
|
|
562
|
+
if (direction === 'next') {
|
|
563
|
+
// Days forward: ((destDay - dow + 6) % 7) + 1
|
|
564
|
+
daysOffset = `${this.mod7(`${destDayZeroBased}-${dowZeroBased}+6`)}+1`;
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
// Days back: ((dow - destDay + 6) % 7) + 1
|
|
568
|
+
daysOffset = `${this.mod7(`${dowZeroBased}-${destDayZeroBased}+6`)}+1`;
|
|
569
|
+
}
|
|
570
|
+
const begin = this.delta(todayBegin, direction === 'next' ? '+' : '-', daysOffset, 'day');
|
|
571
|
+
const end = this.delta(begin, '+', '1', 'day');
|
|
572
|
+
return { begin, end: end.sql };
|
|
573
|
+
}
|
|
584
574
|
}
|
|
585
575
|
exports.TemporalFilterCompiler = TemporalFilterCompiler;
|
|
586
576
|
//# sourceMappingURL=filter_compilers.js.map
|
|
@@ -77,14 +77,22 @@ export declare class QueryStruct {
|
|
|
77
77
|
pathAliasMap: Map<string, string>;
|
|
78
78
|
dialect: Dialect;
|
|
79
79
|
connectionName: string;
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
|
+
* For fields which are a record, but the value is an expression
|
|
82
|
+
* we capture the context needed to generate the expression in
|
|
83
|
+
* QueryQuery.expandFields. Later in the compilation if a
|
|
84
|
+
* reference passes through this struct, this will call
|
|
85
|
+
* the expression compiler with the correct context
|
|
86
|
+
* to compute the record value.
|
|
87
|
+
*/
|
|
88
|
+
computeRecordExpression?: () => string;
|
|
89
|
+
recordValue?: string;
|
|
81
90
|
constructor(structDef: StructDef, sourceArguments: Record<string, Argument> | undefined, parent: ParentQueryStruct | ParentQueryModel, prepareResultOptions: PrepareResultOptions);
|
|
82
91
|
private static turtleFieldMaker;
|
|
83
92
|
static registerTurtleFieldMaker(maker: (field: TurtleDef, parent: QueryStruct) => QueryField): void;
|
|
84
93
|
private _modelTag;
|
|
85
94
|
modelCompilerFlags(): Tag;
|
|
86
95
|
protected findFirstDialect(): string;
|
|
87
|
-
informOfAliasValue(av: string): void;
|
|
88
96
|
maybeEmitParameterizedSourceUsage(): void;
|
|
89
97
|
private resolveParentParameterReferences;
|
|
90
98
|
private _arguments;
|
package/dist/model/query_node.js
CHANGED
|
@@ -219,9 +219,6 @@ class QueryStruct {
|
|
|
219
219
|
}
|
|
220
220
|
throw new Error('Cannot create QueryStruct from record with model parent');
|
|
221
221
|
}
|
|
222
|
-
informOfAliasValue(av) {
|
|
223
|
-
this.recordAlias = av;
|
|
224
|
-
}
|
|
225
222
|
maybeEmitParameterizedSourceUsage() {
|
|
226
223
|
var _a;
|
|
227
224
|
if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
|
|
@@ -373,8 +370,11 @@ class QueryStruct {
|
|
|
373
370
|
// will have joins and thus be in the namespace. We can't compute it here
|
|
374
371
|
// because we don't have access to the Query to call exprToSQL.
|
|
375
372
|
if (this.structDef.type === 'record' && (0, malloy_types_1.hasExpression)(this.structDef)) {
|
|
376
|
-
if (this.
|
|
377
|
-
|
|
373
|
+
if (this.computeRecordExpression) {
|
|
374
|
+
if (!this.recordValue) {
|
|
375
|
+
this.recordValue = this.computeRecordExpression();
|
|
376
|
+
}
|
|
377
|
+
return this.recordValue;
|
|
378
378
|
}
|
|
379
379
|
throw new Error('INTERNAL ERROR, record field alias not pre-computed');
|
|
380
380
|
}
|
|
@@ -43,10 +43,18 @@ export declare class QueryQuery extends QueryField {
|
|
|
43
43
|
};
|
|
44
44
|
private addDependantPath;
|
|
45
45
|
private dependenciesFromFieldUsage;
|
|
46
|
-
findRecordAliases(context: QueryStruct, path: string[]): void;
|
|
47
46
|
getSegmentFields(resultStruct: FieldInstanceResult): SegmentFieldDef[];
|
|
48
47
|
private getDrillExpression;
|
|
49
48
|
expandFields(resultStruct: FieldInstanceResult): void;
|
|
49
|
+
/**
|
|
50
|
+
* Recursively walks the input QueryStruct tree and sets up lazy expression
|
|
51
|
+
* compilation for all records with computed expressions, so that records with
|
|
52
|
+
* expression values have the correct context for evaluating them if needed.
|
|
53
|
+
*
|
|
54
|
+
* @param resultStruct - The FieldInstanceResult containing compilation context
|
|
55
|
+
* @param source - The QueryStruct to traverse (initially the query's parent/input)
|
|
56
|
+
*/
|
|
57
|
+
expandSource(resultStruct: FieldInstanceResult, source: QueryStruct): void;
|
|
50
58
|
generateSQLFilters(resultStruct: FieldInstanceResult, which: 'where' | 'having'): AndChain;
|
|
51
59
|
prepare(_stageWriter: StageWriter | undefined): void;
|
|
52
60
|
private findJoins;
|
|
@@ -157,14 +157,10 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
157
157
|
resultStruct.addStructToJoin(this.parent, usage.uniqueKeyRequirement);
|
|
158
158
|
}
|
|
159
159
|
else {
|
|
160
|
-
this.findRecordAliases(this.parent, usage.path);
|
|
161
160
|
this.addDependantPath(resultStruct, this.parent, usage.path, usage.uniqueKeyRequirement);
|
|
162
161
|
}
|
|
163
162
|
continue;
|
|
164
163
|
}
|
|
165
|
-
if (usage.path.length > 1) {
|
|
166
|
-
this.findRecordAliases(this.parent, usage.path);
|
|
167
|
-
}
|
|
168
164
|
}
|
|
169
165
|
const expandedUngroupings = 'expandedUngroupings' in this.firstSegment
|
|
170
166
|
? this.firstSegment.expandedUngroupings || []
|
|
@@ -207,30 +203,6 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
207
203
|
}
|
|
208
204
|
}
|
|
209
205
|
}
|
|
210
|
-
/*
|
|
211
|
-
** Later on, when a record is referenced, the context needed to translate the
|
|
212
|
-
** reference won't exist, so we translate them all in prepare. The better fix
|
|
213
|
-
** involves understanding more about what a "translation state" is and how
|
|
214
|
-
** to create it at the moment when a field is referenced, but I couldn't do
|
|
215
|
-
** that at the time I did this work. TODO come back and do that.
|
|
216
|
-
*/
|
|
217
|
-
findRecordAliases(context, path) {
|
|
218
|
-
for (const seg of path) {
|
|
219
|
-
const field = context.getChildByName(seg);
|
|
220
|
-
if (!field) {
|
|
221
|
-
throw new Error('findRecordAliases: field not found: ' + path.join('.'));
|
|
222
|
-
}
|
|
223
|
-
if (field instanceof query_node_1.QueryFieldStruct) {
|
|
224
|
-
const qs = field.queryStruct;
|
|
225
|
-
if (qs.structDef.type === 'record' &&
|
|
226
|
-
(0, malloy_types_1.hasExpression)(qs.structDef) &&
|
|
227
|
-
qs.parent) {
|
|
228
|
-
qs.informOfAliasValue((0, expression_compiler_1.exprToSQL)(this.rootResult, qs.parent, qs.structDef.e));
|
|
229
|
-
}
|
|
230
|
-
context = qs;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
206
|
getSegmentFields(resultStruct) {
|
|
235
207
|
const fs = resultStruct.firstSegment;
|
|
236
208
|
return fs.type === 'index'
|
|
@@ -284,6 +256,31 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
284
256
|
resultIndex++;
|
|
285
257
|
}
|
|
286
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Recursively walks the input QueryStruct tree and sets up lazy expression
|
|
261
|
+
* compilation for all records with computed expressions, so that records with
|
|
262
|
+
* expression values have the correct context for evaluating them if needed.
|
|
263
|
+
*
|
|
264
|
+
* @param resultStruct - The FieldInstanceResult containing compilation context
|
|
265
|
+
* @param source - The QueryStruct to traverse (initially the query's parent/input)
|
|
266
|
+
*/
|
|
267
|
+
expandSource(resultStruct, source) {
|
|
268
|
+
for (const field of source.nameMap.values()) {
|
|
269
|
+
if (field instanceof query_node_1.QueryFieldStruct) {
|
|
270
|
+
const qs = field.queryStruct;
|
|
271
|
+
// Set up closure if this is a record with expression
|
|
272
|
+
if (qs.structDef.type === 'record' &&
|
|
273
|
+
(0, malloy_types_1.hasExpression)(qs.structDef) &&
|
|
274
|
+
qs.parent) {
|
|
275
|
+
const parent = qs.parent;
|
|
276
|
+
const e = qs.structDef.e;
|
|
277
|
+
qs.computeRecordExpression = () => (0, expression_compiler_1.exprToSQL)(resultStruct, parent, e);
|
|
278
|
+
}
|
|
279
|
+
// Recurse into this structure
|
|
280
|
+
this.expandSource(resultStruct, qs);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
287
284
|
generateSQLFilters(resultStruct, which
|
|
288
285
|
// filterList: FilterCondition[] | undefined = undefined
|
|
289
286
|
) {
|
|
@@ -307,6 +304,7 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
307
304
|
}
|
|
308
305
|
prepare(_stageWriter) {
|
|
309
306
|
if (!this.prepared) {
|
|
307
|
+
this.expandSource(this.rootResult, this.parent);
|
|
310
308
|
// Add the root base join to the joins map
|
|
311
309
|
this.rootResult.addStructToJoin(this.parent, undefined);
|
|
312
310
|
// Expand fields (just adds them to result, no dependency tracking)
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.309";
|
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.309';
|
|
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.309",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"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"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@malloydata/malloy-filter": "0.0.
|
|
45
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
46
|
-
"@malloydata/malloy-tag": "0.0.
|
|
44
|
+
"@malloydata/malloy-filter": "0.0.309",
|
|
45
|
+
"@malloydata/malloy-interfaces": "0.0.309",
|
|
46
|
+
"@malloydata/malloy-tag": "0.0.309",
|
|
47
47
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
48
48
|
"assert": "^2.0.0",
|
|
49
49
|
"jaro-winkler": "^0.2.8",
|