-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(schema-compiler): Handle measures with dimension-only member expressions #9335
Conversation
8c331af
to
8f73be2
Compare
@@ -1709,7 +1716,64 @@ export class BaseQuery { | |||
const cubeName = m.expressionCubeName ? `\`${m.expressionCubeName}\` ` : ''; | |||
throw new UserError(`The query contains \`COUNT(*)\` expression but cube/view ${cubeName}is missing \`count\` measure`); | |||
} | |||
return [typeof m.measure === 'string' ? m.measure : `${m.measure.cubeName}.${m.measure.name}`, collectedMeasures]; | |||
if (collectedMeasures.length === 0 && m.isMemberExpression) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should put this part related to the member expression over dimension into a separate function and just call it here? There is a lot of code inside the lambda function - it's quite hard to read.
const nonViewMembers = memberNamesForMeasure | ||
.filter(mem => { | ||
const cubeName = this.cubeEvaluator.parsePathAnyType(mem)[0]; | ||
const cubeDef = this.cubeEvaluator.getCubeDefinition(cubeName); | ||
return !cubeDef.isView; | ||
}) | ||
.map(m => this.memberInstanceByPath(m)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be better to use ownedByCube
here?
Something like
const nonViewMembers = memberNamesForMeasure
.map(m => this.memberInstanceByPath(m))
.filter(mem => {
return mem.definition().ownedByCube;
});
20a456f
to
695b941
Compare
…sage in checkShouldBuildJoinForMeasureSelect
…essions in fullKeyQueryAggregateMeasures `fullKeyQueryAggregate` is using measure.cube() a lot, like for grouping measures to key cube This can be wrong for measure targeting view: we want to attach measure to subquery for its definition cube, and there should be no subquery for view itself It's expected that `fullKeyQueryAggregateMeasures` would resolve and prepare all measures from its original form in query to actual leaf measures in cubes, then build subqueries with those, and then `joinFullKeyQueryAggregate` would use `renderedReference` to point to these leaf measures Hard case is a measure that: * targeting view * is a member expression * references only dimensions from that view Measure like that are "leaf" - there's nowhere to push it, member expression has to be directly in leaf subquery If measure references dimension from a single cube it can be multiplied (think `SUM(${view.deep_dimension})`) So, three points: * it must be accounted for in `multipliedMeasures` * it must be attached to a proper cube subquery * it must use renderedReference correctly `collectRootMeasureToHieararchy` will not drop such measure completely. Now it will check is there's 0 measures collected, try to collect all referenced members to gather used cubes and detect multiplication, and add new measure in hierarchy. Because new returned measure is patched, it will be attached to correct cube subquery in `fullKeyQueryAggregate` Then `outerMeasuresJoinFullKeyQueryAggregate` needs to generate proper alias for it, so outer unpatched measure would pick up alias from inner patched one
695b941
to
7893f39
Compare
Check List
Description of Changes Made (if issue reference is not provided)
fullKeyQueryAggregate
is using measure.cube() a lot, like for grouping measures to key cubeThis can be wrong for measure targeting view: we want to attach measure to subquery
for its definition cube, and there should be no subquery for view itself
It's expected that
fullKeyQueryAggregateMeasures
would resolve and prepare all measures from its original form in query to actual leaf measures in cubes, then build subqueries with those, and thenjoinFullKeyQueryAggregate
would userenderedReference
to point to these leaf measuresHard case is a measure that:
Measure like that are "leaf" - there's nowhere to push it, member expression has to be directly in leaf subquery
If measure references dimension from a single cube it can be multiplied (think
SUM(${view.deep_dimension})
)So, three points:
multipliedMeasures
collectRootMeasureToHieararchy
will not drop such measure completely. Now it will check is there's 0 measures collected, try to collect all referenced members to gather used cubes and detect multiplication, and add new measure in hierarchy.Because new returned measure is patched, it will be attached to correct cube subquery in
fullKeyQueryAggregate
Then
outerMeasuresJoinFullKeyQueryAggregate
needs to generate proper alias for it, so outer unpatched measure would pick up alias from inner patched oneFinally,
checkShouldBuildJoinForMeasureSelect
has to be adjusted: it collected cube names and join hints, and for dimensions-only measures on views it would collect too many, and decide that measure is multiplied, when it should not. So now it first collects non-view members, and then collect cubes and join hints from those.