You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/02/03 16:13:18 UTC

[11/50] [abbrv] couchdb-mango git commit: Support escaped period character in query

Support escaped period character in query

If a document has a field with a period character in it, a query
issued with an optional parameter 'fields' will not return this
field because it'll clash with the selector's syntax.

This patch addresses it by allowing to escape a period character
in the request with a backslash.

BugzID: 38248


Project: http://git-wip-us.apache.org/repos/asf/couchdb-mango/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mango/commit/2db372bf
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mango/tree/2db372bf
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mango/diff/2db372bf

Branch: refs/heads/master
Commit: 2db372bf966c5fd239593de4e1cd1702dd562c30
Parents: 4bee6d1
Author: Eric Avdey <e....@cloudant.com>
Authored: Tue Nov 4 10:46:15 2014 -0400
Committer: Eric Avdey <e....@cloudant.com>
Committed: Tue Nov 4 14:58:49 2014 -0400

----------------------------------------------------------------------
 .gitignore                 |  1 +
 src/mango_doc.erl          | 44 ++++++++++++++++++++++++-----------------
 test/02-basic-find-test.py | 30 ++++++++++++++++++++++++++--
 test/user_docs.py          | 29 ++++++++++++++++++++++++++-
 4 files changed, 83 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/2db372bf/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 665827a..50d43d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 ebin/
 test/*.pyc
 venv/
+.eunit

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/2db372bf/src/mango_doc.erl
----------------------------------------------------------------------
diff --git a/src/mango_doc.erl b/src/mango_doc.erl
index 97e8574..666ef9b 100644
--- a/src/mango_doc.erl
+++ b/src/mango_doc.erl
@@ -360,12 +360,7 @@ get_field(Props, Field) ->
 
 
 get_field(Props, Field, Validator) when is_binary(Field) ->
-    Path = re:split(Field, <<"\\.">>),
-    lists:foreach(fun(P) ->
-        if P /= <<>> -> ok; true ->
-            ?MANGO_ERROR({invalid_field_name, Field})
-        end
-    end, Path),
+    {ok, Path} = parse_field(Field),
     get_field(Props, Path, Validator);
 get_field(Props, [], no_validation) ->
     Props;
@@ -403,12 +398,7 @@ get_field(_, [_|_], _) ->
 
 
 rem_field(Props, Field) when is_binary(Field) ->
-    Path = re:split(Field, <<"\\.">>),
-    lists:foreach(fun(P) ->
-        if P /= <<>> -> ok; true ->
-            ?MANGO_ERROR({invalid_field_name, Field})
-        end
-    end, Path),
+    {ok, Path} = parse_field(Field),
     rem_field(Props, Path);
 rem_field({Props}, [Name]) ->
     case lists:keytake(Name, 1, Props) of
@@ -469,12 +459,7 @@ rem_field(_, [_|_]) ->
 
 
 set_field(Props, Field, Value) when is_binary(Field) ->
-    Path = re:split(Field, <<"\\.">>),
-    lists:foreach(fun(P) ->
-        if P /= <<>> -> ok; true ->
-            ?MANGO_ERROR({invalid_field_name, Field})
-        end
-    end, Path),
+    {ok, Path} = parse_field(Field),
     set_field(Props, Path, Value);
 set_field({Props}, [Name], Value) ->
     {lists:keystore(Name, 1, Props, {Name, Value})};
@@ -538,3 +523,26 @@ set_elem(1, [_ | Rest], Value) ->
     [Value | Rest];
 set_elem(I, [Item | Rest], Value) when I > 1 ->
     [Item | set_elem(I-1, Rest, Value)].
+
+parse_field(Field) ->
+    Path = lists:map(fun
+        (P) when P =:= <<>> ->
+            ?MANGO_ERROR({invalid_field_name, Field});
+        (P) ->
+            re:replace(P, <<"\\\\">>, <<>>, [global, {return, binary}])
+    end, re:split(Field, <<"(?<!\\\\)\\.">>)),
+    {ok, Path}.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+parse_field_test() ->
+    ?assertEqual({ok, [<<"ab">>]}, parse_field(<<"ab">>)),
+    ?assertEqual({ok, [<<"a">>, <<"b">>]}, parse_field(<<"a.b">>)),
+    ?assertEqual({ok, [<<"a.b">>]}, parse_field(<<"a\\.b">>)),
+    ?assertEqual({ok, [<<"a">>, <<"b">>, <<"c">>]}, parse_field(<<"a.b.c">>)),
+    ?assertEqual({ok, [<<"a">>, <<"b.c">>]}, parse_field(<<"a.b\\.c">>)),
+    Exception = {mango_error, ?MODULE, {invalid_field_name, <<"a..b">>}},
+    ?assertThrow(Exception, parse_field(<<"a..b">>)).
+
+-endif.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/2db372bf/test/02-basic-find-test.py
----------------------------------------------------------------------
diff --git a/test/02-basic-find-test.py b/test/02-basic-find-test.py
index 4287138..f897ddb 100644
--- a/test/02-basic-find-test.py
+++ b/test/02-basic-find-test.py
@@ -1,7 +1,6 @@
-
+# -*- coding: latin-1 -*-
 import user_docs
 
-
 def setup():
     user_docs.create_db_and_indexes()
 
@@ -213,6 +212,33 @@ def test_missing_not_indexed():
     assert docs[2]["user_id"] == 0
     assert docs[3]["user_id"] == 13
 
+def test_dot_key():
+    db = user_docs.mkdb()
+    fields = ["title", "dot\\.key", "none.dot"]
+    docs = db.find({"type": "complex_key"}, fields = fields)
+    assert len(docs) == 4
+    assert docs[1].has_key("dot.key")
+    assert docs[1]["dot.key"] == "dot's value"
+    assert docs[1].has_key("none")
+    assert docs[1]["none"]["dot"] == "none dot's value"
+
+def test_peso_key():
+    db = user_docs.mkdb()
+    fields = ["title", "$key", "deep.$key"]
+    docs = db.find({"type": "complex_key"}, fields = fields)
+    assert len(docs) == 4
+    assert docs[2].has_key("$key")
+    assert docs[2]["$key"] == "peso"
+    assert docs[2].has_key("deep")
+    assert docs[2]["deep"]["$key"] == "deep peso"
+
+def test_unicode_key():
+    db = user_docs.mkdb()
+    docs = db.find({"type": "complex_key"}, fields = ["title", ""])
+    assert len(docs) == 4
+    # note:  == \uf8ff
+    assert docs[3].has_key(u'\uf8ff')
+    assert docs[3][u'\uf8ff'] == "apple"
 
 def test_limit():
     db = user_docs.mkdb()

http://git-wip-us.apache.org/repos/asf/couchdb-mango/blob/2db372bf/test/user_docs.py
----------------------------------------------------------------------
diff --git a/test/user_docs.py b/test/user_docs.py
index 36f2d2d..d129f59 100644
--- a/test/user_docs.py
+++ b/test/user_docs.py
@@ -1,3 +1,4 @@
+# -*- coding: latin-1 -*-
 """
 Generated with http://www.json-generator.com/
 
@@ -65,7 +66,8 @@ def create_db_and_indexes():
         ["manager"],
         ["favorites"],
         ["favorites.3"],
-        ["twitter"]
+        ["twitter"],
+        ["type"]
     ]
     for idx in indexes:
         assert db.create_index(idx) is True
@@ -455,5 +457,30 @@ DOCS = [
             "Lisp",
             "Lisp"
         ]
+    },
+    {
+        "type": "complex_key",
+        "title": "normal key"
+    },
+    {
+        "type": "complex_key",
+        "title": "key with dot",
+        "dot.key": "dot's value",
+        "none": {
+            "dot": "none dot's value"
+        }
+    },
+    {
+        "type": "complex_key",
+        "title": "key with peso",
+        "$key": "peso",
+        "deep": {
+            "$key": "deep peso"
+        }
+    },
+    {
+        "type": "complex_key",
+        "title": "unicode key",
+        "": "apple"
     }
 ]