diff --git a/src/org/olap4j/Axis.java b/src/org/olap4j/Axis.java index 3fbc689..9561085 100644 --- a/src/org/olap4j/Axis.java +++ b/src/org/olap4j/Axis.java @@ -26,18 +26,6 @@ */ public interface Axis { - /** - * @deprecated Will be removed before olap4j 1.0. - */ - // REVIEW: Is it wise to remove this axis enum value? - // It's existence IS relevant. - Standard UNUSED = null; - - /** - * @deprecated Will be removed before olap4j 1.0. - */ - Standard NONE = null; - /** * Abbreviation for {@link org.olap4j.Axis.Standard#FILTER}. */ diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java index c864504..b0956e9 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java @@ -10,7 +10,7 @@ import org.olap4j.OlapException; import org.olap4j.impl.*; -import org.olap4j.mdx.IdentifierNode; +import org.olap4j.mdx.*; import org.olap4j.metadata.*; import java.util.*; @@ -154,27 +154,12 @@ public Collection getSupportedLocales() { return Collections.singletonList(Locale.getDefault()); } - public Member lookupMember(String... nameParts) throws OlapException { - List segmentList = - new ArrayList(); - for (String namePart : nameParts) { - segmentList.add(new IdentifierNode.NameSegment(namePart)); - } - return lookupMember(segmentList); - } - - /** - * Finds a member, given its fully qualfieid name. - * - * @param segmentList List of the segments of the name - * @return Member, or null if not found - * @throws OlapException on error - */ - private Member lookupMember( - List segmentList) throws OlapException + public Member lookupMember( + List segmentList) + throws OlapException { StringBuilder buf = new StringBuilder(); - for (IdentifierNode.Segment segment : segmentList) { + for (IdentifierSegment segment : segmentList) { if (buf.length() > 0) { buf.append('.'); } @@ -197,14 +182,14 @@ MetadataReader getMetadataReader() { public List lookupMembers( Set treeOps, - String... nameParts) throws OlapException + List nameParts) throws OlapException { StringBuilder buf = new StringBuilder(); - for (String namePart : nameParts) { + for (IdentifierSegment namePart : nameParts) { if (buf.length() > 0) { buf.append('.'); } - buf.append(new IdentifierNode.NameSegment(namePart)); + buf.append(namePart); } final String uniqueName = buf.toString(); final List list = diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java index 094f07a..82e1dd0 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java @@ -313,17 +313,6 @@ public enum Property { Olap4jUtil.discard(description); } } - - /** - * This is a mock subclass to prevent retro-compatibility issues. - * If you're using this class, please change your code to - * use XmlaOlap4jProxy instead. - * @author Luc Boudreau - * - */ - @Deprecated - public static interface Proxy extends XmlaOlap4jProxy { - } } // End XmlaOlap4jDriver.java diff --git a/src/org/olap4j/impl/IdentifierParser.java b/src/org/olap4j/impl/IdentifierParser.java index 94aa395..25aa5ba 100644 --- a/src/org/olap4j/impl/IdentifierParser.java +++ b/src/org/olap4j/impl/IdentifierParser.java @@ -8,8 +8,7 @@ */ package org.olap4j.impl; -import org.olap4j.mdx.IdentifierNode; -import org.olap4j.mdx.ParseRegion; +import org.olap4j.mdx.*; import java.util.*; @@ -211,7 +210,7 @@ public static int parseMember( builder.segmentComplete( null, string.substring(start, i).trim(), - IdentifierNode.Quoting.UNQUOTED, + Quoting.UNQUOTED, syntax); state = AFTER_SEG; break loop; @@ -219,7 +218,7 @@ public static int parseMember( builder.segmentComplete( null, string.substring(start, i).trim(), - IdentifierNode.Quoting.UNQUOTED, + Quoting.UNQUOTED, syntax); syntax = Builder.Syntax.NAME; state = BEFORE_SEG; @@ -229,7 +228,7 @@ public static int parseMember( builder.segmentComplete( null, string.substring(start, i).trim(), - IdentifierNode.Quoting.UNQUOTED, + Quoting.UNQUOTED, syntax); syntax = Builder.Syntax.NEXT_KEY; state = BEFORE_SEG; @@ -254,7 +253,7 @@ public static int parseMember( null, Olap4jUtil.replace( string.substring(start, i), "]]", "]"), - IdentifierNode.Quoting.QUOTED, + Quoting.QUOTED, syntax); ++i; state = AFTER_SEG; @@ -332,7 +331,7 @@ private static IllegalArgumentException fail( * @param s MDX identifier * @return List of segments */ - public static List parseIdentifier(String s) { + public static List parseIdentifier(String s) { final MemberBuilder builder = new MemberBuilder(); int i = parseMember(builder, s, 0); if (i < s.length()) { @@ -357,7 +356,7 @@ public static List parseIdentifier(String s) { * @param s MDX identifier list * @return List of lists of segments */ - public static List> parseIdentifierList( + public static List> parseIdentifierList( String s) { final MemberListBuilder builder = new MemberListBuilder(); @@ -400,7 +399,7 @@ public interface Builder { void segmentComplete( ParseRegion region, String name, - IdentifierNode.Quoting quoting, + Quoting quoting, Syntax syntax); enum Syntax { @@ -416,12 +415,12 @@ enum Syntax { * It cannot handle tuples or lists of members. */ public static class MemberBuilder implements Builder { - protected final List subSegments; - protected final List segmentList; + protected final List subSegments; + protected final List segmentList; public MemberBuilder() { - segmentList = new ArrayList(); - subSegments = new ArrayList(); + segmentList = new ArrayList(); + subSegments = new ArrayList(); } public void tupleComplete() { @@ -434,7 +433,7 @@ public void memberComplete() { private void flushSubSegments() { if (!subSegments.isEmpty()) { - segmentList.add(new IdentifierNode.KeySegment(subSegments)); + segmentList.add(new KeySegment(subSegments)); subSegments.clear(); } } @@ -442,11 +441,11 @@ private void flushSubSegments() { public void segmentComplete( ParseRegion region, String name, - IdentifierNode.Quoting quoting, + Quoting quoting, Syntax syntax) { - final IdentifierNode.NameSegment segment = - new IdentifierNode.NameSegment( + final NameSegment segment = + new NameSegment( region, name, quoting); if (syntax != Syntax.NEXT_KEY) { // If we were building a previous key, write it out. @@ -467,13 +466,13 @@ public void segmentComplete( * then collects members into lists. */ public static class MemberListBuilder extends MemberBuilder { - final List> list = - new ArrayList>(); + final List> list = + new ArrayList>(); public void memberComplete() { super.memberComplete(); list.add( - new ArrayList(segmentList)); + new ArrayList(segmentList)); segmentList.clear(); } } diff --git a/src/org/olap4j/mdx/DefaultMdxValidatorImpl.java b/src/org/olap4j/mdx/DefaultMdxValidatorImpl.java index 23a607d..dcc0329 100644 --- a/src/org/olap4j/mdx/DefaultMdxValidatorImpl.java +++ b/src/org/olap4j/mdx/DefaultMdxValidatorImpl.java @@ -181,8 +181,8 @@ public ParseTreeNode acceptScalar(ParseTreeNode node) { // from IdentifierNode public ParseTreeNode accept(IdentifierNode identifier) { if (identifier.getSegmentList().size() == 1) { - final IdentifierNode.Segment s = identifier.getSegmentList().get(0); - if (s.getQuoting() == IdentifierNode.Quoting.UNQUOTED + final IdentifierSegment s = identifier.getSegmentList().get(0); + if (s.getQuoting() == Quoting.UNQUOTED && isReserved(s.getName())) { return LiteralNode.createSymbol( @@ -209,7 +209,7 @@ public boolean isReserved(String name) { private ParseTreeNode lookup( SelectNode select, - List segments, + List segments, boolean allowProp) { // todo: something like diff --git a/src/org/olap4j/mdx/IdentifierNode.java b/src/org/olap4j/mdx/IdentifierNode.java index 05844a4..a39f6b2 100644 --- a/src/org/olap4j/mdx/IdentifierNode.java +++ b/src/org/olap4j/mdx/IdentifierNode.java @@ -21,8 +21,8 @@ * *

An identifier is immutable. * - *

An identifer consists of one or more {@link Segment}s. A segment is - * either:

    + *

    An identifer consists of one or more {@link IdentifierSegment}s. A segment + * is either:

      *
    • An unquoted value such as '{@code CA}', *
    • A value quoted in brackets, such as '{@code [San Francisco]}', or *
    • A key of one or more parts, each of which is prefixed with '&', @@ -33,16 +33,16 @@ * *

      A key segment is of type {@link Quoting#KEY}, and has one or more * component parts accessed via the - * {@link Segment#getKeyParts()} method. The parts + * {@link IdentifierSegment#getKeyParts()} method. The parts * are of type {@link Quoting#UNQUOTED} or {@link Quoting#QUOTED}. * *

      A simple example is the identifier {@code Measures.[Unit Sales]}. It * has two segments:

        *
      • Segment #0 is - * {@link org.olap4j.mdx.IdentifierNode.Quoting#UNQUOTED UNQUOTED}, + * {@link Quoting#UNQUOTED UNQUOTED}, * name "Measures"
      • *
      • Segment #1 is - * {@link org.olap4j.mdx.IdentifierNode.Quoting#QUOTED QUOTED}, + * {@link Quoting#QUOTED QUOTED}, * name "Unit Sales"
      • *
      * @@ -52,7 +52,7 @@ *
        *
      • Segment #0 is QUOTED, name "Customers"
      • *
      • Segment #1 is QUOTED, name "City"
      • - *
      • Segment #2 is a {@link org.olap4j.mdx.IdentifierNode.Quoting#KEY KEY}. + *
      • Segment #2 is a {@link Quoting#KEY KEY}. * It has 3 sub-segments: *
          *
        • Sub-segment #0 is QUOTED, name "San Francisco"
        • @@ -73,7 +73,7 @@ public class IdentifierNode implements ParseTreeNode { - private final List segments; + private final List segments; /** * Creates an identifier containing one or more segments. @@ -81,7 +81,7 @@ public class IdentifierNode * @param segments Array of Segments, each consisting of a name and quoting * style */ - public IdentifierNode(IdentifierNode.Segment... segments) { + public IdentifierNode(IdentifierSegment... segments) { if (segments.length < 1) { throw new IllegalArgumentException(); } @@ -93,14 +93,14 @@ public IdentifierNode(IdentifierNode.Segment... segments) { * * @param segments List of segments */ - public IdentifierNode(List segments) { + public IdentifierNode(List segments) { if (segments.size() < 1) { throw new IllegalArgumentException(); } this.segments = - new UnmodifiableArrayList( + new UnmodifiableArrayList( segments.toArray( - new Segment[segments.size()])); + new IdentifierSegment[segments.size()])); } public Type getType() { @@ -113,7 +113,7 @@ public Type getType() { * * @return list of constituent segments */ - public List getSegmentList() { + public List getSegmentList() { return segments; } @@ -129,8 +129,8 @@ public ParseRegion getRegion() { * @param segments List of segments * @return Region encompassed by list of segments */ - private static ParseRegion sumSegmentRegions( - final List segments) + static ParseRegion sumSegmentRegions( + final List segments) { return ParseRegion.sum( new AbstractList() { @@ -151,9 +151,9 @@ public int size() { * @param segment Name of segment * @return New identifier */ - public IdentifierNode append(IdentifierNode.Segment segment) { - List newSegments = - new ArrayList(segments); + public IdentifierNode append(IdentifierSegment segment) { + List newSegments = + new ArrayList(segments); newSegments.add(segment); return new IdentifierNode(newSegments); } @@ -179,7 +179,7 @@ public IdentifierNode deepCopy() { * Parses an MDX identifier string into an * {@link org.olap4j.mdx.IdentifierNode}. * - *

          It contains a list of {@link IdentifierNode.Segment segments}, each + *

          It contains a list of {@link IdentifierSegment segments}, each * of which is a name combined with a description of how the name * was {@link Quoting quoted}. For example, * @@ -191,14 +191,14 @@ public IdentifierNode deepCopy() { * returns an IdentifierNode consisting of the following segments: * *

            - *
          • Segment("Customers", QUOTED), - *
          • Segment("USA", UNQUOTED), - *
          • Segment("South Dakota", QUOTED), - *
          • Segment("Sioux Falls", QUOTED), - *
          • Segment("1245", KEY) + *
          • NameSegment("Customers", quoted=true), + *
          • NameSegment("USA", quoted=false), + *
          • NameSegment("South Dakota", quoted=true), + *
          • NameSegment("Sioux Falls", quoted=true), + *
          • KeySegment( { NameSegment("1245", quoted=true) } ) *
          * - * @see org.olap4j.metadata.Cube#lookupMember(String...) + * @see #ofNames(String...) * * @param identifier MDX identifier string * @@ -211,6 +211,39 @@ public static IdentifierNode parseIdentifier(String identifier) { return new IdentifierNode(IdentifierParser.parseIdentifier(identifier)); } + /** + * Converts an array of quoted name segments into an identifier. + * + *

          For example, + * + *

          + * IdentifierNode.ofNames("Store", "USA", "CA")
          + * + * returns an IdentifierNode consisting of the following segments: + * + *
            + *
          • NameSegment("Customers", quoted=true), + *
          • NameSegment("USA", quoted=false), + *
          • NameSegment("South Dakota", quoted=true), + *
          • NameSegment("Sioux Falls", quoted=true), + *
          • KeySegment( { NameSegment("1245", quoted=true) } ) + *
          + * + * @see #parseIdentifier(String) + * + * @param names Array of names + * + * @return Identifier parse tree node + */ + public static IdentifierNode ofNames(String... names) { + final List list = + new ArrayList(); + for (String name : names) { + list.add(new NameSegment(null, name, Quoting.QUOTED)); + } + return new IdentifierNode(list); + } + /** * Returns string quoted in [...]. * @@ -251,10 +284,12 @@ static void quoteMdxIdentifier(String id, StringBuilder buf) { * @param segments List of segments * @return Segments as quoted string */ - static String unparseIdentifierList(List segments) { + static String unparseIdentifierList( + List segments) + { final StringBuilder buf = new StringBuilder(64); for (int i = 0; i < segments.size(); i++) { - Segment segment = segments.get(i); + IdentifierSegment segment = segments.get(i); if (i > 0) { buf.append('.'); } @@ -262,258 +297,6 @@ static String unparseIdentifierList(List segments) { } return buf.toString(); } - - /** - * Component in a compound identifier. It is described by its name and how - * the name is quoted. - * - *

          For example, the identifier - * [Store].USA.[New Mexico].&[45] has four segments:

            - *
          • "Store", {@link IdentifierNode.Quoting#QUOTED}
          • - *
          • "USA", {@link IdentifierNode.Quoting#UNQUOTED}
          • - *
          • "New Mexico", {@link IdentifierNode.Quoting#QUOTED}
          • - *
          • "45", {@link IdentifierNode.Quoting#KEY}
          • - *
          - * - *

          QUOTED and UNQUOTED segments are represented using a - * {@link org.olap4j.mdx.IdentifierNode.NameSegment NameSegment}; - * KEY segments are represented using a - * {@link org.olap4j.mdx.IdentifierNode.KeySegment KeySegment}. - * - *

          To parse an identifier into a list of segments, use the method - * {@link IdentifierNode#parseIdentifier(String)} and then call - * {@link IdentifierNode#getSegmentList()} on the resulting node.

          - */ - public interface Segment { - - /** - * Returns a string representation of this Segment. - * - *

          For example, "[Foo]", "&[123]", "Abc". - * - * @return String representation of this Segment - */ - String toString(); - - /** - * Appends a string representation of this Segment to a StringBuffer. - * - * @param buf StringBuffer - */ - void toString(StringBuilder buf); - - /** - * Returns the region of the source code which this Segment was created - * from, if it was created by parsing. - * - * @return region of source code - */ - ParseRegion getRegion(); - - /** - * Returns how this Segment is quoted. - * - * @return how this Segment is quoted - */ - Quoting getQuoting(); - - /** - * Returns the name of this Segment. - * Returns {@code null} if this Segment represents a key. - * - * @return name of this Segment - */ - String getName(); - - /** - * Returns the key components, if this Segment is a key. (That is, - * if {@link #getQuoting()} returns - * {@link org.olap4j.mdx.IdentifierNode.Quoting#KEY}.) - * - * Returns null otherwise. - * - * @return Components of key, or null if this Segment is not a key - */ - List getKeyParts(); - } - - /** - * Component in a compound identifier that describes the name of an object. - * Optionally, the name is quoted in brackets. - * - * @see org.olap4j.mdx.IdentifierNode.KeySegment - */ - public static class NameSegment implements Segment { - final String name; - final IdentifierNode.Quoting quoting; - private final ParseRegion region; - - /** - * Creates a segment with the given quoting and region. - * - * @param region Region of source code - * @param name Name - * @param quoting Quoting style - */ - public NameSegment( - ParseRegion region, - String name, - IdentifierNode.Quoting quoting) - { - this.region = region; - this.name = name; - this.quoting = quoting; - if (!(quoting == Quoting.QUOTED || quoting == Quoting.UNQUOTED)) { - throw new IllegalArgumentException(); - } - } - - /** - * Creates a quoted segment, "[name]". - * - * @param name Name of segment - */ - public NameSegment(String name) { - this(null, name, Quoting.QUOTED); - } - - public String toString() { - switch (quoting) { - case UNQUOTED: - return name; - case QUOTED: - return quoteMdxIdentifier(name); - default: - throw Olap4jUtil.unexpected(quoting); - } - } - - public void toString(StringBuilder buf) { - switch (quoting) { - case UNQUOTED: - buf.append(name); - return; - case QUOTED: - quoteMdxIdentifier(name, buf); - return; - default: - throw Olap4jUtil.unexpected(quoting); - } - } - public ParseRegion getRegion() { - return region; - } - - public String getName() { - return name; - } - - public Quoting getQuoting() { - return quoting; - } - - public List getKeyParts() { - return null; - } - } - - /** - * Segment that represents a key or compound key. - * - *

          Such a segment appears in an identifier with each component prefixed - * with '&'. For example, in the identifier - * '{@code [Customer].[State].&[WA]&[USA]}', the third segment is a - * compound key whose parts are "@{code WA}" and "{@code USA}". - * - * @see org.olap4j.mdx.IdentifierNode.NameSegment - */ - public static class KeySegment implements Segment { - private final List subSegmentList; - - /** - * Creates a KeySegment with one or more sub-segments. - * - * @param subSegments Array of sub-segments - */ - public KeySegment(NameSegment... subSegments) { - if (subSegments.length < 1) { - throw new IllegalArgumentException(); - } - this.subSegmentList = UnmodifiableArrayList.asCopyOf(subSegments); - } - - /** - * Creates a KeySegment a list of sub-segments. - * - * @param subSegmentList List of sub-segments - */ - public KeySegment(List subSegmentList) { - if (subSegmentList.size() < 1) { - throw new IllegalArgumentException(); - } - this.subSegmentList = - new UnmodifiableArrayList( - subSegmentList.toArray( - new NameSegment[subSegmentList.size()])); - } - - public String toString() { - final StringBuilder buf = new StringBuilder(); - toString(buf); - return buf.toString(); - } - - public void toString(StringBuilder buf) { - for (Segment segment : subSegmentList) { - buf.append('&'); - segment.toString(buf); - } - } - - public ParseRegion getRegion() { - return sumSegmentRegions(subSegmentList); - } - - public Quoting getQuoting() { - return Quoting.KEY; - } - - public String getName() { - return null; - } - - public List getKeyParts() { - return subSegmentList; - } - } - - /** - * Enumeration of styles by which the component of an identifier can be - * quoted. - */ - public enum Quoting { - - /** - * Unquoted identifier, for example "Measures". - */ - UNQUOTED, - - /** - * Quoted identifier, for example "[Measures]". - */ - QUOTED, - - /** - * Identifier quoted with an ampersand and brackets to indicate a key - * value, for example the second segment in "[Employees].&[89]". - * - *

          Such a segment has one or more sub-segments. Each segment is - * either quoted or unquoted. For example, the second segment in - * "[Employees].&[89]&[San Francisco]&CA&USA" has four sub-segments, - * two quoted and two unquoted. - */ - KEY, - } } // End IdentifierNode.java diff --git a/src/org/olap4j/mdx/IdentifierSegment.java b/src/org/olap4j/mdx/IdentifierSegment.java new file mode 100644 index 0000000..1ec6a23 --- /dev/null +++ b/src/org/olap4j/mdx/IdentifierSegment.java @@ -0,0 +1,92 @@ +/* +// $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ +// 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.mdx; + +import java.util.List; + +/** + * Component in a compound identifier. It is described by its name and how + * the name is quoted. + * + *

          For example, the identifier + * [Store].USA.[New Mexico].&[45] has four segments:

            + *
          • "Store", {@link Quoting#QUOTED}
          • + *
          • "USA", {@link Quoting#UNQUOTED}
          • + *
          • "New Mexico", {@link Quoting#QUOTED}
          • + *
          • "45", {@link Quoting#KEY}
          • + *
          + * + *

          QUOTED and UNQUOTED segments are represented using a + * {@link NameSegment NameSegment}; + * KEY segments are represented using a + * {@link KeySegment KeySegment}. + * + *

          To parse an identifier into a list of segments, use the method + * {@link org.olap4j.mdx.IdentifierNode#parseIdentifier(String)} and then call + * {@link org.olap4j.mdx.IdentifierNode#getSegmentList()} on the resulting + * node.

          + * + * @version $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ + * @author jhyde + */ +public interface IdentifierSegment { + + /** + * Returns a string representation of this Segment. + * + *

          For example, "[Foo]", "&[123]", "Abc". + * + * @return String representation of this Segment + */ + String toString(); + + /** + * Appends a string representation of this Segment to a StringBuffer. + * + * @param buf StringBuffer + */ + void toString(StringBuilder buf); + + /** + * Returns the region of the source code which this Segment was created + * from, if it was created by parsing. + * + * @return region of source code + */ + ParseRegion getRegion(); + + /** + * Returns how this Segment is quoted. + * + * @return how this Segment is quoted + */ + Quoting getQuoting(); + + /** + * Returns the name of this IdentifierSegment. + * Returns {@code null} if this IdentifierSegment represents a key. + * + * @return name of this Segment + */ + String getName(); + + /** + * Returns the key components, if this IdentifierSegment is a key. (That is, + * if {@link #getQuoting()} returns + * {@link Quoting#KEY}.) + * + * Returns null otherwise. + * + * @return Components of key, or null if this IdentifierSegment is not a key + */ + List getKeyParts(); +} + +// End IdentifierSegment.java diff --git a/src/org/olap4j/mdx/KeySegment.java b/src/org/olap4j/mdx/KeySegment.java new file mode 100644 index 0000000..36f4587 --- /dev/null +++ b/src/org/olap4j/mdx/KeySegment.java @@ -0,0 +1,89 @@ +/* +// $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ +// 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.mdx; + +import org.olap4j.impl.UnmodifiableArrayList; + +import java.util.List; + +/** + * Segment that represents a key or compound key. + * + *

          Such a segment appears in an identifier with each component prefixed + * with '&'. For example, in the identifier + * '{@code [Customer].[State].&[WA]&[USA]}', the third segment is a + * compound key whose parts are "@{code WA}" and "{@code USA}". + * + * @see org.olap4j.mdx.NameSegment + * + * @version $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ + * @author jhyde + */ +public class KeySegment implements IdentifierSegment { + private final List subSegmentList; + + /** + * Creates a KeySegment with one or more sub-segments. + * + * @param subSegments Array of sub-segments + */ + public KeySegment(NameSegment... subSegments) { + if (subSegments.length < 1) { + throw new IllegalArgumentException(); + } + this.subSegmentList = UnmodifiableArrayList.asCopyOf(subSegments); + } + + /** + * Creates a KeySegment a list of sub-segments. + * + * @param subSegmentList List of sub-segments + */ + public KeySegment(List subSegmentList) { + if (subSegmentList.size() < 1) { + throw new IllegalArgumentException(); + } + this.subSegmentList = + new UnmodifiableArrayList( + subSegmentList.toArray( + new NameSegment[subSegmentList.size()])); + } + + public String toString() { + final StringBuilder buf = new StringBuilder(); + toString(buf); + return buf.toString(); + } + + public void toString(StringBuilder buf) { + for (IdentifierSegment segment : subSegmentList) { + buf.append('&'); + segment.toString(buf); + } + } + + public ParseRegion getRegion() { + return IdentifierNode.sumSegmentRegions(subSegmentList); + } + + public Quoting getQuoting() { + return Quoting.KEY; + } + + public String getName() { + return null; + } + + public List getKeyParts() { + return subSegmentList; + } +} + +// End KeySegment.java diff --git a/src/org/olap4j/mdx/NameSegment.java b/src/org/olap4j/mdx/NameSegment.java new file mode 100644 index 0000000..c34cfde --- /dev/null +++ b/src/org/olap4j/mdx/NameSegment.java @@ -0,0 +1,99 @@ +/* +// $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ +// 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.mdx; + +import org.olap4j.impl.Olap4jUtil; + +import java.util.List; + +/** + * Component in a compound identifier that describes the name of an object. + * Optionally, the name is quoted in brackets. + * + * @see KeySegment + * + * @version $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ + * @author jhyde + */ +public class NameSegment implements IdentifierSegment { + final String name; + final Quoting quoting; + private final ParseRegion region; + + /** + * Creates a segment with the given quoting and region. + * + * @param region Region of source code + * @param name Name + * @param quoting Quoting style + */ + public NameSegment( + ParseRegion region, + String name, + Quoting quoting) + { + this.region = region; + this.name = name; + this.quoting = quoting; + if (!(quoting == Quoting.QUOTED || quoting == Quoting.UNQUOTED)) { + throw new IllegalArgumentException(); + } + } + + /** + * Creates a quoted segment, "[name]". + * + * @param name Name of segment + */ + public NameSegment(String name) { + this(null, name, Quoting.QUOTED); + } + + public String toString() { + switch (quoting) { + case UNQUOTED: + return name; + case QUOTED: + return IdentifierNode.quoteMdxIdentifier(name); + default: + throw Olap4jUtil.unexpected(quoting); + } + } + + public void toString(StringBuilder buf) { + switch (quoting) { + case UNQUOTED: + buf.append(name); + return; + case QUOTED: + IdentifierNode.quoteMdxIdentifier(name, buf); + return; + default: + throw Olap4jUtil.unexpected(quoting); + } + } + public ParseRegion getRegion() { + return region; + } + + public String getName() { + return name; + } + + public Quoting getQuoting() { + return quoting; + } + + public List getKeyParts() { + return null; + } +} + +// End NameSegment.java diff --git a/src/org/olap4j/mdx/Quoting.java b/src/org/olap4j/mdx/Quoting.java new file mode 100644 index 0000000..348fa0b --- /dev/null +++ b/src/org/olap4j/mdx/Quoting.java @@ -0,0 +1,45 @@ +/* +// $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ +// 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.mdx; + +/** + * Enumeration of styles by which the component of an identifier can be + * quoted. + * + * @see org.olap4j.mdx.IdentifierSegment + * + * @version $Id: IdentifierNode.java 359 2010-10-14 21:24:51Z jhyde $ + * @author jhyde + */ +public enum Quoting { + + /** + * Unquoted identifier, for example "Measures". + */ + UNQUOTED, + + /** + * Quoted identifier, for example "[Measures]". + */ + QUOTED, + + /** + * Identifier quoted with an ampersand and brackets to indicate a key + * value, for example the second segment in "[Employees].&[89]". + * + *

          Such a segment has one or more sub-segments. Each segment is + * either quoted or unquoted. For example, the second segment in + * "[Employees].&[89]&[San Francisco]&CA&USA" has four sub-segments, + * two quoted and two unquoted. + */ + KEY, +} + +// End Quoting.java diff --git a/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup b/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup index 62c3790..8827681 100644 --- a/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup +++ b/src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup @@ -365,7 +365,7 @@ non terminal Axis.Standard non terminal String comp_op, keyword; -non terminal IdentifierNode.Segment +non terminal IdentifierSegment identifier, key_identifier, quoted_identifier, @@ -425,34 +425,31 @@ start with statement; quoted_identifier ::= QUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); - RESULT = new IdentifierNode.NameSegment( - region, i, IdentifierNode.Quoting.QUOTED); + RESULT = new NameSegment(region, i, Quoting.QUOTED); :} ; unquoted_identifier ::= ID:i {: ParseRegion region = createRegion(ileft, iright); - RESULT = new IdentifierNode.NameSegment( - region, i, IdentifierNode.Quoting.UNQUOTED); + RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} | keyword:i {: ParseRegion region = createRegion(ileft, iright); - RESULT = new IdentifierNode.NameSegment( - region, i, IdentifierNode.Quoting.UNQUOTED); + RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} ; // for example '&foo&[1]&bar' in '[x].&foo&[1]&bar.[y]' key_identifier ::= amp_identifier_list:list {: - RESULT = new IdentifierNode.KeySegment(list); + RESULT = new KeySegment(list); :} ; amp_identifier_list ::= amp_identifier:i {: - RESULT = new ArrayList(); + RESULT = new ArrayList(); RESULT.add(i); :} | @@ -471,16 +468,14 @@ amp_identifier ::= amp_quoted_identifier ::= AMP_QUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); - RESULT = new IdentifierNode.NameSegment( - region, i, IdentifierNode.Quoting.QUOTED); + RESULT = new NameSegment(region, i, Quoting.QUOTED); :} ; amp_unquoted_identifier ::= AMP_UNQUOTED_ID:i {: ParseRegion region = createRegion(ileft, iright); - RESULT = new IdentifierNode.NameSegment( - region, i, IdentifierNode.Quoting.UNQUOTED); + RESULT = new NameSegment(region, i, Quoting.UNQUOTED); :} ; diff --git a/src/org/olap4j/metadata/Cube.java b/src/org/olap4j/metadata/Cube.java index d5fde7f..95aeb21 100644 --- a/src/org/olap4j/metadata/Cube.java +++ b/src/org/olap4j/metadata/Cube.java @@ -10,6 +10,7 @@ package org.olap4j.metadata; import org.olap4j.OlapException; +import org.olap4j.mdx.IdentifierSegment; import java.util.*; @@ -114,28 +115,44 @@ public interface Cube extends MetadataElement { * each successive member on the path from the root member. If a member's * name is unique within its level, preceding member name can be omitted. * - *

          For example, - * lookupMember("Product", "Food") - * and - * lookupMember("Product", "All Products", "Food") + *

          For example, {@code "[Product].[Food]"} and + * {@code "[Product].[All Products].[Food]"} * are both valid ways to locate the "Food" member of the "Product" * dimension. * + *

          The name is represented as a list of {@link IdentifierSegment} + * objects. There are some common ways to create such a list. If you have an + * identifier, call + * {@link org.olap4j.mdx.IdentifierNode#parseIdentifier(String)} + * to parse the string into an identifier, then + * {@link org.olap4j.mdx.IdentifierNode#getSegmentList()}. For example, + * + *

          Member member = cube.lookupMember(
          + *   IdentifierNode.parseIdentifier( + * "[Product].[Food]").getSegmentList())
          + * + *

          If you have an array of names, call + * {@link org.olap4j.mdx.IdentifierNode#ofNames(String...)}. For example, + * + *

          Member member = cube.lookupMember(
          + *   IdentifierNode.parseIdentifier( + * "[Product].[Food]").getSegmentList())
          + * * @param nameParts Components of the fully-qualified member name * * @return member with the given name, or null if not found * * @throws OlapException if error occurs */ - Member lookupMember(String... nameParts) throws OlapException; + Member lookupMember(List nameParts) throws OlapException; /** * Finds a collection of members in the current Cube related to a given * member. * *

          The method first looks up a member with the given fully-qualified - * name as for {@link #lookupMember(String[])}, then applies the set of - * tree-operations to find related members. + * name as for {@link #lookupMember(java.util.List)}, then applies the set + * of tree-operations to find related members. * *

          The returned collection is sorted by level number then by member * ordinal. If no member is found with the given name, the collection is @@ -182,7 +199,7 @@ public interface Cube extends MetadataElement { */ List lookupMembers( Set treeOps, - String... nameParts) throws OlapException; + List nameParts) throws OlapException; } // End Cube.java diff --git a/src/org/olap4j/query/Query.java b/src/org/olap4j/query/Query.java index 15b2fb5..60be5fb 100644 --- a/src/org/olap4j/query/Query.java +++ b/src/org/olap4j/query/Query.java @@ -141,6 +141,15 @@ public void swapAxes() { down.notifyAdd(acrossChildList); } + /** + * Returns the query axis for a given axis type. + * + *

          If you pass axis=null, returns a special axis that is used to hold + * all unused hierarchies. (We may change this behavior in future.) + * + * @param axis Axis type + * @return Query axis + */ public QueryAxis getAxis(Axis axis) { return this.axes.get(axis); } diff --git a/src/org/olap4j/query/QueryAxis.java b/src/org/olap4j/query/QueryAxis.java index a30ab39..3b137b9 100644 --- a/src/org/olap4j/query/QueryAxis.java +++ b/src/org/olap4j/query/QueryAxis.java @@ -11,6 +11,7 @@ import org.olap4j.Axis; import org.olap4j.OlapException; +import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.Measure; import org.olap4j.metadata.Member; @@ -261,30 +262,31 @@ public void sort(SortOrder order) throws OlapException { } /** - *

          Sorts the axis according to the supplied order + * Sorts the axis according to the supplied order * and member unique name. + * *

          Using this method will try to resolve the supplied name * parts from the underlying cube and find the corresponding * member. This member will then be passed as a sort evaluation * expression. + * * @param order The {@link SortOrder} in which to * sort the axis. * @param nameParts The unique name parts of the sort * evaluation expression. * @throws OlapException If the supplied member cannot be resolved - * with {@link org.olap4j.metadata.Cube#lookupMember(String...)} + * with {@link org.olap4j.metadata.Cube#lookupMember(java.util.List)} */ - public void sort(SortOrder order, String... nameParts) + public void sort(SortOrder order, List nameParts) throws OlapException { assert order != null; assert nameParts != null; Member member = query.getCube().lookupMember(nameParts); - if (member != null) { - sort(order, member); - } else { + if (member == null) { throw new OlapException("Cannot find member."); } + sort(order, member); } /** diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java index 172dca6..2d5b811 100644 --- a/src/org/olap4j/query/QueryDimension.java +++ b/src/org/olap4j/query/QueryDimension.java @@ -11,9 +11,7 @@ import org.olap4j.OlapException; import org.olap4j.impl.IdentifierParser; -import org.olap4j.impl.Olap4jUtil; -import org.olap4j.mdx.IdentifierNode; -import org.olap4j.mdx.IdentifierNode.Segment; +import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.*; import java.util.HashMap; @@ -68,63 +66,37 @@ public String getName() { return dimension.getName(); } - @Deprecated - public void select(String... nameParts) throws OlapException { - this.include(nameParts); - } - - @Deprecated - public void select( - Selection.Operator operator, - String... nameParts) throws OlapException - { - this.include(operator, nameParts); - } - - @Deprecated - public void select(Member member) { - this.include(member); - } - - @Deprecated - public void select( - Selection.Operator operator, - Member member) - { - this.include(operator, member); - } - - /** - * Clears the current member inclusions from this query dimension. - * @deprecated This method is deprecated in favor of - * {@link QueryDimension#clearInclusions()} - */ - @Deprecated - public void clearSelection() { - this.clearInclusions(); - } - /** * Selects members and includes them in the query. + * *

          This method selects and includes a single member with the * {@link Selection.Operator#MEMBER} operator. + * * @param nameParts Name of the member to select and include. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ - public Selection include(String... nameParts) throws OlapException { + public Selection include( + List nameParts) + throws OlapException + { return this.include(Selection.Operator.MEMBER, nameParts); } - public Selection createSelection(String... nameParts) throws OlapException { + public Selection createSelection( + List nameParts) + throws OlapException + { return this.createSelection(Selection.Operator.MEMBER, nameParts); - } + } /** * Selects members and includes them in the query. - *

          This method selects and includes a member along with it's + * + *

          This method selects and includes a member along with its * relatives, depending on the supplied {@link Selection.Operator} * operator. + * * @param operator Selection operator that defines what relatives of the * supplied member name to include along. * @param nameParts Name of the root member to select and include. @@ -133,34 +105,30 @@ public Selection createSelection(String... nameParts) throws OlapException { */ public Selection include( Selection.Operator operator, - String... nameParts) throws OlapException + List nameParts) throws OlapException { Member member = this.getQuery().getCube().lookupMember(nameParts); if (member == null) { throw new OlapException( - "Unable to find a member with name " - + Olap4jUtil.stringArrayToString(nameParts)); - } else { - return this.include( - operator, - member); + "Unable to find a member with name " + nameParts); } + return this.include( + operator, + member); } public Selection createSelection( Selection.Operator operator, - String... nameParts) throws OlapException + List nameParts) throws OlapException { Member member = this.getQuery().getCube().lookupMember(nameParts); if (member == null) { throw new OlapException( - "Unable to find a member with name " - + Olap4jUtil.stringArrayToString(nameParts)); - } else { - return this.createSelection( - operator, - member); + "Unable to find a member with name " + nameParts); } + return this.createSelection( + operator, + member); } /** @@ -250,21 +218,28 @@ public void clearInclusions() { /** * Selects members and excludes them from the query. + * *

          This method selects and excludes a single member with the * {@link Selection.Operator#MEMBER} operator. + * * @param nameParts Name of the member to select and exclude. * @throws OlapException If no member corresponding to the supplied * name parts could be resolved in the cube. */ - public void exclude(String... nameParts) throws OlapException { + public void exclude( + List nameParts) + throws OlapException + { this.exclude(Selection.Operator.MEMBER, nameParts); } /** * Selects members and excludes them from the query. - *

          This method selects and excludes a member along with it's + * + *

          This method selects and excludes a member along with its * relatives, depending on the supplied {@link Selection.Operator} * operator. + * * @param operator Selection operator that defines what relatives of the * supplied member name to exclude along. * @param nameParts Name of the root member to select and exclude. @@ -273,18 +248,16 @@ public void exclude(String... nameParts) throws OlapException { */ public void exclude( Selection.Operator operator, - String... nameParts) throws OlapException + List nameParts) throws OlapException { Member rootMember = this.getQuery().getCube().lookupMember(nameParts); if (rootMember == null) { throw new OlapException( - "Unable to find a member with name " - + Olap4jUtil.stringArrayToString(nameParts)); - } else { - this.exclude( - operator, - rootMember); + "Unable to find a member with name " + nameParts); } + this.exclude( + operator, + rootMember); } /** @@ -344,15 +317,6 @@ public void clearExclusions() { this.notifyRemove(removed); } - public static String[] getNameParts(String sel) { - List list = IdentifierParser.parseIdentifier(sel); - String nameParts[] = new String[list.size()]; - for (int i = 0; i < list.size(); i++) { - nameParts[i] = list.get(i).getName(); - } - return nameParts; - } - /** * Resolves a selection of members into an actual list * of the root member and it's relatives selected by the Selection object. @@ -393,7 +357,7 @@ public List resolve(Selection selection) throws OlapException return query.getCube().lookupMembers( set, - getNameParts(selection.getName())); + IdentifierParser.parseIdentifier(selection.getName())); } catch (Exception e) { throw new OlapException( "Error while resolving selection " + selection.toString(), @@ -401,18 +365,6 @@ public List resolve(Selection selection) throws OlapException } } - /** - * Returns a list of the inclusions within this dimension. - *

          Be aware that modifications to this list might - * have unpredictable consequences.

          - * @deprecated Use {@link QueryDimension#getInclusions()} - * @return list of inclusions - */ - @Deprecated - public List getSelections() { - return this.getInclusions(); - } - /** * Returns a list of the inclusions within this dimension. * diff --git a/src/org/olap4j/sample/SimpleQuerySample.java b/src/org/olap4j/sample/SimpleQuerySample.java index afea5b9..f1b35c7 100644 --- a/src/org/olap4j/sample/SimpleQuerySample.java +++ b/src/org/olap4j/sample/SimpleQuerySample.java @@ -261,7 +261,7 @@ void executeSelectNode(OlapConnection connection) { SelectNode query = new SelectNode(); query.setFrom( new IdentifierNode( - new IdentifierNode.NameSegment("Sales"))); + new NameSegment("Sales"))); query.getAxisList().add( new AxisNode( null, @@ -273,8 +273,8 @@ void executeSelectNode(OlapConnection connection) { "{}", Syntax.Braces, new IdentifierNode( - new IdentifierNode.NameSegment("Measures"), - new IdentifierNode.NameSegment("Unit Sales"))))); + new NameSegment("Measures"), + new NameSegment("Unit Sales"))))); // Create a statement based upon the query model. OlapStatement stmt; diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index fd1b391..ccffa72 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -25,6 +25,8 @@ import java.sql.*; import java.util.*; +import static org.olap4j.test.TestContext.nameList; + /** * Unit test for olap4j Driver and Connection classes. * @@ -1375,7 +1377,7 @@ public void testUnparsing() { // Note that the select statement constructed here is equivalent // to the one in testParsing. final IdentifierNode cubeName = - new IdentifierNode(new IdentifierNode.NameSegment("sales")); + new IdentifierNode(new NameSegment("sales")); SelectNode select = new SelectNode( null, new ArrayList(), @@ -1392,11 +1394,11 @@ public void testUnparsing() { new WithMemberNode( null, new IdentifierNode( - new IdentifierNode.NameSegment("Measures"), - new IdentifierNode.NameSegment("Foo")), + new NameSegment("Measures"), + new NameSegment("Foo")), new IdentifierNode( - new IdentifierNode.NameSegment("Measures"), - new IdentifierNode.NameSegment("Bar")), + new NameSegment("Measures"), + new NameSegment("Bar")), Arrays.asList( new PropertyValueNode( null, @@ -1417,7 +1419,7 @@ public void testUnparsing() { Arrays.asList( (ParseTreeNode) new IdentifierNode( - new IdentifierNode.NameSegment("Gender")))))); + new NameSegment("Gender")))))); select.getAxisList().add( new AxisNode( null, @@ -1433,12 +1435,12 @@ public void testUnparsing() { "Children", Syntax.Property, new IdentifierNode( - new IdentifierNode.NameSegment("Store")))))); + new NameSegment("Store")))))); select.getFilterAxis().setExpression( new IdentifierNode( - new IdentifierNode.NameSegment("Time"), - new IdentifierNode.NameSegment("1997"), - new IdentifierNode.NameSegment("Q4"))); + new NameSegment("Time"), + new NameSegment("1997"), + new NameSegment("Q4"))); assertEquals(select.getFrom(), cubeName); checkUnparsedMdx(select); @@ -1448,7 +1450,7 @@ public void testUnparsing() { null, new ArrayList(), new ArrayList(), - new IdentifierNode(new IdentifierNode.NameSegment("warehouse")), + new IdentifierNode(new NameSegment("warehouse")), new AxisNode( null, false, @@ -1481,7 +1483,7 @@ public void testBuildParseTree() { null, new ArrayList(), new ArrayList(), - new IdentifierNode(new IdentifierNode.NameSegment("sales")), + new IdentifierNode(new NameSegment("sales")), new AxisNode( null, false, @@ -1500,7 +1502,7 @@ public void testBuildParseTree() { null, new ArrayList(), new ArrayList(), - new IdentifierNode(new IdentifierNode.NameSegment("sales")), + new IdentifierNode(new NameSegment("sales")), new AxisNode( null, false, @@ -1526,11 +1528,11 @@ public void testBuildParseTree() { "()", Syntax.Parentheses, new IdentifierNode( - new IdentifierNode.NameSegment("Measures"), - new IdentifierNode.NameSegment("Store Sales")), + new NameSegment("Measures"), + new NameSegment("Store Sales")), new IdentifierNode( - new IdentifierNode.NameSegment("Gender"), - new IdentifierNode.NameSegment("M")))); + new NameSegment("Gender"), + new NameSegment("M")))); checkUnparsedMdx( select, "SELECT\n" @@ -1546,7 +1548,7 @@ public void testBuildParseTree() { } /** - * Tests the {@link Cube#lookupMember(String...)} method. + * Tests the {@link Cube#lookupMember(java.util.List} method. */ public void testCubeLookupMember() throws Exception { Class.forName(tester.getDriverClassName()); @@ -1556,8 +1558,7 @@ public void testCubeLookupMember() throws Exception { Cube cube = olapConnection.getSchema().getCubes().get("Sales Ragged"); Member member = - cube.lookupMember( - "Time", "1997", "Q2"); + cube.lookupMember(nameList("Time", "1997", "Q2")); assertEquals("[Time].[1997].[Q2]", member.getUniqueName()); // Member.getChildMemberCount @@ -1575,25 +1576,23 @@ public void testCubeLookupMember() throws Exception { assertNull(childMembers.get("1")); member = - cube.lookupMember( - "Time", "1997", "Q5"); + cube.lookupMember(nameList("Time", "1997", "Q5")); assertNull(member); // arguably this should return [Customers].[All Customers]; but it // makes a bit more sense for it to return null member = - cube.lookupMember( - "Customers"); + cube.lookupMember(nameList("Customers")); assertNull(member); member = - cube.lookupMember( - "Customers", "All Customers"); + cube.lookupMember(nameList("Customers", "All Customers")); assertTrue(member.isAll()); } /** - * Tests the {@link Cube#lookupMembers(java.util.Set, String...)} method. + * Tests the {@link Cube#lookupMembers(java.util.Set, java.util.List)} + * method. */ public void testCubeLookupMembers() throws Exception { Class.forName(tester.getDriverClassName()); @@ -1606,7 +1605,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), - "Time", "1997", "Q2"); + nameList("Time", "1997", "Q2")); String expected; switch (tester.getFlavor()) { case XMLA: @@ -1635,7 +1634,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), - "Time", "1997", "Q5"); + nameList("Time", "1997", "Q5")); assertTrue(memberList.isEmpty()); // ask for parent & ancestors; should not get duplicates @@ -1643,7 +1642,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), - "Time", "1997", "Q2"); + nameList("Time", "1997", "Q2")); TestContext.assertEqualsVerbose( "[Time].[1997]\n", memberListToString(memberList)); @@ -1653,7 +1652,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), - "Product"); + nameList("Product")); assertTrue(memberList.isEmpty()); // ask for siblings and children, and the results should be @@ -1662,7 +1661,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.SIBLINGS, Member.TreeOp.CHILDREN), - "Time", "1997", "Q2"); + nameList("Time", "1997", "Q2")); switch (tester.getFlavor()) { case XMLA: case REMOTE_XMLA: @@ -1694,7 +1693,7 @@ public void testCubeLookupMembers() throws Exception { memberList = cube.lookupMembers( Olap4jUtil.enumSetOf(Member.TreeOp.SIBLINGS), - "Time", "1997"); + nameList("Time", "1997")); TestContext.assertEqualsVerbose( "[Time].[1998]\n", memberListToString(memberList)); @@ -1703,7 +1702,7 @@ public void testCubeLookupMembers() throws Exception { cube.lookupMembers( Olap4jUtil.enumSetOf( Member.TreeOp.SIBLINGS, Member.TreeOp.SELF), - "Customers", "USA", "OR"); + nameList("Customers", "USA", "OR")); TestContext.assertEqualsVerbose( "[Customers].[USA].[CA]\n" + "[Customers].[USA].[OR]\n" @@ -1868,14 +1867,21 @@ public void testMetadata() throws Exception { // ~ Member - Member member = cube.lookupMember("Product", "Food", "Marshmallows"); + Member member = + cube.lookupMember( + nameList("Product", "Food", "Marshmallows")); assertNull(member); // we don't sell marshmallows! - member = cube.lookupMember("Product", "Food"); + member = + cube.lookupMember( + nameList("Product", "Food")); assertNotNull(member); - Member member2 = cube.lookupMember("Product", "All Products", "Food"); + Member member2 = + cube.lookupMember( + nameList("Product", "All Products", "Food")); assertEquals(member, member2); final Member bread = - cube.lookupMember("Product", "Food", "Baked Goods", "Bread"); + cube.lookupMember( + nameList("Product", "Food", "Baked Goods", "Bread")); assertEquals("[Product].[Food]", member.getUniqueName()); assertEquals("Food", member.getName()); diff --git a/testsrc/org/olap4j/OlapTest.java b/testsrc/org/olap4j/OlapTest.java index 1b1da90..351b3c9 100644 --- a/testsrc/org/olap4j/OlapTest.java +++ b/testsrc/org/olap4j/OlapTest.java @@ -20,6 +20,8 @@ import junit.framework.TestCase; +import static org.olap4j.test.TestContext.nameList; + /** * Unit test illustrating sequence of calls to olap4j API from a graphical * client. @@ -165,21 +167,23 @@ public void testModel() { QueryDimension timeQuery = query.getDimension("Time"); //$NON-NLS-1$ - Member productMember = cube.lookupMember("Product", "Drink"); + Member productMember = + cube.lookupMember(nameList("Product", "Drink")); // create some selections for Store storeQuery.include( - Selection.Operator.CHILDREN, "Store", "USA"); + Selection.Operator.CHILDREN, nameList("Store", "USA")); // create some selections for Product productQuery.clearInclusions(); productQuery.include( Selection.Operator.CHILDREN, productMember); productQuery.include( - Selection.Operator.CHILDREN, "Product", "Food"); + Selection.Operator.CHILDREN, nameList("Product", "Food")); // create some selections for Time - timeQuery.include(Selection.Operator.CHILDREN, "Time", "1997"); + timeQuery.include( + Selection.Operator.CHILDREN, nameList("Time", "1997")); // place our dimensions on the axes query.getAxis(Axis.COLUMNS).addDimension(productQuery); @@ -221,10 +225,10 @@ public void testSelectionModes() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -244,7 +248,7 @@ public void testSelectionModes() { productDimension.clearInclusions(); productDimension.include( - Selection.Operator.ANCESTORS, "Product", "Drink"); + Selection.Operator.ANCESTORS, nameList("Product", "Drink")); query.validate(); @@ -261,7 +265,7 @@ public void testSelectionModes() { productDimension.clearInclusions(); productDimension.include( - Selection.Operator.DESCENDANTS, "Product", "Drink"); + Selection.Operator.DESCENDANTS, nameList("Product", "Drink")); query.validate(); @@ -278,7 +282,8 @@ public void testSelectionModes() { productDimension.clearInclusions(); productDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Product", "Drink"); + Selection.Operator.INCLUDE_CHILDREN, + nameList("Product", "Drink")); query.validate(); @@ -295,7 +300,7 @@ public void testSelectionModes() { productDimension.clearInclusions(); productDimension.include( - Selection.Operator.SIBLINGS, "Product", "Drink"); + Selection.Operator.SIBLINGS, nameList("Product", "Drink")); query.validate(); @@ -325,17 +330,18 @@ public void testMultipleDimensionSelections() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Store", "USA"); + Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include(Selection.Operator.CHILDREN, "Time", "1997"); + timeDimension.include( + Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(storeDimension); @@ -372,10 +378,10 @@ public void testSwapAxes() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -435,13 +441,14 @@ public void testSortDimension() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Product", "Drink"); + Selection.Operator.INCLUDE_CHILDREN, + nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -514,13 +521,13 @@ public void testSortMultipleDimension() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(timeDimension); query.getAxis(Axis.ROWS).addDimension(productDimension); @@ -579,7 +586,7 @@ public void testSortMultipleDimension() { query.getAxis(Axis.ROWS).setNonEmpty(true); productDimension.clearInclusions(); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Food"); + Selection.Operator.CHILDREN, nameList("Product", "Food")); SelectNode sortedMdxNonEmpty = query.getSelect(); String sortedMdxNonEmptyString = sortedMdxNonEmpty.toString(); @@ -645,35 +652,36 @@ public void testSelectionContext() throws Exception { // create selections QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Product", "All Products"); + Selection.Operator.INCLUDE_CHILDREN, + nameList("Product", "All Products")); QueryDimension timeDimension = query.getDimension("Time"); timeDimension.include( - Selection.Operator.MEMBER, "Time", "Year", "1997"); + Selection.Operator.MEMBER, nameList("Time", "Year", "1997")); Selection selection = timeDimension.include( - Selection.Operator.CHILDREN, "Time", "Year", "1997"); + Selection.Operator.CHILDREN, nameList("Time", "Year", "1997")); selection.addContext( productDimension.createSelection( - "Product", "All Products", "Drink")); + nameList("Product", "All Products", "Drink"))); // [Store].[All Stores] QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.MEMBER, "Store", "All Stores"); + Selection.Operator.MEMBER, nameList("Store", "All Stores")); Selection children = storeDimension.include( - Selection.Operator.CHILDREN, "Store", "All Stores"); + Selection.Operator.CHILDREN, nameList("Store", "All Stores")); children.addContext( productDimension.createSelection( - "Product", "All Products", "Drink")); + nameList("Product", "All Products", "Drink"))); children.addContext( - timeDimension.createSelection("Time", "1997", "Q3")); + timeDimension.createSelection(nameList("Time", "1997", "Q3"))); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); @@ -702,8 +710,7 @@ public void testSelectionContext() throws Exception { // Sort the rows in ascending order. query.getAxis(Axis.ROWS).sort( SortOrder.ASC, - "Measures", - "Store Sales"); + nameList("Measures", "Store Sales")); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); @@ -759,18 +766,18 @@ public void testComplexSelectionContext() throws Exception { productDimension.include( - Selection.Operator.MEMBER, "Product", "All Products"); + Selection.Operator.MEMBER, nameList("Product", "All Products")); productDimension.include( - Selection.Operator.CHILDREN, "Product", "All Products"); + Selection.Operator.CHILDREN, nameList("Product", "All Products")); QueryDimension timeDimension = query.getDimension("Time"); Selection selection = timeDimension.include( - Selection.Operator.CHILDREN, "Time", "Year", "1997"); + Selection.Operator.CHILDREN, nameList("Time", "Year", "1997")); selection.addContext( - productDimension.createSelection( - "Product", "All Products")); + productDimension.createSelection( + nameList("Product", "All Products"))); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.ROWS).addDimension(timeDimension); @@ -852,13 +859,14 @@ public void testSortAxis() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Product", "Drink"); + Selection.Operator.INCLUDE_CHILDREN, + nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -886,8 +894,7 @@ public void testSortAxis() { // Sort the rows in ascending order. query.getAxis(Axis.ROWS).sort( SortOrder.BASC, - "Measures", - "Store Sales"); + nameList("Measures", "Store Sales")); SelectNode sortedMdx = query.getSelect(); String sortedMdxString = sortedMdx.toString(); @@ -934,17 +941,18 @@ public void testDimensionsOrder() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Store", "USA"); + Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include(Selection.Operator.CHILDREN, "Time", "1997"); + timeDimension.include( + Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); @@ -1020,11 +1028,11 @@ public void testDimensionsHierarchize() { QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Store", "USA"); + Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); storeDimension.setHierarchizeMode(HierarchizeMode.POST); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -1076,10 +1084,10 @@ public void testQueryVersusParseTreeIndependence() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Product", "Drink"); + Selection.Operator.INCLUDE_CHILDREN, nameList("Product", "Drink")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); @@ -1107,20 +1115,20 @@ public void testQueryVersusParseTreeIndependence() { // change selections measuresDimension.include( - Selection.Operator.SIBLINGS, "Measures", "Customer Count"); + Selection.Operator.SIBLINGS, + nameList("Measures", "Customer Count")); productDimension.include( Selection.Operator.SIBLINGS, - "Product", "All Products", "Drink", "Alcoholic Beverages"); + nameList( + "Product", "All Products", "Drink", "Alcoholic Beverages")); // Add something to crossjoin with query.getAxis(Axis.ROWS).addDimension( query.getDimension("Gender")); query.getDimension("Gender").include( - Operator.CHILDREN, - "Gender", - "All Gender"); + Operator.CHILDREN, nameList("Gender", "All Gender")); - query.getAxis(Axis.UNUSED).addDimension( + query.getAxis(null).addDimension( query.getDimension("Product")); query.validate(); @@ -1145,17 +1153,14 @@ public void testExclusionModes() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.CHILDREN, - "Product", "Drink", - "Beverages"); + nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.CHILDREN, - "Product", - "Food", - "Frozen Foods"); + nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Sales Count"); + measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.COLUMNS).addDimension(measuresDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); @@ -1205,10 +1210,8 @@ public void testExclusionModes() { // Exclude the Carbonated Beverages because they are not good // for your health. query.getDimension("Product").exclude( - "Product", - "Drink", - "Beverages", - "Carbonated Beverages"); + nameList( + "Product", "Drink", "Beverages", "Carbonated Beverages")); // Validate the generated MDX query.validate(); @@ -1267,20 +1270,17 @@ public void testExclusionMultipleDimensionModes() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.CHILDREN, - "Product", "Drink", - "Beverages"); + nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.CHILDREN, - "Product", - "Food", - "Frozen Foods"); + nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Sales Count"); + measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.MEMBER, "Store", "USA"); + Selection.Operator.MEMBER, nameList("Store", "USA")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.ROWS).addDimension(productDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); @@ -1332,10 +1332,8 @@ public void testExclusionMultipleDimensionModes() { // Exclude the Carbonated Beverages because they are not good // for your health. query.getDimension("Product").exclude( - "Product", - "Drink", - "Beverages", - "Carbonated Beverages"); + nameList( + "Product", "Drink", "Beverages", "Carbonated Beverages")); // Validate the generated MDX query.validate(); @@ -1394,20 +1392,17 @@ public void testCompoundFilter() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( Selection.Operator.MEMBER, - "Product", "Drink", - "Beverages"); + nameList("Product", "Drink", "Beverages")); productDimension.include( Selection.Operator.MEMBER, - "Product", - "Food", - "Frozen Foods"); + nameList("Product", "Food", "Frozen Foods")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Sales Count"); + measuresDimension.include(nameList("Measures", "Sales Count")); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include("Time", "Year", "1997", "Q3", "7"); + timeDimension.include(nameList("Time", "Year", "1997", "Q3", "7")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.MEMBER, "Store", "USA"); + Selection.Operator.MEMBER, nameList("Store", "USA")); query.getAxis(Axis.ROWS).addDimension(storeDimension); query.getAxis(Axis.FILTER).addDimension(productDimension); query.getAxis(Axis.FILTER).addDimension(timeDimension); @@ -1455,19 +1450,20 @@ public void testNonMandatoryQueryAxis() { QueryDimension productDimension = query.getDimension("Product"); productDimension.include( - Selection.Operator.CHILDREN, "Product", "Drink"); + Selection.Operator.CHILDREN, nameList("Product", "Drink")); QueryDimension storeDimension = query.getDimension("Store"); storeDimension.include( - Selection.Operator.INCLUDE_CHILDREN, "Store", "USA"); + Selection.Operator.INCLUDE_CHILDREN, nameList("Store", "USA")); storeDimension.setHierarchizeMode(HierarchizeMode.POST); QueryDimension timeDimension = query.getDimension("Time"); - timeDimension.include(Selection.Operator.CHILDREN, "Time", "1997"); + timeDimension.include( + Selection.Operator.CHILDREN, nameList("Time", "1997")); QueryDimension measuresDimension = query.getDimension("Measures"); - measuresDimension.include("Measures", "Store Sales"); + measuresDimension.include(nameList("Measures", "Store Sales")); //query.getAxis(Axis.ROWS).addDimension(productDimension); diff --git a/testsrc/org/olap4j/impl/Olap4jUtilTest.java b/testsrc/org/olap4j/impl/Olap4jUtilTest.java index 72a57d1..88bc7c3 100644 --- a/testsrc/org/olap4j/impl/Olap4jUtilTest.java +++ b/testsrc/org/olap4j/impl/Olap4jUtilTest.java @@ -9,8 +9,7 @@ package org.olap4j.impl; import junit.framework.TestCase; -import org.olap4j.mdx.IdentifierNode; -import org.olap4j.mdx.ParseRegion; +import org.olap4j.mdx.*; import java.util.*; @@ -347,7 +346,7 @@ private void checkParseFormattedCellValue( * Tests the {@link IdentifierNode#parseIdentifier} method. */ public void testParseIdentifier() { - List segments = + List segments = IdentifierParser.parseIdentifier( "[string].[with].[a [bracket]] in it]"); assertEquals(3, segments.size()); @@ -412,26 +411,26 @@ public void testParseIdentifier() { segments = IdentifierParser.parseIdentifier( "[ProductFilterDim].[Product Main Group Name].&[Maingroup (xyz)]"); assertEquals(3, segments.size()); - final IdentifierNode.Segment s0 = segments.get(0); + final IdentifierSegment s0 = segments.get(0); assertEquals("ProductFilterDim", s0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s0.getQuoting()); - final IdentifierNode.Segment s1 = segments.get(1); + assertEquals(Quoting.QUOTED, s0.getQuoting()); + final IdentifierSegment s1 = segments.get(1); assertEquals("Product Main Group Name", s1.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s1.getQuoting()); - assertTrue(segments.get(2) instanceof IdentifierNode.KeySegment); - IdentifierNode.KeySegment s2 = - (IdentifierNode.KeySegment) segments.get(2); + assertEquals(Quoting.QUOTED, s1.getQuoting()); + assertTrue(segments.get(2) instanceof KeySegment); + KeySegment s2 = + (KeySegment) segments.get(2); assertEquals(1, s2.getKeyParts().size()); - final IdentifierNode.NameSegment s2k0 = s2.getKeyParts().get(0); + final NameSegment s2k0 = s2.getKeyParts().get(0); assertEquals("Maingroup (xyz)", s2k0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s2k0.getQuoting()); + assertEquals(Quoting.QUOTED, s2k0.getQuoting()); } /** * Advanced test for the {@link IdentifierNode#parseIdentifier} method. */ public void testParseIdentifierAdvanced() { - List segments; + List segments; // detailed example, per javadoc // @@ -450,39 +449,39 @@ public void testParseIdentifierAdvanced() { segments = IdentifierParser.parseIdentifier( "[Customers].[City].&[San Francisco]&CA&USA.&[cust1234]"); assertEquals(4, segments.size()); - final IdentifierNode.Segment s0 = segments.get(0); + final IdentifierSegment s0 = segments.get(0); assertEquals("Customers", s0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s0.getQuoting()); - final IdentifierNode.Segment s1 = segments.get(1); + assertEquals(Quoting.QUOTED, s0.getQuoting()); + final IdentifierSegment s1 = segments.get(1); assertEquals("City", s1.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s1.getQuoting()); - assertTrue(segments.get(2) instanceof IdentifierNode.KeySegment); - IdentifierNode.KeySegment s2 = - (IdentifierNode.KeySegment) segments.get(2); + assertEquals(Quoting.QUOTED, s1.getQuoting()); + assertTrue(segments.get(2) instanceof KeySegment); + KeySegment s2 = + (KeySegment) segments.get(2); assertEquals(3, s2.getKeyParts().size()); - final IdentifierNode.NameSegment s2k0 = s2.getKeyParts().get(0); + final NameSegment s2k0 = s2.getKeyParts().get(0); assertEquals("San Francisco", s2k0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s2k0.getQuoting()); - final IdentifierNode.NameSegment s2k1 = s2.getKeyParts().get(1); + assertEquals(Quoting.QUOTED, s2k0.getQuoting()); + final NameSegment s2k1 = s2.getKeyParts().get(1); assertEquals("CA", s2k1.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s2k0.getQuoting()); - final IdentifierNode.NameSegment s2k2 = s2.getKeyParts().get(0); + assertEquals(Quoting.QUOTED, s2k0.getQuoting()); + final NameSegment s2k2 = s2.getKeyParts().get(0); assertEquals("San Francisco", s2k2.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s2k2.getQuoting()); - IdentifierNode.KeySegment s3 = - (IdentifierNode.KeySegment) segments.get(3); + assertEquals(Quoting.QUOTED, s2k2.getQuoting()); + KeySegment s3 = + (KeySegment) segments.get(3); assertNull(s3.getName()); assertEquals(1, s3.getKeyParts().size()); - final IdentifierNode.NameSegment s3k0 = s3.getKeyParts().get(0); + final NameSegment s3k0 = s3.getKeyParts().get(0); assertEquals("cust1234", s3k0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, s3k0.getQuoting()); + assertEquals(Quoting.QUOTED, s3k0.getQuoting()); } /** * Tests the {@link IdentifierParser#parseIdentifierList(String)} method. */ public void testParseIdentifierList() { - List> list; + List> list; list = IdentifierParser.parseIdentifierList("{foo, baz.baz}"); assertEquals(2, list.size()); @@ -508,11 +507,11 @@ public void testParseIdentifierList() { assertEquals(1, list.get(0).size()); assertEquals(4, list.get(1).size()); assertEquals("baz", list.get(1).get(0).getName()); - final IdentifierNode.Segment id1s1 = list.get(1).get(1); + final IdentifierSegment id1s1 = list.get(1).get(1); assertEquals(2, id1s1.getKeyParts().size()); assertEquals("k0", id1s1.getKeyParts().get(0).getName()); assertEquals("k1", id1s1.getKeyParts().get(1).getName()); - final IdentifierNode.Segment id1s2 = list.get(1).get(2); + final IdentifierSegment id1s2 = list.get(1).get(2); assertEquals(1, id1s2.getKeyParts().size()); assertEquals("m0", id1s2.getKeyParts().get(0).getName()); assertEquals("boo", list.get(1).get(3).getName()); @@ -564,10 +563,10 @@ public void memberComplete() { public void segmentComplete( ParseRegion region, String name, - IdentifierNode.Quoting quoting, + Quoting quoting, Syntax syntax) { - if (quoting == IdentifierNode.Quoting.QUOTED) { + if (quoting == Quoting.QUOTED) { buf.append("[").append(name).append("]"); } else { buf.append(name); diff --git a/testsrc/org/olap4j/mdx/MdxTest.java b/testsrc/org/olap4j/mdx/MdxTest.java index bf3c0df..23e4864 100644 --- a/testsrc/org/olap4j/mdx/MdxTest.java +++ b/testsrc/org/olap4j/mdx/MdxTest.java @@ -41,43 +41,43 @@ public void testQuoteMdxIdentifier() { "[Store].[USA].[California]", IdentifierNode.unparseIdentifierList( Arrays.asList( - new IdentifierNode.NameSegment( - null, "Store", IdentifierNode.Quoting.QUOTED), - new IdentifierNode.NameSegment( - null, "USA", IdentifierNode.Quoting.QUOTED), - new IdentifierNode.NameSegment( - null, "California", IdentifierNode.Quoting.QUOTED)))); + new NameSegment( + null, "Store", Quoting.QUOTED), + new NameSegment( + null, "USA", Quoting.QUOTED), + new NameSegment( + null, "California", Quoting.QUOTED)))); } public void testImplode() { - List fooBar = - Arrays.asList( - new IdentifierNode.NameSegment( - null, "foo", IdentifierNode.Quoting.UNQUOTED), - new IdentifierNode.NameSegment( - null, "bar", IdentifierNode.Quoting.QUOTED)); + List fooBar = + Arrays.asList( + new NameSegment( + null, "foo", Quoting.UNQUOTED), + new NameSegment( + null, "bar", Quoting.QUOTED)); assertEquals( "foo.[bar]", IdentifierNode.unparseIdentifierList(fooBar)); - List empty = Collections.emptyList(); + List empty = Collections.emptyList(); assertEquals("", IdentifierNode.unparseIdentifierList(empty)); - List nasty = - Arrays.asList( - new IdentifierNode.NameSegment( - null, "string", IdentifierNode.Quoting.QUOTED), - new IdentifierNode.NameSegment( - null, "with", IdentifierNode.Quoting.QUOTED), - new IdentifierNode.NameSegment( - null, "a [bracket] in it", IdentifierNode.Quoting.QUOTED)); + List nasty = + Arrays.asList( + new NameSegment( + null, "string", Quoting.QUOTED), + new NameSegment( + null, "with", Quoting.QUOTED), + new NameSegment( + null, "a [bracket] in it", Quoting.QUOTED)); assertEquals( "[string].[with].[a [bracket]] in it]", IdentifierNode.unparseIdentifierList(nasty)); } public void testParseIdentifier() { - List segments = + List segments = IdentifierNode.parseIdentifier( "[string].[with].[a [bracket]] in it]").getSegmentList(); assertEquals(3, segments.size()); @@ -85,7 +85,7 @@ public void testParseIdentifier() { "a [bracket] in it", segments.get(2).getName()); assertEquals( - IdentifierNode.Quoting.QUOTED, + Quoting.QUOTED, segments.get(2).getQuoting()); segments = IdentifierNode.parseIdentifier( @@ -98,10 +98,10 @@ public void testParseIdentifier() { segments = IdentifierNode.parseIdentifier("[foo].bar").getSegmentList(); assertEquals(2, segments.size()); assertEquals( - IdentifierNode.Quoting.QUOTED, + Quoting.QUOTED, segments.get(0).getQuoting()); assertEquals( - IdentifierNode.Quoting.UNQUOTED, + Quoting.UNQUOTED, segments.get(1).getQuoting()); try { @@ -115,6 +115,43 @@ public void testParseIdentifier() { } } + /** + * Unit test for {@link org.olap4j.mdx.IdentifierNode#ofNames(String...)}. + */ + public void testIdentifierOfNames() { + IdentifierNode identifierNode = + IdentifierNode.ofNames( + "string", "with", "a [bracket] in it"); + List segments = + identifierNode.getSegmentList(); + assertEquals(3, segments.size()); + assertEquals( + "a [bracket] in it", + segments.get(2).getName()); + assertEquals( + Quoting.QUOTED, + segments.get(2).getQuoting()); + + assertEquals( + "xxx", + identifierNode.toString()); + + // Empty array is valid. (I don't feel strongly about this.) + identifierNode = + IdentifierNode.ofNames(); + assertEquals(0, identifierNode.getSegmentList().size()); + assertEquals("", identifierNode.toString()); + + // Array containing null is not valid. + try { + identifierNode = + IdentifierNode.ofNames("foo", null, "bar"); + fail("expected error, got " + identifierNode); + } catch (NullPointerException e) { + // ok + } + } + /** * Tests that escaped single quotes ('') nested inside a quoted * part of a query are handled correctly. The MDX language allows diff --git a/testsrc/org/olap4j/test/ParserTest.java b/testsrc/org/olap4j/test/ParserTest.java index 55d31ce..465da90 100644 --- a/testsrc/org/olap4j/test/ParserTest.java +++ b/testsrc/org/olap4j/test/ParserTest.java @@ -592,36 +592,36 @@ public void testIdWithKey() { assertNotNull(id.getRegion()); assertEquals(3, id.getSegmentList().size()); - final IdentifierNode.Segment seg0 = id.getSegmentList().get(0); + final IdentifierSegment seg0 = id.getSegmentList().get(0); assertNotNull(seg0.getRegion()); assertEquals("Foo", seg0.getName()); - assertEquals(IdentifierNode.Quoting.QUOTED, seg0.getQuoting()); + assertEquals(Quoting.QUOTED, seg0.getQuoting()); - final IdentifierNode.Segment seg1 = id.getSegmentList().get(1); - assertEquals(IdentifierNode.Quoting.KEY, seg1.getQuoting()); + final IdentifierSegment seg1 = id.getSegmentList().get(1); + assertEquals(Quoting.KEY, seg1.getQuoting()); assertNull(seg1.getName()); - List keyParts = seg1.getKeyParts(); + List keyParts = seg1.getKeyParts(); assertNotNull(keyParts); assertEquals(2, keyParts.size()); assertEquals("Key1", keyParts.get(0).getName()); assertEquals( - IdentifierNode.Quoting.UNQUOTED, keyParts.get(0).getQuoting()); + Quoting.UNQUOTED, keyParts.get(0).getQuoting()); assertEquals("Key2", keyParts.get(1).getName()); assertEquals( - IdentifierNode.Quoting.UNQUOTED, keyParts.get(1).getQuoting()); + Quoting.UNQUOTED, keyParts.get(1).getQuoting()); - final IdentifierNode.Segment seg2 = id.getSegmentList().get(2); + final IdentifierSegment seg2 = id.getSegmentList().get(2); assertNotNull(seg2.getRegion()); - assertEquals(IdentifierNode.Quoting.KEY, seg2.getQuoting()); - List keyParts2 = seg2.getKeyParts(); + assertEquals(Quoting.KEY, seg2.getQuoting()); + List keyParts2 = seg2.getKeyParts(); assertNotNull(keyParts2); assertEquals(3, keyParts2.size()); assertEquals( - IdentifierNode.Quoting.QUOTED, keyParts2.get(0).getQuoting()); + Quoting.QUOTED, keyParts2.get(0).getQuoting()); assertEquals( - IdentifierNode.Quoting.UNQUOTED, keyParts2.get(1).getQuoting()); + Quoting.UNQUOTED, keyParts2.get(1).getQuoting()); assertEquals( - IdentifierNode.Quoting.QUOTED, keyParts2.get(2).getQuoting()); + Quoting.QUOTED, keyParts2.get(2).getQuoting()); assertEquals("5", keyParts2.get(2).getName()); assertNotNull(keyParts2.get(2).getRegion()); @@ -759,20 +759,20 @@ public void testIdentifier() { } id = new IdentifierNode( - new IdentifierNode.NameSegment("foo")); + new NameSegment("foo")); assertEquals("[foo]", id.toString()); // append does not mutate IdentifierNode id2 = id.append( - new IdentifierNode.KeySegment( - new IdentifierNode.NameSegment( - null, "bar", IdentifierNode.Quoting.QUOTED))); + new KeySegment( + new NameSegment( + null, "bar", Quoting.QUOTED))); assertTrue(id != id2); assertEquals("[foo]", id.toString()); assertEquals("[foo].&[bar]", id2.toString()); // cannot mutate segment list - final List segments = id.getSegmentList(); + final List segments = id.getSegmentList(); try { segments.remove(0); fail("expected exception"); @@ -787,7 +787,7 @@ public void testIdentifier() { } try { segments.add( - new IdentifierNode.NameSegment("baz")); + new NameSegment("baz")); fail("expected exception"); } catch (UnsupportedOperationException e) { // ok @@ -848,16 +848,16 @@ public void testWithAdd() { SelectNode selectNode = new SelectNode(); IdentifierNode startDate = new IdentifierNode( - new IdentifierNode.NameSegment("Date"), - new IdentifierNode.NameSegment("2010-01-03")); + new NameSegment("Date"), + new NameSegment("2010-01-03")); IdentifierNode endDate = new IdentifierNode( - new IdentifierNode.NameSegment("Date"), - new IdentifierNode.NameSegment("2010-10-03")); + new NameSegment("Date"), + new NameSegment("2010-10-03")); IdentifierNode name = new IdentifierNode( - new IdentifierNode.NameSegment("Date"), - new IdentifierNode.NameSegment("Date Range")); + new NameSegment("Date"), + new NameSegment("Date Range")); CallNode cn = new CallNode(null, ":", Syntax.Infix, startDate, endDate); ParseTreeNode exp = new CallNode( diff --git a/testsrc/org/olap4j/test/TestContext.java b/testsrc/org/olap4j/test/TestContext.java index d378f00..6f0c1c0 100644 --- a/testsrc/org/olap4j/test/TestContext.java +++ b/testsrc/org/olap4j/test/TestContext.java @@ -16,8 +16,7 @@ import org.olap4j.*; import org.olap4j.impl.Olap4jUtil; -import org.olap4j.mdx.ParseTreeNode; -import org.olap4j.mdx.ParseTreeWriter; +import org.olap4j.mdx.*; import org.olap4j.layout.TraditionalCellSetFormatter; import org.apache.commons.dbcp.*; @@ -448,6 +447,16 @@ public static String getStackTrace(Throwable e) { return sw.toString(); } + /** + * Shorthand way to convert array of names into segment list. + * + * @param names Array of names + * @return Segment list + */ + public static List nameList(String... names) { + return IdentifierNode.ofNames(names).getSegmentList(); + } + /** * Checks that an exception is not null and the stack trace contains a * given string. Fails otherwise.