@malloydata/malloy 0.0.331 → 0.0.332
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 +1 -0
- package/dist/dialect/dialect.js +3 -0
- package/dist/dialect/duckdb/duckdb.d.ts +2 -1
- package/dist/dialect/duckdb/duckdb.js +5 -8
- package/dist/lang/ast/field-space/query-spaces.js +3 -0
- package/dist/lang/ast/source-elements/composite-source.js +1 -1
- package/dist/lang/ast/types/expression-def.d.ts +2 -2
- package/dist/lang/ast/types/expression-def.js +2 -2
- package/dist/model/query_query.d.ts +5 -0
- package/dist/model/query_query.js +32 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -76,6 +76,7 @@ export declare abstract class Dialect {
|
|
|
76
76
|
supportsTempTables: boolean;
|
|
77
77
|
hasModOperator: boolean;
|
|
78
78
|
supportsLeftJoinUnnest: boolean;
|
|
79
|
+
requiresExplicitUnnestOrdering: boolean;
|
|
79
80
|
supportsCountApprox: boolean;
|
|
80
81
|
supportsHyperLogLog: boolean;
|
|
81
82
|
supportsFullJoin: boolean;
|
package/dist/dialect/dialect.js
CHANGED
|
@@ -98,6 +98,9 @@ class Dialect {
|
|
|
98
98
|
this.hasModOperator = true;
|
|
99
99
|
// can LEFT JOIN UNNEST
|
|
100
100
|
this.supportsLeftJoinUnnest = true;
|
|
101
|
+
// UNNEST in LATERAL JOINs doesn't guarantee array element order.
|
|
102
|
+
// When true, compiler adds ORDER BY on array ordinality columns (__row_id)
|
|
103
|
+
this.requiresExplicitUnnestOrdering = false;
|
|
101
104
|
this.supportsCountApprox = false;
|
|
102
105
|
this.supportsHyperLogLog = false;
|
|
103
106
|
// MYSQL doesn't have full join, maybe others.
|
|
@@ -22,6 +22,7 @@ export declare class DuckDBDialect extends PostgresBase {
|
|
|
22
22
|
supportsSafeCast: boolean;
|
|
23
23
|
supportsNesting: boolean;
|
|
24
24
|
supportsCountApprox: boolean;
|
|
25
|
+
requiresExplicitUnnestOrdering: boolean;
|
|
25
26
|
integerTypeMappings: IntegerTypeMapping[];
|
|
26
27
|
get udfPrefix(): string;
|
|
27
28
|
quoteTablePath(tableName: string): string;
|
|
@@ -33,7 +34,7 @@ export declare class DuckDBDialect extends PostgresBase {
|
|
|
33
34
|
sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
|
|
34
35
|
sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
|
|
35
36
|
sqlCoaleseMeasuresInline(groupSet: number, fieldList: DialectFieldList): string;
|
|
36
|
-
sqlUnnestAlias(source: string, alias: string, _fieldList: DialectFieldList,
|
|
37
|
+
sqlUnnestAlias(source: string, alias: string, _fieldList: DialectFieldList, _needDistinctKey: boolean, _isArray: boolean, isInNestedPipeline: boolean): string;
|
|
37
38
|
sqlSumDistinctHashedKey(_sqlDistinctKey: string): string;
|
|
38
39
|
sqlGenerateUUID(): string;
|
|
39
40
|
sqlDateToString(sqlDateExp: string): string;
|
|
@@ -73,6 +73,8 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
|
|
|
73
73
|
this.supportsSafeCast = true;
|
|
74
74
|
this.supportsNesting = true;
|
|
75
75
|
this.supportsCountApprox = true;
|
|
76
|
+
// DuckDB UNNEST in LATERAL JOINs doesn't preserve array element order
|
|
77
|
+
this.requiresExplicitUnnestOrdering = true;
|
|
76
78
|
// DuckDB: 32-bit INTEGER is safe, larger integers need bigint
|
|
77
79
|
this.integerTypeMappings = [
|
|
78
80
|
{ min: BigInt(dialect_1.MIN_INT32), max: BigInt(dialect_1.MAX_INT32), numberType: 'integer' },
|
|
@@ -139,7 +141,7 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
|
|
|
139
141
|
// // When DuckDB supports lateral joins...
|
|
140
142
|
// //return `,(select UNNEST(generate_series(1, length(${source}),1))) as ${alias}(__row_id)`;
|
|
141
143
|
// }
|
|
142
|
-
sqlUnnestAlias(source, alias, _fieldList,
|
|
144
|
+
sqlUnnestAlias(source, alias, _fieldList, _needDistinctKey, _isArray, isInNestedPipeline) {
|
|
143
145
|
if (this.unnestWithNumbers) {
|
|
144
146
|
// Duckdb can't unnest in a coorelated subquery at the moment so we hack it.
|
|
145
147
|
const arrayLen = isInNestedPipeline
|
|
@@ -149,13 +151,8 @@ class DuckDBDialect extends pg_impl_1.PostgresBase {
|
|
|
149
151
|
${arrayLen},
|
|
150
152
|
1)) as __row_id) as ${alias} ON ${alias}.__row_id <= array_length(${source})`;
|
|
151
153
|
}
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
return `LEFT JOIN LATERAL (SELECT UNNEST(${source}), 1 as ignoreme) as ${alias}_outer(${alias},ignoreme) ON ${alias}_outer.ignoreme=1`;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
return `LEFT JOIN LATERAL (SELECT UNNEST(GENERATE_SERIES(1, length(${source}),1)) as __row_id, UNNEST(${source}), 1 as ignoreme) as ${alias}_outer(__row_id, ${alias},ignoreme) ON ${alias}_outer.ignoreme=1`;
|
|
158
|
-
}
|
|
154
|
+
// Use WITH ORDINALITY to preserve array element order via __row_id
|
|
155
|
+
return `LEFT JOIN LATERAL UNNEST(${source}) WITH ORDINALITY as ${alias}_outer(${alias}, __row_id) ON true`;
|
|
159
156
|
}
|
|
160
157
|
sqlSumDistinctHashedKey(_sqlDistinctKey) {
|
|
161
158
|
return 'uses sumDistinctFunction, should not be called';
|
|
@@ -296,6 +296,9 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
296
296
|
throw new Error('Invalid type for fieldref');
|
|
297
297
|
}
|
|
298
298
|
ret.location = (_c = ret.location) !== null && _c !== void 0 ? _c : this.astEl.location;
|
|
299
|
+
if (queryFieldDef.annotation) {
|
|
300
|
+
ret.annotation = queryFieldDef.annotation;
|
|
301
|
+
}
|
|
299
302
|
return ret;
|
|
300
303
|
}
|
|
301
304
|
// Gets the primary key field for the output struct of this query;
|
|
@@ -95,7 +95,7 @@ function composeSources(sources, compositeCodeSource) {
|
|
|
95
95
|
fieldUsage: [
|
|
96
96
|
{ path: [fieldName], at: compositeCodeSource.codeLocation },
|
|
97
97
|
],
|
|
98
|
-
code:
|
|
98
|
+
code: undefined,
|
|
99
99
|
location: compositeCodeSource.codeLocation,
|
|
100
100
|
// A composite field's grouping may differ from slice to slice
|
|
101
101
|
requiresGroupBy: undefined,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as Malloy from '@malloydata/malloy-interfaces';
|
|
2
|
-
import type { Expr, TimestampUnit } from '../../../model/malloy_types';
|
|
2
|
+
import type { Expr, TimestampUnit, FilterExprType } from '../../../model/malloy_types';
|
|
3
3
|
import type { ExprValue } from './expr-value';
|
|
4
4
|
import type { FieldSpace } from './field-space';
|
|
5
5
|
import { MalloyElement } from './malloy-element';
|
|
@@ -85,4 +85,4 @@ export declare function getMorphicValue(mv: ExprValue, mt: MorphicType): ExprVal
|
|
|
85
85
|
* @return ExprValue of the expression
|
|
86
86
|
*/
|
|
87
87
|
export declare function applyBinary(fs: FieldSpace, left: ExpressionDef, op: BinaryMalloyOperator, right: ExpressionDef): ExprValue;
|
|
88
|
-
export declare function checkFilterExpression(logTo: MalloyElement, ft:
|
|
88
|
+
export declare function checkFilterExpression(logTo: MalloyElement, ft: FilterExprType, fexpr: Expr): void;
|
|
@@ -207,7 +207,7 @@ class ExprDuration extends ExpressionDef {
|
|
|
207
207
|
}
|
|
208
208
|
exports.ExprDuration = ExprDuration;
|
|
209
209
|
function willMorphTo(ev, t) {
|
|
210
|
-
if (ev.type === t) {
|
|
210
|
+
if (ev.type === t || (t === 'timestamp' && ev.type === 'timestamptz')) {
|
|
211
211
|
return ev.value;
|
|
212
212
|
}
|
|
213
213
|
return ev.morphic && ev.morphic[t];
|
|
@@ -542,7 +542,7 @@ function checkFilterExpression(logTo, ft, fexpr) {
|
|
|
542
542
|
}
|
|
543
543
|
const fsrc = fexpr.filterSrc;
|
|
544
544
|
let err;
|
|
545
|
-
if (
|
|
545
|
+
if ((0, malloy_types_1.isTemporalType)(ft)) {
|
|
546
546
|
err = (_a = malloy_filter_1.TemporalFilterExpression.parse(fsrc).log[0]) === null || _a === void 0 ? void 0 : _a.message;
|
|
547
547
|
}
|
|
548
548
|
else if (ft === 'string') {
|
|
@@ -66,6 +66,11 @@ export declare class QueryQuery extends QueryField {
|
|
|
66
66
|
generateSQLJoinBlock(stageWriter: StageWriter, ji: JoinInstance, depth: number): string;
|
|
67
67
|
generateSQLPassthroughKeys(qs: QueryStruct): string;
|
|
68
68
|
generateSQLJoins(stageWriter: StageWriter): string;
|
|
69
|
+
/**
|
|
70
|
+
* Collect all array joins from the join tree in depth-first order.
|
|
71
|
+
* This ordering ensures parent arrays are ordered before child arrays.
|
|
72
|
+
*/
|
|
73
|
+
collectArrayJoins(ji: JoinInstance): JoinInstance[];
|
|
69
74
|
genereateSQLOrderBy(queryDef: QuerySegment, resultStruct: FieldInstanceResult): string;
|
|
70
75
|
generateSimpleSQL(stageWriter: StageWriter): string;
|
|
71
76
|
generatePipelinedStages(outputPipelinedSQL: OutputPipelinedSQL[], lastStageName: string, stageWriter: StageWriter): string;
|
|
@@ -737,10 +737,37 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
737
737
|
}
|
|
738
738
|
return s;
|
|
739
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Collect all array joins from the join tree in depth-first order.
|
|
742
|
+
* This ordering ensures parent arrays are ordered before child arrays.
|
|
743
|
+
*/
|
|
744
|
+
collectArrayJoins(ji) {
|
|
745
|
+
const result = [];
|
|
746
|
+
if (ji.queryStruct.structDef.type === 'array') {
|
|
747
|
+
result.push(ji);
|
|
748
|
+
}
|
|
749
|
+
for (const child of ji.children) {
|
|
750
|
+
result.push(...this.collectArrayJoins(child));
|
|
751
|
+
}
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
740
754
|
genereateSQLOrderBy(queryDef, resultStruct) {
|
|
741
755
|
let s = '';
|
|
756
|
+
// Collect array joins for dialects that need explicit ordering.
|
|
757
|
+
// Only for project queries - reduce queries aggregate rows so individual
|
|
758
|
+
// row order doesn't matter, and we can't ORDER BY columns not in GROUP BY.
|
|
759
|
+
let arrayJoins = [];
|
|
760
|
+
if (this.parent.dialect.requiresExplicitUnnestOrdering &&
|
|
761
|
+
this.firstSegment.type === 'project') {
|
|
762
|
+
const [[, rootJoin]] = this.rootResult.joins;
|
|
763
|
+
arrayJoins = this.collectArrayJoins(rootJoin);
|
|
764
|
+
}
|
|
742
765
|
if (this.firstSegment.type === 'project' && !queryDef.orderBy) {
|
|
743
|
-
|
|
766
|
+
// For project without explicit ordering, we still need array ordinality
|
|
767
|
+
// ordering if the dialect requires it
|
|
768
|
+
if (arrayJoins.length === 0) {
|
|
769
|
+
return ''; // No default ordering for project.
|
|
770
|
+
}
|
|
744
771
|
}
|
|
745
772
|
// Intermediate results (in a pipeline or join) that have no limit, don't need an orderby
|
|
746
773
|
// Some database don't have this optimization.
|
|
@@ -795,6 +822,10 @@ class QueryQuery extends query_node_1.QueryField {
|
|
|
795
822
|
}
|
|
796
823
|
}
|
|
797
824
|
}
|
|
825
|
+
// Add array ordinality ordering for dialects that require it
|
|
826
|
+
for (const aj of arrayJoins) {
|
|
827
|
+
o.push(`${aj.alias}_outer.__row_id ASC`);
|
|
828
|
+
}
|
|
798
829
|
if (o.length > 0) {
|
|
799
830
|
s = this.parent.dialect.sqlOrderBy(o, 'query') + '\n';
|
|
800
831
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.332";
|
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.332';
|
|
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.332",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"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"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@malloydata/malloy-filter": "0.0.
|
|
49
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
50
|
-
"@malloydata/malloy-tag": "0.0.
|
|
48
|
+
"@malloydata/malloy-filter": "0.0.332",
|
|
49
|
+
"@malloydata/malloy-interfaces": "0.0.332",
|
|
50
|
+
"@malloydata/malloy-tag": "0.0.332",
|
|
51
51
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
52
52
|
"assert": "^2.0.0",
|
|
53
53
|
"jaro-winkler": "^0.2.8",
|