/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr.query.parse;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import java.util.List;
import javax.jcr.Binary;
import org.junit.Before;
import org.junit.Test;
import org.modeshape.common.FixFor;
import org.modeshape.common.text.ParsingException;
import org.modeshape.common.text.Position;
import org.modeshape.common.text.TokenStream;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.api.query.qom.Operator;
import org.modeshape.jcr.api.value.DateTime;
import org.modeshape.jcr.query.model.And;
import org.modeshape.jcr.query.model.Between;
import org.modeshape.jcr.query.model.BindVariableName;
import org.modeshape.jcr.query.model.Cast;
import org.modeshape.jcr.query.model.ChildCount;
import org.modeshape.jcr.query.model.ChildNode;
import org.modeshape.jcr.query.model.Constraint;
import org.modeshape.jcr.query.model.DescendantNode;
import org.modeshape.jcr.query.model.DynamicOperand;
import org.modeshape.jcr.query.model.FullTextSearch;
import org.modeshape.jcr.query.model.FullTextSearch.Conjunction;
import org.modeshape.jcr.query.model.FullTextSearch.Disjunction;
import org.modeshape.jcr.query.model.FullTextSearch.Term;
import org.modeshape.jcr.query.model.FullTextSearchScore;
import org.modeshape.jcr.query.model.Join;
import org.modeshape.jcr.query.model.Length;
import org.modeshape.jcr.query.model.Limit;
import org.modeshape.jcr.query.model.Literal;
import org.modeshape.jcr.query.model.LowerCase;
import org.modeshape.jcr.query.model.NamedSelector;
import org.modeshape.jcr.query.model.NodeDepth;
import org.modeshape.jcr.query.model.NodeLocalName;
import org.modeshape.jcr.query.model.NodeName;
import org.modeshape.jcr.query.model.NodePath;
import org.modeshape.jcr.query.model.Not;
import org.modeshape.jcr.query.model.Or;
import org.modeshape.jcr.query.model.Order;
import org.modeshape.jcr.query.model.Ordering;
import org.modeshape.jcr.query.model.PropertyExistence;
import org.modeshape.jcr.query.model.PropertyValue;
import org.modeshape.jcr.query.model.QueryCommand;
import org.modeshape.jcr.query.model.ReferenceValue;
import org.modeshape.jcr.query.model.SameNode;
import org.modeshape.jcr.query.model.SelectorName;
import org.modeshape.jcr.query.model.Source;
import org.modeshape.jcr.query.model.StaticOperand;
import org.modeshape.jcr.query.model.Subquery;
import org.modeshape.jcr.query.model.TypeSystem;
import org.modeshape.jcr.query.model.UpperCase;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.Path;
import org.modeshape.jcr.value.PropertyType;
/**
*
*/
public class SqlQueryParserTest {
private TypeSystem typeSystem;
private BasicSqlQueryParser parser;
@Before
public void beforeEach() {
typeSystem = new ExecutionContext().getValueFactories().getTypeSystem();
parser = new BasicSqlQueryParser();
}
// ----------------------------------------------------------------------------------------------------------------
// parseQuery
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseNominalQueries() {
parse("SELECT * FROM tableA");
parse("SELECT column1 FROM tableA");
parse("SELECT tableA.column1 FROM tableA");
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA INNER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA LEFT OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA RIGHT OUTER JOIN tableB ON tableA.id = tableB.id");
}
@Test
public void shouldParseQueriesWithNonSqlColumnNames() {
parse("SELECT * FROM [dna:tableA]");
parse("SELECT [jcr:column1] FROM [dna:tableA]");
parse("SELECT 'jcr:column1' FROM 'dna:tableA'");
parse("SELECT \"jcr:column1\" FROM \"dna:tableA\"");
}
@FixFor( "MODE-869" )
@Test
public void shouldParseQueriesWithSubqueries() {
parse("SELECT * FROM tableA WHERE PATH() LIKE (SELECT path FROM tableB)");
parse("SELECT * FROM tableA WHERE PATH() LIKE (SELECT path FROM tableB) AND tableA.propX = 'foo'");
parse("SELECT * FROM tableA WHERE PATH() LIKE (((SELECT path FROM tableB)))");
parse("SELECT * FROM tableA WHERE PATH() LIKE (SELECT path FROM tableB WHERE prop < 2)");
parse("SELECT * FROM tableA WHERE PATH() IN (SELECT path FROM tableB) AND tableA.propX = 'foo'");
parse("SELECT * FROM tableA WHERE PATH() NOT IN (SELECT path FROM tableB) AND tableA.propX = 'foo'");
}
@Test
public void shouldParseQueriesSelectingFromAllTables() {
parse("SELECT * FROM __AllTables__");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseQueriesWithNoFromClause() {
parse("SELECT 'jcr:column1'");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseQueriesWithIncompleteFromClause() {
parse("SELECT 'jcr:column1' FROM ");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseQueriesWithUnmatchedSingleQuoteCharacters() {
parse("SELECT 'jcr:column1' FROM \"dna:tableA'");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseQueriesWithUnmatchedDoubleQuoteCharacters() {
parse("SELECT \"jcr:column1' FROM \"dna:tableA\"");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseQueriesWithUnmatchedBracketQuoteCharacters() {
parse("SELECT [jcr:column1' FROM [dna:tableA]");
}
@Test
public void shouldParseQueriesWithSelectStar() {
parse("SELECT * FROM tableA");
parse("SELECT tableA.* FROM tableA");
parse("SELECT tableA.column1, tableB.* FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.*, tableB.column2 FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.*, tableB.* FROM tableA JOIN tableB ON tableA.id = tableB.id");
}
@Test
public void shouldParseQueriesWithAllKindsOfJoins() {
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA INNER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA LEFT OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA RIGHT OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA FULL OUTER JOIN tableB ON tableA.id = tableB.id");
parse("SELECT tableA.column1, tableB.column2 FROM tableA CROSS JOIN tableB ON tableA.id = tableB.id");
}
@Test
public void shouldParseQueriesWithMultipleJoins() {
parse("SELECT * FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT * FROM tableA JOIN tableB ON tableA.id = tableB.id JOIN tableC ON tableA.id2 = tableC.id2");
}
@Test
public void shouldParseQueriesWithEquiJoinCriteria() {
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON tableA.id = tableB.id");
parse("SELECT * FROM tableA JOIN tableB ON tableA.id = tableB.id JOIN tableC ON tableA.id2 = tableC.id2");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseEquiJoinCriteriaMissingPropertyName() {
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON tableA = tableB.id");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseEquiJoinCriteriaMissingTableName() {
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON column1 = tableB.id");
}
@Test( expected = ParsingException.class )
public void shouldFailToParseEquiJoinCriteriaMissingEquals() {
parse("SELECT tableA.column1, tableB.column2 FROM tableA JOIN tableB ON column1 tableB.id");
}
@Test
public void shouldParseQueriesOnMultpleLines() {
parse("SELECT * \nFROM tableA");
parse("SELECT \ncolumn1 \nFROM tableA");
parse("SELECT \ntableA.column1 \nFROM\n tableA");
parse("SELECT tableA.\ncolumn1, \ntableB.column2 \nFROM tableA JOIN \ntableB ON tableA.id \n= tableB.\nid");
}
@Test
public void shouldParseQueriesThatUseDifferentCaseForKeywords() {
parse("select * from tableA");
parse("SeLeCt * from tableA");
parse("select column1 from tableA");
parse("select tableA.column1 from tableA");
parse("select tableA.column1, tableB.column2 from tableA join tableB on tableA.id = tableB.id");
}
@Test
public void shouldParseUnionQueries() {
parse("SELECT * FROM tableA UNION SELECT * FROM tableB");
parse("SELECT * FROM tableA UNION ALL SELECT * FROM tableB");
parse("SELECT * FROM tableA UNION SELECT * FROM tableB UNION SELECT * FROM tableC");
parse("SELECT * FROM tableA UNION ALL SELECT * FROM tableB UNION SELECT * FROM tableC");
}
@Test
public void shouldParseIntersectQueries() {
parse("SELECT * FROM tableA INTERSECT SELECT * FROM tableB");
parse("SELECT * FROM tableA INTERSECT ALL SELECT * FROM tableB");
parse("SELECT * FROM tableA INTERSECT SELECT * FROM tableB INTERSECT SELECT * FROM tableC");
parse("SELECT * FROM tableA INTERSECT ALL SELECT * FROM tableB INTERSECT ALL SELECT * FROM tableC");
}
@Test
public void shouldParseExceptQueries() {
parse("SELECT * FROM tableA EXCEPT SELECT * FROM tableB");
parse("SELECT * FROM tableA EXCEPT ALL SELECT * FROM tableB");
parse("SELECT * FROM tableA EXCEPT SELECT * FROM tableB EXCEPT SELECT * FROM tableC");
parse("SELECT * FROM tableA EXCEPT ALL SELECT * FROM tableB EXCEPT ALL SELECT * FROM tableC");
}
// ----------------------------------------------------------------------------------------------------------------
// parseSetQuery
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// parseSelect
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// parseFrom
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// parseJoinCondition
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// parseWhere
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithValidExpressions() {
assertParseConstraint("ISSAMENODE('/a/b')");
assertParseConstraint("ISSAMENODE('/a/b') AND NOT(ISCHILDNODE('/parent'))");
assertParseConstraint("ISSAMENODE('/a/b') AND (NOT(ISCHILDNODE('/parent')))");
assertParseConstraint("ISSAMENODE('/a/b') AND (NOT(tableA.id < 1234)))");
}
protected void assertParseConstraint( String expression ) {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
parser.parseConstraint(tokens(expression), typeSystem, selector);
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - between
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithValidBetweenExpressionUsing() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("tableA.id BETWEEN 'lower' AND 'upper'"), typeSystem, selector);
assertThat(constraint, is(instanceOf(Between.class)));
Between between = (Between)constraint;
assertThat(between.isLowerBoundIncluded(), is(true));
assertThat(between.isUpperBoundIncluded(), is(true));
assertThat(between.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue operand = (PropertyValue)between.getOperand();
assertThat(operand.selectorName(), is(selector.name()));
assertThat(operand.getPropertyName(), is("id"));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(literal("lower")));
assertThat(between.getUpperBound(), is(literal("upper")));
}
@Test
public void shouldParseConstraintFromStringWithValidBetweenExpressionUsingExclusiveAndExclusive() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("tableA.id BETWEEN 'lower' EXCLUSIVE AND 'upper' EXCLUSIVE"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(Between.class)));
Between between = (Between)constraint;
assertThat(between.isLowerBoundIncluded(), is(false));
assertThat(between.isUpperBoundIncluded(), is(false));
assertThat(between.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue operand = (PropertyValue)between.getOperand();
assertThat(operand.selectorName(), is(selector.name()));
assertThat(operand.getPropertyName(), is("id"));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(literal("lower")));
assertThat(between.getUpperBound(), is(literal("upper")));
}
@Test
public void shouldParseConstraintFromStringWithValidBetweenExpressionUsingInclusiveAndExclusive() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("tableA.id BETWEEN 'lower' AND 'upper' EXCLUSIVE"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(Between.class)));
Between between = (Between)constraint;
assertThat(between.isLowerBoundIncluded(), is(true));
assertThat(between.isUpperBoundIncluded(), is(false));
assertThat(between.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue operand = (PropertyValue)between.getOperand();
assertThat(operand.selectorName(), is(selector.name()));
assertThat(operand.getPropertyName(), is("id"));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(literal("lower")));
assertThat(between.getUpperBound(), is(literal("upper")));
}
@Test
public void shouldParseConstraintFromStringWithValidBetweenExpressionUsingExclusiveAndInclusive() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("tableA.id BETWEEN 'lower' EXCLUSIVE AND 'upper'"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(Between.class)));
Between between = (Between)constraint;
assertThat(between.isLowerBoundIncluded(), is(false));
assertThat(between.isUpperBoundIncluded(), is(true));
assertThat(between.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue operand = (PropertyValue)between.getOperand();
assertThat(operand.selectorName(), is(selector.name()));
assertThat(operand.getPropertyName(), is("id"));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(literal("lower")));
assertThat(between.getUpperBound(), is(literal("upper")));
}
@Test
public void shouldParseConstraintFromStringWithValidNotBetweenExpression() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("tableA.id NOT BETWEEN 'lower' AND 'upper'"), typeSystem, selector);
assertThat(constraint, is(instanceOf(Not.class)));
constraint = ((Not)constraint).getConstraint();
assertThat(constraint, is(instanceOf(Between.class)));
Between between = (Between)constraint;
assertThat(between.isLowerBoundIncluded(), is(true));
assertThat(between.isUpperBoundIncluded(), is(true));
assertThat(between.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue operand = (PropertyValue)between.getOperand();
assertThat(operand.selectorName(), is(selector.name()));
assertThat(operand.getPropertyName(), is("id"));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(instanceOf(Literal.class)));
assertThat(between.getLowerBound(), is(literal("lower")));
assertThat(between.getUpperBound(), is(literal("upper")));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - parentheses
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithOuterParentheses() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("( ISSAMENODE('/a/b') )"), typeSystem, selector);
assertThat(constraint, is(instanceOf(SameNode.class)));
SameNode same = (SameNode)constraint;
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b"));
}
@Test
public void shouldParseConstraintFromStringWithMultipleOuterParentheses() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("((( ISSAMENODE('/a/b') )))"), typeSystem, selector);
assertThat(constraint, is(instanceOf(SameNode.class)));
SameNode same = (SameNode)constraint;
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b"));
}
@Test
public void shouldParseConstraintFromStringWithParenthesesAndConjunctionAndDisjunctions() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE('/a/b') OR (ISSAMENODE('/c/d') AND ISSAMENODE('/e/f'))"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(Or.class)));
Or or = (Or)constraint;
assertThat(or.left(), is(instanceOf(SameNode.class)));
SameNode first = (SameNode)or.left();
assertThat(first.selectorName(), is(selectorName("tableA")));
assertThat(first.getPath(), is("/a/b"));
assertThat(or.right(), is(instanceOf(And.class)));
And and = (And)or.right();
assertThat(and.left(), is(instanceOf(SameNode.class)));
SameNode second = (SameNode)and.left();
assertThat(second.selectorName(), is(selectorName("tableA")));
assertThat(second.getPath(), is("/c/d"));
assertThat(and.right(), is(instanceOf(SameNode.class)));
SameNode third = (SameNode)and.right();
assertThat(third.selectorName(), is(selectorName("tableA")));
assertThat(third.getPath(), is("/e/f"));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - AND
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithAndExpressionWithNoParentheses() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE('/a/b/c') AND CONTAINS(p1,term1)"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(And.class)));
And and = (And)constraint;
assertThat(and.left(), is(instanceOf(SameNode.class)));
SameNode same = (SameNode)and.left();
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
assertThat(and.right(), is(instanceOf(FullTextSearch.class)));
FullTextSearch search = (FullTextSearch)and.right();
assertThat(search.selectorName(), is(selectorName("tableA")));
assertThat(search.getPropertyName(), is("p1"));
assertThat(search.fullTextSearchExpression(), is("term1"));
}
@Test
public void shouldParseConstraintFromStringWithMultipleAndExpressions() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE('/a/b/c') AND CONTAINS(p1,term1) AND CONTAINS(p2,term2)"),
typeSystem,
selector);
assertThat(constraint, is(instanceOf(And.class)));
And and = (And)constraint;
assertThat(and.left(), is(instanceOf(SameNode.class)));
SameNode same = (SameNode)and.left();
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
assertThat(and.right(), is(instanceOf(And.class)));
And secondAnd = (And)and.right();
assertThat(secondAnd.left(), is(instanceOf(FullTextSearch.class)));
FullTextSearch search1 = (FullTextSearch)secondAnd.left();
assertThat(search1.selectorName(), is(selectorName("tableA")));
assertThat(search1.getPropertyName(), is("p1"));
assertThat(search1.fullTextSearchExpression(), is("term1"));
assertThat(secondAnd.right(), is(instanceOf(FullTextSearch.class)));
FullTextSearch search2 = (FullTextSearch)secondAnd.right();
assertThat(search2.selectorName(), is(selectorName("tableA")));
assertThat(search2.getPropertyName(), is("p2"));
assertThat(search2.fullTextSearchExpression(), is("term2"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithAndExpressionWithNoSecondConstraint() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
parser.parseConstraint(tokens("ISSAMENODE('/a/b/c') AND WHAT THE HECK IS THIS"), typeSystem, selector);
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - OR
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithOrExpressionWithNoParentheses() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE('/a/b/c') OR CONTAINS(p1,term1)"), typeSystem, selector);
assertThat(constraint, is(instanceOf(Or.class)));
Or or = (Or)constraint;
assertThat(or.left(), is(instanceOf(SameNode.class)));
SameNode same = (SameNode)or.left();
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
assertThat(or.right(), is(instanceOf(FullTextSearch.class)));
FullTextSearch search = (FullTextSearch)or.right();
assertThat(search.selectorName(), is(selectorName("tableA")));
assertThat(search.getPropertyName(), is("p1"));
assertThat(search.fullTextSearchExpression(), is("term1"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithOrExpressionWithNoSecondConstraint() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
parser.parseConstraint(tokens("ISSAMENODE('/a/b/c') OR WHAT THE HECK IS THIS"), typeSystem, selector);
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - NOT
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithNotSameNodeExpression() {
Constraint constraint = parser.parseConstraint(tokens("NOT(ISSAMENODE(tableA,'/a/b/c'))"), typeSystem, mock(Source.class));
assertThat(constraint, is(instanceOf(Not.class)));
Not not = (Not)constraint;
assertThat(not.getConstraint(), is(instanceOf(SameNode.class)));
SameNode same = (SameNode)not.getConstraint();
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithNotConstraintWithOutOpeningParenthesis() {
parser.parseConstraint(tokens("NOT CONTAINS(propertyA 'term1 term2 -term3')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithNotConstraintWithOutClosingParenthesis() {
parser.parseConstraint(tokens("NOT( CONTAINS(propertyA 'term1 term2 -term3') BLAH"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - CONTAINS
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithIsContainsExpressionWithPropertyAndNoSelectorNameOnlyIfThereIsOneSelectorSource() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("CONTAINS(propertyA,'term1 term2 -term3')"), typeSystem, selector);
assertThat(constraint, is(instanceOf(FullTextSearch.class)));
FullTextSearch search = (FullTextSearch)constraint;
assertThat(search.selectorName(), is(selectorName("tableA")));
assertThat(search.getPropertyName(), is("propertyA"));
assertThat(search.fullTextSearchExpression(), is("term1 term2 -term3"));
}
@Test
public void shouldParseConstraintFromStringWithIsContainsExpressionWithSelectorNameAndProperty() {
Constraint constraint = parser.parseConstraint(tokens("CONTAINS(tableA.propertyA,'term1 term2 -term3')"),
typeSystem,
mock(Source.class));
assertThat(constraint, is(instanceOf(FullTextSearch.class)));
FullTextSearch search = (FullTextSearch)constraint;
assertThat(search.selectorName(), is(selectorName("tableA")));
assertThat(search.getPropertyName(), is("propertyA"));
assertThat(search.fullTextSearchExpression(), is("term1 term2 -term3"));
}
@Test
public void shouldParseConstraintFromStringWithIsContainsExpressionWithSelectorNameAndAnyProperty() {
Constraint constraint = parser.parseConstraint(tokens("CONTAINS(tableA.*,'term1 term2 -term3')"),
typeSystem,
mock(Source.class));
assertThat(constraint, is(instanceOf(FullTextSearch.class)));
FullTextSearch search = (FullTextSearch)constraint;
assertThat(search.selectorName(), is(selectorName("tableA")));
assertThat(search.getPropertyName(), is(nullValue()));
assertThat(search.fullTextSearchExpression(), is("term1 term2 -term3"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithContainsExpressionWithNoCommaAfterSelectorName() {
parser.parseConstraint(tokens("CONTAINS(propertyA 'term1 term2 -term3')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithContainsExpressionWithNoClosingParenthesis() {
parser.parseConstraint(tokens("CONTAINS(propertyA,'term1 term2 -term3' OTHER"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithContainsExpressionWithNoOpeningParenthesis() {
parser.parseConstraint(tokens("CONTAINS propertyA,'term1 term2 -term3')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithContainsExpressionWithNoSelectorNameIfSourceIsNotSelector() {
parser.parseConstraint(tokens("CONTAINS(propertyA,'term1 term2 -term3')"), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - ISSAMENODE
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithIsSameNodeExpressionWithPathOnlyIfThereIsOneSelectorSource() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE('/a/b/c')"), typeSystem, selector);
assertThat(constraint, is(instanceOf(SameNode.class)));
SameNode same = (SameNode)constraint;
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
}
@Test
public void shouldParseConstraintFromStringWithIsSameNodeExpressionWithSelectorNameAndPath() {
Constraint constraint = parser.parseConstraint(tokens("ISSAMENODE(tableA,'/a/b/c')"), typeSystem, mock(Source.class));
assertThat(constraint, is(instanceOf(SameNode.class)));
SameNode same = (SameNode)constraint;
assertThat(same.selectorName(), is(selectorName("tableA")));
assertThat(same.getPath(), is("/a/b/c"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsSameNodeExpressionWithNoCommaAfterSelectorName() {
parser.parseConstraint(tokens("ISSAMENODE(tableA '/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsSameNodeExpressionWithNoClosingParenthesis() {
parser.parseConstraint(tokens("ISSAMENODE(tableA,'/a/b/c' AND"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsSameNodeExpressionWithNoOpeningParenthesis() {
parser.parseConstraint(tokens("ISSAMENODE tableA,'/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsSameNodeExpressionWithNoSelectorNameIfSourceIsNotSelector() {
parser.parseConstraint(tokens("ISSAMENODE('/a/b/c')"), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - ISCHILDNODE
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithIsChildNodeExpressionWithPathOnlyIfThereIsOneSelectorSource() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISCHILDNODE('/a/b/c')"), typeSystem, selector);
assertThat(constraint, is(instanceOf(ChildNode.class)));
ChildNode child = (ChildNode)constraint;
assertThat(child.selectorName(), is(selectorName("tableA")));
assertThat(child.getParentPath(), is("/a/b/c"));
}
@Test
public void shouldParseConstraintFromStringWithIsChildNodeExpressionWithSelectorNameAndPath() {
Constraint constraint = parser.parseConstraint(tokens("ISCHILDNODE(tableA,'/a/b/c')"), typeSystem, mock(Source.class));
assertThat(constraint, is(instanceOf(ChildNode.class)));
ChildNode child = (ChildNode)constraint;
assertThat(child.selectorName(), is(selectorName("tableA")));
assertThat(child.getParentPath(), is("/a/b/c"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsChildNodeExpressionWithNoCommaAfterSelectorName() {
parser.parseConstraint(tokens("ISCHILDNODE(tableA '/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsChildNodeExpressionWithNoClosingParenthesis() {
parser.parseConstraint(tokens("ISCHILDNODE(tableA,'/a/b/c' AND"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsChildNodeExpressionWithNoOpeningParenthesis() {
parser.parseConstraint(tokens("ISCHILDNODE tableA,'/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsChildNodeExpressionWithNoSelectorNameIfSourceIsNotSelector() {
parser.parseConstraint(tokens("ISCHILDNODE('/a/b/c')"), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseConstraint - ISDESCENDANTNODE
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseConstraintFromStringWithIsDescendantNodeExpressionWithPathOnlyIfThereIsOneSelectorSource() {
NamedSelector selector = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parseConstraint(tokens("ISDESCENDANTNODE('/a/b/c')"), typeSystem, selector);
assertThat(constraint, is(instanceOf(DescendantNode.class)));
DescendantNode descendant = (DescendantNode)constraint;
assertThat(descendant.selectorName(), is(selectorName("tableA")));
assertThat(descendant.getAncestorPath(), is("/a/b/c"));
}
@Test
public void shouldParseConstraintFromStringWithIsDescendantNodeExpressionWithSelectorNameAndPath() {
Constraint constraint = parser.parseConstraint(tokens("ISDESCENDANTNODE(tableA,'/a/b/c')"),
typeSystem,
mock(Source.class));
assertThat(constraint, is(instanceOf(DescendantNode.class)));
DescendantNode descendant = (DescendantNode)constraint;
assertThat(descendant.selectorName(), is(selectorName("tableA")));
assertThat(descendant.getAncestorPath(), is("/a/b/c"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsDescendantNodeExpressionWithNoCommaAfterSelectorName() {
parser.parseConstraint(tokens("ISDESCENDANTNODE(tableA '/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsDescendantNodeExpressionWithNoClosingParenthesis() {
parser.parseConstraint(tokens("ISDESCENDANTNODE(tableA,'/a/b/c' AND"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsDescendantNodeExpressionWithNoOpeningParenthesis() {
parser.parseConstraint(tokens("ISDESCENDANTNODE tableA,'/a/b/c')"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseConstraintFromStringWithIsDescendantNodeExpressionWithNoSelectorNameIfSourceIsNotSelector() {
parser.parseConstraint(tokens("ISDESCENDANTNODE('/a/b/c')"), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseInClause
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseInClauseFromStringWithSingleValidLiteral() {
List<StaticOperand> result = parser.parseInClause(tokens("IN ('value1')"), typeSystem);
assertThat(result.size(), is(1));
assertThat(result.get(0), is((StaticOperand)literal("value1")));
}
@Test
public void shouldParseInClauseFromStringWithTwoValidLiteral() {
List<StaticOperand> result = parser.parseInClause(tokens("IN ('value1','value2')"), typeSystem);
assertThat(result.size(), is(2));
assertThat(result.get(0), is((StaticOperand)literal("value1")));
assertThat(result.get(1), is((StaticOperand)literal("value2")));
}
@Test
public void shouldParseInClauseFromStringWithThreeValidLiteral() {
List<StaticOperand> result = parser.parseInClause(tokens("IN ('value1','value2','value3')"), typeSystem);
assertThat(result.size(), is(3));
assertThat(result.get(0), is((StaticOperand)literal("value1")));
assertThat(result.get(1), is((StaticOperand)literal("value2")));
assertThat(result.get(2), is((StaticOperand)literal("value3")));
}
@Test
public void shouldParseInClauseFromStringWithSingleValidLiteralCast() {
List<StaticOperand> result = parser.parseInClause(tokens("IN (CAST('value1' AS STRING))"), typeSystem);
assertThat(result.size(), is(1));
assertThat(result.iterator().next(), is((StaticOperand)literal("value1")));
result = parser.parseInClause(tokens("IN (CAST('3' AS LONG))"), typeSystem);
assertThat(result.size(), is(1));
assertThat(result.iterator().next(), is((StaticOperand)literal(new Long(3))));
}
@Test
public void shouldParseInClauseFromStringWithMultipleValidLiteralCasts() {
List<StaticOperand> result = parser.parseInClause(tokens("IN (CAST('value1' AS STRING),CAST('3' AS LONG),'4')"),
typeSystem);
assertThat(result.size(), is(3));
assertThat(result.get(0), is((StaticOperand)literal("value1")));
assertThat(result.get(1), is((StaticOperand)literal(new Long(3))));
assertThat(result.get(2), is((StaticOperand)literal("4")));
}
@FixFor( "MODE-869" )
@Test
public void shouldParseInClauseContainingSubqueryWithNoCriteria() {
List<StaticOperand> result = parser.parseInClause(tokens("IN (SELECT * FROM tableA)"), typeSystem);
assertThat(result.size(), is(1));
assertThat(result.get(0), is((StaticOperand)subquery("SELECT * FROM tableA")));
}
@FixFor( "MODE-869" )
@Test
public void shouldParseInClauseContainingSubqueryWithNestedCriteriaAndParentheses() {
String expression = "SELECT * FROM tableA WHERE (foo < 3 AND (bar = 22))";
List<StaticOperand> result = parser.parseInClause(tokens("IN (" + expression + ")"), typeSystem);
assertThat(result.size(), is(1));
assertThat(result.get(0), is((StaticOperand)subquery(expression)));
}
protected Literal literal( Object literalValue ) {
return new Literal(literalValue);
}
protected QueryCommand query( String subquery ) {
return parser.parseQuery(subquery, typeSystem);
}
protected Subquery subquery( String subquery ) {
return new Subquery(query(subquery));
}
// ----------------------------------------------------------------------------------------------------------------
// parseFullTextSearchExpression
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseFullTextSearchExpressionFromStringWithValidExpression() {
Position pos = new Position(500, 100, 13);
FullTextSearch.Term result = parser.parseFullTextSearchExpression("term1 term2 OR -term3 OR -term4 OR term5", pos);
assertThat(result, is(notNullValue()));
assertThat(result, is(instanceOf(Disjunction.class)));
Disjunction disjunction = (Disjunction)result;
assertThat(disjunction.getTerms().size(), is(4));
Conjunction conjunction1 = (Conjunction)disjunction.getTerms().get(0);
Term term3 = disjunction.getTerms().get(1);
Term term4 = disjunction.getTerms().get(2);
Term term5 = disjunction.getTerms().get(3);
FullTextSearchParserTest.assertHasSimpleTerms(conjunction1, "term1", "term2");
FullTextSearchParserTest.assertSimpleTerm(term3, "term3", true, false);
FullTextSearchParserTest.assertSimpleTerm(term4, "term4", true, false);
FullTextSearchParserTest.assertSimpleTerm(term5, "term5", false, false);
}
@Test
public void shouldConvertPositionWhenUnableToParseFullTextSearchExpression() {
try {
parser.parseFullTextSearchExpression("", new Position(500, 100, 13));
fail("Should have thrown an exception");
} catch (ParsingException e) {
assertThat(e.getPosition().getLine(), is(100));
assertThat(e.getPosition().getColumn(), is(13));
assertThat(e.getPosition().getIndexInContent(), is(500));
}
}
// ----------------------------------------------------------------------------------------------------------------
// parseComparisonOperator
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseComparisonOperator() {
// Same case
for (Operator operator : Operator.values()) {
assertThat(parser.parseComparisonOperator(tokens(operator.symbol())), is(operator));
}
// Upper case
for (Operator operator : Operator.values()) {
assertThat(parser.parseComparisonOperator(tokens(operator.symbol().toUpperCase())), is(operator));
}
// Lower case
for (Operator operator : Operator.values()) {
assertThat(parser.parseComparisonOperator(tokens(operator.symbol().toLowerCase())), is(operator));
}
}
@Test( expected = ParsingException.class )
public void shouldFailToParseComparisonOperatorIfOperatorIsUnknown() {
parser.parseComparisonOperator(tokens("FOO"));
}
// ----------------------------------------------------------------------------------------------------------------
// parseOrderBy
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParserOrderByWithOneOrdering() {
List<Ordering> orderBy = parser.parseOrderBy(tokens("ORDER BY NAME(tableA) ASC"), typeSystem, mock(Source.class));
assertThat(orderBy.size(), is(1));
Ordering first = orderBy.get(0);
assertThat(first.getOperand(), is(instanceOf(NodeName.class)));
assertThat(first.order(), is(Order.ASCENDING));
}
@Test
public void shouldParserOrderByWithTwoOrderings() {
List<Ordering> orderBy = parser.parseOrderBy(tokens("ORDER BY NAME(tableA) ASC, SCORE(tableB) DESC"),
typeSystem,
mock(Source.class));
assertThat(orderBy.size(), is(2));
Ordering first = orderBy.get(0);
assertThat(first.getOperand(), is(instanceOf(NodeName.class)));
assertThat(first.order(), is(Order.ASCENDING));
Ordering second = orderBy.get(1);
assertThat(second.getOperand(), is(instanceOf(FullTextSearchScore.class)));
assertThat(second.order(), is(Order.DESCENDING));
}
@Test
public void shouldParserOrderByWithMultipleOrderings() {
List<Ordering> orderBy = parser.parseOrderBy(tokens("ORDER BY NAME(tableA) ASC, SCORE(tableB) DESC, LENGTH(tableC.id) ASC"),
typeSystem,
mock(Source.class));
assertThat(orderBy.size(), is(3));
Ordering first = orderBy.get(0);
assertThat(first.getOperand(), is(instanceOf(NodeName.class)));
assertThat(first.order(), is(Order.ASCENDING));
Ordering second = orderBy.get(1);
assertThat(second.getOperand(), is(instanceOf(FullTextSearchScore.class)));
assertThat(second.order(), is(Order.DESCENDING));
Ordering third = orderBy.get(2);
assertThat(third.getOperand(), is(instanceOf(Length.class)));
assertThat(third.order(), is(Order.ASCENDING));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseOrderByIfCommaNotFollowedByAnotherOrdering() {
parser.parseOrderBy(tokens("ORDER BY NAME(tableA) ASC, NOT A VALID ORDERING"), typeSystem, mock(Source.class));
}
@Test
public void shouldReturnNullFromParseOrderByWithoutOrderByKeywords() {
assertThat(parser.parseOrderBy(tokens("NOT ORDER BY"), typeSystem, mock(Source.class)), is(nullValue()));
}
// ----------------------------------------------------------------------------------------------------------------
// parseOrdering
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseOrderingFromDynamicOperandFollowedByAscendingKeyword() {
Ordering ordering = parser.parseOrdering(tokens("NAME(tableA) ASC"), typeSystem, mock(Source.class));
assertThat(ordering.getOperand(), is(instanceOf(NodeName.class)));
assertThat(ordering.order(), is(Order.ASCENDING));
}
@Test
public void shouldParseOrderingFromDynamicOperandFollowedByDecendingKeyword() {
Ordering ordering = parser.parseOrdering(tokens("NAME(tableA) DESC"), typeSystem, mock(Source.class));
assertThat(ordering.getOperand(), is(instanceOf(NodeName.class)));
assertThat(ordering.order(), is(Order.DESCENDING));
}
@Test
public void shouldParseOrderingFromDynamicOperandAndDefaultToAscendingWhenNotFollowedByAscendingOrDescendingKeyword() {
Ordering ordering = parser.parseOrdering(tokens("NAME(tableA) OTHER"), typeSystem, mock(Source.class));
assertThat(ordering.getOperand(), is(instanceOf(NodeName.class)));
assertThat(ordering.order(), is(Order.ASCENDING));
}
// ----------------------------------------------------------------------------------------------------------------
// parsePropertyExistance
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParsePropertyExistanceFromPropertyNameWithSelectorNameAndPropertyNameFollowedByIsNotNull() {
Constraint constraint = parser.parsePropertyExistance(tokens("tableA.property1 IS NOT NULL"),
typeSystem,
mock(Source.class));
assertThat(constraint, is(instanceOf(PropertyExistence.class)));
PropertyExistence p = (PropertyExistence)constraint;
assertThat(p.getPropertyName(), is("property1"));
assertThat(p.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParsePropertyExistanceFromPropertyNameWithPropertyNameAndNoSelectorNameFollowedByIsNotNull() {
NamedSelector source = new NamedSelector(selectorName("tableA"));
Constraint constraint = parser.parsePropertyExistance(tokens("property1 IS NOT NULL"), typeSystem, source);
assertThat(constraint, is(instanceOf(PropertyExistence.class)));
PropertyExistence p = (PropertyExistence)constraint;
assertThat(p.getPropertyName(), is("property1"));
assertThat(p.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParsePropertyExistanceFromPropertyNameWithNoSelectorNameIfSourceIsNotSelector() {
parser.parsePropertyExistance(tokens("property1 IS NOT NULL"), typeSystem, mock(Source.class));
}
@Test
public void shouldParseNotPropertyExistanceFromPropertyNameWithSelectorNameAndPropertyNameFollowedByIsNull() {
Constraint constraint = parser.parsePropertyExistance(tokens("tableA.property1 IS NULL"), typeSystem, mock(Source.class));
assertThat(constraint, is(instanceOf(Not.class)));
Not not = (Not)constraint;
assertThat(not.getConstraint(), is(instanceOf(PropertyExistence.class)));
PropertyExistence p = (PropertyExistence)not.getConstraint();
assertThat(p.getPropertyName(), is("property1"));
assertThat(p.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldReturnNullFromParsePropertyExistanceIfExpressionDoesNotMatchPattern() {
Source s = mock(Source.class);
assertThat(parser.parsePropertyExistance(tokens("tableA WILL NOT"), typeSystem, s), is(nullValue()));
assertThat(parser.parsePropertyExistance(tokens("tableA.property1 NOT NULL"), typeSystem, s), is(nullValue()));
assertThat(parser.parsePropertyExistance(tokens("tableA.property1 IS NOT SOMETHING"), typeSystem, s), is(nullValue()));
}
// ----------------------------------------------------------------------------------------------------------------
// parseStaticOperand
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseStaticOperandFromStringWithBindVariable() {
StaticOperand operand = parser.parseStaticOperand(tokens("$VAR"), typeSystem);
assertThat(operand, is(instanceOf(BindVariableName.class)));
BindVariableName var = (BindVariableName)operand;
assertThat(var.getBindVariableName(), is("VAR"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseStaticOperandFromStringWithBindVariableWithNoVariableName() {
parser.parseStaticOperand(tokens("$"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseStaticOperandFromStringWithBindVariableWithCharactersThatAreNotFromNCName() {
parser.parseStaticOperand(tokens("$#2VAR"), typeSystem);
}
@Test
public void shouldParseStaticOperandFromStringWithLiteralValue() {
StaticOperand operand = parser.parseStaticOperand(tokens("CAST(123 AS DOUBLE)"), typeSystem);
assertThat(operand, is(instanceOf(Literal.class)));
Literal literal = (Literal)operand;
assertThat(literal.value(), is(typeSystem.getDoubleFactory().create("123")));
}
@FixFor( "MODE-869" )
@Test
public void shouldParseStaticOperandWithSubquery() {
QueryCommand expected = parser.parseQuery(tokens("SELECT * FROM tableA"), typeSystem);
StaticOperand operand = parser.parseStaticOperand(tokens("SELECT * FROM tableA"), typeSystem);
assertThat(operand, is(instanceOf(Subquery.class)));
Subquery subquery = (Subquery)operand;
assertThat(subquery.getQuery(), is(expected));
}
@FixFor( "MODE-869" )
@Test
public void shouldParseStaticOperandWithSubqueryWithoutConsumingExtraTokens() {
QueryCommand expected = parser.parseQuery(tokens("SELECT * FROM tableA"), typeSystem);
TokenStream tokens = tokens("SELECT * FROM tableA)");
StaticOperand operand = parser.parseStaticOperand(tokens, typeSystem);
assertThat(operand, is(instanceOf(Subquery.class)));
Subquery subquery = (Subquery)operand;
assertThat(subquery.getQuery(), is(expected));
assertThat(tokens.canConsume(')'), is(true));
}
// ----------------------------------------------------------------------------------------------------------------
// parseLiteral
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseLiteralFromStringWithCastBooleanLiteralToString() {
assertThat(parser.parseLiteral(tokens("CAST(true AS STRING)"), typeSystem).value(), is(Boolean.TRUE.toString()));
assertThat(parser.parseLiteral(tokens("CAST(false AS STRING)"), typeSystem).value(), is(Boolean.FALSE.toString()));
assertThat(parser.parseLiteral(tokens("CAST(TRUE AS STRING)"), typeSystem).value(), is(Boolean.TRUE.toString()));
assertThat(parser.parseLiteral(tokens("CAST(FALSE AS STRING)"), typeSystem).value(), is(Boolean.FALSE.toString()));
assertThat(parser.parseLiteral(tokens("CAST('true' AS stRinG)"), typeSystem).value(), is(Boolean.TRUE.toString()));
assertThat(parser.parseLiteral(tokens("CAST(\"false\" AS string)"), typeSystem).value(),
is(Boolean.FALSE.toString()));
}
@Test
public void shouldParseLiteralFromStringWithCastBooleanLiteralToBinary() {
Binary binaryTrue = (Binary)typeSystem.getTypeFactory(PropertyType.BINARY.getName()).create(true);
Binary binaryFalse = (Binary)typeSystem.getTypeFactory(PropertyType.BINARY.getName()).create(false);
assertThat(parser.parseLiteral(tokens("CAST(true AS BINARY)"), typeSystem).value(), is(binaryTrue));
assertThat(parser.parseLiteral(tokens("CAST(false AS BINARY)"), typeSystem).value(), is(binaryFalse));
assertThat(parser.parseLiteral(tokens("CAST(TRUE AS BINARY)"), typeSystem).value(), is(binaryTrue));
assertThat(parser.parseLiteral(tokens("CAST(FALSE AS BINARY)"), typeSystem).value(), is(binaryFalse));
assertThat(parser.parseLiteral(tokens("CAST('true' AS biNarY)"), typeSystem).value(), is(binaryTrue));
assertThat(parser.parseLiteral(tokens("CAST(\"false\" AS binary)"), typeSystem).value(), is(binaryFalse));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastBooleanLiteralToLong() {
parser.parseLiteral(tokens("CAST(true AS LONG)"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastBooleanLiteralToDouble() {
parser.parseLiteral(tokens("CAST(true AS DOUBLE)"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastBooleanLiteralToDate() {
parser.parseLiteral(tokens("CAST(true AS DATE)"), typeSystem);
}
@Test
public void shouldParseLiteralFromStringWithCastLongLiteralToString() {
assertThat(parser.parseLiteral(tokens("CAST(123 AS STRING)"), typeSystem).value(), is("123"));
assertThat(parser.parseLiteral(tokens("CAST(+123 AS STRING)"), typeSystem).value(), is("123"));
assertThat(parser.parseLiteral(tokens("CAST(-123 AS STRING)"), typeSystem).value(), is("-123"));
assertThat(parser.parseLiteral(tokens("CAST(0 AS STRING)"), typeSystem).value(), is("0"));
}
@Test
public void shouldParseLiteralFromStringWithCastLongLiteralToLong() {
assertThat(parser.parseLiteral(tokens("CAST(123 AS LONG)"), typeSystem).value(), is(123L));
assertThat(parser.parseLiteral(tokens("CAST(+123 AS LONG)"), typeSystem).value(), is(123L));
assertThat(parser.parseLiteral(tokens("CAST(-123 AS LONG)"), typeSystem).value(), is(-123L));
assertThat(parser.parseLiteral(tokens("CAST(0 AS LONG)"), typeSystem).value(), is(0L));
}
@Test
public void shouldParseLiteralFromStringWithCastDoubleLiteralToString() {
assertThat(parser.parseLiteral(tokens("CAST(1.23 AS STRING)"), typeSystem).value(), is("1.23"));
assertThat(parser.parseLiteral(tokens("CAST(+1.23 AS STRING)"), typeSystem).value(), is("1.23"));
assertThat(parser.parseLiteral(tokens("CAST(-1.23 AS STRING)"), typeSystem).value(), is("-1.23"));
assertThat(parser.parseLiteral(tokens("CAST(1.23e10 AS STRING)"), typeSystem).value(), is("1.23E10"));
assertThat(parser.parseLiteral(tokens("CAST(1.23e+10 AS STRING)"), typeSystem).value(), is("1.23E10"));
assertThat(parser.parseLiteral(tokens("CAST(1.23e-10 AS STRING)"), typeSystem).value(), is("1.23E-10"));
}
@Test
public void shouldParseLiteralFromStringWithCastDateLiteralToString() {
assertThat(parser.parseLiteral(tokens("CAST(2009-03-22T03:22:45.345Z AS STRING)"), typeSystem).value(),
is("2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteral(tokens("CAST(2009-03-22T03:22:45.345UTC AS STRING)"), typeSystem).value(),
is("2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteral(tokens("CAST(2009-03-22T03:22:45.3-01:00 AS STRING)"), typeSystem).value(),
is("2009-03-22T04:22:45.003Z"));
assertThat(parser.parseLiteral(tokens("CAST(2009-03-22T03:22:45.345+01:00 AS STRING)"), typeSystem).value(),
is("2009-03-22T02:22:45.345Z"));
}
@Test
public void shouldParseLiteralFromStringWithCastStringLiteralToName() {
assertThat(parser.parseLiteral(tokens("CAST([mode:name] AS NAME)"), typeSystem).value(), is(name("mode:name")));
assertThat(parser.parseLiteral(tokens("CAST('mode:name' AS NAME)"), typeSystem).value(), is(name("mode:name")));
assertThat(parser.parseLiteral(tokens("CAST(\"mode:name\" AS NAME)"), typeSystem).value(), is(name("mode:name")));
}
@Test
public void shouldParseLiteralFromStringWithCastStringLiteralToPath() {
assertThat(parser.parseLiteral(tokens("CAST([/mode:name/a/b] AS PATH)"), typeSystem).value(),
is(path("/mode:name/a/b")));
}
@Test
public void shouldParseLiteralFromStringWithUncastLiteralValueAndRepresentValueAsStringRepresentation() {
assertThat(parser.parseLiteral(tokens("true"), typeSystem).value(), is((Object)Boolean.TRUE));
assertThat(parser.parseLiteral(tokens("false"), typeSystem).value(), is((Object)Boolean.FALSE));
assertThat(parser.parseLiteral(tokens("TRUE"), typeSystem).value(), is((Object)Boolean.TRUE));
assertThat(parser.parseLiteral(tokens("FALSE"), typeSystem).value(), is((Object)Boolean.FALSE));
assertThat(parser.parseLiteral(tokens("123"), typeSystem).value(), is((Object)123L));
assertThat(parser.parseLiteral(tokens("+123"), typeSystem).value(), is((Object)123L));
assertThat(parser.parseLiteral(tokens("-123"), typeSystem).value(), is((Object)new Long(-123)));
assertThat(parser.parseLiteral(tokens("1.23"), typeSystem).value(), is((Object)1.23D));
assertThat(parser.parseLiteral(tokens("+1.23"), typeSystem).value(), is((Object)1.23D));
assertThat(parser.parseLiteral(tokens("-1.23"), typeSystem).value(), is((Object)new Double(-1.23)));
assertThat(parser.parseLiteral(tokens("1.23e10"), typeSystem).value(), is((Object)new Double(1.23E10)));
assertThat(parser.parseLiteral(tokens("1.23e+10"), typeSystem).value(), is((Object)new Double(1.23E10)));
assertThat(parser.parseLiteral(tokens("1.23e-10"), typeSystem).value(), is((Object)new Double(1.23E-10)));
assertThat(parser.parseLiteral(tokens("0"), typeSystem).value(), is((Object)0L));
assertThat(parser.parseLiteral(tokens("2009-03-22T03:22:45.345Z"), typeSystem).value(),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteral(tokens("2009-03-22T03:22:45.345UTC"), typeSystem).value(),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteral(tokens("2009-03-22T03:22:45.3-01:00"), typeSystem).value(),
is((Object)"2009-03-22T04:22:45.003Z"));
assertThat(parser.parseLiteral(tokens("2009-03-22T03:22:45.345+01:00"), typeSystem).value(),
is((Object)"2009-03-22T02:22:45.345Z"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastAndNoEndingParenthesis() {
parser.parseLiteral(tokens("CAST(123 AS STRING OTHER"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastAndNoOpeningParenthesis() {
parser.parseLiteral(tokens("CAST 123 AS STRING) OTHER"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastAndInvalidType() {
parser.parseLiteral(tokens("CAST(123 AS FOOD) OTHER"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastAndNoAsKeyword() {
parser.parseLiteral(tokens("CAST(123 STRING) OTHER"), typeSystem);
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLiteralFromStringWithCastAndNoLiteralValueBeforeAs() {
parser.parseLiteral(tokens("CAST(AS STRING) OTHER"), typeSystem);
}
// ----------------------------------------------------------------------------------------------------------------
// parseLiteralValue - unquoted
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseLiteralValueFromStringWithPositiveAndNegativeIntegerValues() {
assertThat(parser.parseLiteralValue(tokens("123"), typeSystem), is((Object)123L));
assertThat(parser.parseLiteralValue(tokens("-123"), typeSystem), is((Object)new Long(-123)));
assertThat(parser.parseLiteralValue(tokens("- 123"), typeSystem), is((Object)new Long(-123)));
assertThat(parser.parseLiteralValue(tokens("+123"), typeSystem), is((Object)123L));
assertThat(parser.parseLiteralValue(tokens("+ 123"), typeSystem), is((Object)123L));
assertThat(parser.parseLiteralValue(tokens("0"), typeSystem), is((Object)0L));
}
@Test
public void shouldParseLiteralValueFromStringWithPositiveAndNegativeDecimalValues() {
assertThat(parser.parseLiteralValue(tokens("1.23"), typeSystem), is((Object)1.23D));
assertThat(parser.parseLiteralValue(tokens("-1.23"), typeSystem), is((Object)new Double(-1.23)));
assertThat(parser.parseLiteralValue(tokens("+0.123"), typeSystem), is((Object)0.123D));
}
@Test
public void shouldParseLiteralValueFromStringWithPositiveAndNegativeDecimalValuesInScientificNotation() {
assertThat(parser.parseLiteralValue(tokens("1.23"), typeSystem), is((Object)1.23D));
assertThat(parser.parseLiteralValue(tokens("1.23e10"), typeSystem), is((Object)1.23E10));
assertThat(parser.parseLiteralValue(tokens("- 1.23e10"), typeSystem), is((Object)new Double(-1.23E10)));
assertThat(parser.parseLiteralValue(tokens("- 1.23e-10"), typeSystem), is((Object)new Double(-1.23E-10)));
}
@Test
public void shouldParseLiteralValueFromStringWithBooleanValues() {
assertThat(parser.parseLiteralValue(tokens("true"), typeSystem), is((Object)Boolean.TRUE));
assertThat(parser.parseLiteralValue(tokens("false"), typeSystem), is((Object)Boolean.FALSE));
assertThat(parser.parseLiteralValue(tokens("TRUE"), typeSystem), is((Object)Boolean.TRUE));
assertThat(parser.parseLiteralValue(tokens("FALSE"), typeSystem), is((Object)Boolean.FALSE));
}
@Test
public void shouldParseLiteralValueFromStringWithDateValues() {
// sYYYY-MM-DDThh:mm:ss.sssTZD
assertThat(parser.parseLiteralValue(tokens("2009-03-22T03:22:45.345Z"), typeSystem),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("2009-03-22T03:22:45.345UTC"), typeSystem),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("2009-03-22T03:22:45.3-01:00"), typeSystem),
is((Object)"2009-03-22T04:22:45.003Z"));
assertThat(parser.parseLiteralValue(tokens("2009-03-22T03:22:45.345+01:00"), typeSystem),
is((Object)"2009-03-22T02:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("-2009-03-22T03:22:45.345Z"), typeSystem),
is((Object)"-2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("-2009-03-22T03:22:45.345UTC"), typeSystem),
is((Object)"-2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("-2009-03-22T03:22:45.3-01:00"), typeSystem),
is((Object)"-2009-03-22T04:22:45.003Z"));
assertThat(parser.parseLiteralValue(tokens("-2009-03-22T03:22:45.345+01:00"), typeSystem),
is((Object)"-2009-03-22T02:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("+2009-03-22T03:22:45.345Z"), typeSystem),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("+2009-03-22T03:22:45.345UTC"), typeSystem),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("+2009-03-22T03:22:45.3-01:00"), typeSystem),
is((Object)"2009-03-22T04:22:45.003Z"));
assertThat(parser.parseLiteralValue(tokens("+2009-03-22T03:22:45.345+01:00"), typeSystem),
is((Object)"2009-03-22T02:22:45.345Z"));
}
// ----------------------------------------------------------------------------------------------------------------
// parseLiteralValue - quoted
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseLiteralValueFromQuotedStringWithPositiveAndNegativeIntegerValues() {
assertThat(parser.parseLiteralValue(tokens("'123'"), typeSystem), is((Object)"123"));
assertThat(parser.parseLiteralValue(tokens("'-123'"), typeSystem), is((Object)"-123"));
assertThat(parser.parseLiteralValue(tokens("'- 123'"), typeSystem), is((Object)"- 123"));
assertThat(parser.parseLiteralValue(tokens("'+123'"), typeSystem), is((Object)"+123"));
assertThat(parser.parseLiteralValue(tokens("'+ 123'"), typeSystem), is((Object)"+ 123"));
assertThat(parser.parseLiteralValue(tokens("'0'"), typeSystem), is((Object)"0"));
}
@Test
public void shouldParseLiteralValueFromQuotedStringWithPositiveAndNegativeDecimalValues() {
assertThat(parser.parseLiteralValue(tokens("'1.23'"), typeSystem), is((Object)"1.23"));
assertThat(parser.parseLiteralValue(tokens("'-1.23'"), typeSystem), is((Object)"-1.23"));
assertThat(parser.parseLiteralValue(tokens("'+0.123'"), typeSystem), is((Object)"+0.123"));
}
@Test
public void shouldParseLiteralValueFromQuotedStringWithPositiveAndNegativeDecimalValuesInScientificNotation() {
assertThat(parser.parseLiteralValue(tokens("'1.23'"), typeSystem), is((Object)"1.23"));
assertThat(parser.parseLiteralValue(tokens("'1.23e10'"), typeSystem), is((Object)"1.23e10"));
assertThat(parser.parseLiteralValue(tokens("'- 1.23e10'"), typeSystem), is((Object)"- 1.23e10"));
assertThat(parser.parseLiteralValue(tokens("'- 1.23e-10'"), typeSystem), is((Object)"- 1.23e-10"));
}
@Test
public void shouldParseLiteralValueFromQuotedStringWithBooleanValues() {
assertThat(parser.parseLiteralValue(tokens("'true'"), typeSystem), is((Object)"true"));
assertThat(parser.parseLiteralValue(tokens("'false'"), typeSystem), is((Object)"false"));
assertThat(parser.parseLiteralValue(tokens("'TRUE'"), typeSystem), is((Object)"TRUE"));
assertThat(parser.parseLiteralValue(tokens("'FALSE'"), typeSystem), is((Object)"FALSE"));
}
@Test
public void shouldParseLiteralValueFromQuotedStringWithDateValues() {
// sYYYY-MM-DDThh:mm:ss.sssTZD
assertThat(parser.parseLiteralValue(tokens("'2009-03-22T03:22:45.345Z'"), typeSystem),
is((Object)"2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("'2009-03-22T03:22:45.345UTC'"), typeSystem),
is((Object)"2009-03-22T03:22:45.345UTC"));
assertThat(parser.parseLiteralValue(tokens("'2009-03-22T03:22:45.3-01:00'"), typeSystem),
is((Object)"2009-03-22T03:22:45.3-01:00"));
assertThat(parser.parseLiteralValue(tokens("'2009-03-22T03:22:45.345+01:00'"), typeSystem),
is((Object)"2009-03-22T03:22:45.345+01:00"));
assertThat(parser.parseLiteralValue(tokens("'-2009-03-22T03:22:45.345Z'"), typeSystem),
is((Object)"-2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("'-2009-03-22T03:22:45.345UTC'"), typeSystem),
is((Object)"-2009-03-22T03:22:45.345UTC"));
assertThat(parser.parseLiteralValue(tokens("'-2009-03-22T03:22:45.3-01:00'"), typeSystem),
is((Object)"-2009-03-22T03:22:45.3-01:00"));
assertThat(parser.parseLiteralValue(tokens("'-2009-03-22T03:22:45.345+01:00'"), typeSystem),
is((Object)"-2009-03-22T03:22:45.345+01:00"));
assertThat(parser.parseLiteralValue(tokens("'+2009-03-22T03:22:45.345Z'"), typeSystem),
is((Object)"+2009-03-22T03:22:45.345Z"));
assertThat(parser.parseLiteralValue(tokens("'+2009-03-22T03:22:45.345UTC'"), typeSystem),
is((Object)"+2009-03-22T03:22:45.345UTC"));
assertThat(parser.parseLiteralValue(tokens("'+2009-03-22T03:22:45.3-01:00'"), typeSystem),
is((Object)"+2009-03-22T03:22:45.3-01:00"));
assertThat(parser.parseLiteralValue(tokens("'+2009-03-22T03:22:45.345+01:00'"), typeSystem),
is((Object)"+2009-03-22T03:22:45.345+01:00"));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - LENGTH
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingLengthOfPropertyValue() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("LENGTH(tableA.property)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(Length.class)));
Length length = (Length)operand;
assertThat(length.getPropertyValue().getPropertyName(), is("property"));
assertThat(length.getPropertyValue().selectorName(), is(selectorName("tableA")));
assertThat(length.selectorName(), is(selectorName("tableA")));
Source source = new NamedSelector(selectorName("tableA"));
operand = parser.parseDynamicOperand(tokens("LENGTH(property)"), typeSystem, source);
assertThat(operand, is(instanceOf(Length.class)));
length = (Length)operand;
assertThat(length.getPropertyValue().getPropertyName(), is("property"));
assertThat(length.getPropertyValue().selectorName(), is(selectorName("tableA")));
assertThat(length.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLengthWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("LENGTH(tableA.property other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLengthWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("LENGTH tableA.property other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - LOWER
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingLowerOfAnotherDynamicOperand() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("LOWER(tableA.property)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(LowerCase.class)));
LowerCase lower = (LowerCase)operand;
assertThat(lower.selectorName(), is(selectorName("tableA")));
assertThat(lower.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)lower.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
Source source = new NamedSelector(selectorName("tableA"));
operand = parser.parseDynamicOperand(tokens("LOWER(property)"), typeSystem, source);
assertThat(operand, is(instanceOf(LowerCase.class)));
lower = (LowerCase)operand;
assertThat(lower.selectorName(), is(selectorName("tableA")));
assertThat(lower.getOperand(), is(instanceOf(PropertyValue.class)));
value = (PropertyValue)lower.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingLowerOfUpperCaseOfAnotherOperand() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("LOWER(UPPER(tableA.property))"),
typeSystem,
mock(Source.class));
assertThat(operand, is(instanceOf(LowerCase.class)));
LowerCase lower = (LowerCase)operand;
assertThat(lower.selectorName(), is(selectorName("tableA")));
assertThat(lower.getOperand(), is(instanceOf(UpperCase.class)));
UpperCase upper = (UpperCase)lower.getOperand();
assertThat(upper.selectorName(), is(selectorName("tableA")));
assertThat(upper.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)upper.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLowerWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("LOWER(tableA.property other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLowerWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("LOWER tableA.property other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - UPPER
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingUpperOfAnotherDynamicOperand() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("UPPER(tableA.property)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(UpperCase.class)));
UpperCase upper = (UpperCase)operand;
assertThat(upper.selectorName(), is(selectorName("tableA")));
assertThat(upper.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)upper.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
Source source = new NamedSelector(selectorName("tableA"));
operand = parser.parseDynamicOperand(tokens("UPPER(property)"), typeSystem, source);
assertThat(operand, is(instanceOf(UpperCase.class)));
upper = (UpperCase)operand;
assertThat(upper.selectorName(), is(selectorName("tableA")));
assertThat(upper.getOperand(), is(instanceOf(PropertyValue.class)));
value = (PropertyValue)upper.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingUpperOfLowerCaseOfAnotherOperand() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("UPPER(LOWER(tableA.property))"),
typeSystem,
mock(Source.class));
assertThat(operand, is(instanceOf(UpperCase.class)));
UpperCase upper = (UpperCase)operand;
assertThat(upper.selectorName(), is(selectorName("tableA")));
assertThat(upper.getOperand(), is(instanceOf(LowerCase.class)));
LowerCase lower = (LowerCase)upper.getOperand();
assertThat(lower.selectorName(), is(selectorName("tableA")));
assertThat(lower.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)lower.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingUpperWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("UPPER(tableA.property other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingUpperWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Upper tableA.property other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - CAST
// ----------------------------------------------------------------------------------------------------------------
@Test
@FixFor( "MODE-2166" )
public void shouldParseDynamicOperandFromStringContainingCast() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("CAST(tableA.property AS DOUBLE)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(Cast.class)));
Cast cast = (Cast)operand;
assertThat(cast.selectorName(), is(selectorName("tableA")));
assertThat(cast.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)cast.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
assertEquals(PropertyType.DOUBLE.toString(), cast.getDesiredTypeName());
}
@Test
@FixFor( "MODE-2166" )
public void shouldParseDynamicOperandFromStringContainingCastOfLowerCaseOfAnotherOperand() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("CAST(LOWER(tableA.property) AS DATE)"),
typeSystem,
mock(Source.class));
assertThat(operand, is(instanceOf(Cast.class)));
Cast cast = (Cast)operand;
assertThat(cast.selectorName(), is(selectorName("tableA")));
assertThat(cast.getOperand(), is(instanceOf(LowerCase.class)));
assertEquals(PropertyType.DATE.toString(), cast.getDesiredTypeName());
LowerCase lower = (LowerCase)cast.getOperand();
assertThat(lower.selectorName(), is(selectorName("tableA")));
assertThat(lower.getOperand(), is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)lower.getOperand();
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
@FixFor( "MODE-2166" )
public void shouldFailToParseDynamicOperandFromStringContainingCastWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("CAST(tableA.property AS integer"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
@FixFor( "MODE-2166" )
public void shouldFailToParseDynamicOperandFromStringContainingCastWithoutAs() {
parser.parseDynamicOperand(tokens("CAST(tableA.property something)"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
@FixFor( "MODE-2166" )
public void shouldFailToParseDynamicOperandFromStringContainingCastWithInvalidType() {
parser.parseDynamicOperand(tokens("CAST(tableA.property AS invalid)"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - CHILDCOUNT
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingChildCountOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("CHILDCOUNT(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(ChildCount.class)));
ChildCount count = (ChildCount)operand;
assertThat(count.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingChildCountWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("CHILDCOUNT()"), typeSystem, source);
assertThat(operand, is(instanceOf(ChildCount.class)));
ChildCount count = (ChildCount)operand;
assertThat(count.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingChildCountWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("CHILDCOUNT()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingChildCountWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("CHILDCOUNT(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingChildCountWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("CHILDCOUNT(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingChildCountWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Childcount tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - DEPTH
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingDepthOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("DEPTH(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(NodeDepth.class)));
NodeDepth depth = (NodeDepth)operand;
assertThat(depth.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingDepthWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("DEPTH()"), typeSystem, source);
assertThat(operand, is(instanceOf(NodeDepth.class)));
NodeDepth depth = (NodeDepth)operand;
assertThat(depth.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingDepthWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("DEPTH()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingDepthWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("DEPTH(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingDepthWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("DEPTH(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingDepthWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Depth tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - PATH
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingPathOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("PATH(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(NodePath.class)));
NodePath path = (NodePath)operand;
assertThat(path.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingPathWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("PATH()"), typeSystem, source);
assertThat(operand, is(instanceOf(NodePath.class)));
NodePath path = (NodePath)operand;
assertThat(path.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingPathWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("PATH()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingPathWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("PATH(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingPathWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("PATH(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingPathWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Path tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - NAME
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingNameOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("NAME(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(NodeName.class)));
NodeName name = (NodeName)operand;
assertThat(name.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingNameWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("NAME()"), typeSystem, source);
assertThat(operand, is(instanceOf(NodeName.class)));
NodeName name = (NodeName)operand;
assertThat(name.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingNameWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("NAME()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingNameWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("NAME(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingNameWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("NAME(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingNameWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Name tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - LOCALNAME
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingLocalNameOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("LOCALNAME(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(NodeLocalName.class)));
NodeLocalName name = (NodeLocalName)operand;
assertThat(name.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingLocalNameWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("LOCALNAME()"), typeSystem, source);
assertThat(operand, is(instanceOf(NodeLocalName.class)));
NodeLocalName name = (NodeLocalName)operand;
assertThat(name.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLocalNameWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("LOCALNAME()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLocalNameWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("LOCALNAME(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLocalNameWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("LOCALNAME(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingLocalNameWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("LocalName tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - SCORE
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingFullTextSearchScoreOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("SCORE(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(FullTextSearchScore.class)));
FullTextSearchScore score = (FullTextSearchScore)operand;
assertThat(score.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringContainingFullTextSearchScoreWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("SCORE()"), typeSystem, source);
assertThat(operand, is(instanceOf(FullTextSearchScore.class)));
FullTextSearchScore score = (FullTextSearchScore)operand;
assertThat(score.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingFullTextSearchScoreWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("SCORE()"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingFullTextSearchScoreWithWithSelectorNameAndProperty() {
parser.parseDynamicOperand(tokens("SCORE(tableA.property) other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingFullTextSearchScoreWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("SCORE(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingFullTextSearchScoreWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Score tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - PropertyValue
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringWithUnquotedSelectorNameAndUnquotedPropertyName() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("tableA.property"), typeSystem, mock(Join.class));
assertThat(operand, is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)operand;
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringWithQuotedSelectorNameAndUnquotedPropertyName() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("[mode:tableA].property"), typeSystem, mock(Join.class));
assertThat(operand, is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)operand;
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringWithQuotedSelectorNameAndQuotedPropertyName() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("[mode:tableA].[mode:property]"), typeSystem, mock(Join.class));
assertThat(operand, is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)operand;
assertThat(value.getPropertyName(), is("mode:property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParseDynamicOperandFromStringWithOnlyPropertyNameIfSourceIsSelector() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("property"), typeSystem, source);
assertThat(operand, is(instanceOf(PropertyValue.class)));
PropertyValue value = (PropertyValue)operand;
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToDynamicOperandValueFromStringWithOnlyPropertyNameIfSourceIsNotSelector() {
parser.parsePropertyValue(tokens("property"), typeSystem, mock(Join.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringWithOnlySelectorNameAndPeriod() {
parser.parsePropertyValue(tokens("tableA. "), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseDynamicOperand - ReferenceValue
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueOfSelector() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE(tableA)"), typeSystem, mock(Source.class));
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is(nullValue()));
}
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueWithNoSelectorOnlyIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE()"), typeSystem, source);
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is(nullValue()));
}
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueWithWithOnlyPropertyNameIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE(property) other"), typeSystem, source);
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is("property"));
}
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueWithWithSelectorNameAndPropertyNameIfThereIsOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE(tableA.property) other"), typeSystem, source);
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is("property"));
}
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueWithWithOnlySelectorNameMatchingThatOfOneSelectorAsSource() {
Source source = new NamedSelector(selectorName("tableA"));
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE(tableA) other"), typeSystem, source);
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is(nullValue()));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingReferenceValueWithNoSelectorIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("REFERENCE()"), typeSystem, mock(Source.class));
}
@Test
public void shouldParseDynamicOperandFromStringContainingReferenceValueWithWithSelectorNameAndProperty() {
DynamicOperand operand = parser.parseDynamicOperand(tokens("REFERENCE(tableA.property) other"),
typeSystem,
mock(Source.class));
assertThat(operand, is(instanceOf(ReferenceValue.class)));
ReferenceValue value = (ReferenceValue)operand;
assertThat(value.selectorName(), is(selectorName("tableA")));
assertThat(value.getPropertyName(), is("property"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingReferenceValueWithoutClosingParenthesis() {
parser.parseDynamicOperand(tokens("REFERENCE(tableA other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingReferenceValueWithoutSelectorOrPropertyIfTheSourceIsNotASelector() {
parser.parseDynamicOperand(tokens("REFERENCE() other"), typeSystem, mock(Source.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseDynamicOperandFromStringContainingReferenceValueWithoutOpeningParenthesis() {
parser.parseDynamicOperand(tokens("Reference tableA other"), typeSystem, mock(Source.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parsePropertyValue
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParsePropertyValueFromStringWithUnquotedSelectorNameAndUnquotedPropertyName() {
PropertyValue value = parser.parsePropertyValue(tokens("tableA.property"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParsePropertyValueFromStringWithQuotedSelectorNameAndUnquotedPropertyName() {
PropertyValue value = parser.parsePropertyValue(tokens("[mode:tableA].property"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParsePropertyValueFromStringWithQuotedSelectorNameAndQuotedPropertyName() {
PropertyValue value = parser.parsePropertyValue(tokens("[mode:tableA].[mode:property]"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("mode:property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParsePropertyValueFromStringWithOnlyPropertyNameIfSourceIsSelector() {
Source source = new NamedSelector(selectorName("tableA"));
PropertyValue value = parser.parsePropertyValue(tokens("property"), typeSystem, source);
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParsePropertyValueFromStringWithOnlyPropertyNameIfSourceIsNotSelector() {
parser.parsePropertyValue(tokens("property"), typeSystem, mock(Join.class));
}
@Test( expected = ParsingException.class )
public void shouldFailToParsePropertyValueFromStringWithOnlySelectorNameAndPeriod() {
parser.parsePropertyValue(tokens("tableA. "), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseReferenceValue
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseReferenceValueFromStringWithUnquotedSelectorNameAndUnquotedPropertyName() {
ReferenceValue value = parser.parseReferenceValue(tokens("tableA.property"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
Source source = new NamedSelector(selectorName("tableA"));
value = parser.parseReferenceValue(tokens("tableA.property"), typeSystem, source);
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseReferenceValueFromStringWithQuotedSelectorNameAndUnquotedPropertyName() {
ReferenceValue value = parser.parseReferenceValue(tokens("[mode:tableA].property"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
Source source = new NamedSelector(selectorName("mode:tableA"));
value = parser.parseReferenceValue(tokens("[mode:tableA].property"), typeSystem, source);
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParseReferenceValueFromStringWithQuotedSelectorNameAndQuotedPropertyName() {
ReferenceValue value = parser.parseReferenceValue(tokens("[mode:tableA].[mode:property]"), typeSystem, mock(Join.class));
assertThat(value.getPropertyName(), is("mode:property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
Source source = new NamedSelector(selectorName("mode:tableA"));
value = parser.parseReferenceValue(tokens("[mode:tableA].[mode:property]"), typeSystem, source);
assertThat(value.getPropertyName(), is("mode:property"));
assertThat(value.selectorName(), is(selectorName("mode:tableA")));
}
@Test
public void shouldParseReferenceValueFromStringWithOnlyPropertyNameIfSourceIsSelector() {
Source source = new NamedSelector(selectorName("tableA"));
ReferenceValue value = parser.parseReferenceValue(tokens("property)"), typeSystem, source);
assertThat(value.getPropertyName(), is("property"));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseReferenceValueFromStringWithMatchingSelectorNameIfSourceIsSelector() {
Source source = new NamedSelector(selectorName("tableA"));
ReferenceValue value = parser.parseReferenceValue(tokens("tableA)"), typeSystem, source);
assertThat(value.getPropertyName(), is(nullValue()));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test
public void shouldParseReferenceValueFromStringWithOnlySelectorNameIfSourceIsNotSelector() {
Source source = mock(Join.class);
ReferenceValue value = parser.parseReferenceValue(tokens("tableA)"), typeSystem, source);
assertThat(value.getPropertyName(), is(nullValue()));
assertThat(value.selectorName(), is(selectorName("tableA")));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseReferenceValueFromStringWithOnlySelectorNameAndPeriod() {
parser.parseReferenceValue(tokens("tableA. "), typeSystem, mock(Join.class));
}
// ----------------------------------------------------------------------------------------------------------------
// parseLimit
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseLimitFromFormWithJustOneNumber() {
Limit limit = parser.parseLimit(tokens("LIMIT 10"));
assertThat(limit.getRowLimit(), is(10));
assertThat(limit.getOffset(), is(0));
limit = parser.parseLimit(tokens("LIMIT 10 NONOFFSET"));
assertThat(limit.getRowLimit(), is(10));
assertThat(limit.getOffset(), is(0));
}
@Test
public void shouldParseLimitFromFormWithRowLimitAndOffset() {
Limit limit = parser.parseLimit(tokens("LIMIT 10 OFFSET 30"));
assertThat(limit.getRowLimit(), is(10));
assertThat(limit.getOffset(), is(30));
limit = parser.parseLimit(tokens("LIMIT 10 OFFSET 30 OTHER"));
assertThat(limit.getRowLimit(), is(10));
assertThat(limit.getOffset(), is(30));
}
@Test
public void shouldParseLimitFromFormWithTwoCommaSeparatedNumbers() {
Limit limit = parser.parseLimit(tokens("LIMIT 10,30"));
assertThat(limit.getRowLimit(), is(20));
assertThat(limit.getOffset(), is(10));
}
@Test
public void shouldReturnNullFromParseLimitWithNoLimitKeyword() {
assertThat(parser.parseLimit(tokens("OTHER")), is(nullValue()));
assertThat(parser.parseLimit(tokens(" ")), is(nullValue()));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLimitIfRowLimitNumberTokenIsNotAnInteger() {
parser.parseLimit(tokens("LIMIT 10a OFFSET 30"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLimitIfOffsetNumberTokenIsNotAnInteger() {
parser.parseLimit(tokens("LIMIT 10 OFFSET 30a"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLimitIfStartingRowNumberTokenIsNotAnInteger() {
parser.parseLimit(tokens("LIMIT 10a,20"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseLimitIfEndingRowNumberTokenIsNotAnInteger() {
parser.parseLimit(tokens("LIMIT 10,20a"));
}
// ----------------------------------------------------------------------------------------------------------------
// parseNamedSelector
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseNamedSelectorFromUnquotedNameWithNoAlias() {
NamedSelector selector = parser.parseNamedSelector(tokens("name"), typeSystem);
assertThat(selector.name(), is(selectorName("name")));
assertThat(selector.alias(), is(nullValue()));
assertThat(selector.aliasOrName(), is(selectorName("name")));
}
@Test
public void shouldParseNamedSelectorFromUnquotedNameWithUnquotedAlias() {
NamedSelector selector = parser.parseNamedSelector(tokens("name AS alias"), typeSystem);
assertThat(selector.name(), is(selectorName("name")));
assertThat(selector.alias(), is(selectorName("alias")));
assertThat(selector.aliasOrName(), is(selectorName("alias")));
}
@Test
public void shouldParseNamedSelectorFromQuotedNameWithUnquotedAlias() {
NamedSelector selector = parser.parseNamedSelector(tokens("'name' AS alias"), typeSystem);
assertThat(selector.name(), is(selectorName("name")));
assertThat(selector.alias(), is(selectorName("alias")));
assertThat(selector.aliasOrName(), is(selectorName("alias")));
}
@Test
public void shouldParseNamedSelectorFromQuotedNameWithQuotedAlias() {
NamedSelector selector = parser.parseNamedSelector(tokens("'name' AS [alias]"), typeSystem);
assertThat(selector.name(), is(selectorName("name")));
assertThat(selector.alias(), is(selectorName("alias")));
assertThat(selector.aliasOrName(), is(selectorName("alias")));
}
@Test( expected = ParsingException.class )
public void shouldFailInParseNamedSelectorIfNoMoreTokens() {
parser.parseNamedSelector(tokens(" "), typeSystem);
}
// ----------------------------------------------------------------------------------------------------------------
// parseSelectorName
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseSelectorNameFromUnquotedString() {
assertThat(parser.parseSelectorName(tokens("name"), typeSystem), is(selectorName("name")));
}
@Test
public void shouldParseSelectorNameFromQuotedString() {
assertThat(parser.parseSelectorName(tokens("'name'"), typeSystem), is(selectorName("name")));
}
@Test( expected = ParsingException.class )
public void shouldFailInParseSelectorNameIfNoMoreTokens() {
parser.parseSelectorName(tokens(" "), typeSystem);
}
// ----------------------------------------------------------------------------------------------------------------
// parseName
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseNameFromSingleQuotedString() {
assertThat(parser.parseName(tokens("'jcr:name'"), typeSystem), is("jcr:name"));
}
@Test
public void shouldParseNameFromDoubleQuotedString() {
assertThat(parser.parseName(tokens("\"jcr:name\""), typeSystem), is("jcr:name"));
}
@Test
public void shouldParseNameFromBracketedString() {
assertThat(parser.parseName(tokens("[jcr:name]"), typeSystem), is("jcr:name"));
}
@Test
public void shouldParseNameFromUnquotedStringWithoutPrefix() {
assertThat(parser.parseName(tokens("name"), typeSystem), is("name"));
}
@Test
public void shouldParseNameFromSingleQuotedStringWithoutPrefix() {
assertThat(parser.parseName(tokens("'name'"), typeSystem), is("name"));
}
@Test
public void shouldParseNameFromDoubleQuotedStringWithoutPrefix() {
assertThat(parser.parseName(tokens("\"name\""), typeSystem), is("name"));
}
@Test
public void shouldParseNameFromBracketedStringWithoutPrefix() {
assertThat(parser.parseName(tokens("[name]"), typeSystem), is("name"));
}
@Test
public void shouldParseNameFromBracketedAndQuotedStringWithoutPrefix() {
assertThat(parser.parseName(tokens("['name']"), typeSystem), is("name"));
assertThat(parser.parseName(tokens("[\"name\"]"), typeSystem), is("name"));
}
@Test( expected = ParsingException.class )
public void shouldFailToParseNameIfNoMoreTokens() {
parser.parseName(tokens(" "), typeSystem);
}
// ----------------------------------------------------------------------------------------------------------------
// parsePath
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParsePathFromUnquotedStringConsistingOfSql92Identifiers() {
String identifier = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
assertThat(parser.parsePath(tokens(identifier), typeSystem), is(identifier));
}
@Test
public void shouldParsePathFromSingleQuotedString() {
assertThat(parser.parsePath(tokens("'/a/b/c/mode:something/d'"), typeSystem), is("/a/b/c/mode:something/d"));
}
@Test
public void shouldParsePathFromDoubleQuotedString() {
assertThat(parser.parsePath(tokens("\"/a/b/c/mode:something/d\""), typeSystem), is("/a/b/c/mode:something/d"));
}
@Test( expected = ParsingException.class )
public void shouldFailInParsePathIfNoMoreTokens() {
parser.parsePath(tokens(" "), typeSystem);
}
// ----------------------------------------------------------------------------------------------------------------
// removeBracketsAndQuotes
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldRemoveBracketsAndQuotes() {
assertThat(parser.removeBracketsAndQuotes("string", null), is("string"));
assertThat(parser.removeBracketsAndQuotes("[string]", null), is("string"));
assertThat(parser.removeBracketsAndQuotes("'string'", null), is("string"));
assertThat(parser.removeBracketsAndQuotes("\"string\"", null), is("string"));
assertThat(parser.removeBracketsAndQuotes("word one and two", null), is("word one and two"));
assertThat(parser.removeBracketsAndQuotes("[word one and two]", null), is("word one and two"));
assertThat(parser.removeBracketsAndQuotes("'word one and two'", null), is("word one and two"));
assertThat(parser.removeBracketsAndQuotes("\"word one and two\"", null), is("word one and two"));
}
// ----------------------------------------------------------------------------------------------------------------
// Utility methods
// ----------------------------------------------------------------------------------------------------------------
protected void parse( String query ) {
parser.parseQuery(query, typeSystem);
}
protected SelectorName selectorName( String name ) {
return new SelectorName(name);
}
protected Name name( String name ) {
return (Name)typeSystem.getTypeFactory(PropertyType.NAME.getName()).create(name);
}
protected Path path( String path ) {
return (Path)typeSystem.getTypeFactory(PropertyType.PATH.getName()).create(path);
}
protected DateTime date( String dateTime ) {
return (DateTime)typeSystem.getDateTimeFactory().create(dateTime);
}
protected TokenStream tokens( String content ) {
return new TokenStream(content, new BasicSqlQueryParser.SqlTokenizer(false), false).start();
}
}