blob: 6375153bed0a7678c3431f60d244099bc5b57b35 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you 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.apache.jackrabbit.oak.query.index;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.of;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
import static org.apache.jackrabbit.oak.api.Type.LONG;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.jackrabbit.oak.Oak;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.ContentRepository;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.InitialContent;
import org.apache.jackrabbit.oak.query.AbstractQueryTest;
import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests the query engine using the default index implementation: the
* {@link TraversingIndex}
*/
public class TraversingIndexQueryTest extends AbstractQueryTest {
@Override
protected ContentRepository createRepository() {
return new Oak()
.with(new OpenSecurityProvider())
.with(new InitialContent())
.createContentRepository();
}
@Test
public void sql1() throws Exception {
test("sql1.txt");
}
@Test
public void sql2() throws Exception {
test("sql2.txt");
}
@Test
@Ignore("OAK-2050")
public void testFullTextTerm() throws Exception {
//OAK-1024 allow '/' in a full-text query
Tree node = root.getTree("/").addChild("content");
node.setProperty("jcr:mimeType", "text/plain");
root.commit();
assertQuery("//*[jcr:contains(., 'text/plain')]", "xpath",
ImmutableList.of("/content"));
}
@Test
@Ignore("OAK-2050")
public void testFullTextTermName() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("testFullTextTermNameSimple");
c.addChild("testFullTextTermNameFile.txt");
root.commit();
assertQuery("//*[jcr:contains(., 'testFullTextTermNameSimple')]",
"xpath",
ImmutableList.of("/content/testFullTextTermNameSimple"));
assertQuery("//*[jcr:contains(., 'testFullTextTermNameFile.txt')]",
"xpath",
ImmutableList.of("/content/testFullTextTermNameFile.txt"));
}
@Test
public void testMultiNotEqual() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("one").setProperty("prop", "value");
c.addChild("two").setProperty("prop",
ImmutableList.of("aaa", "value", "bbb"), Type.STRINGS);
c.addChild("three").setProperty("prop",
ImmutableList.of("aaa", "bbb", "ccc"), Type.STRINGS);
root.commit();
assertQuery("//*[@prop != 'value']", "xpath",
ImmutableList.of("/content/two", "/content/three"));
}
@Test
public void testMultiAndEquals() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("one").setProperty("prop", "aaa");
c.addChild("two").setProperty("prop",
ImmutableList.of("aaa", "bbb", "ccc"), Type.STRINGS);
c.addChild("three").setProperty("prop", ImmutableList.of("aaa", "bbb"),
Type.STRINGS);
root.commit();
assertQuery("//*[(@prop = 'aaa' and @prop = 'bbb' and @prop = 'ccc')]",
"xpath", ImmutableList.of("/content/two"));
}
@Test
public void testMultiAndLike() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("one").setProperty("prop", "aaaBoom");
c.addChild("two").setProperty("prop",
ImmutableList.of("aaaBoom", "bbbBoom", "cccBoom"), Type.STRINGS);
c.addChild("three").setProperty("prop", ImmutableList.of("aaaBoom", "bbbBoom"),
Type.STRINGS);
root.commit();
assertQuery("//*[(jcr:like(@prop, 'aaa%') and jcr:like(@prop, 'bbb%') and jcr:like(@prop, 'ccc%'))]",
"xpath", ImmutableList.of("/content/two"));
}
@Test
public void testSubPropertyMultiAndEquals() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("one").addChild("child").setProperty("prop", "aaa");
c.addChild("two")
.addChild("child")
.setProperty("prop", ImmutableList.of("aaa", "bbb", "ccc"),
Type.STRINGS);
c.addChild("three")
.addChild("child")
.setProperty("prop", ImmutableList.of("aaa", "bbb"),
Type.STRINGS);
root.commit();
assertQuery(
"//*[(child/@prop = 'aaa' and child/@prop = 'bbb' and child/@prop = 'ccc')]",
"xpath", ImmutableList.of("/content/two"));
}
@Test
public void testSubPropertyMultiAndLike() throws Exception {
Tree c = root.getTree("/").addChild("content");
c.addChild("one").addChild("child").setProperty("prop", "aaaBoom");
c.addChild("two")
.addChild("child")
.setProperty("prop", ImmutableList.of("aaaBoom", "bbbBoom", "cccBoom"),
Type.STRINGS);
c.addChild("three")
.addChild("child")
.setProperty("prop", ImmutableList.of("aaaBoom", "bbbBoom"),
Type.STRINGS);
root.commit();
assertQuery(
"//*[(jcr:like(child/@prop, 'aaa%') and jcr:like(child/@prop, 'bbb%') and jcr:like(child/@prop, 'ccc%'))]",
"xpath", ImmutableList.of("/content/two"));
}
@Test
public void testOak1301() throws Exception {
Tree t1 = root.getTree("/").addChild("home").addChild("users")
.addChild("testing").addChild("socialgraph_test_user_4");
t1.setProperty("jcr:primaryType", "rep:User");
t1.setProperty("rep:authorizableId", "socialgraph_test_user_4");
Tree s = t1.addChild("social");
s.setProperty("jcr:primaryType", "sling:Folder");
Tree r = s.addChild("relationships");
r.setProperty("jcr:primaryType", "sling:Folder");
Tree f = r.addChild("friend");
f.setProperty("jcr:primaryType", "sling:Folder");
Tree sg = f.addChild("socialgraph_test_group");
sg.setProperty("jcr:primaryType", "nt:unstructured");
sg.setProperty("id", "socialgraph_test_group");
Tree t2 = root.getTree("/").addChild("home").addChild("groups")
.addChild("testing").addChild("socialgraph_test_group");
root.commit();
// select [jcr:path], [jcr:score], * from [nt:base] as a where [id/*] =
// 'socialgraph_test_group' and isdescendantnode(a, '/home') /* xpath:
// /jcr:root/home//*[id='socialgraph_test_group'] */
assertQuery(
"/jcr:root/home//*[@id='socialgraph_test_group']",
"xpath",
ImmutableList
.of("/home/users/testing/socialgraph_test_user_4/social/relationships/friend/socialgraph_test_group"));
// sql2 select c.[jcr:path] as [jcr:path], c.[jcr:score] as [jcr:score],
// c.* from [nt:base] as a inner join [nt:base] as b on ischildnode(b,
// a) inner join [nt:base] as c on isdescendantnode(c, b) where name(a)
// = 'social' and isdescendantnode(a, '/home') and name(b) =
// 'relationships' and c.[id/*] = 'socialgraph_test_group' /* xpath:
// /jcr:root/home//social/relationships//*[id='socialgraph_test_group']
// */
assertQuery(
"/jcr:root/home//social/relationships//*[@id='socialgraph_test_group']",
"xpath",
ImmutableList
.of("/home/users/testing/socialgraph_test_user_4/social/relationships/friend/socialgraph_test_group"));
}
@Test
public void testRelativeProperties() throws Exception {
root.getTree("/").addChild("content").addChild("node1")
.setProperty("prop", 128);
root.commit();
assertQuery("//*[(@prop > 1)]", "xpath",
ImmutableList.of("/content/node1"));
assertQuery("//*[(@prop > 2)]", "xpath",
ImmutableList.of("/content/node1"));
assertQuery("//*[(@prop > 20)]", "xpath",
ImmutableList.of("/content/node1"));
assertQuery("//*[(@prop > 100)]", "xpath",
ImmutableList.of("/content/node1"));
assertQuery("//*[(@prop > 200)]", "xpath", new ArrayList<String>());
assertQuery("//*[(@prop > 1000)]", "xpath", new ArrayList<String>());
assertQuery("//*[(*/@prop > 1)]", "xpath", ImmutableList.of("/content"));
assertQuery("//*[(*/@prop > 2)]", "xpath", ImmutableList.of("/content"));
assertQuery("//*[(*/@prop > 20)]", "xpath",
ImmutableList.of("/content"));
assertQuery("//*[(*/@prop > 100)]", "xpath",
ImmutableList.of("/content"));
assertQuery("//*[(*/@prop > 200)]", "xpath", new ArrayList<String>());
assertQuery("//*[(*/@prop > 1000)]", "xpath", new ArrayList<String>());
}
@Test // OAK-2062
public void testRelativeProperties2() throws Exception {
Tree t = root.getTree("/").addChild("content").addChild("nodes");
Tree a = t.addChild("a");
a.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
Tree b = a.addChild("b");
b.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
Tree c = b.addChild("c");
c.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
Tree d1 = c.addChild("d1");
d1.setProperty("prop", 10);
d1.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
Tree d2 = c.addChild("d2");
d2.setProperty("prop", 20);
d2.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
Tree d3 = c.addChild("d3");
d3.setProperty("prop", 30);
d3.setProperty(JCR_PRIMARYTYPE, "nt:unstructured", Type.NAME);
root.commit();
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 9)]", "xpath",
ImmutableList.of("/content/nodes/a"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 9)]",
"xpath", ImmutableList.of("/content/nodes/a"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 10)]", "xpath",
ImmutableList.of("/content/nodes/a"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 10)]",
"xpath", ImmutableList.of("/content/nodes/a"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 15)]", "xpath",
ImmutableList.of("/content/nodes/a"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 15)]",
"xpath", ImmutableList.of("/content/nodes/a"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 20)]", "xpath",
ImmutableList.of("/content/nodes/a"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 20)]",
"xpath", ImmutableList.of("/content/nodes/a"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 30)]", "xpath",
ImmutableList.of("/content/nodes/a"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 30)]",
"xpath", ImmutableList.of("/content/nodes/a"));
}
/**
* tests range queries, long comparisons and relative properties
* @throws CommitFailedException
*/
@Test // OAK-2062
public void testRangeRelativeProperties() throws CommitFailedException {
final List<String> emptyList = new ArrayList<String>();
final String property = "prop";
Tree contentNodes, t;
contentNodes = root.getTree("/").addChild("content").addChild("nodes");
/* creating content structure
* content : {
* nodes : {
* a9 {
* b : {
* c : {
* d9 : {
* prop : 9
* }
* }
* }
* },
* a10 {
* b : {
* c : {
* d10 : {
* prop : 10
* }
* }
* }
* },
* a20 {
* b : {
* c : {
* d20 : {
* prop : 20
* }
* }
* }
* },
* a30 {
* b : {
* c : {
* d30 : {
* prop : 30
* }
* }
* }
* },
* }
* }
*
*/
t = addNtUnstructuredChild(contentNodes, "a9", null, null);
t = addNtUnstructuredChild(t, "b", null, null);
t = addNtUnstructuredChild(t, "c", null, null);
t = addNtUnstructuredChild(t, "d9", property, 9L);
t = addNtUnstructuredChild(contentNodes, "a10", null, null);
t = addNtUnstructuredChild(t, "b", null, null);
t = addNtUnstructuredChild(t, "c", null, null);
t = addNtUnstructuredChild(t, "d10", property, 10L);
t = addNtUnstructuredChild(contentNodes, "a20", null, null);
t = addNtUnstructuredChild(t, "b", null, null);
t = addNtUnstructuredChild(t, "c", null, null);
t = addNtUnstructuredChild(t, "d20", property, 20L);
t = addNtUnstructuredChild(contentNodes, "a30", null, null);
t = addNtUnstructuredChild(t, "b", null, null);
t = addNtUnstructuredChild(t, "c", null, null);
t = addNtUnstructuredChild(t, "d30", property, 30L);
root.commit();
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 9)]", "xpath",
of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20",
"/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 10)]", "xpath",
of("/content/nodes/a10", "/content/nodes/a20", "/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 20)]", "xpath",
of("/content/nodes/a20", "/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 30)]", "xpath",
of("/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 40)]", "xpath", emptyList);
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 8)]", "xpath", emptyList);
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 9)]", "xpath",
of("/content/nodes/a9"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 10)]", "xpath",
of("/content/nodes/a9", "/content/nodes/a10"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 20)]", "xpath",
of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20"));
assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 30)]", "xpath",
of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20",
"/content/nodes/a30"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 9)]",
"xpath",
of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20",
"/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 10)]",
"xpath", of("/content/nodes/a10", "/content/nodes/a20", "/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 20)]",
"xpath", of("/content/nodes/a20", "/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 30)]",
"xpath", of("/content/nodes/a30"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 40)]",
"xpath", emptyList);
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 8)]",
"xpath", emptyList);
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 9)]",
"xpath", of("/content/nodes/a9"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 10)]",
"xpath", of("/content/nodes/a9", "/content/nodes/a10"));
assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 20)]",
"xpath", of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20"));
assertQuery(
"/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 30)]",
"xpath",
of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20",
"/content/nodes/a30"));
}
/**
* adds a child of type {@link JcrConstants#NT_UNSTRUCTURED} under the provided {@code parent}
* with the provided {@code name} and an optional {@code propertyName} and {@code value}. If
* either {@code propertyName} or {@code value} are null the property won't be set.
*
* @param parent
* @param name
* @param propertyName
* @param value
* @return
*/
private static Tree addNtUnstructuredChild(@NotNull final Tree parent,
@NotNull final String name,
@Nullable final String propertyName,
@Nullable final Long value) {
checkNotNull(parent);
checkNotNull(name);
Tree ret = parent.addChild(name);
ret.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME);
if (propertyName != null && value != null) {
ret.setProperty(propertyName, value, LONG);
}
return ret;
}
@Test
public void testMultipleRelativeProperties() throws Exception {
Tree content = root.getTree("/").addChild("content");
content.addChild("node1").setProperty("a", 128);
content.addChild("node2").setProperty("a", "abc");
content.addChild("node3").setProperty("a", "1280");
content.addChild("node1").setProperty("b", 128);
content.addChild("node2").setProperty("b", 1024);
content.addChild("node3").setProperty("b", 2048);
content.addChild("node1").setProperty("c", 10.3);
content.addChild("node2").setProperty("c", -10.3);
content.addChild("node3").setProperty("c", 9.8);
content.addChild("node1").setProperty("d", Arrays.asList("x", "y"), Type.STRINGS);
content.addChild("node2").setProperty("d", 10);
content.addChild("node3").setProperty("d", Arrays.asList(1L, 2L), Type.LONGS);
root.commit();
assertQuery("//*[*/@a > 2]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@a > '1']", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@a > 'abd']", "xpath", Arrays.<String>asList());
assertQuery("//*[*/@a = 'abc']", "xpath", Arrays.asList("/content"));
// this may be unexpected: it is evaluated as
// ['128', 'abc', '1280'] >= 'abc'
assertQuery("//*[*/@a >= 'abc']", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@b > 2]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@b > 2048]", "xpath", Arrays.<String>asList());
assertQuery("//*[*/@b > '1']", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@b = 128]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@c > 10]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@c > 11]", "xpath", Arrays.<String>asList());
assertQuery("//*[*/@c > '1']", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@c = 9.8]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@d > 10]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@d > 11]", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@d > '1']", "xpath", Arrays.asList("/content"));
assertQuery("//*[*/@d = 10]", "xpath", Arrays.asList("/content"));
// this may be unexpected: it is evaluated as
// ['x', 'y', '10', '1', '2'] < '3'
assertQuery("//*[*/@d < 3]", "xpath", Arrays.asList("/content"));
}
@Test
public void testLowercaseOnArrays() throws Exception {
// OAK-1829
Tree content = root.getTree("/").addChild("content");
content.setProperty("array", Arrays.asList("X", "Y"), Type.STRINGS);
root.commit();
assertQuery("//*[jcr:like(fn:lower-case(@array), '%x%')]", "xpath",
Arrays.asList("/content"));
}
}