/* * 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.xpath; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.modeshape.common.FixFor; import org.modeshape.jcr.ExecutionContext; import org.modeshape.jcr.query.model.QueryCommand; import org.modeshape.jcr.query.model.TypeSystem; import org.modeshape.jcr.query.parse.BasicSqlQueryParser; import org.modeshape.jcr.query.xpath.XPath.Component; /** * */ public class XPathToQueryTranslatorTest { private ExecutionContext context; private TypeSystem typeSystem; private XPathParser parser; @Before public void beforeEach() { context = new ExecutionContext(); context.getNamespaceRegistry().register("x", "http://example.com"); typeSystem = context.getValueFactories().getTypeSystem(); parser = new XPathParser(typeSystem); } @After public void afterEach() { parser = null; } @Test public void shouldTranslateXPathExpressionsToSql() { printSqlFor("//element(*,my:type)"); printSqlFor("//element(nodeName,my:type)"); } @Test public void shouldTranslateFromXPathOfAnyNode() { assertThat(xpath("//element(*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("/jcr:root//element(*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("//*"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("/jcr:root//*"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("//."), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("/jcr:root//."), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1")); } @Test public void shouldTranslateFromXPathContainingExplicitRootPath() { assertThat(xpath("/jcr:root"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) = '/'")); } @Test public void shouldTranslateFromXPathContainingExplicitPath() { assertThat(xpath("/jcr:root/a"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]'")); assertThat(xpath("/jcr:root/a/b"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); assertThat(xpath("/jcr:root/a/b/c"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]/c[%]' AND DEPTH(nodeSet1) = CAST(3 AS LONG)")); assertThat(xpath("/jcr:root/a/b/c/d"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]/c[%]/d[%]' AND DEPTH(nodeSet1) = CAST(4 AS LONG)")); } @Test public void shouldTranslateFromXPathContainingExplicitPathWithChildNumbers() { assertThat(xpath("/jcr:root/a[2]/b"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[2]/b[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); assertThat(xpath("/jcr:root/a/b[3]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[3]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); assertThat(xpath("/jcr:root/a[2]/b[3]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) = '/a[2]/b[3]'")); } @Test public void shouldTranslateFromXPathContainingExplicitPathWithWildcardChildNumbers() { assertThat(xpath("/jcr:root/a[*]/b"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); assertThat(xpath("/jcr:root/a/b[*]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); assertThat(xpath("/jcr:root/a[*]/b[*]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingNameTestsAndWildcardWithNoPredicates() { assertThat(xpath("/jcr:root/testroot/*"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE PATH(nodeSet1) LIKE '/testroot[%]/%' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingNameTestsAndWildcardWithPredicates() { assertThat(xpath("/jcr:root/testroot/*[@prop1]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE (PATH(nodeSet1) LIKE '/testroot[%]/%' AND DEPTH(nodeSet1) = CAST(2 AS LONG)) AND nodeSet1.prop1 IS NOT NULL")); } @Test public void shouldTranslateFromXPathContainingPathWithDescendantOrSelf() { assertThat(xpath("/jcr:root/a/b//c"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]/c[%]' OR PATH(nodeSet1) LIKE '/a[%]/b[%]/%/c[%]'")); assertThat(xpath("/jcr:root/a/b[2]//c"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[2]/c[%]' OR PATH(nodeSet1) LIKE '/a[%]/b[2]/%/c[%]'")); assertThat(xpath("/jcr:root/a/b//c[4]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[%]/c[4]' OR PATH(nodeSet1) LIKE '/a[%]/b[%]/%/c[4]'")); assertThat(xpath("/jcr:root/a/b[2]//c[4]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/a[%]/b[2]/c[4]' OR PATH(nodeSet1) LIKE '/a[%]/b[2]/%/c[4]'")); } @Test public void shouldTranslateFromXPathContainingPathWithMultipleDescendantOrSelf() { assertThat(xpath("/jcr:root/a/b//c//d"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE (((PATH(nodeSet1) LIKE '/a[%]/b[%]/c[%]/d[%]' OR PATH(nodeSet1) LIKE '/a[%]/b[%]/%/c[%]/d[%]') OR PATH(nodeSet1) LIKE '/a[%]/b[%]/c[%]/%/d[%]') OR PATH(nodeSet1) LIKE '/a[%]/b[%]/%/c[%]/%/d[%]')")); } @Test public void shouldTranslateFromXPathContainingPredicatesUsingRelativePaths() { assertThat(xpath("//element(*,my:type)[a/@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) WHERE NAME(nodeSet1) = 'a' AND nodeSet1.id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[a/b/@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE (NAME(nodeSet1) = 'a' AND NAME(nodeSet2) = 'b') AND nodeSet2.id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[a/b/((@id and @name) or not(@address))]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE (NAME(nodeSet1) = 'a' AND NAME(nodeSet2) = 'b') AND ((nodeSet2.id IS NOT NULL and nodeSet2.name IS NOT NULL) OR (NOT(nodeSet2.address IS NOT NULL)))")); assertThat(xpath("//element(*,my:type)[./a/b/((@id and @name) or not(@address))]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE (NAME(nodeSet1) = 'a' AND NAME(nodeSet2) = 'b') AND ((nodeSet2.id IS NOT NULL and nodeSet2.name IS NOT NULL) OR (NOT(nodeSet2.address IS NOT NULL)))")); assertThat(xpath("//element(*,my:type)[a/b/((@id and @name) or not(jcr:contains(@desc,'rock star')))]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE (NAME(nodeSet1) = 'a' AND NAME(nodeSet2) = 'b') AND ((nodeSet2.id IS NOT NULL and nodeSet2.name IS NOT NULL) OR (NOT(CONTAINS(nodeSet2.desc,'rock star'))))")); assertThat(xpath("//element(*,my:type)[*/@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) WHERE nodeSet1.id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[*/*/@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE nodeSet2.id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[./*/*/@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISCHILDNODE(nodeSet1,[my:type]) JOIN __ALLNODES__ as nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE nodeSet2.id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[.//@id]"), isSql("SELECT * FROM [my:type] JOIN __ALLNODES__ as nodeSet1 ON ISDESCENDANTNODE(nodeSet1,[my:type]) WHERE nodeSet1.id IS NOT NULL")); } @Test public void shouldTranslateFromXPathContainingPredicatesIdentifyingPropertiesThatMustHaveValues() { assertThat(xpath("/jcr:root/testroot/serializationNode[@jcr:primaryType]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE (PATH(nodeSet1) LIKE '/testroot[%]/serializationNode[%]' AND DEPTH(nodeSet1) = CAST(2 AS LONG)) AND nodeSet1.[jcr:primaryType] IS NOT NULL")); assertThat(xpath("//element(*,my:type)[@id]"), isSql("SELECT * FROM [my:type] WHERE id IS NOT NULL")); assertThat(xpath("//element(*,my:type)[@id][@name]"), isSql("SELECT * FROM [my:type] WHERE id IS NOT NULL AND name IS NOT NULL")); assertThat(xpath("//element(*,my:type)[@id | @name]"), isSql("SELECT * FROM [my:type] WHERE id IS NOT NULL OR name IS NOT NULL")); assertThat(xpath("//element(*,my:type)[@id | (@name and @address)]"), isSql("SELECT * FROM [my:type] WHERE id IS NOT NULL OR (name IS NOT NULL AND address IS NOT NULL)")); } @Test public void shouldTranslateFromXPathContainingPredicatesUsingNot() { assertThat(xpath("//element(*,my:type)[not(@id)]"), isSql("SELECT * FROM [my:type] WHERE NOT(id IS NOT NULL)")); assertThat(xpath("//element(*,my:type)[not(jcr:contains(@desc,'rock star'))]"), isSql("SELECT * FROM [my:type] WHERE NOT(CONTAINS(desc,'rock star'))")); assertThat(xpath("//element(*,my:type)[not(@id < 1 and jcr:contains(@desc,'rock star'))]"), isSql("SELECT * FROM [my:type] WHERE NOT(id < '1' AND CONTAINS(desc,'rock star'))")); } @Test public void shouldTranslateFromXPathContainingPredicatesIdentifyingPropertyCriteria() { assertThat(xpath("//element(*,my:type)[@id = 1]"), isSql("SELECT * FROM [my:type] WHERE id = '1'")); assertThat(xpath("//element(*,my:type)[@id < 1 and @name = 'john']"), isSql("SELECT * FROM [my:type] WHERE id < '1' AND name = 'john'")); assertThat(xpath("//element(*,my:type)[@id < 1 and ( @name = 'john' or @name = 'mary')]"), isSql("SELECT * FROM [my:type] WHERE id < '1' AND (name = 'john' OR name = 'mary')")); assertThat(xpath("//element(*,my:type)[@id < 1 and ( jcr:like(@name,'%john') or @name = 'mary')]"), isSql("SELECT * FROM [my:type] WHERE id < '1' AND (name like '%john' OR name = 'mary')")); assertThat(xpath("//element(*,my:type)[@id < 1 and jcr:contains(@desc,'rock star')]"), isSql("SELECT * FROM [my:type] WHERE id < '1' AND CONTAINS(desc,'rock star')")); } @Test public void shouldTranslateFromXPathContainingPredicatesIdentifyingPropertyCriteriaWithTypeCasts() { assertThat(xpath("//element(*,my:type)[@datestart<=xs:dateTime('2009-09-24T11:53:23.293-05:00')]"), isSql("SELECT * FROM [my:type] WHERE datestart <= CAST('2009-09-24T11:53:23.293-05:00' AS DATE)")); assertThat(xpath("//element(*,my:type)[@prop<=xs:boolean('true')]"), isSql("SELECT * FROM [my:type] WHERE prop <= CAST('true' AS BOOLEAN)")); } @Test public void shouldTranslateFromXPathContainingAttributesInPathIdentifyingPropertiesToBeSelected() { assertThat(xpath("//element(*,my:type)/@id"), isSql("SELECT id FROM [my:type]")); assertThat(xpath("//element(*,my:type)/(@id|@name)"), isSql("SELECT id, name FROM [my:type]")); assertThat(xpath("//element(*,my:type)/(@id|@x:address)"), isSql("SELECT id, [x:address] FROM [my:type]")); assertThat(xpath("//element(*,my:type)/(@id|@name|@x:address)"), isSql("SELECT id, name, [x:address] FROM [my:type]")); assertThat(xpath("//element(*,my:type)/(@id union @name)"), isSql("SELECT id, name FROM [my:type]")); assertThat(xpath("//element(*,my:type)/(@id union @name union @x:address)"), isSql("SELECT id, name, [x:address] FROM [my:type]")); assertThat(xpath("//(@id|@name)"), isSql("SELECT nodeSet1.id, nodeSet1.name FROM __ALLNODES__ AS nodeSet1")); assertThat(xpath("//./(@id|@name)"), isSql("SELECT nodeSet1.id, nodeSet1.name FROM __ALLNODES__ AS nodeSet1")); } @Test public void shouldTranslateFromXPathOfAnyNodeOfSpecificType() { assertThat(xpath("//element(*,my:type)"), isSql("SELECT * FROM [my:type]")); } @Test public void shouldTranslateFromXPathOfAnyNodeOfSpecificTypeAndWithSpecificName() { assertThat(xpath("//element(nodeName,my:type)"), isSql("SELECT * FROM [my:type] WHERE NAME([my:type]) = 'nodeName'")); } @Test public void shouldTranslateFromXPathOfAnyNodeWithName() { assertThat(xpath("//element(nodeName,*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName'")); assertThat(xpath("//element(nodeName,*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName'")); assertThat(xpath("//nodeName"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName'")); assertThat(xpath("/jcr:root//element(nodeName,*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName'")); assertThat(xpath("/jcr:root//nodeName"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName'")); } @Test public void shouldTranslateFromXPathOfNodeWithNameUnderRoot() { assertThat(xpath("/jcr:root/element(nodeName,*)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = CAST(1 AS LONG)")); assertThat(xpath("/jcr:root/nodeName"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/nodeName[%]'")); assertThat(xpath("nodeName"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) LIKE '/nodeName[%]'")); } @Test public void shouldTranslateFromXPathOfAnyNodeUsingPredicate() { assertThat(xpath("//.[jcr:contains(.,'bar')]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE CONTAINS(nodeSet1.*,'bar')")); assertThat(xpath("//.[jcr:contains(a,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE CONTAINS(nodeSet2.*,'bar')")); assertThat(xpath("//*[jcr:contains(.,'bar')]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE CONTAINS(nodeSet1.*,'bar')")); assertThat(xpath("//*[jcr:contains(a,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE CONTAINS(nodeSet2.*,'bar')")); assertThat(xpath("//*[jcr:contains(a/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet2.b,'bar')")); assertThat(xpath("//*[jcr:contains(a/*/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) JOIN __ALLNODES__ AS nodeSet3 ON ISCHILDNODE(nodeSet3,nodeSet2) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet3.b,'bar')")); assertThat(xpath("/jcr:root//element(*)[jcr:contains(a/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet2.b,'bar')")); assertThat(xpath("/jcr:root//element(*)[jcr:contains(a/*/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) JOIN __ALLNODES__ AS nodeSet3 ON ISCHILDNODE(nodeSet3,nodeSet2) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet3.b,'bar')")); assertThat(xpath("/jcr:root//*[jcr:contains(a/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet2.b,'bar')")); assertThat(xpath("/jcr:root//*[jcr:contains(a/*/@b,'bar')]"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 JOIN __ALLNODES__ AS nodeSet2 ON ISCHILDNODE(nodeSet2,nodeSet1) JOIN __ALLNODES__ AS nodeSet3 ON ISCHILDNODE(nodeSet3,nodeSet2) WHERE NAME(nodeSet2) = 'a' AND CONTAINS(nodeSet3.b,'bar')")); } @Test public void shouldTranslateFromXPathUsingElementWildcardAndOrderBy() { assertThat(xpath("//element(*,*) order by @title"), isSql("SELECT nodeSet1.title FROM __ALLNODES__ AS nodeSet1 ORDER BY nodeSet1.title")); } @Test public void shouldTranslateFromXPathUsingNameTestsAndWildcardOrderBy() { assertThat(xpath("/jcr:root/testroot/*[@prop1] order by @prop1 ascending"), isSql("SELECT nodeSet1.prop1 FROM __ALLNODES__ as nodeSet1 WHERE (PATH(nodeSet1) LIKE '/testroot[%]/%' AND DEPTH(nodeSet1) = CAST(2 AS LONG)) AND nodeSet1.prop1 IS NOT NULL ORDER BY nodeSet1.prop1")); } @Test public void shouldTranslateFromXPathUsingElementTestForChildrenOfRoot() { assertThat(xpath("/jcr:root/element()"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE DEPTH(nodeSet1) = CAST(1 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingElementTestAndParentPath() { assertThat(xpath("/jcr:root/testroot/element()"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE PATH(nodeSet1) LIKE '/testroot[%]/%' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingElementTestAndAncestorPath() { assertThat(xpath("/jcr:root/testroot//element()"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE PATH(nodeSet1) LIKE '/testroot[%]/%'")); } @Test public void shouldTranslateFromXPathUsingElementTestWithTypeNameForChildrenOfRoot() { assertThat(xpath("/jcr:root/element(nodeName)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = CAST(1 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingElementTestWithTypeNameAndParentPath() { assertThat(xpath("/jcr:root/testroot/element(nodeName)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND PATH(nodeSet1) LIKE '/testroot[%]/%' AND DEPTH(nodeSet1) = CAST(2 AS LONG)")); } @Test public void shouldTranslateFromXPathUsingElementTestWithTypeNameAndAncestorPath() { assertThat(xpath("/jcr:root/testroot//element(nodeName)"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND PATH(nodeSet1) LIKE '/testroot[%]/%'")); } @Test public void shouldTranslateFromXPathContainingSpacesInPath() { assertThat(xpath("/jcr:root/Cars/Sports/Infiniti_x0020_G37[@foo:year='2008']"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE (PATH(nodeSet1) LIKE '/Cars[%]/Sports[%]/Infiniti G37[%]' AND DEPTH(nodeSet1) = CAST(3 AS LONG)) AND nodeSet1.[foo:year] = '2008'")); } @Test public void shouldTranslateFromXPathContainingPathAndAttributeMatch() { assertThat(xpath("/jcr:root/Cars/Sports/InfinitiG37[@foo:year='2008']"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE (PATH(nodeSet1) LIKE '/Cars[%]/Sports[%]/InfinitiG37[%]' AND DEPTH(nodeSet1) = CAST(3 AS LONG)) AND nodeSet1.[foo:year] = '2008'")); } @Test public void shouldTranslateFromXPathContainingAttributeMatch() { assertThat(xpath("//InfinitiG37[@foo:year='2008']"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ as nodeSet1 WHERE PATH(nodeSet1) LIKE '%/InfinitiG37[%]' AND nodeSet1.[foo:year] = '2008'")); } @FixFor( "MODE-790" ) @Test public void shouldTranslateFromXPathContainingCompoundCriteria() { assertThat(xpath("/jcr:root/Cars//element(*,car:Car)[@car:year='2008' and jcr:contains(., '\"liter V 12\"')]"), isSql("SELECT * FROM [car:Car] WHERE (PATH([car:Car]) LIKE '/Cars[%]/%' AND ([car:Car].[car:year] = '2008' AND CONTAINS([car:Car].*,'\"liter V 12\"')))")); } @FixFor( "MODE-790" ) @Test public void shouldTranslateFromXPathContainingCompoundCriteria2() { assertThat(xpath("/jcr:root/drools:repository/drools:package_area//element(*, drools:assetNodeType)[jcr:contains(., 'testQueryText*')]"), isSql("SELECT * FROM [drools:assetNodeType] WHERE (PATH([drools:assetNodeType]) LIKE '/drools:repository[%]/drools:package_area[%]/%' AND CONTAINS([drools:assetNodeType].*,'testQueryText*'))")); } @FixFor( "MODE-790" ) @Test public void shouldTranslateFromXPathContainingCompoundCriteria3() { assertThat(xpath("/jcr:root/drools:repository/drools:package_area//element(*, drools:assetNodeType)[jcr:contains(., 'testQueryText*') and drools:archive = 'false']"), isSql("SELECT * FROM [drools:assetNodeType] WHERE (PATH([drools:assetNodeType]) LIKE '/drools:repository[%]/drools:package_area[%]/%' AND CONTAINS([drools:assetNodeType].*,'testQueryText*') AND [drools:archive] = 'false')")); } @FixFor( "MODE-790" ) @Test public void shouldTranslateFromXPathContainingCompoundCriteria4() { assertThat(xpath("/jcr:root/drools:repository/drools:package_area//element(*, drools:assetNodeType)[jcr:contains(., 'testQueryText*') and @drools:archive = 'false']"), isSql("SELECT * FROM [drools:assetNodeType] WHERE (PATH([drools:assetNodeType]) LIKE '/drools:repository[%]/drools:package_area[%]/%' AND CONTAINS([drools:assetNodeType].*,'testQueryText*') AND [drools:archive] = 'false')")); } @Test public void shouldParseXPathExpressions() { xpath("/jcr:root/a/b/c"); xpath("/jcr:root/a/b/c[*]"); xpath("/jcr:root/some[1]/element(nodes, my:type)[1]"); xpath("//element(*,my:type)"); xpath("//element(*,my:type)[@jcr:title='something' and @globalProperty='something else']"); xpath("//element(*,my:type)[@jcr:title | @globalProperty]"); xpath("//element(*, my:type) order by @my:title"); xpath("//element(*, my:type) [jcr:contains(., 'jcr')] order by jcr:score() descending"); xpath("//element(*, employee)[@secretary and @assistant]"); } @FixFor( "MODE-1144" ) @Test public void shouldTranslateFromXPathContainingContainsCriteria() { assertThat(xpath("//*[@jcr:primaryType='mgnl:content']//*[jcr:contains(., 'paragraph')]"), isSql("SELECT nodeSet1.[jcr:primaryType] FROM __ALLNODES__ AS nodeSet1 WHERE (nodeSet1.[jcr:primaryType] = 'mgnl:content' AND CONTAINS(nodeSet1.*,'paragraph'))")); } @FixFor("MODE-1680") @Test public void shouldTranslateOrderByClauseWithChildAxis() { assertThat(xpath("/jcr:root//element(*,nt:file)[(@jcr:mixinTypes = 'mix:simpleVersionable') and jcr:like(fn:name(), 'a%')]order by jcr:content/@jcr:created ascending"), isSql("SELECT [nt:file].[jcr:created] FROM [nt:file] INNER JOIN [nt:base] AS content ON ISCHILDNODE(content,[nt:file]) WHERE ([nt:file].[jcr:mixinTypes] = 'mix:simpleVersionable' AND NAME([nt:file]) LIKE 'a%') ORDER BY content.[jcr:created] ASC")); } // ---------------------------------------------------------------------------------------------------------------- // utility methods // ---------------------------------------------------------------------------------------------------------------- protected void printSqlFor( String xpath ) { System.out.println("XPath: " + xpath); System.out.println("SQL: " + translateToSql(xpath)); System.out.println(); } private QueryCommand translateToSql( String xpath ) { Component component = parser.parseXPath(xpath); XPathToQueryTranslator translator = new XPathToQueryTranslator(typeSystem, xpath); return translator.createQuery(component); } private QueryCommand xpath( String xpath ) { Component component = parser.parseXPath(xpath); XPathToQueryTranslator translator = new XPathToQueryTranslator(typeSystem, xpath); return translator.createQuery(component); } protected QueryCommand sql( String sql ) { return new BasicSqlQueryParser().parseQuery(sql, typeSystem); } protected Matcher<QueryCommand> isSql( String sql ) { return is(sql(sql)); } }