Author: rombert
Date: Tue Sep  5 12:20:11 2017
New Revision: 1807343

URL: http://svn.apache.org/viewvc?rev=1807343&view=rev
Log:
OAK-6578 - Enhance the UniqueEntryStoreStrategy to return list of
matching values and paths

Add a new queryEntries method to the UniqueIndexStoreStrategy.

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java?rev=1807343&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
 Tue Sep  5 12:20:11 2017
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.property.strategy;
+
+/**
+ * An entry in the index
+ *
+ */
+public final class IndexEntry {
+    
+    private final String path;
+    private final String propertyValue;
+    
+    IndexEntry(String path, String propertyValue) {
+        this.path = path;
+        this.propertyValue = propertyValue;
+        
+    }
+    
+    public String getPath() {
+        return path;
+    }
+    
+    public String getPropertyValue() {
+        return propertyValue;
+    }
+
+    
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((path == null) ? 0 : path.hashCode());
+        result = prime * result + ((propertyValue == null) ? 0 : 
propertyValue.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        IndexEntry other = (IndexEntry) obj;
+        if (path == null) {
+            if (other.path != null)
+                return false;
+        } else if (!path.equals(other.path))
+            return false;
+        if (propertyValue == null) {
+            if (other.propertyValue != null)
+                return false;
+        } else if (!propertyValue.equals(other.propertyValue))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        
+        return getClass().getSimpleName() + "# path: " + path + ", 
propertyValue: " + propertyValue;
+    }
+}
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java?rev=1807343&r1=1807342&r2=1807343&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
 Tue Sep  5 12:20:11 2017
@@ -119,26 +119,62 @@ public class UniqueEntryStoreStrategy im
     @Override
     public Iterable<String> query(final Filter filter, final String indexName, 
             final NodeState indexMeta, final Iterable<String> values) {
+        return query0(filter, indexName, indexMeta, values, new 
HitProducer<String>() {
+            @Override
+            public String produce(NodeState indexHit, String pathName) {
+                PropertyState s = indexHit.getProperty("entry");
+                return s.getValue(Type.STRING, 0);
+            }
+        });        
+    }
+
+    
+    
+    /**
+     * Search for a given set of values, returning <tt>IndexEntry</tt> results
+     * 
+     * @param filter the filter (can optionally be used for optimized query 
execution)
+     * @param indexName the name of the index (for logging)
+     * @param indexMeta the index metadata node (may not be null)
+     * @param values values to look for (null to check for property existence)
+     * @return an iterator of index entries
+     * 
+     * @throws UnsupportedOperationException if the operation is not supported
+     */
+    public Iterable<IndexEntry> queryEntries(Filter filter, String indexName, 
NodeState indexMeta,
+            Iterable<String> values) {
+        return query0(filter, indexName, indexMeta, values, new 
HitProducer<IndexEntry>() {
+            @Override
+            public IndexEntry produce(NodeState indexHit, String pathName) {
+                PropertyState s = indexHit.getProperty("entry");
+                return new IndexEntry(s.getValue(Type.STRING, 0), pathName);
+            }
+        });
+    }
+
+    private <T> Iterable<T> query0(Filter filter, String indexName, NodeState 
indexMeta,
+            Iterable<String> values, HitProducer<T> prod) {
         final NodeState index = indexMeta.getChildNode(getIndexNodeName());
-        return new Iterable<String>() {
+        return new Iterable<T>() {
             @Override
-            public Iterator<String> iterator() {
+            public Iterator<T> iterator() {
                 if (values == null) {
-                    return new Iterator<String>() {
+                    return new Iterator<T>() {
                         
                         Iterator<? extends ChildNodeEntry> it = 
index.getChildNodeEntries().iterator();
-
+                        
                         @Override
                         public boolean hasNext() {
                             return it.hasNext();
                         }
-
+                        
                         @Override
-                        public String next() {
-                            PropertyState s = 
it.next().getNodeState().getProperty("entry");
-                            return s.getValue(Type.STRING, 0);
+                        public T next() {
+                            ChildNodeEntry indexEntry = it.next();
+                            
+                            return prod.produce(indexEntry.getNodeState(), 
indexEntry.getName());
                         }
-
+                        
                         @Override
                         public void remove() {
                             it.remove();
@@ -146,21 +182,19 @@ public class UniqueEntryStoreStrategy im
                         
                     };
                 }
-                ArrayList<String> list = new ArrayList<String>();
+                ArrayList<T> list = new ArrayList<>();
                 for (String p : values) {
                     NodeState key = index.getChildNode(p);
                     if (key.exists()) {
                         // we have an entry for this value, so use it
-                        PropertyState s = key.getProperty("entry");
-                        String v = s.getValue(Type.STRING, 0);
-                        list.add(v);
+                        list.add(prod.produce(key, p));
                     }
                 }
                 return list.iterator();
             }
         };
     }
-
+    
     @Override
     public boolean exists(Supplier<NodeBuilder> index, String key) {
         return index.get().hasChildNode(key);
@@ -209,4 +243,24 @@ public class UniqueEntryStoreStrategy im
     public String getIndexNodeName() {
         return indexName;
     }
+
+    /**
+     * Creates a specific type of "hit" to return from the query methods
+     * 
+     * <p>Use primarily to reduce duplication when the query algorithms 
execute mostly the same steps but return different objects.</p>
+     * 
+     * @param <T> The type of Hit to produce
+     */
+    private interface HitProducer<T> {
+        
+        /**
+         * Invoked when a matching index entry is found 
+         * 
+         * @param indexHit the index node
+         * @param propertyValue the value of the property
+         * @return the value produced for the specific "hit" 
+         */
+        T produce(NodeState indexHit, String propertyValue);
+    }
+    
 }

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java?rev=1807343&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
 Tue Sep  5 12:20:11 2017
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.property.strategy;
+
+import static com.google.common.base.Suppliers.memoize;
+import static com.google.common.collect.Sets.newHashSet;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.iterableWithSize;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Supplier;
+
+public class UniqueEntryStoreStrategyTest {
+    
+    private static final Set<String> EMPTY = newHashSet();
+    private String indexName;
+    private NodeBuilder indexMeta;
+    private UniqueEntryStoreStrategy store;
+    
+    @Before
+    public void fillIndex() throws Exception {
+        
+        store = new UniqueEntryStoreStrategy();
+        
+        indexName = "foo";
+        
+        NodeState root = EMPTY_NODE;
+        indexMeta = root.builder();
+        Supplier<NodeBuilder> index = memoize(() -> 
indexMeta.child(INDEX_CONTENT_NODE_NAME));
+        store.update(index, "/some/node1", null, null, EMPTY, 
newHashSet("key1"));
+        store.update(index, "/some/node2", null, null, EMPTY, 
newHashSet("key2"));
+    }
+
+    @Test
+    public void queryEntries_All() {
+        
+        Iterable<IndexEntry> hits = 
store.queryEntries(FilterImpl.newTestInstance(), indexName, 
indexMeta.getNodeState(), null);
+        
+        assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1", 
"key1"), new IndexEntry("/some/node2", "key2")));
+    }
+    
+    @Test
+    public void queryEntries_some() {
+
+        Iterable<IndexEntry> hits = 
store.queryEntries(FilterImpl.newTestInstance(), indexName, 
indexMeta.getNodeState(), Arrays.asList("key1"));
+        
+        assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1", 
"key1")));
+    }
+    
+    @Test
+    public void queryEntries_none() {
+        
+        Iterable<IndexEntry> hits = 
store.queryEntries(FilterImpl.newTestInstance(), indexName, 
indexMeta.getNodeState(), Arrays.asList("key3"));
+        
+        assertThat(hits, iterableWithSize(0));
+    }
+}


Reply via email to