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());
+    }
 }


Reply via email to