@malloydata/malloy 0.0.412 → 0.0.413
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/databricks/databricks.d.ts +2 -1
- package/dist/dialect/databricks/databricks.js +11 -6
- package/dist/dialect/dialect.d.ts +2 -1
- package/dist/dialect/dialect.js +7 -0
- package/dist/dialect/duckdb/duckdb.d.ts +2 -1
- package/dist/dialect/duckdb/duckdb.js +8 -2
- package/dist/dialect/mysql/mysql.d.ts +2 -1
- package/dist/dialect/mysql/mysql.js +7 -2
- package/dist/dialect/postgres/postgres.d.ts +2 -1
- package/dist/dialect/postgres/postgres.js +8 -2
- package/dist/dialect/snowflake/snowflake.d.ts +2 -1
- package/dist/dialect/snowflake/snowflake.js +9 -3
- package/dist/dialect/standardsql/standardsql.d.ts +2 -1
- package/dist/dialect/standardsql/standardsql.js +6 -2
- package/dist/dialect/trino/trino.d.ts +2 -1
- package/dist/dialect/trino/trino.js +6 -2
- package/dist/lang/ast/field-space/dynamic-space.js +9 -1
- package/dist/lang/ast/field-space/query-spaces.d.ts +1 -0
- package/dist/lang/ast/field-space/query-spaces.js +5 -0
- package/dist/lang/ast/query-items/field-references.d.ts +10 -1
- package/dist/lang/ast/query-items/field-references.js +67 -4
- package/dist/lang/ast/query-properties/nest.js +15 -0
- package/dist/lang/parse-log.d.ts +10 -0
- package/dist/lang/parse-log.js +3 -0
- package/dist/model/field_instance.js +9 -0
- package/dist/model/nest-capability.d.ts +37 -0
- package/dist/model/nest-capability.js +31 -0
- package/dist/model/query_query.d.ts +7 -4
- package/dist/model/query_query.js +176 -79
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -25,6 +25,7 @@ export declare class DatabricksDialect extends Dialect {
|
|
|
25
25
|
dontUnionIndex: boolean;
|
|
26
26
|
supportsQualify: boolean;
|
|
27
27
|
supportsNesting: boolean;
|
|
28
|
+
supportsNestedProjectionLimit: boolean;
|
|
28
29
|
hasLateralColumnAliasInSelect: boolean;
|
|
29
30
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
30
31
|
experimental: boolean;
|
|
@@ -48,7 +49,7 @@ export declare class DatabricksDialect extends Dialect {
|
|
|
48
49
|
sqlOrderBy(orderTerms: string[], obr?: OrderByRequest): string;
|
|
49
50
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
50
51
|
private buildNamedStructExpression;
|
|
51
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
52
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
52
53
|
private buildArraySortComparator;
|
|
53
54
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
54
55
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
@@ -62,6 +62,7 @@ class DatabricksDialect extends dialect_1.Dialect {
|
|
|
62
62
|
this.dontUnionIndex = false;
|
|
63
63
|
this.supportsQualify = false;
|
|
64
64
|
this.supportsNesting = true;
|
|
65
|
+
this.supportsNestedProjectionLimit = true;
|
|
65
66
|
this.hasLateralColumnAliasInSelect = true;
|
|
66
67
|
this.cantPartitionWindowFunctionsOnExpressions = true;
|
|
67
68
|
this.experimental = false;
|
|
@@ -169,13 +170,17 @@ class DatabricksDialect extends dialect_1.Dialect {
|
|
|
169
170
|
.join(', ') +
|
|
170
171
|
')');
|
|
171
172
|
}
|
|
172
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
173
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
173
174
|
const namedStruct = this.buildNamedStructExpression(fieldList);
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
176
|
+
const collectExpr = `COLLECT_LIST(${namedStruct}) FILTER (WHERE group_set=${groupSet}${filter})`;
|
|
177
|
+
// COLLECT_LIST is unordered, so ordering is done post-aggregation via
|
|
178
|
+
// ARRAY_SORT — the limit must slice the *ordered* array.
|
|
179
|
+
const ordered = !orderBy || orderBy.length === 0
|
|
180
|
+
? collectExpr
|
|
181
|
+
: `ARRAY_SORT(${collectExpr}, (l, r) -> ${this.buildArraySortComparator(orderBy)})`;
|
|
182
|
+
// SLICE(array, start, length) is 1-based; length n keeps the first n.
|
|
183
|
+
return limit !== undefined ? `SLICE(${ordered}, 1, ${limit})` : ordered;
|
|
179
184
|
}
|
|
180
185
|
// Build a lambda comparator for ARRAY_SORT that handles multi-field
|
|
181
186
|
// mixed-direction ordering. Each field comparison returns -1/0/1;
|
|
@@ -99,6 +99,7 @@ export declare abstract class Dialect {
|
|
|
99
99
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
100
100
|
sqlLateralJoinBag(_expressions: LateralJoinExpression[]): string;
|
|
101
101
|
supportsPipelinesInViews: boolean;
|
|
102
|
+
supportsNestedProjectionLimit: boolean;
|
|
102
103
|
supportsArraysInData: boolean;
|
|
103
104
|
hasTimestamptz: boolean;
|
|
104
105
|
readsNestedData: boolean;
|
|
@@ -175,7 +176,7 @@ export declare abstract class Dialect {
|
|
|
175
176
|
sqlValidateTableName(input: string): ValidateTablePathResult;
|
|
176
177
|
abstract sqlGroupSetTable(groupSetCount: number): string;
|
|
177
178
|
abstract sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
178
|
-
abstract sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
179
|
+
abstract sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
179
180
|
sqlTurtleOrderByClause(orderBy: CompiledOrderBy[]): string;
|
|
180
181
|
abstract sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
181
182
|
abstract sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
package/dist/dialect/dialect.js
CHANGED
|
@@ -73,6 +73,13 @@ class Dialect {
|
|
|
73
73
|
this.cantPartitionWindowFunctionsOnExpressions = false;
|
|
74
74
|
// Snowflake can't yet support pipelines in nested views.
|
|
75
75
|
this.supportsPipelinesInViews = true;
|
|
76
|
+
// Can the dialect apply a `limit:` to a nested `select:` (a projection
|
|
77
|
+
// nest)? A projection has no group-by keys to ROW_NUMBER-shave on, so the
|
|
78
|
+
// limit is applied by limiting/slicing the aggregated array inside
|
|
79
|
+
// `sqlAggregateTurtle`. Defaults false so a new dialect must consciously
|
|
80
|
+
// opt in (and implement the slice) rather than silently dropping the limit;
|
|
81
|
+
// the compiler rejects projection `limit:` when this is false.
|
|
82
|
+
this.supportsNestedProjectionLimit = false;
|
|
76
83
|
// Some dialects don't supporrt arrays (mysql)
|
|
77
84
|
this.supportsArraysInData = true;
|
|
78
85
|
// Does the dialect support timestamptz (TIMESTAMP WITH TIME ZONE)?
|
|
@@ -22,6 +22,7 @@ export declare class DuckDBDialect extends PostgresBase {
|
|
|
22
22
|
supportsQualify: boolean;
|
|
23
23
|
supportsSafeCast: boolean;
|
|
24
24
|
supportsNesting: boolean;
|
|
25
|
+
supportsNestedProjectionLimit: boolean;
|
|
25
26
|
supportsCountApprox: boolean;
|
|
26
27
|
requiresExplicitUnnestOrdering: boolean;
|
|
27
28
|
integerTypeMappings: IntegerTypeMapping[];
|
|
@@ -31,7 +32,7 @@ export declare class DuckDBDialect extends PostgresBase {
|
|
|
31
32
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
32
33
|
sqlLiteralNumber(literal: string): string;
|
|
33
34
|
mapFields(fieldList: DialectFieldList): string;
|
|
34
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
35
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
35
36
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
36
37
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
37
38
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -55,6 +55,7 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
|
|
|
55
55
|
this.supportsQualify = true;
|
|
56
56
|
this.supportsSafeCast = true;
|
|
57
57
|
this.supportsNesting = true;
|
|
58
|
+
this.supportsNestedProjectionLimit = true;
|
|
58
59
|
this.supportsCountApprox = true;
|
|
59
60
|
// DuckDB UNNEST in LATERAL JOINs doesn't preserve array element order
|
|
60
61
|
this.requiresExplicitUnnestOrdering = true;
|
|
@@ -91,12 +92,17 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
|
|
|
91
92
|
mapFields(fieldList) {
|
|
92
93
|
return fieldList.join(', ');
|
|
93
94
|
}
|
|
94
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
95
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
95
96
|
const fields = fieldList
|
|
96
97
|
.map(f => `\n ${f.sqlOutputName}: ${f.sqlExpression}`)
|
|
97
98
|
.join(', ');
|
|
98
99
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
99
|
-
|
|
100
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
101
|
+
const list = `LIST({${fields}} ${orderByClause}) FILTER (WHERE group_set=${groupSet}${filter})`;
|
|
102
|
+
// A projection nest's limit is applied by slicing the aggregated array
|
|
103
|
+
// (duckdb lists are 1-based, inclusive).
|
|
104
|
+
const limited = limit !== undefined ? `(${list})[1:${limit}]` : list;
|
|
105
|
+
return `COALESCE(${limited},[])`;
|
|
100
106
|
}
|
|
101
107
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
102
108
|
const fields = fieldList
|
|
@@ -31,6 +31,7 @@ export declare class MySQLDialect extends Dialect {
|
|
|
31
31
|
readsNestedData: boolean;
|
|
32
32
|
supportsComplexFilteredSources: boolean;
|
|
33
33
|
supportsArraysInData: boolean;
|
|
34
|
+
supportsNestedProjectionLimit: boolean;
|
|
34
35
|
compoundObjectInSchema: boolean;
|
|
35
36
|
booleanType: BooleanTypeSupport;
|
|
36
37
|
orderByClause: OrderByClauseType;
|
|
@@ -41,7 +42,7 @@ export declare class MySQLDialect extends Dialect {
|
|
|
41
42
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
42
43
|
sqlAnyValue(_groupSet: number, fieldName: string): string;
|
|
43
44
|
private mapFields;
|
|
44
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
45
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, _limit?: number, filterSQL?: string): string;
|
|
45
46
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
46
47
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
47
48
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -102,6 +102,10 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
102
102
|
this.readsNestedData = false;
|
|
103
103
|
this.supportsComplexFilteredSources = false;
|
|
104
104
|
this.supportsArraysInData = false;
|
|
105
|
+
// MySQL builds nested arrays with GROUP_CONCAT (not an array type), which has
|
|
106
|
+
// no in-expression slice; limiting would need query-level ROW_NUMBER plumbing
|
|
107
|
+
// the sqlAggregateTurtle seam doesn't expose. Left false (default) explicitly.
|
|
108
|
+
this.supportsNestedProjectionLimit = false;
|
|
105
109
|
this.compoundObjectInSchema = false;
|
|
106
110
|
this.booleanType = 'simulated';
|
|
107
111
|
this.orderByClause = 'ordinal';
|
|
@@ -157,11 +161,12 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
157
161
|
.map(f => `${this.sqlLiteralString(f.rawName)}, ${f.sqlExpression}`)
|
|
158
162
|
.join(', ');
|
|
159
163
|
}
|
|
160
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
164
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, _limit, filterSQL) {
|
|
161
165
|
const separator = ',';
|
|
162
166
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
167
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
163
168
|
let gc = `GROUP_CONCAT(
|
|
164
|
-
IF(group_set=${groupSet},
|
|
169
|
+
IF(group_set=${groupSet}${filter},
|
|
165
170
|
JSON_OBJECT(${this.mapFields(fieldList)})
|
|
166
171
|
, null
|
|
167
172
|
)
|
|
@@ -21,6 +21,7 @@ export declare class PostgresDialect extends PostgresBase {
|
|
|
21
21
|
dontUnionIndex: boolean;
|
|
22
22
|
supportsQualify: boolean;
|
|
23
23
|
supportsNesting: boolean;
|
|
24
|
+
supportsNestedProjectionLimit: boolean;
|
|
24
25
|
experimental: boolean;
|
|
25
26
|
readsNestedData: boolean;
|
|
26
27
|
supportsComplexFilteredSources: boolean;
|
|
@@ -31,7 +32,7 @@ export declare class PostgresDialect extends PostgresBase {
|
|
|
31
32
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
32
33
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
33
34
|
mapFields(fieldList: DialectFieldList): string;
|
|
34
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
35
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
35
36
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
36
37
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
37
38
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -75,6 +75,7 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
75
75
|
this.dontUnionIndex = false;
|
|
76
76
|
this.supportsQualify = false;
|
|
77
77
|
this.supportsNesting = true;
|
|
78
|
+
this.supportsNestedProjectionLimit = true;
|
|
78
79
|
this.experimental = false;
|
|
79
80
|
this.readsNestedData = false;
|
|
80
81
|
this.supportsComplexFilteredSources = false;
|
|
@@ -96,10 +97,15 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
96
97
|
.map(f => `\n ${f.sqlExpression}${f.typeDef.type === 'number' ? `::${this.defaultNumberType}` : ''} as ${f.sqlOutputName}`)
|
|
97
98
|
.join(', ');
|
|
98
99
|
}
|
|
99
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
100
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
100
101
|
const fields = this.mapFields(fieldList);
|
|
101
102
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
102
|
-
|
|
103
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
104
|
+
const arrayAgg = `(ARRAY_AGG((SELECT TO_JSONB(__x) FROM (SELECT ${fields}\n ) as __x) ${orderByClause} ) FILTER (WHERE group_set=${groupSet}${filter}))`;
|
|
105
|
+
// Slice the native ARRAY (1-based, inclusive) before TO_JSONB turns it into
|
|
106
|
+
// a single jsonb value — a jsonb scalar can't be range-sliced.
|
|
107
|
+
const limited = limit !== undefined ? `${arrayAgg}[1:${limit}]` : arrayAgg;
|
|
108
|
+
return `COALESCE(TO_JSONB(${limited}),'[]'::JSONB)`;
|
|
103
109
|
}
|
|
104
110
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
105
111
|
const fields = fieldList
|
|
@@ -17,6 +17,7 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
17
17
|
supportsSumDistinctFunction: boolean;
|
|
18
18
|
supportsSafeCast: boolean;
|
|
19
19
|
supportsNesting: boolean;
|
|
20
|
+
supportsNestedProjectionLimit: boolean;
|
|
20
21
|
defaultSampling: {
|
|
21
22
|
rows: number;
|
|
22
23
|
};
|
|
@@ -35,7 +36,7 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
35
36
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
36
37
|
mapFields(fieldList: DialectFieldList): string;
|
|
37
38
|
mapFieldsForObjectConstruct(fieldList: DialectFieldList): string;
|
|
38
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
39
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
39
40
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
40
41
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
41
42
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -71,6 +71,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
71
71
|
this.supportsSumDistinctFunction = true;
|
|
72
72
|
this.supportsSafeCast = true;
|
|
73
73
|
this.supportsNesting = true;
|
|
74
|
+
this.supportsNestedProjectionLimit = true;
|
|
74
75
|
this.defaultSampling = { rows: 50000 };
|
|
75
76
|
this.supportsHyperLogLog = true;
|
|
76
77
|
// NOTE: safely setting all these to false for now
|
|
@@ -107,13 +108,18 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
107
108
|
.map(f => `${this.sqlLiteralString(f.rawName)}, (${f.sqlExpression})`)
|
|
108
109
|
.join(', ');
|
|
109
110
|
}
|
|
110
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
111
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
111
112
|
const fields = this.mapFieldsForObjectConstruct(fieldList);
|
|
112
113
|
const orderByClause = orderBy
|
|
113
114
|
? ` WITHIN GROUP (${this.sqlTurtleOrderByClause(orderBy)})`
|
|
114
115
|
: '';
|
|
115
|
-
const
|
|
116
|
-
|
|
116
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
117
|
+
const aggClause = `ARRAY_AGG(CASE WHEN group_set=${groupSet}${filter} THEN OBJECT_CONSTRUCT_KEEP_NULL(${fields}) END)${orderByClause}`;
|
|
118
|
+
// ARRAY_SLICE is 0-based, end-exclusive, so (0, n) keeps the first n.
|
|
119
|
+
const limited = limit !== undefined
|
|
120
|
+
? `ARRAY_SLICE(${aggClause}, 0, ${limit})`
|
|
121
|
+
: aggClause;
|
|
122
|
+
return `COALESCE(${limited}, [])`;
|
|
117
123
|
}
|
|
118
124
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
119
125
|
const fields = this.mapFieldsForObjectConstruct(fieldList);
|
|
@@ -25,6 +25,7 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
25
25
|
supportsQualify: boolean;
|
|
26
26
|
supportsSafeCast: boolean;
|
|
27
27
|
supportsNesting: boolean;
|
|
28
|
+
supportsNestedProjectionLimit: boolean;
|
|
28
29
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
29
30
|
hasModOperator: boolean;
|
|
30
31
|
sqlLateralJoinBag(expressions: LateralJoinExpression[]): string;
|
|
@@ -42,7 +43,7 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
42
43
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
43
44
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
44
45
|
sqlOrderBy(orderTerms: string[], obr?: OrderByRequest): string;
|
|
45
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
46
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
46
47
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
47
48
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
48
49
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -77,6 +77,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
77
77
|
this.supportsQualify = true;
|
|
78
78
|
this.supportsSafeCast = true;
|
|
79
79
|
this.supportsNesting = true;
|
|
80
|
+
this.supportsNestedProjectionLimit = true;
|
|
80
81
|
this.cantPartitionWindowFunctionsOnExpressions = true;
|
|
81
82
|
this.hasModOperator = false;
|
|
82
83
|
this.nestedArrays = false; // Can't have an array of arrays for some reason
|
|
@@ -147,12 +148,15 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
147
148
|
return `ORDER BY ${orderTerms.map(t => `${t} NULLS LAST`).join(',')}`;
|
|
148
149
|
}
|
|
149
150
|
// can array agg or any_value a struct...
|
|
150
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
151
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
151
152
|
const fields = fieldList
|
|
152
153
|
.map(f => `\n ${f.sqlExpression} as ${f.sqlOutputName}`)
|
|
153
154
|
.join(', ');
|
|
154
155
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
155
|
-
|
|
156
|
+
// BigQuery ARRAY_AGG takes LIMIT as its final sub-clause, after ORDER BY.
|
|
157
|
+
const limitClause = limit !== undefined ? ` LIMIT ${limit}` : '';
|
|
158
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
159
|
+
return `ARRAY_AGG(CASE WHEN group_set=${groupSet}${filter} THEN STRUCT(${fields}\n ) END IGNORE NULLS ${orderByClause}${limitClause})`;
|
|
156
160
|
}
|
|
157
161
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
158
162
|
const fields = fieldList
|
|
@@ -22,6 +22,7 @@ export declare class TrinoDialect extends PostgresBase {
|
|
|
22
22
|
supportsQualify: boolean;
|
|
23
23
|
supportsSafeCast: boolean;
|
|
24
24
|
supportsNesting: boolean;
|
|
25
|
+
supportsNestedProjectionLimit: boolean;
|
|
25
26
|
cantPartitionWindowFunctionsOnExpressions: boolean;
|
|
26
27
|
orderByClause: OrderByClauseType;
|
|
27
28
|
nullMatchesFunctionSignature: boolean;
|
|
@@ -35,7 +36,7 @@ export declare class TrinoDialect extends PostgresBase {
|
|
|
35
36
|
exprToSQL(qi: QueryInfo, df: Expr): string | undefined;
|
|
36
37
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
37
38
|
buildTypeExpression(fieldList: DialectFieldList): string;
|
|
38
|
-
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined): string;
|
|
39
|
+
sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: CompiledOrderBy[] | undefined, limit?: number, filterSQL?: string): string;
|
|
39
40
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
40
41
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
41
42
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
@@ -76,6 +76,7 @@ class TrinoDialect extends pg_impl_1.PostgresBase {
|
|
|
76
76
|
this.supportsQualify = true;
|
|
77
77
|
this.supportsSafeCast = true;
|
|
78
78
|
this.supportsNesting = true;
|
|
79
|
+
this.supportsNestedProjectionLimit = true;
|
|
79
80
|
this.cantPartitionWindowFunctionsOnExpressions = false;
|
|
80
81
|
this.orderByClause = 'output_name';
|
|
81
82
|
this.nullMatchesFunctionSignature = false;
|
|
@@ -225,11 +226,14 @@ class TrinoDialect extends pg_impl_1.PostgresBase {
|
|
|
225
226
|
.join(', \n');
|
|
226
227
|
}
|
|
227
228
|
// can array agg or any_value a struct...
|
|
228
|
-
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
229
|
+
sqlAggregateTurtle(groupSet, fieldList, orderBy, limit, filterSQL) {
|
|
229
230
|
const expressions = fieldList.map(f => f.sqlExpression).join(',\n ');
|
|
230
231
|
const definitions = this.buildTypeExpression(fieldList);
|
|
231
232
|
const orderByClause = orderBy ? this.sqlTurtleOrderByClause(orderBy) : '';
|
|
232
|
-
|
|
233
|
+
const filter = filterSQL ? ` AND ${filterSQL}` : '';
|
|
234
|
+
const arrayAgg = `ARRAY_AGG(CAST(ROW(${expressions}) AS ROW(${definitions})) ${orderByClause}) FILTER (WHERE group_set=${groupSet}${filter})`;
|
|
235
|
+
// SLICE(array, start, length) is 1-based; length n keeps the first n.
|
|
236
|
+
return limit !== undefined ? `SLICE(${arrayAgg}, 1, ${limit})` : arrayAgg;
|
|
233
237
|
}
|
|
234
238
|
sqlAnyValueTurtle(groupSet, fieldList) {
|
|
235
239
|
const expressions = fieldList.map(f => f.sqlExpression).join(',\n ');
|
|
@@ -79,7 +79,15 @@ class DynamicSpace extends static_space_1.StaticSpace {
|
|
|
79
79
|
}
|
|
80
80
|
newEntry(name, logTo, entry) {
|
|
81
81
|
if (this.entry(name)) {
|
|
82
|
-
|
|
82
|
+
if (this.isQueryFieldSpace() &&
|
|
83
|
+
this.outputSpace().synthesizedNames.has(name)) {
|
|
84
|
+
logTo.logError('definition-name-conflict', `Cannot redefine '${name}', which was auto-generated by renaming an ` +
|
|
85
|
+
'ambiguous reference; name one of the conflicting references ' +
|
|
86
|
+
"explicitly with 'is' to resolve this");
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
logTo.logError('definition-name-conflict', `Cannot redefine '${name}'`);
|
|
90
|
+
}
|
|
83
91
|
return;
|
|
84
92
|
}
|
|
85
93
|
this.setEntry(name, entry);
|
|
@@ -43,6 +43,7 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
|
|
|
43
43
|
name: string;
|
|
44
44
|
field: SpaceField;
|
|
45
45
|
})[];
|
|
46
|
+
synthesizedNames: Set<string>;
|
|
46
47
|
private _refSummary;
|
|
47
48
|
private _refSummaryComputed;
|
|
48
49
|
get refSummary(): model.RefSummary | undefined;
|
|
@@ -80,6 +80,11 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
|
|
|
80
80
|
this.expandedWild = new Map();
|
|
81
81
|
this.drillDimensions = [];
|
|
82
82
|
this.compositeFieldUsers = [];
|
|
83
|
+
// Output names this space generated by auto-renaming an ambiguous reference
|
|
84
|
+
// (e.g. `user.name` -> `user_name`). Tracked here, on the namespace that
|
|
85
|
+
// minted them, rather than on the entries: a later explicit definition that
|
|
86
|
+
// lands on a synthesized name is a hard error, not a silent shadow.
|
|
87
|
+
this.synthesizedNames = new Set();
|
|
83
88
|
// Reference summary is not computed until `queryFieldDefs` is called
|
|
84
89
|
// (or `getPipeSegment` for index segments). Reading it before that throws;
|
|
85
90
|
// assigning to it (via the setter) flips the computed flag.
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import type { AnnotationsDef, FieldDef, RefToField, TypeDesc } from '../../../model/malloy_types';
|
|
2
2
|
import type { DynamicSpace } from '../field-space/dynamic-space';
|
|
3
3
|
import { DefinitionList } from '../types/definition-list';
|
|
4
|
-
import type {
|
|
4
|
+
import type { FieldSpace } from '../types/field-space';
|
|
5
|
+
import { FieldName } from '../types/field-space';
|
|
5
6
|
import type { LookupResult } from '../types/lookup-result';
|
|
6
7
|
import { ListOf, MalloyElement } from '../types/malloy-element';
|
|
7
8
|
import type { Noteable } from '../types/noteable';
|
|
8
9
|
import { extendNoteMethod } from '../types/noteable';
|
|
9
10
|
import type { MakeEntry } from '../types/space-entry';
|
|
11
|
+
import type { FieldDeclarationConstructor } from './field-declaration';
|
|
12
|
+
import { AggregateFieldDeclaration, CalculateFieldDeclaration, GroupByFieldDeclaration, ProjectFieldDeclaration } from './field-declaration';
|
|
10
13
|
export type FieldReferenceConstructor = new (names: FieldName[]) => FieldReference;
|
|
11
14
|
export declare abstract class FieldReference extends ListOf<FieldName> implements Noteable, MakeEntry {
|
|
12
15
|
readonly isNoteableObj = true;
|
|
13
16
|
note?: AnnotationsDef;
|
|
14
17
|
extendNote: typeof extendNoteMethod;
|
|
15
18
|
constructor(names: FieldName[]);
|
|
19
|
+
protected autoRenameDeclarationCtor(): FieldDeclarationConstructor | undefined;
|
|
16
20
|
makeEntry(fs: DynamicSpace): void;
|
|
21
|
+
private autoRename;
|
|
17
22
|
getName(): string;
|
|
18
23
|
get refToField(): RefToField;
|
|
19
24
|
get refString(): string;
|
|
@@ -58,6 +63,7 @@ export declare class DrillFieldReference extends FieldReference {
|
|
|
58
63
|
}
|
|
59
64
|
export declare class CalculateFieldReference extends FieldReference {
|
|
60
65
|
elementType: string;
|
|
66
|
+
protected autoRenameDeclarationCtor(): typeof CalculateFieldDeclaration;
|
|
61
67
|
typecheck(type: TypeDesc): void;
|
|
62
68
|
}
|
|
63
69
|
export declare class IndexFieldReference extends FieldReference {
|
|
@@ -68,14 +74,17 @@ export declare class IndexFieldReference extends FieldReference {
|
|
|
68
74
|
}
|
|
69
75
|
export declare class AggregateFieldReference extends FieldReference {
|
|
70
76
|
elementType: string;
|
|
77
|
+
protected autoRenameDeclarationCtor(): typeof AggregateFieldDeclaration;
|
|
71
78
|
typecheck(type: TypeDesc): void;
|
|
72
79
|
}
|
|
73
80
|
export declare class GroupByFieldReference extends FieldReference {
|
|
74
81
|
elementType: string;
|
|
82
|
+
protected autoRenameDeclarationCtor(): typeof GroupByFieldDeclaration;
|
|
75
83
|
typecheck(type: TypeDesc): void;
|
|
76
84
|
}
|
|
77
85
|
export declare class ProjectFieldReference extends FieldReference {
|
|
78
86
|
elementType: string;
|
|
87
|
+
protected autoRenameDeclarationCtor(): typeof ProjectFieldDeclaration;
|
|
79
88
|
typecheck(type: TypeDesc): void;
|
|
80
89
|
}
|
|
81
90
|
export declare class DeclareFieldReference extends FieldReference {
|
|
@@ -7,8 +7,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.FieldReferences = exports.WildcardFieldReference = exports.ViewOrScalarFieldReference = exports.DimensionFieldReference = exports.MeasureFieldReference = exports.DeclareFieldReference = exports.ProjectFieldReference = exports.GroupByFieldReference = exports.AggregateFieldReference = exports.IndexFieldReference = exports.CalculateFieldReference = exports.DrillFieldReference = exports.ParameterFieldReference = exports.GroupedByReference = exports.PartitionByFieldReference = exports.RefineFromFieldReference = exports.ExpressionFieldReference = exports.AccessModifierFieldReference = exports.AcceptExceptFieldReference = exports.FieldReference = void 0;
|
|
8
8
|
const reference_field_1 = require("../field-space/reference-field");
|
|
9
9
|
const definition_list_1 = require("../types/definition-list");
|
|
10
|
+
const field_space_1 = require("../types/field-space");
|
|
10
11
|
const malloy_element_1 = require("../types/malloy-element");
|
|
11
12
|
const noteable_1 = require("../types/noteable");
|
|
13
|
+
const expr_id_reference_1 = require("../expressions/expr-id-reference");
|
|
14
|
+
const field_declaration_1 = require("./field-declaration");
|
|
12
15
|
const typecheck_utils_1 = require("./typecheck_utils");
|
|
13
16
|
class FieldReference extends malloy_element_1.ListOf {
|
|
14
17
|
constructor(names) {
|
|
@@ -16,16 +19,64 @@ class FieldReference extends malloy_element_1.ListOf {
|
|
|
16
19
|
this.isNoteableObj = true;
|
|
17
20
|
this.extendNote = noteable_1.extendNoteMethod;
|
|
18
21
|
}
|
|
22
|
+
// The `name is path` declaration constructor used to auto-resolve an output
|
|
23
|
+
// name collision for this kind of reference, or undefined if this reference
|
|
24
|
+
// does not produce an output column named for its last path element (e.g.
|
|
25
|
+
// index references, view references). Overridden by the references that do.
|
|
26
|
+
autoRenameDeclarationCtor() {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
19
29
|
makeEntry(fs) {
|
|
20
30
|
const refName = this.outputName;
|
|
21
|
-
if (fs.entry(refName)) {
|
|
22
|
-
this.logError('output-name-conflict', `Output already has a field named '${refName}'`);
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
31
|
+
if (fs.entry(refName) === undefined) {
|
|
25
32
|
// In a QuerySpace, this needs to be able to find the thing to which it refers
|
|
26
33
|
const fromFS = fs.isQueryFieldSpace() ? fs.inputSpace() : fs;
|
|
27
34
|
fs.newEntry(refName, this, new reference_field_1.ReferenceField(this, fromFS));
|
|
35
|
+
return;
|
|
28
36
|
}
|
|
37
|
+
// The natural (last-segment) name is taken. A dotted reference can be
|
|
38
|
+
// auto-renamed using its full path; a single-name reference has no prefix
|
|
39
|
+
// to disambiguate with, so it stays a hard error.
|
|
40
|
+
const declCtor = this.autoRenameDeclarationCtor();
|
|
41
|
+
if (declCtor && this.list.length > 1 && fs.isQueryFieldSpace()) {
|
|
42
|
+
this.autoRename(fs, fs.outputSpace().synthesizedNames, declCtor, refName);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (fs.isQueryFieldSpace() &&
|
|
46
|
+
fs.outputSpace().synthesizedNames.has(refName)) {
|
|
47
|
+
this.logError('output-name-conflict', `Output already has a field named '${refName}', which was ` +
|
|
48
|
+
'auto-generated by renaming an ambiguous reference; name one of the ' +
|
|
49
|
+
"conflicting references explicitly with 'is' to resolve this");
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.logError('output-name-conflict', `Output already has a field named '${refName}'`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Rewrite `path.to.field` into the equivalent `autoName is path.to.field`
|
|
56
|
+
// declaration — the same AST the user would write to fix it by hand — and
|
|
57
|
+
// let its normal makeEntry produce the (renamed) output field.
|
|
58
|
+
autoRename(fs, synthesizedNames, declCtor, refName) {
|
|
59
|
+
// `path.join('_')`, then `_2`, `_3`, ... until free. The synthetic name
|
|
60
|
+
// yields to whatever is already in the output, so a user-written name wins.
|
|
61
|
+
const base = this.path.join('_');
|
|
62
|
+
let autoName = base;
|
|
63
|
+
let n = 2;
|
|
64
|
+
while (fs.entry(autoName) !== undefined) {
|
|
65
|
+
autoName = `${base}_${n++}`;
|
|
66
|
+
}
|
|
67
|
+
synthesizedNames.add(autoName);
|
|
68
|
+
this.logWarning('output-field-auto-renamed', `Output already has a field named '${refName}', so '${this.refString}' ` +
|
|
69
|
+
`was renamed to '${autoName}'. Write '${autoName} is ${this.refString}' ` +
|
|
70
|
+
'to set the name explicitly and silence this warning.');
|
|
71
|
+
const renamedRef = new ExpressionFieldReference(this.list.map(n => new field_space_1.FieldName(n.refString)));
|
|
72
|
+
const decl = new declCtor(new expr_id_reference_1.ExprIdReference(renamedRef), autoName);
|
|
73
|
+
if (this.note) {
|
|
74
|
+
decl.note = this.note;
|
|
75
|
+
}
|
|
76
|
+
// Attach under this reference so the synthetic nodes inherit its location
|
|
77
|
+
// and resolve back to the translator for logging.
|
|
78
|
+
this.has({ autoRenamed: decl });
|
|
79
|
+
decl.makeEntry(fs);
|
|
29
80
|
}
|
|
30
81
|
getName() {
|
|
31
82
|
return this.nameString;
|
|
@@ -161,6 +212,9 @@ class CalculateFieldReference extends FieldReference {
|
|
|
161
212
|
super(...arguments);
|
|
162
213
|
this.elementType = 'calculateFieldReference';
|
|
163
214
|
}
|
|
215
|
+
autoRenameDeclarationCtor() {
|
|
216
|
+
return field_declaration_1.CalculateFieldDeclaration;
|
|
217
|
+
}
|
|
164
218
|
typecheck(type) {
|
|
165
219
|
(0, typecheck_utils_1.typecheckCalculate)(type, this);
|
|
166
220
|
}
|
|
@@ -188,6 +242,9 @@ class AggregateFieldReference extends FieldReference {
|
|
|
188
242
|
super(...arguments);
|
|
189
243
|
this.elementType = 'aggregateFieldReference';
|
|
190
244
|
}
|
|
245
|
+
autoRenameDeclarationCtor() {
|
|
246
|
+
return field_declaration_1.AggregateFieldDeclaration;
|
|
247
|
+
}
|
|
191
248
|
typecheck(type) {
|
|
192
249
|
(0, typecheck_utils_1.typecheckAggregate)(type, this);
|
|
193
250
|
}
|
|
@@ -198,6 +255,9 @@ class GroupByFieldReference extends FieldReference {
|
|
|
198
255
|
super(...arguments);
|
|
199
256
|
this.elementType = 'groupByFieldReference';
|
|
200
257
|
}
|
|
258
|
+
autoRenameDeclarationCtor() {
|
|
259
|
+
return field_declaration_1.GroupByFieldDeclaration;
|
|
260
|
+
}
|
|
201
261
|
typecheck(type) {
|
|
202
262
|
(0, typecheck_utils_1.typecheckGroupBy)(type, this);
|
|
203
263
|
}
|
|
@@ -208,6 +268,9 @@ class ProjectFieldReference extends FieldReference {
|
|
|
208
268
|
super(...arguments);
|
|
209
269
|
this.elementType = 'projectFieldReference';
|
|
210
270
|
}
|
|
271
|
+
autoRenameDeclarationCtor() {
|
|
272
|
+
return field_declaration_1.ProjectFieldDeclaration;
|
|
273
|
+
}
|
|
211
274
|
typecheck(type) {
|
|
212
275
|
(0, typecheck_utils_1.typecheckProject)(type, this);
|
|
213
276
|
}
|
|
@@ -39,6 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.NestFieldDeclaration = void 0;
|
|
41
41
|
const model = __importStar(require("../../../model/malloy_types"));
|
|
42
|
+
const nest_capability_1 = require("../../../model/nest-capability");
|
|
42
43
|
const query_utils_1 = require("../query-utils");
|
|
43
44
|
const view_field_declaration_1 = require("../source-properties/view-field-declaration");
|
|
44
45
|
const query_property_interface_1 = require("../types/query-property-interface");
|
|
@@ -63,6 +64,20 @@ class NestFieldDeclaration extends view_field_declaration_1.ViewFieldDeclaration
|
|
|
63
64
|
? pipeline[0].refSummary
|
|
64
65
|
: undefined;
|
|
65
66
|
const checkedPipeline = (0, query_utils_1.detectAndRemovePartialStages)(pipeline, this);
|
|
67
|
+
// Reject — at translate time, with a located message — any stage of this
|
|
68
|
+
// nest the compiler can't emit for this dialect, rather than producing
|
|
69
|
+
// broken SQL. The compiler asks segment-at-a-time as it recurses; the
|
|
70
|
+
// translator holds the whole pipeline, so it asks every stage.
|
|
71
|
+
const dialect = fs.dialectObj();
|
|
72
|
+
if (dialect) {
|
|
73
|
+
for (let i = 0; i < checkedPipeline.length; i++) {
|
|
74
|
+
const strategy = (0, nest_capability_1.nestStrategy)(checkedPipeline[i], dialect, i < checkedPipeline.length - 1);
|
|
75
|
+
if (strategy.kind === 'unsupported') {
|
|
76
|
+
this.logError(strategy.reason, { dialect: dialect.name });
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
66
81
|
const pipelineWithDrillPaths = (0, drill_1.attachDrillPaths)(checkedPipeline, this.name);
|
|
67
82
|
this.turtleDef = {
|
|
68
83
|
type: 'turtle',
|
package/dist/lang/parse-log.d.ts
CHANGED
|
@@ -61,6 +61,15 @@ type MessageParameterTypes = {
|
|
|
61
61
|
'experimental-dialect-not-enabled': {
|
|
62
62
|
dialect: string;
|
|
63
63
|
};
|
|
64
|
+
'nesting-unsupported': {
|
|
65
|
+
dialect: string;
|
|
66
|
+
};
|
|
67
|
+
'nested-multi-stage-unsupported': {
|
|
68
|
+
dialect: string;
|
|
69
|
+
};
|
|
70
|
+
'nested-projection-limit-unsupported': {
|
|
71
|
+
dialect: string;
|
|
72
|
+
};
|
|
64
73
|
'sql-native-not-allowed-in-expression': {
|
|
65
74
|
rawType: string | undefined;
|
|
66
75
|
};
|
|
@@ -185,6 +194,7 @@ type MessageParameterTypes = {
|
|
|
185
194
|
'invalid-type-for-field-definition': string;
|
|
186
195
|
'circular-reference-in-field-definition': string;
|
|
187
196
|
'output-name-conflict': string;
|
|
197
|
+
'output-field-auto-renamed': string;
|
|
188
198
|
'select-of-view': string;
|
|
189
199
|
'select-of-analytic': string;
|
|
190
200
|
'select-of-aggregate': string;
|
package/dist/lang/parse-log.js
CHANGED
|
@@ -55,6 +55,9 @@ exports.MESSAGE_FORMATTERS = {
|
|
|
55
55
|
tag: 'pick-values-must-match',
|
|
56
56
|
}),
|
|
57
57
|
'experimental-dialect-not-enabled': e => `Requires compiler flag '##! experimental.dialect.${e.dialect}'`,
|
|
58
|
+
'nesting-unsupported': e => `'${e.dialect}' does not support nested queries`,
|
|
59
|
+
'nested-multi-stage-unsupported': e => `'${e.dialect}' does not support a multi-stage pipeline ('->') in a nested query`,
|
|
60
|
+
'nested-projection-limit-unsupported': e => `'${e.dialect}' does not support 'limit:' on a nested 'select:'`,
|
|
58
61
|
'pick-missing-else': "pick incomplete, missing 'else'",
|
|
59
62
|
'pick-missing-value': 'pick with no value can only be used with apply',
|
|
60
63
|
'pick-illegal-partial': 'pick with partial when can only be used with apply',
|