Screenshot of the sample application showing a filtered query and filter editor. |
So I've decide to change the behavior of some QueryHierarchy's methods when the instance lives in a slicer axis (hierarchy.geAxis().getLocation() == Axis.FILTER):
- include(Member m, Operator op), exclude(Member m, Operator op)Both methods ignore the op argument and assume Operator.DESCENDANTS instead.
- isIncluded(Member m)Returns true if and only if m and all of its descendants are included.
- isExcluded(Member m)
(new)
Returns true if and only if m and all of its descendants are excluded. Equivalente to !isIncluded(m) for instances living in query axes.
- The operator dropdown menu disappears
- The include/exclude buttons are replaced by tri-state checkbox buttons, checked when the member is included, unchecked when it's excluded, or mixed if neither isIncluded(m)
nor isExcluded(m) return true.
MDX Generation for WHERE clause
The package private method toOlap4j in the QueryAxis class delegates in the new toOlap4jFilter() method when generating the MDX expression for a slicer axis. This method generates a cross join of the expressions returned by the olap4jFilter() method for each hierarchy in the axis:private AxisNode toOlap4jFilter() {
CrossJoinBuilder xJoin = new CrossJoinBuilder();
for(QueryHierarchy h : hierarchies) {
xJoin.join(h.toOlap4jFilter());
}
return
new AxisNode(null, false, axis, null, xJoin.getJoinNode());
}
The MDX expression for a silcer QueryHierarchy is computed recursively based on the tree of included/excluded members:
- Simple case: current node has no overriding children.The resulting expression is the MemberNode for the current member if it's included, void expression if it's not included.
- Recursive case: current node has overriding children.
- If the current node is excluded, return the union of the recursive expressions for every overriding children
- If the current node is included, return the union of
- computing the set of non-overriding children as EXCEPT(<currentNode>.CHILDREN, <set of overriding children>)
- computing the union of the recursive expression for every overriding children
- computing the set of non-overriding children as EXCEPT(<currentNode>.CHILDREN, <set of overriding children>)
- If the current node is excluded, return the union of the recursive expressions for every overriding children
private
ParseTreeNode toOlap4jFilter(SelectionTree selectionNode,
Sign defaultSign) {
Sign selectionSign = selectionNode.getStatus().getEffectiveSign(
Operator.DESCENDANTS, defaultSign);
if (!selectionNode.hasOverridingChildren()) {
// Current node has no overriding children, its filter expression is
// the corresponding MemberNode if the member is included, void in
// other case.
if (selectionSign == Sign.INCLUDE)
return Mdx.member(selectionNode.getMember());
else
return
null;
} else {
// Current node has overriding children
UnionBuilder finalExpression = new UnionBuilder();
if (selectionSign == Sign.INCLUDE) {
// Current node is included, so overriding children are excluded
// or have excluded descendants.
UnionBuilder overridingChildren = new UnionBuilder();
for (SelectionTree overriding : selectionNode
.getOverridingChildren()) {
overridingChildren.add(Mdx.member(overriding.getMember()));
finalExpression.add(toOlap4jFilter(overriding,
selectionSign));
}
// Return the set of non overriding children plus recursive
// expression evaluations
finalExpression.add(Mdx.except(
Mdx.children(selectionNode.getMember()),
overridingChildren));
} else {
// Current node is excluded, returns the union of recursive
// evaluation for overriding children.
for (SelectionTree overriding : selectionNode
.getOverridingChildren()) {
finalExpression.add(toOlap4jFilter(overriding,
selectionSign));
}
}
return finalExpression.getUnionNode();
}
}
FilterAxisInfo Composite Faces Component
The component to display the filter axis for the current query hides a standard <h:dataTable> and relays on a managed bean to compute the filter expression to generate the textual description of the filter and adapt the call to remove a hierarchy from the filter axis. This component has the following attributes:- value (instance of AbstractQueryBean)
The query containing the axis to display (used to remove a hierarchy from the axis) - style, styleClass
CSS style and CSS style class to be applied to the component - headerClassCSS style class to be applied to the column showing the hierarchy captions.
- expressionClassCSS style class to be applied to the column showing the filter descriptions.
<h:panelGroup
id="filterAxisInfo"
>
<olap:filterAxisInfo
value="#{queryBean}">
<f:ajax
render=":form:filterAxisInfo :form:table :form:hierarchyEditor"/>
</olap:filterAxisInfo>
</h:panelGroup>
It uses default style classes and uses the client event to re-render itself, the result set table and the query hierarchy editor after filter hierarchy removal.