You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2017/09/21 15:30:53 UTC

[couchdb] branch master updated: Rename selector to partialfilterselector in indexes (#818)

This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 00df0de  Rename selector to partialfilterselector in indexes (#818)
00df0de is described below

commit 00df0def7fb8107717ed2274b88f855d18402a72
Author: garren smith <ga...@gmail.com>
AuthorDate: Thu Sep 21 17:30:49 2017 +0200

    Rename selector to partialfilterselector in indexes (#818)
    
    To make it easier to distinguish between a selector in _find and a
    selector in _index. Rename the selector in the _index to
    partialfilterselector. It also gives a bit more of an explanation of
    what this selector does.
---
 src/mango/src/mango_cursor.erl       |   8 +--
 src/mango/src/mango_idx.erl          |  61 +++++++++++++++++--
 src/mango/src/mango_idx_text.erl     |   8 ++-
 src/mango/src/mango_idx_view.erl     |   4 +-
 src/mango/src/mango_native_proc.erl  |  23 ++++++--
 src/mango/test/16-index-selectors.py | 111 ++++++++++++++++++++++++++++++-----
 src/mango/test/mango.py              |  14 +++--
 7 files changed, 192 insertions(+), 37 deletions(-)

diff --git a/src/mango/src/mango_cursor.erl b/src/mango/src/mango_cursor.erl
index f36febd..e0792b7 100644
--- a/src/mango/src/mango_cursor.erl
+++ b/src/mango/src/mango_cursor.erl
@@ -90,9 +90,9 @@ execute(#cursor{index=Idx}=Cursor, UserFun, UserAcc) ->
 maybe_filter_indexes_by_ddoc(Indexes, Opts) ->
     case lists:keyfind(use_index, 1, Opts) of
         {use_index, []} ->
-            %We remove any indexes that have a selector 
+            % We remove any indexes that have a selector 
             % since they are only used when specified via use_index
-            remove_indexes_with_selector(Indexes);
+            remove_indexes_with_partial_filter_selector(Indexes);
         {use_index, [DesignId]} ->
             filter_indexes(Indexes, DesignId);
         {use_index, [DesignId, ViewName]} ->
@@ -117,9 +117,9 @@ filter_indexes(Indexes0, DesignId, ViewName) ->
     lists:filter(FiltFun, Indexes).
 
 
-remove_indexes_with_selector(Indexes) ->
+remove_indexes_with_partial_filter_selector(Indexes) ->
     FiltFun = fun(Idx) -> 
-        case mango_idx:get_idx_selector(Idx) of
+        case mango_idx:get_partial_filter_selector(Idx) of
             undefined -> true;
             _ -> false
         end
diff --git a/src/mango/src/mango_idx.erl b/src/mango/src/mango_idx.erl
index b812251..04f84c8 100644
--- a/src/mango/src/mango_idx.erl
+++ b/src/mango/src/mango_idx.erl
@@ -44,7 +44,7 @@
     to_json/1,
     delete/4,
     get_usable_indexes/3,
-    get_idx_selector/1
+    get_partial_filter_selector/1
 ]).
 
 
@@ -368,13 +368,66 @@ filter_opts([Opt | Rest]) ->
     [Opt | filter_opts(Rest)].
 
 
-get_idx_selector(#idx{def = Def}) when Def =:= all_docs; Def =:= undefined ->
+get_partial_filter_selector(#idx{def = Def}) when Def =:= all_docs; Def =:= undefined ->
     undefined;
-get_idx_selector(#idx{def = {Def}}) ->
+get_partial_filter_selector(#idx{def = {Def}}) ->
+    case proplists:get_value(<<"partial_filter_selector">>, Def) of
+        undefined -> get_legacy_selector(Def);
+        {[]} -> undefined;
+        Selector -> Selector
+    end.
+
+
+% Partial filter selectors is supported in text indexes via the selector field
+% This adds backwards support for existing indexes that might have a selector in it
+get_legacy_selector(Def) ->
     case proplists:get_value(<<"selector">>, Def) of
         undefined -> undefined;
         {[]} -> undefined;
         Selector -> Selector
     end.
 
-
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+index(SelectorName, Selector) ->
+    {
+        idx,<<"mango_test_46418cd02081470d93290dc12306ebcb">>,
+           <<"_design/57e860dee471f40a2c74ea5b72997b81dda36a24">>,
+           <<"Selected">>,<<"json">>,
+           {[{<<"fields">>,{[{<<"location">>,<<"asc">>}]}},
+             {SelectorName,{Selector}}]},
+           [{<<"def">>,{[{<<"fields">>,[<<"location">>]}]}}]
+    }.
+
+get_partial_filter_all_docs_test() ->
+    Idx = #idx{def = all_docs},
+    ?assertEqual(undefined, get_partial_filter_selector(Idx)).
+
+get_partial_filter_undefined_def_test() ->
+    Idx = #idx{def = undefined},
+    ?assertEqual(undefined, get_partial_filter_selector(Idx)).
+
+get_partial_filter_selector_default_test() ->
+    Idx = index(<<"partial_filter_selector">>, []),
+    ?assertEqual(undefined, get_partial_filter_selector(Idx)).
+
+get_partial_filter_selector_missing_test() ->
+    Idx = index(<<"partial_filter_selector">>, []),
+    ?assertEqual(undefined, get_partial_filter_selector(Idx)).
+
+get_partial_filter_selector_with_selector_test() ->
+    Selector = [{<<"location">>,{[{<<"$gt">>,<<"FRA">>}]}}],
+    Idx = index(<<"partial_filter_selector">>, Selector),
+    ?assertEqual({Selector}, get_partial_filter_selector(Idx)).
+
+get_partial_filter_selector_with_legacy_selector_test() ->
+    Selector = [{<<"location">>,{[{<<"$gt">>,<<"FRA">>}]}}],
+    Idx = index(<<"selector">>, Selector),
+    ?assertEqual({Selector}, get_partial_filter_selector(Idx)).
+
+get_partial_filter_selector_with_legacy_default_selector_test() ->
+    Idx = index(<<"selector">>, []),
+    ?assertEqual(undefined, get_partial_filter_selector(Idx)).
+
+-endif.
diff --git a/src/mango/src/mango_idx_text.erl b/src/mango/src/mango_idx_text.erl
index f90ac7f..3ccb017 100644
--- a/src/mango/src/mango_idx_text.erl
+++ b/src/mango/src/mango_idx_text.erl
@@ -223,7 +223,13 @@ opts() ->
             {optional, true},
             {default, {[]}}
         ]},
-         {<<"selector">>, [
+        {<<"partial_filter_selector">>, [
+            {tag, partial_filter_selector},
+            {optional, true},
+            {default, {[]}},
+            {validator, fun mango_opts:validate_selector/1}
+        ]},
+        {<<"selector">>, [
             {tag, selector},
             {optional, true},
             {default, {[]}},
diff --git a/src/mango/src/mango_idx_view.erl b/src/mango/src/mango_idx_view.erl
index 7e9e646..4cb039c 100644
--- a/src/mango/src/mango_idx_view.erl
+++ b/src/mango/src/mango_idx_view.erl
@@ -199,8 +199,8 @@ opts() ->
             {tag, fields},
             {validator, fun mango_opts:validate_sort/1}
         ]},
-        {<<"selector">>, [
-            {tag, selector},
+        {<<"partial_filter_selector">>, [
+            {tag, partial_filter_selector},
             {optional, true},
             {default, {[]}},
             {validator, fun mango_opts:validate_selector/1}
diff --git a/src/mango/src/mango_native_proc.erl b/src/mango/src/mango_native_proc.erl
index 82081a9..61d79b7 100644
--- a/src/mango/src/mango_native_proc.erl
+++ b/src/mango/src/mango_native_proc.erl
@@ -135,7 +135,7 @@ index_doc(#st{indexes=Indexes}, Doc) ->
 
 get_index_entries({IdxProps}, Doc) ->
     {Fields} = couch_util:get_value(<<"fields">>, IdxProps),
-    Selector = get_index_selector(IdxProps),
+    Selector = get_index_partial_filter_selector(IdxProps),
     case should_index(Selector, Doc) of
         false -> 
             [];
@@ -159,7 +159,7 @@ get_index_values(Fields, Doc) ->
 
 
 get_text_entries({IdxProps}, Doc) ->
-    Selector = get_index_selector(IdxProps),
+    Selector = get_index_partial_filter_selector(IdxProps),
     case should_index(Selector, Doc) of
         true ->
             get_text_entries0(IdxProps, Doc);
@@ -168,10 +168,21 @@ get_text_entries({IdxProps}, Doc) ->
     end.
 
 
-get_index_selector(IdxProps) ->
-    case couch_util:get_value(<<"selector">>, IdxProps) of
-        [] -> {[]};
-        Else -> Else
+get_index_partial_filter_selector(IdxProps) ->
+    case couch_util:get_value(<<"partial_filter_selector">>, IdxProps) of
+        undefined ->
+            % this is to support legacy text indexes that had the partial_filter_selector
+            % set as selector
+            case couch_util:get_value(<<"selector">>, IdxProps, []) of
+                [] -> 
+                    {[]};
+                Else -> 
+                    Else
+            end;
+        [] -> 
+            {[]};
+        Else -> 
+            Else
     end.
 
 
diff --git a/src/mango/test/16-index-selectors.py b/src/mango/test/16-index-selectors.py
index b189456..cc83251 100644
--- a/src/mango/test/16-index-selectors.py
+++ b/src/mango/test/16-index-selectors.py
@@ -73,20 +73,84 @@ DOCS = [
     },
 ]
 
+oldschoolddoc = {
+    "_id": "_design/oldschool",
+    "language": "query",
+    "views": {
+        "oldschool": {
+            "map": {
+                "fields": {
+                    "location": "asc"
+                },
+                "selector": {
+                    "location": {"$gte": "FRA"}
+                }
+            },
+            "reduce": "_count",
+            "options": {
+                "def": {
+                    "fields": [
+                        "location"
+                    ]
+                }
+            }
+        }
+    }
+}
+
+oldschoolddoctext = {
+    "_id": "_design/oldschooltext",
+    "language": "query",
+    "indexes": {
+        "oldschooltext": {
+            "index": {
+                "default_analyzer": "keyword",
+                "default_field": {},
+                "selector": {
+                    "location": {"$gte": "FRA"}
+                },
+                "fields": [
+                    {
+                        "name": "location",
+                        "type": "string"
+                    }
+                ],
+                "index_array_lengths": True
+        },
+            "analyzer": {
+                "name": "perfield",
+                "default": "keyword",
+                "fields": {
+                    "$default": "standard"
+                }
+            }
+        }
+    }
+}
+
 class IndexSelectorJson(mango.DbPerClass):
     def setUp(self):
         self.db.recreate()
         self.db.save_docs(copy.deepcopy(DOCS))
 
-    def test_saves_selector_in_index(self):
+    def test_saves_partial_filter_selector_in_index(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_index(["location"], selector=selector)
+        self.db.create_index(["location"], partial_filter_selector=selector)
         indexes = self.db.list_indexes()
-        self.assertEqual(indexes[1]["def"]["selector"], selector)
+        self.assertEqual(indexes[1]["def"]["partial_filter_selector"], selector)
+
+    def test_saves_selector_in_index_throws(self):
+        selector = {"location": {"$gte": "FRA"}}
+        try:
+            self.db.create_index(["location"], selector=selector)
+        except Exception, e:
+            assert e.response.status_code == 400
+        else:
+            raise AssertionError("bad index creation")
 
     def test_uses_partial_index_for_query_selector(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_index(["location"], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_index(["location"], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector, explain=True, use_index='Selected')
         self.assertEqual(resp["index"]["name"], "Selected")
         docs = self.db.find(selector, use_index='Selected')
@@ -95,7 +159,7 @@ class IndexSelectorJson(mango.DbPerClass):
     def test_uses_partial_index_with_different_selector(self):
         selector = {"location": {"$gte": "FRA"}}
         selector2 = {"location": {"$gte": "A"}}
-        self.db.create_index(["location"], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_index(["location"], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector2, explain=True, use_index='Selected')
         self.assertEqual(resp["index"]["name"], "Selected")
         docs = self.db.find(selector2, use_index='Selected')
@@ -103,28 +167,36 @@ class IndexSelectorJson(mango.DbPerClass):
 
     def test_doesnot_use_selector_when_not_specified(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_index(["location"], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_index(["location"], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector, explain=True)
         self.assertEqual(resp["index"]["name"], "_all_docs")
 
     def test_doesnot_use_selector_when_not_specified_with_index(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_index(["location"], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_index(["location"], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         self.db.create_index(["location"], name="NotSelected")
         resp = self.db.find(selector, explain=True)
         self.assertEqual(resp["index"]["name"], "NotSelected")
 
+    def test_old_selector_still_supported(self):
+        selector = {"location": {"$gte": "FRA"}}
+        self.db.save_doc(oldschoolddoc)
+        resp = self.db.find(selector, explain=True, use_index='oldschool')
+        self.assertEqual(resp["index"]["name"], "oldschool")
+        docs = self.db.find(selector, use_index='oldschool')
+        self.assertEqual(len(docs), 3)
+
     @unittest.skipUnless(mango.has_text_service(), "requires text service")
-    def test_text_saves_selector_in_index(self):
+    def test_text_saves_partialfilterselector_in_index(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], selector=selector)
+        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], partial_filter_selector=selector)
         indexes = self.db.list_indexes()
-        self.assertEqual(indexes[1]["def"]["selector"], selector)
+        self.assertEqual(indexes[1]["def"]["partial_filter_selector"], selector)
 
     @unittest.skipUnless(mango.has_text_service(), "requires text service")
     def test_text_uses_partial_index_for_query_selector(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector, explain=True, use_index='Selected')
         self.assertEqual(resp["index"]["name"], "Selected")
         docs = self.db.find(selector, use_index='Selected', fields=['_id', 'location'])
@@ -134,7 +206,7 @@ class IndexSelectorJson(mango.DbPerClass):
     def test_text_uses_partial_index_with_different_selector(self):
         selector = {"location": {"$gte": "FRA"}}
         selector2 = {"location": {"$gte": "A"}}
-        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector2, explain=True, use_index='Selected')
         self.assertEqual(resp["index"]["name"], "Selected")
         docs = self.db.find(selector2, use_index='Selected')
@@ -143,14 +215,23 @@ class IndexSelectorJson(mango.DbPerClass):
     @unittest.skipUnless(mango.has_text_service(), "requires text service")
     def test_text_doesnot_use_selector_when_not_specified(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         resp = self.db.find(selector, explain=True)
         self.assertEqual(resp["index"]["name"], "_all_docs")
 
     @unittest.skipUnless(mango.has_text_service(), "requires text service")
     def test_text_doesnot_use_selector_when_not_specified_with_index(self):
         selector = {"location": {"$gte": "FRA"}}
-        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], selector=selector, ddoc="Selected", name="Selected")
+        self.db.create_text_index(fields=[{"name":"location", "type":"string"}], partial_filter_selector=selector, ddoc="Selected", name="Selected")
         self.db.create_text_index(fields=[{"name":"location", "type":"string"}], name="NotSelected")
         resp = self.db.find(selector, explain=True)
-        self.assertEqual(resp["index"]["name"], "NotSelected")
\ No newline at end of file
+        self.assertEqual(resp["index"]["name"], "NotSelected")
+
+    @unittest.skipUnless(mango.has_text_service(), "requires text service")
+    def test_text_old_selector_still_supported(self):
+        selector = {"location": {"$gte": "FRA"}}
+        self.db.save_doc(oldschoolddoctext)
+        resp = self.db.find(selector, explain=True, use_index='oldschooltext')
+        self.assertEqual(resp["index"]["name"], "oldschooltext")
+        docs = self.db.find(selector, use_index='oldschooltext')
+        self.assertEqual(len(docs), 3)
\ No newline at end of file
diff --git a/src/mango/test/mango.py b/src/mango/test/mango.py
index 2c89714..342d5fd 100644
--- a/src/mango/test/mango.py
+++ b/src/mango/test/mango.py
@@ -84,7 +84,8 @@ class Database(object):
         r.raise_for_status()
         return r.json()
 
-    def create_index(self, fields, idx_type="json", name=None, ddoc=None, selector=None):
+    def create_index(self, fields, idx_type="json", name=None, ddoc=None, 
+        partial_filter_selector=None, selector=None):
         body = {
             "index": {
                 "fields": fields
@@ -98,6 +99,8 @@ class Database(object):
             body["ddoc"] = ddoc
         if selector is not None:
             body["index"]["selector"] = selector
+        if partial_filter_selector is not None:
+            body["index"]["partial_filter_selector"] = partial_filter_selector
         body = json.dumps(body)
         r = self.sess.post(self.path("_index"), data=body)
         r.raise_for_status()
@@ -105,8 +108,9 @@ class Database(object):
         assert r.json()["name"] is not None
         return r.json()["result"] == "created"
 
-    def create_text_index(self, analyzer=None, selector=None, idx_type="text",
-        default_field=None, fields=None, name=None, ddoc=None,index_array_lengths=None):
+    def create_text_index(self, analyzer=None, idx_type="text",
+        partial_filter_selector=None, default_field=None, fields=None, 
+        name=None, ddoc=None,index_array_lengths=None):
         body = {
             "index": {
             },
@@ -121,8 +125,8 @@ class Database(object):
             body["index"]["default_field"] = default_field
         if index_array_lengths is not None:
             body["index"]["index_array_lengths"] = index_array_lengths
-        if selector is not None:
-            body["index"]["selector"] = selector
+        if partial_filter_selector is not None:
+            body["index"]["partial_filter_selector"] = partial_filter_selector
         if fields is not None:
             body["index"]["fields"] = fields
         if ddoc is not None:

-- 
To stop receiving notification emails like this one, please contact
['"commits@couchdb.apache.org" <co...@couchdb.apache.org>'].