You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-issues@jackrabbit.apache.org by "Thomas Mueller (JIRA)" <ji...@apache.org> on 2015/08/12 10:31:46 UTC

[jira] [Commented] (OAK-3213) Improve DocumentStore API

    [ https://issues.apache.org/jira/browse/OAK-3213?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14693123#comment-14693123 ] 

Thomas Mueller commented on OAK-3213:
-------------------------------------

Some sample code (as a patch). Do you think this is reasonable syntax?

{noformat}
Index: src/test/java/org/apache/jackrabbit/oak/plugins/document/QueryTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/oak/plugins/document/QueryTest.java	(revision 0)
+++ src/test/java/org/apache/jackrabbit/oak/plugins/document/QueryTest.java	(working copy)
+package org.apache.jackrabbit.oak.plugins.document;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.junit.Test;
+
+public class QueryTest {
+
+    @Test
+    public void query() {
+        DocumentStore store = new MemoryDocumentStore();
+        NodeDocument nd = store.newQuery(Collection.NODES).
+                greater("modCount", 123).
+                findOne();
+        List<NodeDocument> list = store.newQuery(Collection.NODES).
+                in("key", Arrays.asList("1", "2", "3")).
+                find();
+        int removedCount = store.newQuery(Collection.NODES).
+                greater("modCount", 123).
+                remove();        
+    }
+}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java	(revision 1695224)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java	(working copy)
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.oak.plugins.document;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -25,6 +27,8 @@
 import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
 
+import com.google.common.base.Preconditions;
+
 /**
  * The interface for the backend storage for documents.
  * <p>
@@ -125,7 +129,7 @@
                                        String toKey,
                                        String indexedProperty,
                                        long startValue,
-                                       int limit);
+                                       int limit); 
 
     /**
      * Remove a document. This method does nothing if there is no document
@@ -308,4 +312,87 @@
      * @return description of the underlying storage.
      */
     Map<String, String> getMetadata();
+    
+    <T extends Document> Query<T> newQuery(Collection<T> collection);    
+    
+    <T extends Document> List<T> find(Collection<T> collection, Query<T> query);
+
+    <T extends Document> T findOne(Collection<T> collection, Query<T> query);    
+
+    <T extends Document> int remove(Collection<T> collection, Query<T> query);
+
+    static class QueryCondition<T> {
+        static enum Operator {
+            EQUAL,
+            GREATER_THAN,
+            GREATER_OR_EQUAL,
+            LESS_THAN,
+            LESS_OR_EQUAL,
+            IN
+        }
+        private final String propertyName;
+        private final Operator operator;
+        private final List<T> values;
+        
+        QueryCondition(String propertyName, Operator op, List<T> values) {
+            Preconditions.checkNotNull(propertyName);
+            Preconditions.checkNotNull(op);
+            Preconditions.checkNotNull(values);
+            this.propertyName = propertyName;
+            this.operator = op;
+            Preconditions.checkState(values.size() > 1, "No values provided");
+            if (op != Operator.IN) {
+                Preconditions.checkState(values.size() == 1, "One value exapected");
+            }
+            this.values = values;
+        }
+        
+    }
+    
+    static final class Query<D extends Document> {
+        final DocumentStore store;
+        final Collection<D> collection;
+        final ArrayList<QueryCondition<?>> conditions = new ArrayList<QueryCondition<?>>();
+        
+        public Query(DocumentStore store, Collection<D> collection) {
+            this.store = store;
+            this.collection = collection;
+        }
+        
+        public <T> Query<D> in(String propertyName, List<T> values) {
+            return addCondition(propertyName, QueryCondition.Operator.IN, values);
+        }
+        
+        public <T> Query<D> equal(String propertyName, T value) {
+            return addCondition(propertyName, QueryCondition.Operator.EQUAL, value);
+        }
+        
+        public <T> Query<D> greater(String propertyName, T value) {
+            return addCondition(propertyName, QueryCondition.Operator.GREATER_THAN, value);
+        }
+        
+        public List<D> find() {
+            return store.find(collection, this);
+        }
+
+        public D findOne() {
+            return store.findOne(collection, this);
+        }
+
+        public int remove() {
+            return store.remove(collection, this);
+        }
+
+        private <T> Query<D> addCondition(String propertyName, QueryCondition.Operator op, T value) {
+            conditions.add(new QueryCondition<T>(propertyName, op, Collections.singletonList(value)));
+            return this;
+        }
+
+        private <T> Query<D> addCondition(String propertyName, QueryCondition.Operator op, List<T> values) {
+            conditions.add(new QueryCondition<T>(propertyName, op, values));
+            return this;
+        }
+
+    }
+    
 }
Index: src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java	(revision 1695224)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java	(working copy)
@@ -41,6 +41,7 @@
 import org.apache.jackrabbit.oak.plugins.document.StableRevisionComparator;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.UpdateUtils;
 
 import com.google.common.base.Splitter;
@@ -190,7 +191,7 @@
 
     @Override
     public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<UpdateOp.Key, Condition>> toRemove) {
+                                           Map<String, Map<UpdateOp.Key,Condition>> toRemove) {
         int num = 0;
         ConcurrentSkipListMap<String, T> map = getMap(collection);
         for (Map.Entry<String, Map<UpdateOp.Key, Condition>> entry : toRemove.entrySet()) {
@@ -402,4 +403,30 @@
         return metadata;
     }
 
+    @Override
+    public <T extends Document> Query<T> newQuery(Collection<T> collection) {
+        return new Query<T>(this, collection);
+    }
+
+    @Override
+    public <T extends Document> List<T> find(Collection<T> collection,
+            Query<T> query) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <T extends Document> T findOne(Collection<T> collection,
+            Query<T> query) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <T extends Document> int remove(Collection<T> collection,
+            Query<T> query) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
 }
\ No newline at end of file
{noformat}

The "Query" class would be implemented just once. Each DocumentStore would implement "newQuery" exactly as above. The user could call "store.newQuery", he would not call "store.find" or "store.findOne" but instead use the fluent syntax to call "Query.find" / "findOne" / "remove".

> Improve DocumentStore API
> -------------------------
>
>                 Key: OAK-3213
>                 URL: https://issues.apache.org/jira/browse/OAK-3213
>             Project: Jackrabbit Oak
>          Issue Type: Improvement
>          Components: core, mongomk
>            Reporter: Thomas Mueller
>
> The current DocumentStore API needs to be improved to support new requirements, for example OAK-3001, to avoid "instanceof XYZDocumentStore" in the DocumentNodeStore implementation, to possibly improve performance, and to make it (more) future-proof.
> * Improved query functionality to support many constraints (currently, DocumentStore.query only fromKey, toKey, and startValue).
> * Allow query results to not be ordered by key if not needed at the caller side.
> * Maybe support remove with constraints (for OAK-3001).
> * Define if only the whole document is needed, or just the key, or the key plus some of its properties.
> * Define how old the result can be (is it allowed to return cached documents, how fresh does the result need to be, is it allowed to return some cached and some new documents).
> * In case of version changes in the data model (additional collections, additional indexes), allow to work with existing data, possibly without having to upgrade the store (maybe in read-only mode).
> Documentation might need to be improved to cover the data model as well (list of collections, list of indexes, possibility of additional indexes), and expected performance characteristics.
> There are some options questions:
> * Should we backport this change (to the 1.0 and / or 1.2 branch)?
> * Should we keep the current API (DocumentStore.query for example)?



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)