You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by to...@apache.org on 2015/10/30 23:04:31 UTC
couchdb-mango git commit: Fix user defined index selection
Repository: couchdb-mango
Updated Branches:
refs/heads/2835-fix-index-selection [created] 62362de9a
Fix user defined index selection
This fix modifies indexable_fields to remove extraneous fields
that are created by the mango_selector_text:convert function so that
the index can now be used when accessing arrays, $in operations, and
$size operations.
COUCHDB-2835
Project: http://git-wip-us.apache.org/repos/asf/couchdb-mango/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mango/commit/62362de9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mango/tree/62362de9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mango/diff/62362de9
Branch: refs/heads/2835-fix-index-selection
Commit: 62362de9a2d46f392315a4399d8a7bb5e1c499e0
Parents: 090dc67
Author: Tony Sun <to...@cloudant.com>
Authored: Fri Oct 30 15:02:50 2015 -0700
Committer: Tony Sun <to...@cloudant.com>
Committed: Fri Oct 30 15:02:50 2015 -0700
----------------------------------------------------------------------
src/mango_idx_text.erl | 20 ++++++++++++++
test/07-text-custom-field-list-test.py | 42 +++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/62362de9/src/mango_idx_text.erl
----------------------------------------------------------------------
diff --git a/src/mango_idx_text.erl b/src/mango_idx_text.erl
index 9ade6e2..ba92a32 100644
--- a/src/mango_idx_text.erl
+++ b/src/mango_idx_text.erl
@@ -283,6 +283,23 @@ indexable_fields(Fields, {op_and, Args}) when is_list(Args) ->
lists:foldl(fun(Arg, Fields0) -> indexable_fields(Fields0, Arg) end,
Fields, Args);
+%% For queries that use array element access or $in operations, two
+%% fields get generated by mango_selector_text:convert. At index
+%% definition time, only one field gets defined. In this situation, we
+%% remove the extra generated field so that the index can be used. For
+%% all other situations, we include the fields as normal.
+indexable_fields(Fields, {op_or, [{op_field, Field0},
+ {op_field, {[Name | _], _}} = Field1]}) ->
+ case lists:member(<<"[]">>, Name) of
+ true ->
+ indexable_fields(Fields, Field1);
+ false ->
+ Fields1 = indexable_fields(Fields, Field0),
+ indexable_fields(Fields1, Field1)
+ end;
+indexable_fields(Fields, {op_or, Args}) when is_list(Args) ->
+ lists:foldl(fun(Arg, Fields0) -> indexable_fields(Fields0, Arg) end,
+ Fields, Args);
indexable_fields(Fields, {op_or, Args}) when is_list(Args) ->
lists:foldl(fun(Arg, Fields0) -> indexable_fields(Fields0, Arg) end,
Fields, Args);
@@ -294,6 +311,9 @@ indexable_fields(Fields, {op_not, {ExistsQuery, Arg}}) when is_tuple(Arg) ->
indexable_fields(Fields, {op_insert, Arg}) when is_binary(Arg) ->
Fields;
+%% fieldname.[]:length is not a user defined field.
+indexable_fields(Fields, {op_field, {[_, <<":length">>], _}}) ->
+ Fields;
indexable_fields(Fields, {op_field, {Name, _}}) ->
[iolist_to_binary(Name) | Fields];
http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/62362de9/test/07-text-custom-field-list-test.py
----------------------------------------------------------------------
diff --git a/test/07-text-custom-field-list-test.py b/test/07-text-custom-field-list-test.py
index f299ef7..8a8a5f8 100644
--- a/test/07-text-custom-field-list-test.py
+++ b/test/07-text-custom-field-list-test.py
@@ -44,6 +44,48 @@ class CustomFieldsTest(mango.UserDocsTextTests):
docs = self.db.find({"age": 22, "manager": False})
assert len(docs) == 0
+ def test_element_acess(self):
+ docs = self.db.find({"favorites.0": "Ruby"})
+ assert len(docs) == 3
+ for d in docs:
+ assert "Ruby" in d["favorites"]
+
+ # This should throw an exception because we only index the array
+ # favorites.[], and not the string field favorites
+ def test_index_selection(self):
+ try:
+ self.db.find({"selector": {"$or": [{"favorites": "Ruby"},
+ {"favorites.0":"Ruby"}]}})
+ except Exception, e:
+ assert e.response.status_code == 400
+
+ def test_in_with_array(self):
+ vals = ["Lisp", "Python"]
+ docs = self.db.find({"favorites": {"$in": vals}})
+ assert len(docs) == 10
+
+ # This should also throw an error because we only indexed
+ # favorites.[] of type string. For the following query to work, the
+ # user has to index favorites.[] of type number, and also
+ # favorites.[].Versions.Alpha of type string.
+ def test_in_different_types(self):
+ vals = ["Random Garbage", 52, {"Versions": {"Alpha": "Beta"}}]
+ try:
+ self.db.find({"favorites": {"$in": vals}})
+ except Exception, e:
+ assert e.response.status_code == 400
+
+ # This test differs from the situation where we index everything.
+ # When we index everything the actual number of docs that gets
+ # returned is 5. That's because of the special situation where we
+ # have an array of an array, i.e: [["Lisp"]], because we're indexing
+ # specifically favorites.[] of type string. So it does not count
+ # the example and we only get 4 back.
+ def test_nin_with_array(self):
+ vals = ["Lisp", "Python"]
+ docs = self.db.find({"favorites": {"$nin": vals}})
+ assert len(docs) == 4
+
def test_missing(self):
self.db.find({"location.state": "Nevada"})