garrensmith closed pull request #1482: add partition endpoint for views along 
with validation on which
URL: https://github.com/apache/couchdb/pull/1482
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index d8925b7d13..7c2410823d 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -18,7 +18,8 @@
     db_req/2, couch_doc_open/4,handle_changes_req/2,
     update_doc_result_to_json/1, update_doc_result_to_json/2,
     handle_design_info_req/3, handle_view_cleanup_req/2,
-    update_doc/4, http_code_from_status/1]).
+    update_doc/4, http_code_from_status/1,
+    handle_partition_design_req/2]).
 
 -import(chttpd,
     [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
@@ -250,20 +251,83 @@ handle_view_cleanup_req(Req, Db) ->
     ok = fabric:cleanup_index_files_all_nodes(Db),
     send_json(Req, 202, {[{ok, true}]}).
 
+
+handle_partition_design_req(#httpd{
+        path_parts=[DbName, <<"_partition">>, PartitionKey, _Design, Name, 
<<"_",_/binary>> = Action | _Rest]
+    }=Req, Db) -> 
+    validate_partition_key(PartitionKey),
+
+    case chttpd:qs_value(Req, "partition") of
+        undefined ->
+            ok;
+        _ ->
+            throw({
+                bad_request,
+                <<"Partition key is not allowed in the query string">>
+            })
+     end,
+
+    case mem3:is_partitioned(DbName) of
+        false -> throw(<<"Database is not partitioned">>);
+        true -> ok
+    end,
+
+    DDoc = get_design_doc(DbName, Name),
+    case check_ddoc_can_use_partitionkey(DDoc) of
+        true ->
+            Handler = chttpd_handlers:partition_design_handler(Action, fun 
bad_action_partition_req/4),
+            Handler(Req, Db, DDoc, PartitionKey);
+        false ->
+            throw({bad_request, <<"Design doc cannot be used on a partitioned 
query">>})
+    end;
+handle_partition_design_req(_Req, _Db) ->
+    throw({bad_request, <<"missing partition key">>}).
+
+
+validate_partition_key(<<"_", _/binary>>) ->
+    throw({bad_request, <<"partition keys must not begin with an 
underscore">>});
+validate_partition_key(<<" ">>) ->
+    throw({bad_request, <<"partition keys cannot begin with a space">>});
+validate_partition_key(_) ->
+    ok.
+
+
+check_ddoc_can_use_partitionkey(#doc{body={DDocBody}}) ->
+    case lists:keyfind(<<"options">>, 1, DDocBody) of
+        false ->
+            true; %design docs default to being partitioned query only
+        {_, {Options}} ->
+            case lists:keyfind(<<"partitioned">>, 1, Options) of
+                false -> true;
+                {_, Partitioned} -> Partitioned
+            end
+    end.
+
+    
+bad_action_partition_req(Req, _Db, _DDoc, _PartitionKey) ->
+    chttpd:send_error(Req, 404, <<"partition_error">>, <<"Invalid path.">>).
+
+
 handle_design_req(#httpd{
         path_parts=[_DbName, _Design, Name, <<"_",_/binary>> = Action | _Rest]
     }=Req, Db) ->
     DbName = mem3:dbname(couch_db:name(Db)),
+    DDoc = get_design_doc(DbName, Name),
+    Handler = chttpd_handlers:design_handler(Action, fun bad_action_req/3),
+    Handler(Req, Db, DDoc);
+
+handle_design_req(Req, Db) ->
+    db_req(Req, Db).
+    
+
+get_design_doc(DbName, Name) ->
     case ddoc_cache:open(DbName, <<"_design/", Name/binary>>) of
     {ok, DDoc} ->
-        Handler = chttpd_handlers:design_handler(Action, fun bad_action_req/3),
-        Handler(Req, Db, DDoc);
+        DDoc;
     Error ->
         throw(Error)
-    end;
+    end.
 
-handle_design_req(Req, Db) ->
-    db_req(Req, Db).
 
 bad_action_req(#httpd{path_parts=[_, _, Name|FileNameParts]}=Req, Db, _DDoc) ->
     db_attachment_req(Req, Db, <<"_design/",Name/binary>>, FileNameParts).
diff --git a/src/chttpd/src/chttpd_handlers.erl 
b/src/chttpd/src/chttpd_handlers.erl
index 930563230e..3d61f0b431 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -15,7 +15,8 @@
 -export([
     url_handler/2,
     db_handler/2,
-    design_handler/2
+    design_handler/2,
+    partition_design_handler/2
 ]).
 
 -define(SERVICE_ID, chttpd_handlers).
@@ -35,6 +36,9 @@ db_handler(HandlerKey, DefaultFun) ->
 design_handler(HandlerKey, DefaultFun) ->
     select(collect(design_handler, [HandlerKey]), DefaultFun).
 
+partition_design_handler(HandlerKey, DefaultFun) ->
+    select(collect(partition_design_handler, [HandlerKey]), DefaultFun).
+
 %% ------------------------------------------------------------------
 %% Internal Function Definitions
 %% ------------------------------------------------------------------
diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl 
b/src/chttpd/src/chttpd_httpd_handlers.erl
index cb52e2c40d..0ad499ffc0 100644
--- a/src/chttpd/src/chttpd_httpd_handlers.erl
+++ b/src/chttpd/src/chttpd_httpd_handlers.erl
@@ -12,7 +12,7 @@
 
 -module(chttpd_httpd_handlers).
 
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, 
partition_design_handler/1]).
 
 url_handler(<<>>)                  -> fun chttpd_misc:handle_welcome_req/1;
 url_handler(<<"favicon.ico">>)     -> fun chttpd_misc:handle_favicon_req/1;
@@ -32,6 +32,7 @@ url_handler(_) -> no_match.
 db_handler(<<"_view_cleanup">>) -> fun chttpd_db:handle_view_cleanup_req/2;
 db_handler(<<"_compact">>)      -> fun chttpd_db:handle_compact_req/2;
 db_handler(<<"_design">>)       -> fun chttpd_db:handle_design_req/2;
+db_handler(<<"_partition">>)    -> fun chttpd_db:handle_partition_design_req/2;
 db_handler(<<"_temp_view">>)    -> fun chttpd_view:handle_temp_view_req/2;
 db_handler(<<"_changes">>)      -> fun chttpd_db:handle_changes_req/2;
 db_handler(_) -> no_match.
@@ -43,3 +44,6 @@ design_handler(<<"_update">>)  -> fun 
chttpd_show:handle_doc_update_req/3;
 design_handler(<<"_info">>)    -> fun chttpd_db:handle_design_info_req/3;
 design_handler(<<"_rewrite">>) -> fun chttpd_rewrite:handle_rewrite_req/3;
 design_handler(_) -> no_match.
+
+partition_design_handler(<<"_view">>) -> fun 
chttpd_view:handle_partition_view_req/4;
+partition_design_handler(_) -> no_match.
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 799df61b48..1c83764160 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -14,7 +14,8 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
 
--export([handle_view_req/3, handle_temp_view_req/2]).
+-export([handle_view_req/3, handle_temp_view_req/2, 
handle_partition_view_req/4]).
+
 
 multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
     Args0 = couch_mrview_http:parse_params(Req, undefined),
@@ -42,6 +43,9 @@ multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
 
 design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
     Args = couch_mrview_http:parse_params(Req, Keys),
+    design_doc_view_int(Req, Db, DDoc, ViewName, Args).
+
+design_doc_view_int(Req, Db, DDoc, ViewName, #mrargs{} = Args) ->
     Max = chttpd:chunked_response_buffer_size(),
     VAcc = #vacc{db=Db, req=Req, threshold=Max},
     Options = [{user_ctx, Req#httpd.user_ctx}],
@@ -49,6 +53,7 @@ design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
         fun couch_mrview_http:view_cb/2, VAcc, Args),
     {ok, Resp#vacc.resp}.
 
+
 handle_view_req(#httpd{method='POST',
     path_parts=[_, _, _, _, ViewName, <<"queries">>]}=Req, Db, DDoc) ->
     chttpd:validate_ctype(Req, "application/json"),
@@ -101,6 +106,37 @@ handle_temp_view_req(Req, _Db) ->
     chttpd:send_error(Req, 410, gone, Msg).
 
 
+handle_partition_view_req(#httpd{method='GET',
+    path_parts=[_, _, _, _, _, _, ViewName]} = Req, Db, DDoc, PartitionKey) ->
+    Keys = chttpd:qs_json_value(Req, "keys", undefined),
+    Args = couch_mrview_http:parse_params(Req, Keys),
+
+    Restrictions = [
+        {include_docs, Args#mrargs.include_docs, true},
+        {conflicts, Args#mrargs.conflicts, true},
+        {stable, Args#mrargs.stable, true}
+    ],
+    lists:foreach(fun ({Param, Field, Value}) ->
+        case Field =:= Value of
+            true ->
+                Msg = iolist_to_binary(io_lib:format("~s is not allowed for a 
partition query", [Param])),
+                throw({
+                    bad_request,
+                    Msg
+                });
+            false ->
+                ok
+        end
+    end, Restrictions),
+    Args1 = Args#mrargs{
+        partition = PartitionKey,
+        partitioned = true
+    },
+    design_doc_view_int(Req, Db, DDoc, ViewName, Args1);
+
+handle_partition_view_req(Req, _Db, _DDoc, _Pk) ->
+        chttpd:send_method_not_allowed(Req, "GET").
+
 
 -ifdef(TEST).
 
diff --git a/src/couch_mrview/src/couch_mrview_http.erl 
b/src/couch_mrview/src/couch_mrview_http.erl
index fac1d42ced..9dae1d86c4 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -582,8 +582,6 @@ parse_param(Key, Val, Args, IsDecoded) ->
             Args#mrargs{callback=couch_util:to_binary(Val)};
         "sorted" ->
             Args#mrargs{sorted=parse_boolean(Val)};
-        "partition" ->
-            Args#mrargs{partition=couch_util:to_binary(Val)};
         _ ->
             BKey = couch_util:to_binary(Key),
             BVal = couch_util:to_binary(Val),


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to