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
diff --git a/src/mango_idx_text.erl b/src/mango_idx_text.erl
index 9ade6e2..5528915 100644
--- a/src/mango_idx_text.erl
+++ b/src/mango_idx_text.erl
@@ -283,6 +283,20 @@
     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);
@@ -294,6 +308,9 @@
 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];
 
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 @@
         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"})