/*
* 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.nullValue;
import static org.junit.Assert.assertThat;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Set;
import javax.jcr.Value;
import javax.jcr.query.qom.EquiJoinCondition;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.modeshape.common.FixFor;
import org.modeshape.common.text.TokenStream;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.JcrValueFactory;
import org.modeshape.jcr.cache.NodeKey;
import org.modeshape.jcr.query.JcrTypeSystem;
import org.modeshape.jcr.query.model.And;
import org.modeshape.jcr.query.model.Comparison;
import org.modeshape.jcr.query.model.Constraint;
import org.modeshape.jcr.query.model.DescendantNode;
import org.modeshape.jcr.query.model.DescendantNodeJoinCondition;
import org.modeshape.jcr.query.model.DynamicOperand;
import org.modeshape.jcr.query.model.Join;
import org.modeshape.jcr.query.model.JoinCondition;
import org.modeshape.jcr.query.model.JoinType;
import org.modeshape.jcr.query.model.Literal;
import org.modeshape.jcr.query.model.LiteralValue;
import org.modeshape.jcr.query.model.NamedSelector;
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.Query;
import org.modeshape.jcr.query.model.QueryCommand;
import org.modeshape.jcr.query.model.SameNodeJoinCondition;
import org.modeshape.jcr.query.model.SelectorName;
import org.modeshape.jcr.query.model.SetQuery;
import org.modeshape.jcr.query.model.Source;
import org.modeshape.jcr.query.model.StaticOperand;
import org.modeshape.jcr.query.model.TypeSystem;
import org.modeshape.jcr.value.BinaryValue;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.Path;
import org.modeshape.jcr.value.PropertyType;
import org.modeshape.jcr.value.Reference;
/**
*
*/
public class JcrSql2QueryParserTest {
/**
* Note that this ValueFactory is a simple mock that just returns null for each of its <code>createX()</code> methods, since
* the {@link Value} objects are just placed into the {@link LiteralValue} objects, and we never call
* {@link LiteralValue#getLiteralValue()} in these tests.
*/
@Mock
private JcrValueFactory valueFactory;
private JcrTypeSystem typeSystem;
private JcrSql2QueryParser parser;
private Query query;
@Before
public void beforeEach() {
MockitoAnnotations.initMocks(this);
typeSystem = new MockJcrTypeSystem(valueFactory);
parser = new JcrSql2QueryParser();
}
// ----------------------------------------------------------------------------------------------------------------
// parseQuery
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldParseNominalQueries() {
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived1' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived1' AND PATH() LIKE '/drools:repository/drools:package_area/%'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived2' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived%' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived2' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived1' AND PATH() LIKE '/drools:repository/drools:package_area/%'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived1' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived%' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNameArchived%' AND PATH() LIKE '/drools:repository/drools:package_area/%'");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testRestPost/assets[%]/%' and ( [drools:format]='drl' OR [drools:format]='xls' ) AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testRestDelete/assets[%]/%' and [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testRestDelete/assets[%]/%' and [drools:archive] = 'true' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testRestDelete/assets[%]/%' and [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testPackageSnapshot/assets[%]/%' and [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testPackageSnapshot/assets[%]/%' and [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:packagesnapshot_area/testPackageSnapshot/PROD 2.0/assets[%]/%' and [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/searchByFormat/assets[%]/%' and [drools:format]='xyz' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/searchByFormat/assets[%]/%' and [drools:format]='xyz' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/searchByFormat/assets[%]/%' and ( [drools:format]='xyz' OR [drools:format]='ABC' ) AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/globalArea/assets[%]/%' and [drools:format]='testSearchSharedAssetByFormat' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/org.drools.archivedtest/assets[%]/%' and [drools:archive] = 'true' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/org.drools.archivedtest/assets[%]/%' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testExcludeAssetTypes/assets[%]/%' and not [drools:format]='drl' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testExcludeAssetTypes/assets[%]/%' and not ( [drools:format]='drl' OR [drools:format]='wang' ) AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/testExcludeAssetTypes/assets[%]/%' and not ( [drools:format]='drl' OR [drools:format]='xls' ) AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNamex1' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNamex2' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNamex%' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNamex2' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE [drools:title] LIKE 'findRulesByNamex%' AND PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:subject] LIKE 'testQueryXXX42' AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND [drools:subject] LIKE 'testQueryXXX42' AND [drools:source] LIKE 'database'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false' AND [jcr:created] > '1974-07-10T00:00:00.000-05:00' AND [jcr:created] < '3074-07-10T00:00:00.000-05:00'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false' AND [jcr:created] > '1974-07-10T00:00:00.000-05:00'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false' AND [jcr:created] < '3074-07-10T00:00:00.000-05:00'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false' AND [jcr:created] > '3074-07-10T00:00:00.000-05:00'");
parse("SELECT [drools:title], [drools:description], [drools:archive] FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/%' AND ([drools:subject] LIKE 'testQueryXXX42' OR [drools:subject] LIKE 'wankle') AND ([drools:source] LIKE 'database' OR [drools:source] LIKE 'wankle') AND [drools:archive] = 'false' AND [jcr:created] < '1974-07-10T00:00:00.000-05:00'");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/globalArea/assets[%]/%' and [drools:format]='xyz' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("SELECT * FROM [drools:assetNodeType] WHERE PATH() LIKE '/drools:repository/drools:package_area/globalArea/assets[%]/%' and [drools:format]='xyz' AND [drools:archive] = 'false' ORDER BY [drools:title]");
parse("select * from [mgnl:content] where PATH() like '/modules/%/templates'");
}
@Test
public void shouldParseQueriesUsedInJcrTckTests() {
parse("SELECT * FROM [nt:unstructured] JOIN [mix:referenceable] ON ISSAMENODE([nt:unstructured],[mix:referenceable]) WHERE PATH([nt:unstructured]) LIKE '/testroot/%'");
parse("SELECT * FROM [nt:unstructured] JOIN [nt:base] ON ISSAMENODE([nt:base], [nt:unstructured]) WHERE PATH([nt:unstructured]) LIKE '/testroot/%'");
parse("SELECT * FROM [nt:base] JOIN [mix:referenceable] ON ISSAMENODE([nt:base], [mix:referenceable]) WHERE PATH([nt:base]) LIKE '/testroot/%'");
parse("SELECT * FROM [nt:unstructured] JOIN [mix:referenceable] ON ISSAMENODE([nt:unstructured], [mix:referenceable]) WHERE PATH([nt:unstructured]) LIKE '/testroot/%'");
parse("SELECT prop1 FROM [nt:unstructured] WHERE prop2 IN ('two') AND prop1 = 'existence' AND PATH() LIKE '/testroot/%'");
}
@Test
public void shouldParseSelectStarFromSingleSourceWithWhereContainingPathLikeConstraint() {
query = parse("SELECT * FROM [mgnl:content] WHERE PATH() LIKE '/modules/%/templates'");
assertThat(query.source(), is(instanceOf(NamedSelector.class)));
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("mgnl:content")));
assertThat(selector.aliasOrName(), is(selectorName("mgnl:content")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
Comparison comparison = isComparison(query.constraint());
assertThat(comparison.getOperand1(), is((DynamicOperand)nodePath(selectorName("mgnl:content"))));
assertThat(comparison.getOperand2(), is((StaticOperand)literal("/modules/%/templates")));
}
@Test
public void shouldParseSelectStarFromSingleSourceWithWhereContainingTwoPathLikeConstraints() {
query = parse("SELECT * FROM [mgnl:content] WHERE PATH() LIKE '/modules/%/templates' or PATH() like '/modules/%/other'");
assertThat(query.source(), is(instanceOf(NamedSelector.class)));
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("mgnl:content")));
assertThat(selector.aliasOrName(), is(selectorName("mgnl:content")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
Or and = isOr(query.constraint());
Comparison comparison1 = isComparison(and.left());
assertThat(comparison1.getOperand1(), is((DynamicOperand)nodePath(selectorName("mgnl:content"))));
assertThat(comparison1.getOperand2(), is((StaticOperand)literal("/modules/%/templates")));
Comparison comparison2 = isComparison(and.right());
assertThat(comparison2.getOperand1(), is((DynamicOperand)nodePath(selectorName("mgnl:content"))));
assertThat(comparison2.getOperand2(), is((StaticOperand)literal("/modules/%/other")));
}
@Test
public void shouldParseSelectStarFromTwoJoinedSourcesWithWhereContainingJoinCriteria() {
query = parse("SELECT * FROM [mgnl:content] JOIN [acme:stuff] ON ISSAMENODE([mgnl:content],[acme:stuff])");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
Join join = isJoin(query.source());
assertThat(join.getLeft(), is((Source)namedSelector(selectorName("mgnl:content"))));
assertThat(join.getRight(), is((Source)namedSelector(selectorName("acme:stuff"))));
assertThat(join.type(), is(JoinType.INNER));
SameNodeJoinCondition joinCondition = isSameNodeJoinCondition(join.getJoinCondition());
assertThat(joinCondition.selector1Name(), is(selectorName("mgnl:content")));
assertThat(joinCondition.selector2Name(), is(selectorName("acme:stuff")));
assertThat(joinCondition.getSelector2Path(), is(nullValue()));
// WHERE ...
assertThat(query.constraint(), is(nullValue()));
}
@Test
public void shouldParseSelectStarFromThreeJoinedSourcesWithWhereContainingJoinCriteria() {
query = parse("SELECT * FROM [mgnl:content] JOIN [acme:stuff] ON ISSAMENODE([mgnl:content],[acme:stuff]) JOIN [foo:bar] ON ISSAMENODE([mgnl:content],[foo:bar])");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
Join join = isJoin(query.source());
Join join2 = isJoin(join.getLeft());
assertThat(join2.getLeft(), is((Source)namedSelector(selectorName("mgnl:content"))));
assertThat(join2.getRight(), is((Source)namedSelector(selectorName("acme:stuff"))));
assertThat(join2.type(), is(JoinType.INNER));
SameNodeJoinCondition joinCondition2 = isSameNodeJoinCondition(join2.getJoinCondition());
assertThat(joinCondition2.selector1Name(), is(selectorName("mgnl:content")));
assertThat(joinCondition2.selector2Name(), is(selectorName("acme:stuff")));
assertThat(joinCondition2.getSelector2Path(), is(nullValue()));
assertThat(join.getRight(), is((Source)namedSelector(selectorName("foo:bar"))));
assertThat(join.type(), is(JoinType.INNER));
SameNodeJoinCondition joinCondition = isSameNodeJoinCondition(join.getJoinCondition());
assertThat(joinCondition.selector1Name(), is(selectorName("mgnl:content")));
assertThat(joinCondition.selector2Name(), is(selectorName("foo:bar")));
assertThat(joinCondition.getSelector2Path(), is(nullValue()));
// WHERE ...
assertThat(query.constraint(), is(nullValue()));
}
@Test
public void shouldParseSelectStarFromEquijoinAndAdditionalCriteria() {
query = parse("SELECT * FROM [modetest:queryable] JOIN [mix:referenceable] ON ISSAMENODE([modetest:queryable],[mix:referenceable]) WHERE PATH([modetest:queryable]) LIKE '/testroot/someQueryableNodeD/%'");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
Join join = isJoin(query.source());
assertThat(join.getLeft(), is((Source)namedSelector(selectorName("modetest:queryable"))));
assertThat(join.getRight(), is((Source)namedSelector(selectorName("mix:referenceable"))));
assertThat(join.type(), is(JoinType.INNER));
SameNodeJoinCondition joinCondition = isSameNodeJoinCondition(join.getJoinCondition());
assertThat(joinCondition.selector1Name(), is(selectorName("modetest:queryable")));
assertThat(joinCondition.selector2Name(), is(selectorName("mix:referenceable")));
assertThat(joinCondition.getSelector2Path(), is(nullValue()));
// WHERE ...
Comparison comparison = isComparison(query.constraint());
assertThat(comparison.getOperand1(), is((DynamicOperand)nodePath(selectorName("modetest:queryable"))));
assertThat(comparison.getOperand2(), is((StaticOperand)literal("/testroot/someQueryableNodeD/%")));
}
@Test
public void shouldParseSelectWithOrderByClause() {
query = parse("SELECT [car:model] FROM [car:Car] WHERE [car:model] IS NOT NULL ORDER BY [car:model] ASC");
// SELECT car:model ...
assertThat(query.columns().size(), is(1));
assertThat(query.columns().get(0).selectorName(), is(selectorName("car:Car")));
assertThat(query.columns().get(0).getColumnName(), is("car:model"));
assertThat(query.columns().get(0).getPropertyName(), is("car:model"));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("car:Car")));
assertThat(selector.aliasOrName(), is(selectorName("car:Car")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
PropertyExistence constraint = isPropertyExistence(query.constraint());
assertThat(constraint.getPropertyName(), is("car:model"));
assertThat(constraint.selectorName(), is(selectorName("car:Car")));
// ORDER BY ...
assertThat(query.orderings().size(), is(1));
Ordering ordering = query.orderings().get(0);
assertThat(ordering.order(), is(Order.ASCENDING));
assertThat(ordering.getOperand(), is((DynamicOperand)propertyValue(selectorName("car:Car"), "car:model")));
}
/**
* Tests that the child nodes (but no grandchild nodes) are returned.
*/
@Test
public void shouldParseSelectWithChildAxisCriteria() {
query = parse("SELECT * FROM [nt:base] WHERE PATH() LIKE '/a/b/%' AND NOT PATH() LIKE '/a/b/%/%'");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("nt:base")));
assertThat(selector.aliasOrName(), is(selectorName("nt:base")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
And and = isAnd(query.constraint());
Comparison comparison1 = isComparison(and.left());
assertThat(comparison1.getOperand1(), is((DynamicOperand)nodePath(selectorName("nt:base"))));
assertThat(comparison1.getOperand2(), is((StaticOperand)literal("/a/b/%")));
Not not = isNot(and.right());
Comparison comparison2a = isComparison(not.getConstraint());
assertThat(comparison2a.getOperand1(), is((DynamicOperand)nodePath(selectorName("nt:base"))));
assertThat(comparison2a.getOperand2(), is((StaticOperand)literal("/a/b/%/%")));
}
@Test
public void shouldParseDescendantNodeJoinWithNoCriteria() {
query = parse("select * from [lom:Metadata] as lom join [lom:LangString] as lang on isdescendantnode(lang,lom)");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
Join join = isJoin(query.source());
assertThat(join.getLeft(), is((Source)namedSelector(selectorName("lom:Metadata"), selectorName("lom"))));
assertThat(join.getRight(), is((Source)namedSelector(selectorName("lom:LangString"), selectorName("lang"))));
assertThat(join.type(), is(JoinType.INNER));
DescendantNodeJoinCondition joinCondition = isDescendantNodeJoinCondition(join.getJoinCondition());
assertThat(joinCondition.ancestorSelectorName(), is(selectorName("lom")));
assertThat(joinCondition.descendantSelectorName(), is(selectorName("lang")));
}
@FixFor( "MODE-1366" )
@Test
public void shouldParseSelectStarFromSourceWithDescendantNodeCriteriaWithNoSnsIndexInPath() {
query = parse("SELECT * FROM [car:Car] WHERE ISDESCENDANTNODE([car:Car],[/foo/bar])");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("car:Car")));
assertThat(selector.aliasOrName(), is(selectorName("car:Car")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
DescendantNode desc = isDescendantNodeCriteria(query.constraint());
assertThat(desc.getSelectorName(), is("car:Car"));
assertThat(desc.getAncestorPath(), is("/foo/bar"));
}
@FixFor( "MODE-1366" )
@Test
public void shouldParseSelectStarFromSourceWithDescendantNodeCriteriaWithSnsIndexInPathAndSquareBrackets() {
query = parse("SELECT * FROM [car:Car] WHERE ISDESCENDANTNODE([car:Car],[/foo/bar[2]])");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("car:Car")));
assertThat(selector.aliasOrName(), is(selectorName("car:Car")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
DescendantNode desc = isDescendantNodeCriteria(query.constraint());
assertThat(desc.getSelectorName(), is("car:Car"));
assertThat(desc.getAncestorPath(), is("/foo/bar[2]"));
}
@FixFor( "MODE-1366" )
@Test
public void shouldParseSelectStarFromSourceWithDescendantNodeCriteriaWithSnsIndexInPath() {
query = parse("SELECT * FROM [car:Car] WHERE ISDESCENDANTNODE([car:Car],'/foo/bar[2]')");
// SELECT * ...
assertThat(query.columns().isEmpty(), is(true));
// FROM ...
NamedSelector selector = (NamedSelector)query.source();
assertThat(selector.name(), is(selectorName("car:Car")));
assertThat(selector.aliasOrName(), is(selectorName("car:Car")));
assertThat(selector.alias(), is(nullValue()));
// WHERE ...
DescendantNode desc = isDescendantNodeCriteria(query.constraint());
assertThat(desc.getSelectorName(), is("car:Car"));
assertThat(desc.getAncestorPath(), is("/foo/bar[2]"));
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedPathInSelect() {
query = parse("select [jcr:primaryType], [jcr:path] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeNameInSelect() {
query = parse("select [jcr:primaryType], [jcr:name] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeLocalNameInSelect() {
query = parse("select [jcr:primaryType], [jcr:localName] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeDepthInSelect() {
query = parse("select [jcr:primaryType], [jcr:depth] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeScoreInSelect() {
query = parse("select [jcr:primaryType], [jcr:score] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedPathInSelect() {
query = parse("select [nt:base].[jcr:primaryType], [nt:base].[jcr:path] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeNameInSelect() {
query = parse("select [nt:base].[jcr:primaryType], [nt:base].[jcr:name] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeLocalNameInSelect() {
query = parse("select [nt:base].[jcr:primaryType], [nt:base].[jcr:localName] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeDepthInSelect() {
query = parse("select [nt:base].[jcr:primaryType], [nt:base].[jcr:depth] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeScoreInSelect() {
query = parse("select [nt:base].[jcr:primaryType], [nt:base].[jcr:score] FROM [nt:base]");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedPathInCriteria() {
query = parse("select [jcr:primaryType] FROM [nt:base] WHERE [jcr:path] = '/some/path'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeNameInCriteria() {
query = parse("select [jcr:primaryType] FROM [nt:base] WHERE [jcr:path] = 'mode:nodeName'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeLocalNameInCriteria() {
query = parse("select [jcr:primaryType] FROM [nt:base] WHERE [jcr:localName] = 'nodeName'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeDepthInCriteria() {
query = parse("select [jcr:primaryType] FROM [nt:base] WHERE [jcr:depth] = 2");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithUnqualifiedNodeScoreInCriteria() {
query = parse("select [jcr:primaryType] FROM [nt:base] WHERE [jcr:score] <= 2.0");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedPathInCriteria() {
query = parse("select [nt:base].[jcr:primaryType] FROM [nt:base] WHERE [nt:base].[jcr:path] = '/some/path'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeNameInCriteria() {
query = parse("select [nt:base].[jcr:primaryType] FROM [nt:base] WHERE [nt:base].[jcr:name] = 'mode:nodeName'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeLocalNameInCriteria() {
query = parse("select [nt:base].[jcr:primaryType] FROM [nt:base] WHERE [nt:base].[jcr:localName] = 'nodeName'");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeDepthInCriteria() {
query = parse("select [nt:base].[jcr:primaryType] FROM [nt:base] WHERE [nt:base].[jcr:depth] = 3");
}
@FixFor( "MODE-934" )
@Test
public void shouldParseQueryWithQualifiedNodeScoreInCriteria() {
query = parse("select [nt:base].[jcr:primaryType] FROM [nt:base] WHERE [nt:base].[jcr:score] <= 1.3");
}
@Test
public void shouldParseQuery() {
query = parse("SELECT post.\"jcr:uuid\", post.\"text\", post.\"user\" FROM [fincayra.Post] AS post JOIN [fincayra.User] AS u ON post.\"user\"=u.\"jcr:uuid\"");
System.out.println(query);
// SELECT * ...
assertThat(query.columns().size(), is(3));
assertThat(query.columns().get(0).selectorName(), is(selectorName("post")));
assertThat(query.columns().get(0).getColumnName(), is("jcr:uuid"));
assertThat(query.columns().get(0).getPropertyName(), is("jcr:uuid"));
assertThat(query.columns().get(1).selectorName(), is(selectorName("post")));
assertThat(query.columns().get(1).getColumnName(), is("text"));
assertThat(query.columns().get(1).getPropertyName(), is("text"));
assertThat(query.columns().get(2).selectorName(), is(selectorName("post")));
assertThat(query.columns().get(2).getColumnName(), is("user"));
assertThat(query.columns().get(2).getPropertyName(), is("user"));
// FROM ...
Join join = isJoin(query.source());
assertThat(join.getLeft(), is((Source)namedSelector(selectorName("fincayra.Post"), selectorName("post"))));
assertThat(join.getRight(), is((Source)namedSelector(selectorName("fincayra.User"), selectorName("u"))));
assertThat(join.type(), is(JoinType.INNER));
EquiJoinCondition joinCondition = isEquiJoinCondition(join.getJoinCondition());
assertThat(joinCondition.getSelector1Name(), is("post"));
assertThat(joinCondition.getSelector2Name(), is("u"));
assertThat(joinCondition.getProperty1Name(), is("user"));
assertThat(joinCondition.getProperty2Name(), is("jcr:uuid"));
// WHERE ...
assertThat(query.constraint(), is(nullValue()));
}
@Test
@FixFor( "MODE-1594" )
public void shouldParseSetQuery() {
parseSetQuery("SELECT nodes.col1, nodes.col2 FROM table1 AS nodes UNION SELECT edges.col3, edges.col4 FROM table2 AS edges");
parseSetQuery("SELECT nodes.col1, nodes.col2 FROM table1 AS nodes INTERSECT SELECT edges.col3, edges.col4 FROM table2 AS edges");
parseSetQuery("SELECT nodes.col1, nodes.col2 FROM table1 AS nodes EXCEPT SELECT edges.col3, edges.col4 FROM table2 AS edges");
}
protected Join isJoin( Source source ) {
assertThat(source, is(instanceOf(Join.class)));
return (Join)source;
}
protected PropertyExistence isPropertyExistence( Constraint constraint ) {
assertThat(constraint, is(instanceOf(PropertyExistence.class)));
return (PropertyExistence)constraint;
}
protected Not isNot( Constraint constraint ) {
assertThat(constraint, is(instanceOf(Not.class)));
return (Not)constraint;
}
protected Comparison isComparison( Constraint constraint ) {
assertThat(constraint, is(instanceOf(Comparison.class)));
return (Comparison)constraint;
}
protected DescendantNode isDescendantNodeCriteria( Constraint constraint ) {
assertThat(constraint, is(instanceOf(DescendantNode.class)));
return (DescendantNode)constraint;
}
protected SameNodeJoinCondition isSameNodeJoinCondition( JoinCondition condition ) {
assertThat(condition, is(instanceOf(SameNodeJoinCondition.class)));
return (SameNodeJoinCondition)condition;
}
protected EquiJoinCondition isEquiJoinCondition( JoinCondition condition ) {
assertThat(condition, is(instanceOf(EquiJoinCondition.class)));
return (EquiJoinCondition)condition;
}
protected DescendantNodeJoinCondition isDescendantNodeJoinCondition( JoinCondition condition ) {
assertThat(condition, is(instanceOf(DescendantNodeJoinCondition.class)));
return (DescendantNodeJoinCondition)condition;
}
protected And isAnd( Constraint constraint ) {
assertThat(constraint, is(instanceOf(And.class)));
return (And)constraint;
}
protected Or isOr( Constraint constraint ) {
assertThat(constraint, is(instanceOf(Or.class)));
return (Or)constraint;
}
protected NodePath nodePath( SelectorName name ) {
return new NodePath(name);
}
protected PropertyValue propertyValue( SelectorName selectorName,
String propertyName ) {
return new PropertyValue(selectorName, propertyName);
}
protected Literal literal( Object value ) {
return new Literal(value);
}
protected NamedSelector namedSelector( SelectorName selectorName ) {
return new NamedSelector(selectorName);
}
protected NamedSelector namedSelector( SelectorName selectorName,
SelectorName alias ) {
return new NamedSelector(selectorName, alias);
}
// ----------------------------------------------------------------------------------------------------------------
// removeBracketsAndQuotes
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// Utility methods
// ----------------------------------------------------------------------------------------------------------------
protected Query parse( String query ) {
QueryCommand command = parseCommand(query);
assertThat(command, is(instanceOf(Query.class)));
return (Query)command;
}
protected SetQuery parseSetQuery( String query ) {
QueryCommand command = parser.parseQuery(query, typeSystem);
assertThat(command, is(instanceOf(SetQuery.class)));
return (SetQuery)command;
}
protected QueryCommand parseCommand( String query ) {
return 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 TokenStream tokens( String content ) {
return new TokenStream(content, new BasicSqlQueryParser.SqlTokenizer(false), false).start();
}
protected static class MockJcrTypeSystem extends JcrTypeSystem {
protected final JcrValueFactory valueFactory;
protected final TypeSystem delegate;
protected final ExecutionContext executionContext;
protected MockJcrTypeSystem( JcrValueFactory valueFactory ) {
this.executionContext = new ExecutionContext();
this.valueFactory = valueFactory;
this.delegate = this.executionContext.getValueFactories().getTypeSystem();
}
@Override
public Set<String> getTypeNames() {
return delegate.getTypeNames();
}
@Override
public TypeFactory<?> getTypeFactory( Object prototype ) {
return delegate.getTypeFactory(prototype);
}
@Override
public TypeFactory<?> getTypeFactory( String typeName ) {
return delegate.getTypeFactory(typeName);
}
@Override
public TypeFactory<String> getStringFactory() {
return delegate.getStringFactory();
}
@Override
public TypeFactory<Reference> getReferenceFactory() {
return delegate.getReferenceFactory();
}
@Override
public TypeFactory<Path> getPathFactory() {
return delegate.getPathFactory();
}
@Override
public TypeFactory<Long> getLongFactory() {
return delegate.getLongFactory();
}
@Override
public TypeFactory<Double> getDoubleFactory() {
return delegate.getDoubleFactory();
}
@Override
public TypeFactory<Name> getNameFactory() {
return delegate.getNameFactory();
}
@Override
public TypeFactory<NodeKey> getNodeKeyFactory() {
return delegate.getNodeKeyFactory();
}
@Override
public String getDefaultType() {
return delegate.getDefaultType();
}
@Override
public Comparator<Object> getDefaultComparator() {
return delegate.getDefaultComparator();
}
@Override
public TypeFactory<BigDecimal> getDecimalFactory() {
return delegate.getDecimalFactory();
}
@Override
public TypeFactory<?> getDateTimeFactory() {
return delegate.getDateTimeFactory();
}
@Override
public String getCompatibleType( String type1,
String type2 ) {
return delegate.getCompatibleType(type1, type2);
}
@Override
public TypeFactory<?> getCompatibleType( TypeFactory<?> type1,
TypeFactory<?> type2 ) {
return delegate.getCompatibleType(type1, type2);
}
@Override
public TypeFactory<Boolean> getBooleanFactory() {
return delegate.getBooleanFactory();
}
@Override
public TypeFactory<BinaryValue> getBinaryFactory() {
return delegate.getBinaryFactory();
}
@Override
public String asString( Object value ) {
return delegate.asString(value);
}
@Override
public JcrValueFactory getValueFactory() {
return valueFactory;
}
}
}