Author: thomasm
Date: Mon Mar 24 14:14:50 2014
New Revision: 1580862
URL: http://svn.apache.org/r1580862
Log:
OAK-1561 Implement optimised range queries
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTuple.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTupleTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndex.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndex.java
Mon Mar 24 14:14:50 2014
@@ -119,30 +119,32 @@ public class OrderedPropertyIndex extend
String propertyName = PathUtils.getName(pr.propertyName);
if (lookup.isIndexed(propertyName, "/", filter)) {
PropertyValue value = null;
- boolean createPlan = true;
+ boolean createPlan = false;
if (pr.first == null && pr.last == null) {
// open query: [property] is not null
value = null;
+ createPlan = true;
} else if (pr.first != null && pr.first.equals(pr.last) &&
pr.firstIncluding
&& pr.lastIncluding) {
// [property]=[value]
value = pr.first;
-// ----------- DISABLING RANGE QUERIES FOR NOW. EASYING THE INTEGRATION WITH
OAK-622 [BEGIN]
-// } else if (pr.first != null &&
!pr.first.equals(pr.last)) {
-// // '>' & '>=' use cases
-// if (lookup.isAscending(root, propertyName, filter)) {
-// value = pr.first;
-// } else {
-// createPlan = false;
-// }
-// } else if (pr.last != null && !pr.last.equals(pr.first))
{
-// // '<' & '<='
-// if (!lookup.isAscending(root, propertyName, filter))
{
-// value = pr.last;
-// } else {
-// createPlan = false;
-// }
-// ----------- DISABLING RANGE QUERIES FOR NOW. EASYING THE INTEGRATION WITH
OAK-622 [ END ]
+ createPlan = true;
+ } else if (pr.first != null && !pr.first.equals(pr.last)) {
+ // '>' & '>=' use cases
+ if (lookup.isAscending(root, propertyName, filter)) {
+ value = pr.first;
+ createPlan = true;
+ } else {
+ createPlan = false;
+ }
+ } else if (pr.last != null && !pr.last.equals(pr.first)) {
+ // '<' & '<='
+ if (!lookup.isAscending(root, propertyName, filter)) {
+ value = pr.last;
+ createPlan = true;
+ } else {
+ createPlan = false;
+ }
}
if (createPlan) {
// we always return a sorted set
@@ -150,8 +152,8 @@ public class OrderedPropertyIndex extend
b.setSortOrder(ImmutableList.of(new OrderEntry(
propertyName,
Type.UNDEFINED,
- (lookup.isAscending(root, propertyName, filter) ?
OrderEntry.Order.ASCENDING
- :
OrderEntry.Order.DESCENDING))));
+ lookup.isAscending(root, propertyName, filter) ?
OrderEntry.Order.ASCENDING
+ :
OrderEntry.Order.DESCENDING)));
long count =
lookup.getEstimatedEntryCount(propertyName, value, filter, pr);
b.setEstimatedEntryCount(count);
LOG.debug("estimatedCount: {}", count);
@@ -174,7 +176,6 @@ public class OrderedPropertyIndex extend
LOG.debug("getPlanDescription() - plan: {}", plan);
LOG.error("Not implemented yet");
throw new UnsupportedOperationException("Not implemented yet.");
-// return null;
}
@Override
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
Mon Mar 24 14:14:50 2014
@@ -44,7 +44,6 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
-import com.google.common.collect.Iterators;
/**
* Same as for {@link ContentMirrorStoreStrategy} but the order of the keys is
kept by using the
@@ -240,48 +239,7 @@ public class OrderedContentMirrorStoreSt
// if the property is not there or is empty it means we're empty
cne = Collections.emptyList();
} else {
- cne = new Iterable<ChildNodeEntry>() {
- private NodeState localIndex = index;
- private NodeState localStart = includeStart && !start.exists()
? EMPTY_START_NODE
- :
start;
- private NodeState current = localStart;
- private boolean localIncludeStart = includeStart;
-
- @Override
- public Iterator<ChildNodeEntry> iterator() {
- return new Iterator<ChildNodeEntry>() {
-
- @Override
- public boolean hasNext() {
- return (localIncludeStart &&
localStart.equals(current)) || (!localIncludeStart &&
!Strings.isNullOrEmpty(current.getString(NEXT)));
- }
-
- @Override
- public ChildNodeEntry next() {
- ChildNodeEntry localCNE = null;
- if (localIncludeStart &&
localStart.equals(current)) {
- localCNE = new OrderedChildNodeEntry(START,
current);
- // let's set it to false. We just included it.
- localIncludeStart = false;
- } else {
- if (hasNext()) {
- final String name =
current.getString(NEXT);
- current = localIndex.getChildNode(name);
- localCNE = new OrderedChildNodeEntry(name,
current);
- } else {
- throw new NoSuchElementException();
- }
- }
- return localCNE;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
+ cne = new FullIterable(index, includeStart);
}
return cne;
}
@@ -319,52 +277,26 @@ public class OrderedContentMirrorStoreSt
if (pr.first != null && !pr.first.equals(pr.last)) {
// '>' & '>=' use case
- return new Iterable<String>() {
- private PropertyRestriction lpr = pr;
-
- @Override
- public Iterator<String> iterator() {
- PathIterator pi = new PathIterator(filter, indexName);
- Iterator<? extends ChildNodeEntry> children =
getChildNodeEntries(
- index).iterator();
- pi.setPathContainsValue(true);
- pi.enqueue(Iterators.filter(children,
- new Predicate<ChildNodeEntry>() {
- @Override
- public boolean apply(ChildNodeEntry entry) {
- String value = lpr.first
- .getValue(Type.STRING);
- String name = convert(entry.getName());
- return value.compareTo(name) < 0 ||
(lpr.firstIncluding && value
- .equals(name));
- }
- }));
- return pi;
- }
- };
- } else if (pr.last != null && !pr.last.equals(pr.first)) {
+ ChildNodeEntry firstValueableItem = seek(index,
+ new PredicateGreaterThan(pr.first.getValue(Type.STRING),
pr.firstIncluding));
+ Iterable<String> it = Collections.emptyList();
+ if (firstValueableItem != null) {
+ Iterable<ChildNodeEntry> childrenIterable = (pr.last == null)
? new SeekedIterable(
+ index, firstValueableItem) : new BetweenIterable(index,
firstValueableItem,
+ pr.last.getValue(Type.STRING), pr.lastIncluding);
+ it = new QueryResultsWrapper(filter, indexName,
childrenIterable);
+ }
+ return it;
+ } else if (pr.last != null && !pr.last.equals(pr.first)) {
// '<' & '<=' use case
- return new Iterable<String>() {
- private PropertyRestriction lpr = pr;
-
- @Override
- public Iterator<String> iterator() {
- PathIterator pi = new PathIterator(filter, indexName);
- Iterator<? extends ChildNodeEntry> children =
getChildNodeEntries(index)
- .iterator();
- pi.setPathContainsValue(true);
- pi.enqueue(Iterators.filter(children, new
Predicate<ChildNodeEntry>() {
- @Override
- public boolean apply(ChildNodeEntry entry) {
- String value = lpr.last.getValue(Type.STRING);
- String name = convert(entry.getName());
- return (value.compareTo(name) > 0)
- || (lpr.lastIncluding && value.equals(name));
- }
- }));
- return pi;
- }
- };
+ ChildNodeEntry firstValueableItem = seek(index,
+ new PredicateLessThan(pr.last.getValue(Type.STRING),
pr.lastIncluding));
+ Iterable<String> it = Collections.emptyList();
+ if (firstValueableItem != null) {
+ it = new QueryResultsWrapper(filter, indexName, new
SeekedIterable(index,
+ firstValueableItem));
+ }
+ return it;
} else {
// property is not null. AKA "open query"
Iterable<String> values = null;
@@ -499,4 +431,324 @@ public class OrderedContentMirrorStoreSt
}
return count;
}
-}
+
+ /**
+ * wrap an {@code Iterable<ChildNodeEntry>} in something that can be
understood by the Query
+ * Engine
+ */
+ private static class QueryResultsWrapper implements Iterable<String> {
+ private Iterable<ChildNodeEntry> children;
+ private String indexName;
+ private Filter filter;
+
+ public QueryResultsWrapper(Filter filter, String indexName,
+ Iterable<ChildNodeEntry> children) {
+ this.children = children;
+ this.indexName = indexName;
+ this.filter = filter;
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ PathIterator pi = new PathIterator(filter, indexName);
+ pi.setPathContainsValue(true);
+ pi.enqueue(children.iterator());
+ return pi;
+ }
+ }
+
+ /**
+ * iterating throughout the index in the correct order. Externalised as
class for easy
+ * overloading.
+ */
+ private static class FullIterator implements Iterator<ChildNodeEntry> {
+ private boolean includeStart;
+ private NodeState start;
+ private NodeState current;
+ private NodeState index;
+ private String currentName;
+
+ public FullIterator(NodeState index, NodeState start, boolean
includeStart,
+ NodeState current) {
+ this.includeStart = includeStart;
+ this.start = start;
+ this.current = current;
+ this.index = index;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return (includeStart && start.equals(current))
+ || (!includeStart &&
!Strings.isNullOrEmpty(current.getString(NEXT)));
+ }
+
+ @Override
+ public ChildNodeEntry next() {
+ ChildNodeEntry entry = null;
+ if (includeStart && start.equals(current)) {
+ entry = new OrderedChildNodeEntry(START, current);
+ // let's set it to false. We just included it.
+ includeStart = false;
+ } else {
+ if (hasNext()) {
+ currentName = current.getString(NEXT);
+ current = index.getChildNode(currentName);
+ entry = new OrderedChildNodeEntry(currentName, current);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ return entry;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @return the name of the current node. May be null in some cases.
+ */
+ @Nullable
+ String getCurrentName() {
+ return currentName;
+ }
+ }
+
+ /**
+ * Convenience class for iterating throughout the index in the correct
order
+ */
+ private static class FullIterable implements Iterable<ChildNodeEntry> {
+ private boolean includeStart;
+
+ NodeState index;
+ NodeState start;
+ NodeState current;
+
+ /**
+ * @param index the current index content state. The {@code :index}
node
+ * @param includeStart whether include {@code :start} or not.
+ */
+ public FullIterable(NodeState index, boolean includeStart) {
+ this.index = index;
+ this.includeStart = includeStart;
+ NodeState s = index.getChildNode(START);
+ if (includeStart && !s.exists()) {
+ start = EMPTY_START_NODE;
+ } else {
+ start = s;
+ }
+ current = start;
+ }
+
+ @Override
+ public Iterator<ChildNodeEntry> iterator() {
+ return new FullIterator(index, start, includeStart, current);
+ }
+ }
+
+ /**
+ * Iterator that allows to start iterating from a given position
+ */
+ private static class SeekedIterator extends FullIterator {
+ /**
+ * whether the seekeed item has been returned already or not.
+ */
+ private boolean firstReturned;
+
+ /**
+ * the seeked item
+ */
+ private ChildNodeEntry first;
+
+ public SeekedIterator(NodeState index, NodeState start, ChildNodeEntry
first) {
+ super(index, start, false, first.getNodeState());
+ this.first = first;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return !firstReturned || super.hasNext();
+ }
+
+ @Override
+ public ChildNodeEntry next() {
+ if (firstReturned) {
+ return super.next();
+ } else {
+ firstReturned = true;
+ return first;
+ }
+ }
+ }
+
+ /**
+ * iterable that starts at a provided position ({@code ChildNodeEntry})
+ */
+ private static class SeekedIterable extends FullIterable {
+ ChildNodeEntry first;
+
+ public SeekedIterable(NodeState index, ChildNodeEntry first) {
+ super(index, false);
+ this.first = first;
+ }
+
+ @Override
+ public Iterator<ChildNodeEntry> iterator() {
+ return new SeekedIterator(index, start, first);
+ }
+ }
+
+ /**
+ * seek for an element in the index given the provided Predicate
+ *
+ * @param index the index content node {@code :index}
+ * @param condition the predicate to evaluate
+ * @return the entry or null if not found
+ */
+ static ChildNodeEntry seek(@Nonnull NodeState index,
+ @Nonnull Predicate<ChildNodeEntry>
condition) {
+
+ // TODO the FullIterable will have to be replaced with something else
once we'll have the
+ // Skip part of the list implemented.
+ Iterable<ChildNodeEntry> children = new FullIterable(index, false);
+ ChildNodeEntry entry = null;
+ for (ChildNodeEntry child : children) {
+ if (condition.apply(child)) {
+ entry = child;
+ break;
+ }
+ }
+ return entry;
+ }
+
+ /**
+ * predicate for evaluating 'key' equality across index
+ */
+ static class PredicateEquals implements Predicate<ChildNodeEntry> {
+ private String searchfor;
+
+ public PredicateEquals(@Nonnull String searchfor) {
+ this.searchfor = searchfor;
+ }
+
+ @Override
+ public boolean apply(ChildNodeEntry arg0) {
+ return arg0 != null && searchfor.equals(arg0.getName());
+ }
+ }
+
+ /**
+ * evaluates when the current element is greater than (>) and greater than
equal
+ * {@code searchfor}
+ */
+ static class PredicateGreaterThan implements Predicate<ChildNodeEntry> {
+ private String searchfor;
+ private boolean include;
+
+ public PredicateGreaterThan(@Nonnull String searchfor) {
+ this(searchfor, false);
+ }
+
+ public PredicateGreaterThan(@Nonnull String searchfor, boolean
include) {
+ this.searchfor = searchfor;
+ this.include = include;
+ }
+
+ @Override
+ public boolean apply(ChildNodeEntry arg0) {
+ boolean b = false;
+ if (arg0 != null) {
+ String name = convert(arg0.getName());
+ b = searchfor.compareTo(name) < 0 || (include && searchfor
+ .equals(name));
+ }
+
+ return b;
+ }
+ }
+
+ /**
+ * evaluates when the current element is less than (<) and less than equal
{@code searchfor}
+ */
+ static class PredicateLessThan implements Predicate<ChildNodeEntry> {
+ private String searchfor;
+ private boolean include;
+
+ public PredicateLessThan(@Nonnull String searchfor) {
+ this(searchfor, false);
+ }
+
+ public PredicateLessThan(@Nonnull String searchfor, boolean include) {
+ this.searchfor = searchfor;
+ this.include = include;
+ }
+
+ @Override
+ public boolean apply(ChildNodeEntry arg0) {
+ boolean b = false;
+ if (arg0 != null) {
+ String name = convert(arg0.getName());
+ b = searchfor.compareTo(name) > 0 || (include &&
searchfor.equals(name));
+ }
+
+ return b;
+ }
+ }
+
+ /**
+ * iterable for going through a set of data in the case of BETWEEN
queries. We don't have to
+ * return more data for having the Query Engine to skip them later.
+ */
+ private static class BetweenIterable extends SeekedIterable {
+ private String lastKey;
+ private boolean lastInclude;
+
+ public BetweenIterable(NodeState index, ChildNodeEntry first, String
lastKey,
+ boolean lastInclude) {
+ super(index, first);
+ this.lastKey = lastKey;
+ this.lastInclude = lastInclude;
+ }
+
+ @Override
+ public Iterator<ChildNodeEntry> iterator() {
+ return new BetweenIterator(index, start, first, lastKey,
lastInclude);
+ }
+ }
+
+ /**
+ * iterator for iterating in the cases of BETWEEN queries.
+ */
+ private static class BetweenIterator extends SeekedIterator {
+ private String lastKey;
+ private boolean lastInclude;
+
+ /**
+ * @param index the current index content {@code :index}
+ * @param start the {@code :start} node
+ * @param first the first valuable options for starting iterating from.
+ * @param lastKey the last key to be returned
+ * @param lastInclude whether including the last key or not.
+ */
+ public BetweenIterator(NodeState index, NodeState start,
ChildNodeEntry first,
+ String lastKey, boolean lastInclude) {
+ super(index, start, first);
+ this.lastInclude = lastInclude;
+ this.lastKey = lastKey;
+ }
+
+ @Override
+ public boolean hasNext() {
+ boolean next = super.hasNext();
+ String name = getCurrentName();
+
+ if (name != null && next) {
+ name = convert(name);
+ next = next && (lastKey.compareTo(name) > 0 || (lastInclude &&
lastKey
+ .equals(name)));
+ }
+ return next;
+ }
+ }
+}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
Mon Mar 24 14:14:50 2014
@@ -39,7 +39,6 @@ import org.apache.jackrabbit.oak.plugins
import
org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
import org.apache.jackrabbit.oak.spi.query.PropertyValues;
import org.apache.jackrabbit.oak.util.NodeUtil;
-import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.ImmutableMap;
@@ -136,7 +135,7 @@ public class OrderedPropertyIndexDescend
* test the range query in case of '>' condition
* @throws Exception
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryGreaterThan() throws Exception {
initWithProperProvider();
setTravesalEnabled(false);
@@ -172,7 +171,7 @@ public class OrderedPropertyIndexDescend
* test the range query in case of '>=' condition
* @throws Exception
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryGreaterEqualThan() throws Exception {
initWithProperProvider();
setTravesalEnabled(false);
@@ -285,4 +284,40 @@ public class OrderedPropertyIndexDescend
setTravesalEnabled(true);
}
+ /**
+ * testing explicitly OAK-1561 use-case
+ *
+ * @throws CommitFailedException
+ * @throws ParseException
+ */
+ @Test
+ public void queryGreaterThenWithCast() throws CommitFailedException,
ParseException {
+
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY
+ + "> cast('%s' as date)";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+ addChildNodes(generateOrderedDates(NUMBER_OF_NODES, direction, start),
test, direction,
+ Type.DATE);
+ root.commit();
+
+ Calendar searchForCalendar = (Calendar) start.clone();
+ searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
+ String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+ Iterator<? extends ResultRow> results =
executeQuery(String.format(query, searchFor), SQL2,
+ null).getRows().iterator();
+ assertFalse("the index should not be used in this case",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
Mon Mar 24 14:14:50 2014
@@ -55,7 +55,6 @@ import org.apache.jackrabbit.oak.spi.que
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.util.NodeUtil;
-import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
@@ -145,7 +144,7 @@ public class OrderedPropertyIndexQueryTe
* @throws CommitFailedException
* @throws ParseException
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryGreaterThan() throws CommitFailedException,
ParseException {
setTravesalEnabled(false);
@@ -184,7 +183,7 @@ public class OrderedPropertyIndexQueryTe
* @throws CommitFailedException
* @throws ParseException
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryGreaterEqualThan() throws CommitFailedException,
ParseException {
setTravesalEnabled(false);
@@ -226,7 +225,7 @@ public class OrderedPropertyIndexQueryTe
* provider. not the lowcost one.
* @throws Exception
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryLessThan() throws Exception {
initWithProperProvider();
setTravesalEnabled(false);
@@ -264,7 +263,7 @@ public class OrderedPropertyIndexQueryTe
* provider. not the lowcost one.
* @throws Exception
*/
- @Test @Ignore("Disabling for now. Integration with OAK-622 and
prioritising.")
+ @Test
public void queryLessEqualThan() throws Exception {
initWithProperProvider();
initWithProperProvider();
@@ -556,4 +555,247 @@ public class OrderedPropertyIndexQueryTe
setTravesalEnabled(true);
}
+ /**
+ * testing explicitly OAK-1561 use-case
+ *
+ * @throws CommitFailedException
+ * @throws ParseException
+ */
+ @Test
+ public void queryGreaterThenWithCast() throws CommitFailedException,
ParseException {
+
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY
+ + "> cast('%s' as date)";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+ List<ValuePathTuple> nodes = addChildNodes(
+ generateOrderedDates(NUMBER_OF_NODES, direction, start), test,
direction, Type.DATE);
+ root.commit();
+
+ Calendar searchForCalendar = (Calendar) start.clone();
+ searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
+ String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+ Iterator<? extends ResultRow> results =
executeQuery(String.format(query, searchFor), SQL2,
+ null).getRows().iterator();
+ Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
+ new ValuePathTuple.GreaterThanPredicate(searchFor)).iterator();
+ assertRightOrder(Lists.newArrayList(filtered), results);
+ assertFalse("We should have looped throuhg all the results",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
+
+ @Test
+ public void queryBetweenNoIncludes() throws Exception {
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY + "> $start AND "
+ + ORDERED_PROPERTY + " < $end";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+
+ List<ValuePathTuple> nodes = addChildNodes(
+ generateOrderedDates(NUMBER_OF_NODES, direction, start), test,
direction, Type.DATE);
+ root.commit();
+
+ Calendar searchForCalendarStart = (Calendar) start.clone();
+ searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
+ String searchForStart =
ISO_8601_2000.format(searchForCalendarStart.getTime());
+
+ Calendar endCalendar = Calendar.getInstance();
+ endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() -
1).getValue()));
+ endCalendar.add(Calendar.HOUR_OF_DAY, -36);
+ String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+
+ Map<String, PropertyValue> filter = ImmutableMap.of("start",
+ PropertyValues.newDate(searchForStart), "end",
PropertyValues.newDate(searchForEnd));
+ Iterator<? extends ResultRow> results = executeQuery(query, SQL2,
filter).getRows()
+ .iterator();
+
+ Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
false, false))
+ .iterator();
+
+ assertRightOrder(Lists.newArrayList(filtered), results);
+ assertFalse("We should have looped throuhg all the results",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
+
+ @Test
+ public void queryBetweenIncludeLower() throws Exception {
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY + ">= $start AND "
+ + ORDERED_PROPERTY + " < $end";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+
+ List<ValuePathTuple> nodes = addChildNodes(
+ generateOrderedDates(NUMBER_OF_NODES, direction, start), test,
direction, Type.DATE);
+ root.commit();
+
+ Calendar searchForCalendarStart = (Calendar) start.clone();
+ searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
+ String searchForStart =
ISO_8601_2000.format(searchForCalendarStart.getTime());
+
+ Calendar endCalendar = Calendar.getInstance();
+ endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() -
1).getValue()));
+ endCalendar.add(Calendar.HOUR_OF_DAY, -36);
+ String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+
+ Map<String, PropertyValue> filter = ImmutableMap.of("start",
+ PropertyValues.newDate(searchForStart), "end",
PropertyValues.newDate(searchForEnd));
+ Iterator<? extends ResultRow> results = executeQuery(query, SQL2,
filter).getRows()
+ .iterator();
+
+ Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
true, false))
+ .iterator();
+
+ assertRightOrder(Lists.newArrayList(filtered), results);
+ assertFalse("We should have looped throuhg all the results",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
+
+ @Test
+ public void queryBetweenIncludeHigher() throws Exception {
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY + "> $start AND "
+ + ORDERED_PROPERTY + " <= $end";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+
+ List<ValuePathTuple> nodes = addChildNodes(
+ generateOrderedDates(10, direction, start), test, direction,
Type.DATE);
+ root.commit();
+
+ for (ValuePathTuple n : nodes) {
+ n.toString();
+ // System.out.println("+++" + n);
+ }
+
+ Calendar searchForCalendarStart = (Calendar) start.clone();
+ searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
+ String searchForStart =
ISO_8601_2000.format(searchForCalendarStart.getTime());
+
+ Calendar endCalendar = Calendar.getInstance();
+ endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() -
1).getValue()));
+ endCalendar.add(Calendar.HOUR_OF_DAY, -36);
+ String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+
+ Map<String, PropertyValue> filter = ImmutableMap.of("start",
+ PropertyValues.newDate(searchForStart), "end",
PropertyValues.newDate(searchForEnd));
+ Iterator<? extends ResultRow> results = executeQuery(query, SQL2,
filter).getRows()
+ .iterator();
+
+ Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
false, true))
+ .iterator();
+
+ while (filtered.hasNext()) {
+ System.out.println("---" + filtered.next());
+ }
+ filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
false, true))
+ .iterator();
+
+ assertRightOrder(Lists.newArrayList(filtered), results);
+ assertFalse("We should have looped throuhg all the results",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
+
+ @Test
+ public void queryBetweenIncludeBoth() throws Exception {
+ setTravesalEnabled(false);
+
+ final OrderDirection direction = OrderDirection.ASC;
+ final String query = "SELECT * FROM [nt:base] WHERE " +
ORDERED_PROPERTY + ">= $start AND "
+ + ORDERED_PROPERTY + " <= $end";
+
+ // index automatically created by the framework:
+ // {@code createTestIndexNode()}
+
+ // initialising the data
+ Tree rTree = root.getTree("/");
+ Tree test = rTree.addChild("test");
+ Calendar start = midnightFirstJan2013();
+
+ List<ValuePathTuple> nodes = addChildNodes(
+ generateOrderedDates(10, direction, start), test, direction,
Type.DATE);
+ root.commit();
+
+ for (ValuePathTuple n : nodes) {
+ n.toString();
+ // System.out.println("+++" + n);
+ }
+
+ Calendar searchForCalendarStart = (Calendar) start.clone();
+ searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
+ String searchForStart =
ISO_8601_2000.format(searchForCalendarStart.getTime());
+
+ Calendar endCalendar = Calendar.getInstance();
+ endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() -
1).getValue()));
+ endCalendar.add(Calendar.HOUR_OF_DAY, -36);
+ String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+
+ Map<String, PropertyValue> filter = ImmutableMap.of("start",
+ PropertyValues.newDate(searchForStart), "end",
PropertyValues.newDate(searchForEnd));
+ Iterator<? extends ResultRow> results = executeQuery(query, SQL2,
filter).getRows()
+ .iterator();
+
+ Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
false, true))
+ .iterator();
+
+ while (filtered.hasNext()) {
+ System.out.println("---" + filtered.next());
+ }
+ filtered = Iterables.filter(nodes,
+ new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd,
true, true))
+ .iterator();
+
+ assertRightOrder(Lists.newArrayList(filtered), results);
+ assertFalse("We should have looped throuhg all the results",
results.hasNext());
+
+ setTravesalEnabled(true);
+
+ }
}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTuple.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTuple.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTuple.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTuple.java
Mon Mar 24 14:14:50 2014
@@ -87,6 +87,28 @@ public class ValuePathTuple implements C
}
+ public static class BetweenPredicate implements Predicate<ValuePathTuple> {
+ private String start;
+ private String end;
+ private boolean includeStart;
+ private boolean includeEnd;
+
+ public BetweenPredicate(String start, String end, boolean
includeStart, boolean includeEnd) {
+ this.start = start;
+ this.end = end;
+ this.includeStart = includeStart;
+ this.includeEnd = includeEnd;
+ }
+
+ @Override
+ public boolean apply(ValuePathTuple arg0) {
+ String other = arg0.getValue();
+ return
+ (start.compareTo(other) < 0 || (includeStart &&
start.equals(other)))
+ && (end.compareTo(other) > 0 || (includeEnd &&
end.equals(other)));
+ }
+ }
+
ValuePathTuple(String value, String path) {
this.value = value;
this.path = path;
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTupleTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTupleTest.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTupleTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/ValuePathTupleTest.java
Mon Mar 24 14:14:50 2014
@@ -140,7 +140,7 @@ public class ValuePathTupleTest {
new ValuePathTuple("e", "foobar"),
new ValuePathTuple("f", "foobar"));
Iterator<ValuePathTuple> filtered = Iterables.filter(data,
- new ValuePathTuple.LessThanPredicate("e",true)).iterator();
+ new ValuePathTuple.LessThanPredicate("e", true)).iterator();
assertTrue(filtered.hasNext());
assertEquals("a", filtered.next().getValue());
assertEquals("b", filtered.next().getValue());
@@ -149,4 +149,72 @@ public class ValuePathTupleTest {
assertEquals("e", filtered.next().getValue());
assertFalse(filtered.hasNext());
}
+
+ @Test
+ public void betweenNoIncludes() {
+ List<ValuePathTuple> data = ImmutableList.of(
+ new ValuePathTuple("a", "foobar"),
+ new ValuePathTuple("b", "foobar"),
+ new ValuePathTuple("c", "foobar"),
+ new ValuePathTuple("d", "foobar"),
+ new ValuePathTuple("e", "foobar"),
+ new ValuePathTuple("f", "foobar"));
+ Iterator<ValuePathTuple> filtered = Iterables.filter(data,
+ new ValuePathTuple.BetweenPredicate("b", "d", false,
false)).iterator();
+ assertTrue(filtered.hasNext());
+ assertEquals("c", filtered.next().getValue());
+ assertFalse(filtered.hasNext());
+ }
+
+ @Test
+ public void betweenIncludeStart() {
+ List<ValuePathTuple> data = ImmutableList.of(
+ new ValuePathTuple("a", "foobar"),
+ new ValuePathTuple("b", "foobar"),
+ new ValuePathTuple("c", "foobar"),
+ new ValuePathTuple("d", "foobar"),
+ new ValuePathTuple("e", "foobar"),
+ new ValuePathTuple("f", "foobar"));
+ Iterator<ValuePathTuple> filtered = Iterables.filter(data,
+ new ValuePathTuple.BetweenPredicate("b", "d", true,
false)).iterator();
+ assertTrue(filtered.hasNext());
+ assertEquals("b", filtered.next().getValue());
+ assertEquals("c", filtered.next().getValue());
+ assertFalse(filtered.hasNext());
+ }
+
+ @Test
+ public void betweenIncludeEnd() {
+ List<ValuePathTuple> data = ImmutableList.of(
+ new ValuePathTuple("a", "foobar"),
+ new ValuePathTuple("b", "foobar"),
+ new ValuePathTuple("c", "foobar"),
+ new ValuePathTuple("d", "foobar"),
+ new ValuePathTuple("e", "foobar"),
+ new ValuePathTuple("f", "foobar"));
+ Iterator<ValuePathTuple> filtered = Iterables.filter(data,
+ new ValuePathTuple.BetweenPredicate("b", "d", false,
true)).iterator();
+ assertTrue(filtered.hasNext());
+ assertEquals("c", filtered.next().getValue());
+ assertEquals("d", filtered.next().getValue());
+ assertFalse(filtered.hasNext());
+ }
+
+ @Test
+ public void betweenIncludeBoth() {
+ List<ValuePathTuple> data = ImmutableList.of(
+ new ValuePathTuple("a", "foobar"),
+ new ValuePathTuple("b", "foobar"),
+ new ValuePathTuple("c", "foobar"),
+ new ValuePathTuple("d", "foobar"),
+ new ValuePathTuple("e", "foobar"),
+ new ValuePathTuple("f", "foobar"));
+ Iterator<ValuePathTuple> filtered = Iterables.filter(data,
+ new ValuePathTuple.BetweenPredicate("b", "d", true,
true)).iterator();
+ assertTrue(filtered.hasNext());
+ assertEquals("b", filtered.next().getValue());
+ assertEquals("c", filtered.next().getValue());
+ assertEquals("d", filtered.next().getValue());
+ assertFalse(filtered.hasNext());
+ }
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java?rev=1580862&r1=1580861&r2=1580862&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
Mon Mar 24 14:14:50 2014
@@ -23,6 +23,7 @@ import static org.apache.jackrabbit.oak.
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.text.DecimalFormat;
@@ -1360,4 +1361,229 @@ public class OrderedContentMirrorStorage
assertEquals(store.count(ascendingMeta, pr, maxNodeCount),
descendingStore.count(descendingMeta, pr, maxNodeCount));
}
+
+ @Test
+ public void seekEqualsNotFound() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+ String nonExisting = "dsrfgdrtfhg";
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ assertNull("The item should have not been found",
OrderedContentMirrorStoreStrategy.seek(
+ index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateEquals(nonExisting)));
+ }
+
+ @Test
+ public void seekEquals() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n1;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor));
+
+ assertNotNull("we should have found an item", item);
+ assertEquals(searchFor, item.getName());
+ }
+
+ @Test
+ public void seekGreaterThanNotFound() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n1;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor));
+
+ assertNull("no item should have been found", item);
+ }
+
+ @Test
+ public void seekGreaterThan() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n2;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor));
+
+ assertNotNull("we should have found an item", item);
+ assertEquals(n1, item.getName());
+ }
+
+ @Test
+ public void seekGreaterThanEqualsNotFound() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = KEYS[3];
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor, true));
+
+ assertNull("we should have not found an item", item);
+ }
+
+ @Test
+ public void seekGreaterThanEquals() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy();
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n2;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor, true));
+
+ assertNotNull("we should have found an item", item);
+ assertEquals(n2, item.getName());
+ }
+
+ @Test
+ public void seekLessThanNotFound() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy(
+ OrderDirection.DESC);
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n3;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor));
+
+ assertNull("we should have not found an item", item);
+ }
+
+ @Test
+ public void seekLessThan() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy(
+ OrderDirection.DESC);
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n2 = KEYS[2];
+ String n3 = KEYS[0];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+
+ String searchFor = n2;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new
OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor));
+
+ assertNotNull("we should have found an item", item);
+ assertEquals(n0, item.getName());
+ }
+
+ @Test
+ public void seekLessThanEqualNotFound() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy(
+ OrderDirection.DESC);
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+
+ String searchFor = KEYS[0];
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor,
true));
+
+ assertNull("we should have not found an item", item);
+ }
+
+ @Test
+ public void seekLessThanEqual() {
+ OrderedContentMirrorStoreStrategy store = new
OrderedContentMirrorStoreStrategy(
+ OrderDirection.DESC);
+ NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+ String n0 = KEYS[1];
+ String n1 = KEYS[3];
+ String n2 = KEYS[2];
+
+ // initialising the store
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+ store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+
+ String searchFor = n2;
+
+ ChildNodeEntry item =
OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+ new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor,
true));
+
+ assertNotNull("we should have found an item", item);
+ assertEquals(n2, item.getName());
+ }
}