From 72cf6cc6b0714932fd4bfff2c94a541d11443846 Mon Sep 17 00:00:00 2001 From: Luc Boudreau Date: Tue, 21 Jul 2009 16:23:03 +0000 Subject: [PATCH] Added a function to QueryDimension to allow hierarchization of the included member selections. Also added a regression test to OlapTest. git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@271 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- src/org/olap4j/query/Olap4jNodeConverter.java | 36 +++++++++- src/org/olap4j/query/QueryDimension.java | 26 +++++++ testsrc/org/olap4j/OlapTest.java | 68 +++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/org/olap4j/query/Olap4jNodeConverter.java b/src/org/olap4j/query/Olap4jNodeConverter.java index b27038c..8ace0d0 100644 --- a/src/org/olap4j/query/Olap4jNodeConverter.java +++ b/src/org/olap4j/query/Olap4jNodeConverter.java @@ -212,7 +212,41 @@ private static List toOlap4j(QueryDimension dimension) { } else { listWithExclusions.addAll(orderedList); } - return listWithExclusions; + + // Do we need to wrap it all in a Hierarchize function? + List listWithHierarchy = + new ArrayList(); + if (dimension.getHierarchizeMode() != null) { + CallNode hierarchyNode; + // There are two modes available, PRE and POST. + if (dimension.getHierarchizeMode().equals( + QueryDimension.HierarchizeMode.PRE)) + { + // In pre mode, we don't add the "POST" literal. + hierarchyNode = new CallNode( + null, + "Hierarchize", + Syntax.Function, + generateListSetCall(listWithExclusions)); + } else if (dimension.getHierarchizeMode().equals( + QueryDimension.HierarchizeMode.POST)) + { + hierarchyNode = new CallNode( + null, + "Hierarchize", + Syntax.Function, + generateListSetCall(listWithExclusions), + LiteralNode.createSymbol( + null, dimension.getHierarchizeMode().name())); + } else { + throw new RuntimeException("Missing value handler."); + } + listWithHierarchy.add(hierarchyNode); + } else { + listWithHierarchy.addAll(listWithExclusions); + } + + return listWithHierarchy; } private static ParseTreeNode toOlap4j(Selection selection) { diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java index d57ccaa..a03d8b0 100644 --- a/src/org/olap4j/query/QueryDimension.java +++ b/src/org/olap4j/query/QueryDimension.java @@ -42,6 +42,7 @@ public class QueryDimension extends QueryNodeImpl { private final Query query; protected Dimension dimension; private SortOrder sortOrder = null; + private HierarchizeMode hierarchizeMode = null; public QueryDimension(Query query, Dimension dimension) { super(); @@ -314,6 +315,20 @@ public SortOrder getSortOrder() { return this.sortOrder; } + public HierarchizeMode getHierarchizeMode() { + return hierarchizeMode; + } + + /** + * Triggers the hierarchization of the included members within this + * QueryDimension. + * @param hierarchizeMode Whether or not to include the POST litteral + * inside the Hierarchize() MDX function call. + */ + public void setHierarchizeMode(HierarchizeMode hierarchizeMode) { + this.hierarchizeMode = hierarchizeMode; + } + private class SelectionList extends AbstractList { private final List list = new ArrayList(); @@ -353,6 +368,17 @@ public static enum SortOrder { DESC } + public static enum HierarchizeMode { + /** + * Parents are placed before children. + */ + PRE, + /** + * Parents are placed after children + */ + POST + } + void tearDown() { for (Selection node : this.inclusions) { ((QueryNodeImpl)node).clearListeners(); diff --git a/testsrc/org/olap4j/OlapTest.java b/testsrc/org/olap4j/OlapTest.java index a0b3096..cebf65c 100644 --- a/testsrc/org/olap4j/OlapTest.java +++ b/testsrc/org/olap4j/OlapTest.java @@ -11,6 +11,7 @@ import org.olap4j.mdx.SelectNode; import org.olap4j.metadata.*; import org.olap4j.query.*; +import org.olap4j.query.QueryDimension.HierarchizeMode; import org.olap4j.query.QueryDimension.SortOrder; import org.olap4j.query.Selection.Operator; import org.olap4j.test.TestContext; @@ -612,6 +613,73 @@ public void testDimensionsOrder() { } } + public void testDimensionsHierarchize() { + try { + Cube cube = getFoodmartCube("Sales"); + if (cube == null) { + fail("Could not find Sales cube"); + } + Query query = new Query("my query", cube); + + // create selections + + QueryDimension productDimension = query.getDimension("Product"); + productDimension.include( + Selection.Operator.CHILDREN, "Product", "Drink"); + + QueryDimension storeDimension = query.getDimension("Store"); + storeDimension.include( + Selection.Operator.INCLUDE_CHILDREN, "Store", "USA"); + storeDimension.setHierarchizeMode(HierarchizeMode.POST); + + QueryDimension timeDimension = query.getDimension("Time"); + + timeDimension.include(Selection.Operator.CHILDREN, "Time", "1997"); + + QueryDimension measuresDimension = query.getDimension("Measures"); + measuresDimension.include("Measures", "Store Sales"); + + + query.getAxis(Axis.ROWS).addDimension(productDimension); + query.getAxis(Axis.ROWS).addDimension(storeDimension); + query.getAxis(Axis.ROWS).addDimension(timeDimension); + query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); + + query.validate(); + + SelectNode mdx = query.getSelect(); + String mdxString = mdx.toString(); + TestContext.assertEqualsVerbose( + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "CrossJoin({[Product].[All Products].[Drink].Children}, " + + "CrossJoin({Hierarchize({{[Store].[All Stores].[USA], " + + "[Store].[All Stores].[USA].Children}}, POST)}, " + + "{[Time].[1997].Children})) ON ROWS\n" + + "FROM [Sales]", + mdxString); + + storeDimension.setHierarchizeMode(HierarchizeMode.PRE); + + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + TestContext.assertEqualsVerbose( + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "CrossJoin({[Product].[All Products].[Drink].Children}, " + + "CrossJoin({Hierarchize({{[Store].[All Stores].[USA], " + + "[Store].[All Stores].[USA].Children}})}, " + + "{[Time].[1997].Children})) ON ROWS\n" + + "FROM [Sales]", + mdxString); + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + /** * This test makes sure that the generated MDX model is not affected * by subsequent operations performed on the source query model.