You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2015/09/24 17:15:37 UTC

couch-mrview commit: updated refs/heads/master to aa51eb4

Repository: couchdb-couch-mrview
Updated Branches:
  refs/heads/master dfa6f7eee -> aa51eb4be


Fix validation of query design documents

Jira: COUCHDB-2818

If language is "query" then map functions will be objects.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/commit/aa51eb4b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/tree/aa51eb4b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/diff/aa51eb4b

Branch: refs/heads/master
Commit: aa51eb4beefaf69d32f835df82bd7f9e738c1884
Parents: dfa6f7e
Author: Nick Vatamaniuc <va...@gmail.com>
Authored: Thu Sep 24 11:07:25 2015 -0400
Committer: Nick Vatamaniuc <va...@gmail.com>
Committed: Thu Sep 24 11:07:25 2015 -0400

----------------------------------------------------------------------
 src/couch_mrview.erl                        | 46 ++++++++++++++----------
 test/couch_mrview_ddoc_validation_tests.erl | 34 +++++++++++++++++-
 2 files changed, 60 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/blob/aa51eb4b/src/couch_mrview.erl
----------------------------------------------------------------------
diff --git a/src/couch_mrview.erl b/src/couch_mrview.erl
index bd866a2..612e31b 100644
--- a/src/couch_mrview.erl
+++ b/src/couch_mrview.erl
@@ -52,24 +52,31 @@
 %% In the most common case name is the view name and
 %% value is an object that must have a "map" function,
 %% and an optional "reduce" function. "map" and "reduce"
-%% values should be strings (function contents).
+%% values should be strings (function contents), except
+%% in case when langauge is <<query>> then maps must
+%% be objects.
 %%
 %% "lib" is a special case. The value
 %% of "lib" is an object that will contain libary code
 %% so it not validated.
 %%
-validate_view(<<"lib">>, {_Libs})->
+validate_view(<<"lib">>, {_Libs}, _Language)->
     ok;
-validate_view(VName, {Views}) ->
-    case couch_util:get_value(<<"map">>, Views) of
-        MapVal when is_binary(MapVal) ->
+validate_view(VName, {Views}, Language) ->
+    case {couch_util:get_value(<<"map">>, Views), Language}  of
+        {{[_ | _]}, <<"query">>} ->
             ok;
-        undefined ->
+        {_, <<"query">>} ->
+            Err1 = <<"`map` in ", VName/binary, " for queries must be an object">>,
+            throw({invalid_design_doc,Err1});
+        {Mapval, _} when is_binary(Mapval)  ->
+            ok;
+        {undefined, _} ->
             Err0 = <<"View ",VName/binary, " must have a map function">>,
             throw ({invalid_design_doc, Err0});
-        _ ->
-            Err1 = <<"`map` in ", VName/binary, " must be a string">>,
-            throw({invalid_design_doc, Err1})
+        {_, _} ->
+            Err2 = <<"`map` in ", VName/binary, " must be a string">>,
+            throw({invalid_design_doc, Err2})
     end,
     case couch_util:get_value(<<"reduce">>, Views) of
         RedVal when is_binary(RedVal) ->
@@ -77,11 +84,11 @@ validate_view(VName, {Views}) ->
         undefined ->
             ok; % note: unlike map,  reduce function is optional
         _ ->
-            Err2 = <<"`reduce` in ", VName/binary, " must be a string">>,
-            throw({invalid_design_doc, Err2})
+            Err3 = <<"`reduce` in ", VName/binary, " must be a string">>,
+            throw({invalid_design_doc, Err3})
     end,
     ok;
-validate_view(VName, _) ->
+validate_view(VName, _, _Language) ->
     throw({invalid_design_doc, <<"View ", VName/binary, " must be an object">>}).
 
 
@@ -99,17 +106,17 @@ validate_view(VName, _) ->
 %%  - views :  Validated by a special function.
 %%  - options : Allowed to contain non-string values.
 %%
-validate_opt_object(<<"views">>, {Views})->
-    [validate_view(VName, ViewObj) || {VName, ViewObj} <- Views],
+validate_opt_object(<<"views">>, {Views}, Language)->
+    [validate_view(VName, ViewObj, Language) || {VName, ViewObj} <- Views],
     ok;
-validate_opt_object(<<"options">>, {_})->
+validate_opt_object(<<"options">>, {_}, _Language)->
     ok;
-validate_opt_object(Section, {Fields}) ->
+validate_opt_object(Section, {Fields}, _Language) ->
     [validate_opt_string(FName, FVal, Section) || {FName, FVal} <- Fields],
     ok;
-validate_opt_object(_, undefined) ->
+validate_opt_object(_, undefined, _Language) ->
     ok;
-validate_opt_object(FieldName, _) ->
+validate_opt_object(FieldName, _, _Language) ->
     throw({invalid_design_doc, <<"`", FieldName/binary, "` is not an object">>}).
 
 
@@ -141,9 +148,10 @@ validate(DbName,  DDoc) ->
                   <<"shows">>, <<"updates">>, <<"views">>],
     StringFields = [<<"language">>, <<"validate_doc_update">>],
     ArrayFields = [<<"rewrites">>],
-    [validate_opt_object(F, couch_util:get_value(F, Fields)) || F <- ObjFields],
     [validate_opt_string(F, couch_util:get_value(F, Fields)) || F <- StringFields],
     [validate_opt_array(F, couch_util:get_value(F, Fields))  || F <- ArrayFields],
+    Language = couch_util:get_value(<<"language">>, Fields),
+    [validate_opt_object(F, couch_util:get_value(F, Fields), Language) || F <- ObjFields],
     GetName = fun
         (#mrview{map_names = [Name | _]}) -> Name;
         (#mrview{reduce_funs = [{Name, _} | _]}) -> Name;

http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/blob/aa51eb4b/test/couch_mrview_ddoc_validation_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_mrview_ddoc_validation_tests.erl b/test/couch_mrview_ddoc_validation_tests.erl
index 1717616..279d4e2 100644
--- a/test/couch_mrview_ddoc_validation_tests.erl
+++ b/test/couch_mrview_ddoc_validation_tests.erl
@@ -63,7 +63,9 @@ ddoc_validation_test_() ->
                     fun should_reject_view_without_map_function/1,
                     fun should_reject_view_with_non_string_map_function/1,
                     fun should_reject_view_with_non_string_reduce_function/1,
-                    fun should_accept_any_in_lib/1
+                    fun should_accept_any_in_lib/1,
+                    fun should_accept_map_object_for_queries/1,
+                    fun should_reject_map_non_objects_for_queries/1
                 ]
             }
         }
@@ -363,3 +365,33 @@ should_accept_any_in_lib(Db) ->
                        ]}}
     ]}),
     ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+
+
+should_accept_map_object_for_queries(Db) ->
+    Doc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/should_accept_map_objects_for_queries">>},
+        {<<"language">>, <<"query">>},
+        {<<"views">>, {[
+            {<<"view1">>, {[
+                {<<"map">>, {[
+                    {<<"x">>, <<"y">>}
+                ]}}
+           ]}}
+        ]}}
+    ]}),
+    ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+
+
+should_reject_map_non_objects_for_queries(Db) ->
+    Doc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/should_reject_map_non_objects__with_nonstr_reduce">>},
+        {<<"language">>, <<"query">>},
+        {<<"views">>, {[
+            {<<"view1">>, {[
+                {<<"map">>, <<"function(d){}">>}
+            ]}}
+        ]}}
+    ]}),
+    ?_assertThrow({bad_request,invalid_design_doc,
+                   <<"`map` in view1 for queries must be an object">>},
+                  couch_db:update_doc(Db, Doc, [])).