@malloydata/malloy 0.0.110 → 0.0.111-dev231204165238
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/lang/ast/query-properties/joins.d.ts +2 -0
- package/dist/lang/ast/query-properties/joins.js +12 -1
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +103 -99
- package/dist/lang/lib/Malloy/MalloyLexer.js +1164 -1142
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +186 -167
- package/dist/lang/lib/Malloy/MalloyParser.js +1792 -1685
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +11 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +7 -0
- package/dist/lang/malloy-to-ast.js +8 -0
- package/dist/lang/test/field-symbols.spec.js +1 -0
- package/dist/lang/test/test-translator.js +1 -0
- package/dist/model/malloy_query.d.ts +1 -0
- package/dist/model/malloy_query.js +20 -3
- package/dist/model/malloy_types.d.ts +3 -0
- package/dist/model/malloy_types.js +6 -2
- package/package.json +1 -1
|
@@ -137,6 +137,7 @@ import { QueryExtendStatementContext } from "./MalloyParser";
|
|
|
137
137
|
import { QueryExtendStatementListContext } from "./MalloyParser";
|
|
138
138
|
import { JoinListContext } from "./MalloyParser";
|
|
139
139
|
import { IsExploreContext } from "./MalloyParser";
|
|
140
|
+
import { MatrixOperationContext } from "./MalloyParser";
|
|
140
141
|
import { JoinDefContext } from "./MalloyParser";
|
|
141
142
|
import { JoinExpressionContext } from "./MalloyParser";
|
|
142
143
|
import { FilterStatementContext } from "./MalloyParser";
|
|
@@ -1742,6 +1743,16 @@ export interface MalloyParserListener extends ParseTreeListener {
|
|
|
1742
1743
|
* @param ctx the parse tree
|
|
1743
1744
|
*/
|
|
1744
1745
|
exitIsExplore?: (ctx: IsExploreContext) => void;
|
|
1746
|
+
/**
|
|
1747
|
+
* Enter a parse tree produced by `MalloyParser.matrixOperation`.
|
|
1748
|
+
* @param ctx the parse tree
|
|
1749
|
+
*/
|
|
1750
|
+
enterMatrixOperation?: (ctx: MatrixOperationContext) => void;
|
|
1751
|
+
/**
|
|
1752
|
+
* Exit a parse tree produced by `MalloyParser.matrixOperation`.
|
|
1753
|
+
* @param ctx the parse tree
|
|
1754
|
+
*/
|
|
1755
|
+
exitMatrixOperation?: (ctx: MatrixOperationContext) => void;
|
|
1745
1756
|
/**
|
|
1746
1757
|
* Enter a parse tree produced by `MalloyParser.joinDef`.
|
|
1747
1758
|
* @param ctx the parse tree
|
|
@@ -137,6 +137,7 @@ import { QueryExtendStatementContext } from "./MalloyParser";
|
|
|
137
137
|
import { QueryExtendStatementListContext } from "./MalloyParser";
|
|
138
138
|
import { JoinListContext } from "./MalloyParser";
|
|
139
139
|
import { IsExploreContext } from "./MalloyParser";
|
|
140
|
+
import { MatrixOperationContext } from "./MalloyParser";
|
|
140
141
|
import { JoinDefContext } from "./MalloyParser";
|
|
141
142
|
import { JoinExpressionContext } from "./MalloyParser";
|
|
142
143
|
import { FilterStatementContext } from "./MalloyParser";
|
|
@@ -1117,6 +1118,12 @@ export interface MalloyParserVisitor<Result> extends ParseTreeVisitor<Result> {
|
|
|
1117
1118
|
* @return the visitor result
|
|
1118
1119
|
*/
|
|
1119
1120
|
visitIsExplore?: (ctx: IsExploreContext) => Result;
|
|
1121
|
+
/**
|
|
1122
|
+
* Visit a parse tree produced by `MalloyParser.matrixOperation`.
|
|
1123
|
+
* @param ctx the parse tree
|
|
1124
|
+
* @return the visitor result
|
|
1125
|
+
*/
|
|
1126
|
+
visitMatrixOperation?: (ctx: MatrixOperationContext) => Result;
|
|
1120
1127
|
/**
|
|
1121
1128
|
* Visit a parse tree produced by `MalloyParser.joinDef`.
|
|
1122
1129
|
* @param ctx the parse tree
|
|
@@ -432,10 +432,18 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
|
432
432
|
return result;
|
|
433
433
|
}
|
|
434
434
|
visitJoinOn(pcx) {
|
|
435
|
+
var _a;
|
|
435
436
|
const joinAs = this.getModelEntryName(pcx.joinNameDef());
|
|
436
437
|
const { joinFrom, notes } = this.getJoinSource(joinAs, pcx.isExplore());
|
|
437
438
|
const join = new ast.ExpressionJoin(joinAs, joinFrom);
|
|
438
439
|
const onCx = pcx.joinExpression();
|
|
440
|
+
const mop = ((_a = pcx.matrixOperation()) === null || _a === void 0 ? void 0 : _a.text.toLocaleLowerCase()) || 'left';
|
|
441
|
+
if ((0, malloy_types_1.isMatrixOperation)(mop)) {
|
|
442
|
+
join.matrixOperation = mop;
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
this.contextError(pcx, 'Internal Error: Unknown matrixOperation');
|
|
446
|
+
}
|
|
439
447
|
if (onCx) {
|
|
440
448
|
join.joinOn = this.getFieldExpr(onCx);
|
|
441
449
|
}
|
|
@@ -195,6 +195,7 @@ declare class JoinInstance {
|
|
|
195
195
|
children: JoinInstance[];
|
|
196
196
|
constructor(queryStruct: QueryStruct, alias: string, parent: JoinInstance | undefined);
|
|
197
197
|
parentRelationship(): 'root' | JoinRelationship;
|
|
198
|
+
forceAllSymmetricCalculations(): boolean;
|
|
198
199
|
getDialectFieldList(): DialectFieldList;
|
|
199
200
|
}
|
|
200
201
|
/** nested query */
|
|
@@ -696,6 +696,7 @@ class QueryFieldStruct extends QueryAtomicField {
|
|
|
696
696
|
...this.parent.fieldDef,
|
|
697
697
|
structRelationship: {
|
|
698
698
|
type: 'one',
|
|
699
|
+
matrixOperation: 'left',
|
|
699
700
|
onExpression: [
|
|
700
701
|
{
|
|
701
702
|
type: 'field',
|
|
@@ -1138,7 +1139,8 @@ class FieldInstanceResultRoot extends FieldInstanceResult {
|
|
|
1138
1139
|
for (const [name, join] of this.joins) {
|
|
1139
1140
|
// first join is by default the
|
|
1140
1141
|
const relationship = join.parentRelationship();
|
|
1141
|
-
if (relationship === 'many_to_many'
|
|
1142
|
+
if (relationship === 'many_to_many' ||
|
|
1143
|
+
join.forceAllSymmetricCalculations()) {
|
|
1142
1144
|
// everything must be calculated with symmetric aggregates
|
|
1143
1145
|
leafiest = '0never';
|
|
1144
1146
|
}
|
|
@@ -1231,6 +1233,20 @@ class JoinInstance {
|
|
|
1231
1233
|
throw new Error(`Internal error unknown relationship type to parent for ${this.queryStruct.fieldDef.name}`);
|
|
1232
1234
|
}
|
|
1233
1235
|
}
|
|
1236
|
+
// For now, we force all symmetric calculations for full and right joins
|
|
1237
|
+
// because we need distinct keys for COUNT(xx) operations. Don't really need
|
|
1238
|
+
// this for sums. This will produce correct results and we can optimize this
|
|
1239
|
+
// at some point..
|
|
1240
|
+
forceAllSymmetricCalculations() {
|
|
1241
|
+
const sr = this.queryStruct.fieldDef.structRelationship;
|
|
1242
|
+
if (this.queryStruct.parent === undefined || !(0, malloy_types_1.isJoinOn)(sr)) {
|
|
1243
|
+
return false;
|
|
1244
|
+
}
|
|
1245
|
+
if (sr.matrixOperation === 'right' || sr.matrixOperation === 'full') {
|
|
1246
|
+
return true;
|
|
1247
|
+
}
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1234
1250
|
// postgres unnest needs to know the names of the physical fields.
|
|
1235
1251
|
getDialectFieldList() {
|
|
1236
1252
|
const dialectFieldList = [];
|
|
@@ -1869,6 +1885,7 @@ class QueryQuery extends QueryField {
|
|
|
1869
1885
|
const structRelationship = qs.fieldDef.structRelationship;
|
|
1870
1886
|
let structSQL = qs.structSourceSQL(stageWriter);
|
|
1871
1887
|
if ((0, malloy_types_1.isJoinOn)(structRelationship)) {
|
|
1888
|
+
const matrixOperation = structRelationship.matrixOperation.toUpperCase();
|
|
1872
1889
|
if (ji.makeUniqueKey) {
|
|
1873
1890
|
const passKeys = this.generateSQLPassthroughKeys(qs);
|
|
1874
1891
|
structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as __distinct_key, x.* ${passKeys} FROM ${structSQL} as x)`;
|
|
@@ -1896,7 +1913,7 @@ class QueryQuery extends QueryField {
|
|
|
1896
1913
|
if (conditions !== undefined && conditions.length >= 1) {
|
|
1897
1914
|
filters = ` AND (${conditions.join(' AND ')})`;
|
|
1898
1915
|
}
|
|
1899
|
-
s += `
|
|
1916
|
+
s += ` ${matrixOperation} JOIN ${structSQL} AS ${ji.alias}\n ON ${onCondition}${filters}\n`;
|
|
1900
1917
|
}
|
|
1901
1918
|
else {
|
|
1902
1919
|
let select = `SELECT ${ji.alias}.*`;
|
|
@@ -1907,7 +1924,7 @@ class QueryQuery extends QueryField {
|
|
|
1907
1924
|
select += `, ${this.parent.dialect.sqlSelectAliasAsStruct(childJoin.alias, physicalFields)} AS ${childJoin.alias}`;
|
|
1908
1925
|
}
|
|
1909
1926
|
select += `\nFROM ${structSQL} AS ${ji.alias}\n${joins}\nWHERE ${conditions === null || conditions === void 0 ? void 0 : conditions.join(' AND ')}\n`;
|
|
1910
|
-
s +=
|
|
1927
|
+
s += `${matrixOperation} JOIN (\n${(0, utils_1.indent)(select)}) AS ${ji.alias}\n ON ${onCondition}\n`;
|
|
1911
1928
|
return s;
|
|
1912
1929
|
}
|
|
1913
1930
|
}
|
|
@@ -459,8 +459,11 @@ export interface TurtleDef extends NamedObject, Pipeline {
|
|
|
459
459
|
annotation?: Annotation;
|
|
460
460
|
}
|
|
461
461
|
export type JoinRelationship = 'one_to_one' | 'one_to_many' | 'many_to_one' | 'many_to_many';
|
|
462
|
+
export type MatrixOperation = 'left' | 'right' | 'full' | 'inner';
|
|
463
|
+
export declare function isMatrixOperation(x: string): x is MatrixOperation;
|
|
462
464
|
export interface JoinOn {
|
|
463
465
|
type: 'one' | 'many' | 'cross';
|
|
466
|
+
matrixOperation: MatrixOperation;
|
|
464
467
|
onExpression?: Expr;
|
|
465
468
|
}
|
|
466
469
|
export declare function isJoinOn(sr: StructRelationship): sr is JoinOn;
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
26
|
-
exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.isMeasureLike = exports.getPhysicalFields = exports.getDimensions = exports.isPhysical = exports.isDimensional = exports.isAtomicField = exports.isTurtleDef = exports.getIdentifier = exports.isFieldStructDef = exports.isFieldTimeBased = exports.isFieldTypeDef = exports.isSQLBlockStruct = exports.mergeEvalSpaces = void 0;
|
|
25
|
+
exports.isJoinOn = exports.isMatrixOperation = exports.isIndexSegment = exports.isSamplingEnable = exports.isSamplingPercent = exports.isSamplingRows = exports.isQuerySegment = exports.isProjectSegment = exports.isPartialSegment = exports.isReduceSegment = exports.refIsStructDef = exports.isByExpression = exports.isByName = exports.ValueType = exports.isExtractUnit = exports.isTimestampUnit = exports.isDateUnit = exports.FieldIsIntrinsic = exports.isCastType = exports.isAtomicFieldType = exports.isTimeFieldType = exports.hasExpression = exports.maxOfExpressionTypes = exports.maxExpressionType = exports.isExpressionTypeLEQ = exports.expressionIsAnalytic = exports.expressionIsCalculation = exports.expressionInvolvesAggregate = exports.expressionIsUngroupedAggregate = exports.expressionIsAggregate = exports.expressionIsScalar = exports.mkExpr = exports.isApplyFragment = exports.isApplyValue = exports.isParameterFragment = exports.isFieldFragment = exports.isSpreadFragment = exports.isSQLExpressionFragment = exports.isFunctionCallFragment = exports.isFunctionParameterFragment = exports.isUngroupFragment = exports.isAsymmetricFragment = exports.isAggregateFragment = exports.isDialectFragment = exports.isFilterFragment = exports.isOutputFieldFragment = exports.isFilteredAliasedName = exports.paramHasValue = exports.isConditionParameter = exports.isValueParameter = void 0;
|
|
26
|
+
exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.isMeasureLike = exports.getPhysicalFields = exports.getDimensions = exports.isPhysical = exports.isDimensional = exports.isAtomicField = exports.isTurtleDef = exports.getIdentifier = exports.isFieldStructDef = exports.isFieldTimeBased = exports.isFieldTypeDef = exports.isSQLBlockStruct = exports.mergeEvalSpaces = exports.isSQLFragment = void 0;
|
|
27
27
|
function isValueParameter(p) {
|
|
28
28
|
return p.value !== undefined;
|
|
29
29
|
}
|
|
@@ -314,6 +314,10 @@ function isIndexSegment(pe) {
|
|
|
314
314
|
return pe.type === 'index';
|
|
315
315
|
}
|
|
316
316
|
exports.isIndexSegment = isIndexSegment;
|
|
317
|
+
function isMatrixOperation(x) {
|
|
318
|
+
return ['left', 'right', 'full', 'inner'].includes(x);
|
|
319
|
+
}
|
|
320
|
+
exports.isMatrixOperation = isMatrixOperation;
|
|
317
321
|
function isJoinOn(sr) {
|
|
318
322
|
return ['one', 'many', 'cross'].includes(sr.type);
|
|
319
323
|
}
|