From 633ca0a55cc662d1a3f1754d4d1c4c79c2644bc3 Mon Sep 17 00:00:00 2001 From: Paul Stoellberger Date: Thu, 3 Feb 2011 22:32:06 +0000 Subject: [PATCH] Fix Bug 2850060 (QueryModel needs to perform selections on levels) git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@400 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- src/org/olap4j/query/LevelSelectionImpl.java | 183 ++++++++++++++++++ ...tionImpl.java => MemberSelectionImpl.java} | 10 +- src/org/olap4j/query/Olap4jNodeConverter.java | 35 +++- src/org/olap4j/query/QueryDimension.java | 43 ++++ src/org/olap4j/query/Selection.java | 4 + src/org/olap4j/query/SelectionFactory.java | 15 +- testsrc/org/olap4j/OlapTest.java | 17 ++ 7 files changed, 300 insertions(+), 7 deletions(-) create mode 100644 src/org/olap4j/query/LevelSelectionImpl.java rename src/org/olap4j/query/{SelectionImpl.java => MemberSelectionImpl.java} (94%) diff --git a/src/org/olap4j/query/LevelSelectionImpl.java b/src/org/olap4j/query/LevelSelectionImpl.java new file mode 100644 index 0000000..b4f3bf1 --- /dev/null +++ b/src/org/olap4j/query/LevelSelectionImpl.java @@ -0,0 +1,183 @@ +/* +// $Id: LevelSelectionImpl.java 399 2011-02-03 20:53:50Z pstoellberger $ +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// Copyright (C) 2007-2010 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. + */ +package org.olap4j.query; + +import java.util.ArrayList; +import java.util.List; + +import org.olap4j.metadata.Dimension; +import org.olap4j.metadata.Level; +import org.olap4j.metadata.Member; + +/** + * Abstract implementation of {@link Selection}. + * + * @author pstoellberger + * @version $Id: LevelSelectionImpl.java 399 2011-02-03 20:53:50Z pstoellberger $ + * @since Feb 3, 2011 + */ +class LevelSelectionImpl extends QueryNodeImpl implements Selection { + + protected Level level; + protected String dimensionName; + protected String hierarchyName; + protected String levelName; + protected Dimension dimension; + protected Operator operator = Operator.MEMBER; + protected List selectionContext; + + /** + * Creates a SelectionImpl. + * + * @pre operator != null + */ + public LevelSelectionImpl( + Level level, + Dimension dimension, + String hierarchyName, + String levelName, + Operator operator) + { + super(); + this.level = level; + this.dimension = dimension; + this.hierarchyName = hierarchyName; + this.levelName = levelName; + this.operator = operator; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((level == null) ? 0 : level.getUniqueName().hashCode()); + result = prime * result + + ((operator == null) ? 0 : operator.hashCode()); + result = prime * result + + ((selectionContext == null) ? 0 : selectionContext.hashCode()); + return result; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof LevelSelectionImpl)) { + return false; + } + LevelSelectionImpl other = (LevelSelectionImpl) obj; + if (level == null) { + if (other.level != null) { + return false; + } + } else if (!level.getUniqueName().equals( + other.level.getUniqueName())) + { + return false; + } + if (operator == null) { + if (other.operator != null) { + return false; + } + } else if (!operator.equals(other.operator)) { + return false; + } + if (selectionContext == null) { + if (other.selectionContext != null) { + return false; + } + } else if (!selectionContext.equals(other.selectionContext)) { + return false; + } + return true; + } + + public String getName() { + return levelName; + } + + public void setName(String name) { + levelName = name; + } + + public Dimension getDimension() { + return dimension; + } + + public void setDimension(Dimension dimension) { + this.dimension = dimension; + } + + public Level getLevel() { + return level; + } + + public String getDimensionName() { + return dimensionName; + } + + public void setDimensionName(String dimensionName) { + this.dimensionName = dimensionName; + } + + public String getHierarchyName() { + return hierarchyName; + } + + public void setHierarchyName(String hierarchyName) { + this.hierarchyName = hierarchyName; + } + + public String getLevelName() { + return levelName; + } + + public void setLevelName(String levelName) { + this.levelName = levelName; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + assert operator != null; + this.operator = operator; + notifyChange(this,-1); + } + + void tearDown() { + } + + public List getSelectionContext() { + return selectionContext; + } + + public void addContext(Selection selection) { + if (selectionContext == null) { + selectionContext = new ArrayList(); + } + selectionContext.add(selection); + } + + public void removeContext(Selection selection) { + selectionContext.remove(selection); + } + + public Member getMember() { + // there is no member in this type of Selections + return null; + } +} + +// End LevelSelectionImpl.java diff --git a/src/org/olap4j/query/SelectionImpl.java b/src/org/olap4j/query/MemberSelectionImpl.java similarity index 94% rename from src/org/olap4j/query/SelectionImpl.java rename to src/org/olap4j/query/MemberSelectionImpl.java index 91693ad..e98927f 100644 --- a/src/org/olap4j/query/SelectionImpl.java +++ b/src/org/olap4j/query/MemberSelectionImpl.java @@ -22,7 +22,7 @@ * @version $Id$ * @since May 30, 2007 */ -class SelectionImpl extends QueryNodeImpl implements Selection { +class MemberSelectionImpl extends QueryNodeImpl implements Selection { protected Member member; protected String dimensionName; @@ -38,7 +38,7 @@ class SelectionImpl extends QueryNodeImpl implements Selection { * * @pre operator != null */ - public SelectionImpl( + public MemberSelectionImpl( Member member, Dimension dimension, String hierarchyName, @@ -74,10 +74,10 @@ public boolean equals(Object obj) { if (obj == null) { return false; } - if (!(obj instanceof SelectionImpl)) { + if (!(obj instanceof MemberSelectionImpl)) { return false; } - SelectionImpl other = (SelectionImpl) obj; + MemberSelectionImpl other = (MemberSelectionImpl) obj; if (member == null) { if (other.member != null) { return false; @@ -177,4 +177,4 @@ public void removeContext(Selection selection) { } } -// End SelectionImpl.java +// End MemberSelectionImpl.java diff --git a/src/org/olap4j/query/Olap4jNodeConverter.java b/src/org/olap4j/query/Olap4jNodeConverter.java index d20a057..6b127cd 100644 --- a/src/org/olap4j/query/Olap4jNodeConverter.java +++ b/src/org/olap4j/query/Olap4jNodeConverter.java @@ -19,11 +19,13 @@ import org.olap4j.mdx.CubeNode; import org.olap4j.mdx.DimensionNode; import org.olap4j.mdx.IdentifierNode; +import org.olap4j.mdx.LevelNode; import org.olap4j.mdx.LiteralNode; import org.olap4j.mdx.MemberNode; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.mdx.SelectNode; import org.olap4j.mdx.Syntax; +import org.olap4j.metadata.Level; import org.olap4j.metadata.Member; /** @@ -405,7 +407,14 @@ private static List toOlap4j(QueryDimension dimension) { private static ParseTreeNode toOlap4j(Selection selection) { try { - return toOlap4j(selection.getMember(), selection.getOperator()); + if (selection instanceof MemberSelectionImpl) { + return toOlap4j(selection.getMember(), selection.getOperator()); + } + if (selection instanceof LevelSelectionImpl) { + return toOlap4j( + ((LevelSelectionImpl) selection).getLevel(), + selection.getOperator()); + } } catch (Exception e) { e.printStackTrace(); } @@ -469,6 +478,30 @@ private static ParseTreeNode toOlap4j( return node; } + private static ParseTreeNode toOlap4j( + Level level, + Selection.Operator oper) + { + ParseTreeNode node = null; + try { + switch (oper) { + case MEMBERS: + node = + new CallNode( + null, + "Members", + Syntax.Property, + new LevelNode(null, level)); + break; + default: + System.out.println("NOT IMPLEMENTED: " + oper); + } + } catch (Exception e) { + e.printStackTrace(); + } + return node; + } + private static List toOlap4j(List axes) { final ArrayList axisList = new ArrayList(); for (QueryAxis axis : axes) { diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java index 2d5b811..0349fe2 100644 --- a/src/org/olap4j/query/QueryDimension.java +++ b/src/org/olap4j/query/QueryDimension.java @@ -145,6 +145,19 @@ public Selection createSelection(Member member) { return createSelection(Selection.Operator.MEMBER, member); } + /** + * Selects a level and includes it in the query. + *

This method selects and includes a all members of the given + * query using the {@link Selection.Operator#MEMBERS} selection operator. + * @param member The member to select and include in the query. + */ + public void include(Level level) { + if (level.getDimension().equals(this.dimension)) { + Selection selection = + query.getSelectionFactory().createLevelSelection(level); + this.include(selection); + } + } /** * Selects members and includes them in the query. *

This method selects and includes a member along with it's @@ -167,6 +180,22 @@ public Selection createSelection( return null; } + /** + * Selects level and includes all members in the query. + *

This method selects and includes all members of a + * given Level, using the MEMBERS operator {@link Selection.Operator} + * @param member Root member to select and include. + */ + public Selection createSelection(Level level) + { + if (level.getDimension().equals(this.dimension)) { + Selection selection = + query.getSelectionFactory().createLevelSelection(level); + return selection; + } + return null; + } + /** * Selects members and includes them in the query. *

This method selects and includes a member along with it's @@ -260,6 +289,20 @@ public void exclude( rootMember); } + /** + * Selects level members and excludes them from the query. + *

This method selects and excludes members of a level with the + * {@link Selection.Operator#MEMBERS} selection operator. + * @param level The level to select and exclude from the query. + */ + public void exclude(Level level) { + if (level.getDimension().equals(this.dimension)) { + Selection selection = + query.getSelectionFactory().createLevelSelection(level); + this.exclude(selection); + } + } + /** * Selects members and excludes them from the query. *

This method selects and excludes a single member with the diff --git a/src/org/olap4j/query/Selection.java b/src/org/olap4j/query/Selection.java index 3331b36..00f127c 100644 --- a/src/org/olap4j/query/Selection.java +++ b/src/org/olap4j/query/Selection.java @@ -74,6 +74,10 @@ public enum Operator { * Only the root member will be selected. */ MEMBER, + /** + * All members of Level will be selected (LevelSelection only) + */ + MEMBERS, /** * Only the children of the root member will be selected. * This excludes the root member itself. diff --git a/src/org/olap4j/query/SelectionFactory.java b/src/org/olap4j/query/SelectionFactory.java index f8a2f58..8376bcc 100644 --- a/src/org/olap4j/query/SelectionFactory.java +++ b/src/org/olap4j/query/SelectionFactory.java @@ -9,6 +9,7 @@ */ package org.olap4j.query; +import org.olap4j.metadata.Level; import org.olap4j.metadata.Member; /** @@ -27,7 +28,7 @@ Selection createMemberSelection( Selection.Operator operator) { return - new SelectionImpl( + new MemberSelectionImpl( member, member.getDimension(), member.getHierarchy().getUniqueName(), @@ -35,6 +36,18 @@ Selection createMemberSelection( member.getUniqueName(), operator); } + + Selection createLevelSelection( + Level level) + { + return + new LevelSelectionImpl( + level, + level.getDimension(), + level.getHierarchy().getUniqueName(), + level.getUniqueName(), + Selection.Operator.MEMBERS); + } } // End SelectionFactory.java diff --git a/testsrc/org/olap4j/OlapTest.java b/testsrc/org/olap4j/OlapTest.java index 1735339..3f21479 100644 --- a/testsrc/org/olap4j/OlapTest.java +++ b/testsrc/org/olap4j/OlapTest.java @@ -290,6 +290,23 @@ public void testSelectionModes() { + "{[Product].[Drink].Siblings} ON ROWS\n" + "FROM [Sales]", mdxString); + + // TEST LEVEL MEMBERS SELECTION + + NamedList productLevels = + productDimension.getDimension().getDefaultHierarchy().getLevels(); + + Level productDepartments = productLevels.get("Product Department"); + productDimension.include(productDepartments); + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + TestContext.assertEqualsVerbose( + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{[Product].[Drink].Siblings, [Product].[Product Department].Members} ON ROWS\n" + + "FROM [Sales]", mdxString); } catch (Exception e) { e.printStackTrace(); fail();