You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2018/08/30 09:34:36 UTC

[couchdb] branch partition-add-post created (now a3a105c)

This is an automated email from the ASF dual-hosted git repository.

garren pushed a change to branch partition-add-post
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


      at a3a105c  add POST support for keys for views

This branch includes the following new commits:

     new ec8b203  Add /_partition/$partition/... endpoints
     new a3a105c  add POST support for keys for views

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 02/02: add POST support for keys for views

Posted by ga...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch partition-add-post
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit a3a105ccbec3332edc6955579e6a1e14b5c4c427
Author: Garren Smith <ga...@gmail.com>
AuthorDate: Thu Aug 30 11:34:20 2018 +0200

    add POST support for keys for views
---
 src/chttpd/src/chttpd_view.erl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 627663c..557f2b6 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -106,6 +106,25 @@ handle_temp_view_req(Req, _Db) ->
     chttpd:send_error(Req, 410, gone, Msg).
 
 
+handle_partition_view_req(#httpd{method='POST',
+        path_parts=[_, _, _, _, _, _, ViewName]} = Req, Db, DDoc, Partition) ->
+    chttpd:validate_ctype(Req, "application/json"),
+    Props = couch_httpd:json_body_obj(Req),
+    Keys = couch_mrview_util:get_view_keys(Props),
+    case Keys of
+        Keys when is_list(Keys) ->
+            couch_stats:increment_counter([couchdb, httpd, view_reads]),
+            Args = couch_mrview_http:parse_params(Req, Keys),
+            Args1 = couch_mrview_util:set_extra(Args, partition, Partition),
+            Args2 = couch_mrview_util:set_extra(Args1, partitioned, true),
+            design_doc_view_int(Req, Db, DDoc, ViewName, Args2);
+        _ ->
+            throw({
+                bad_request,
+                "POST body must contain `keys` field"
+            })
+    end;
+
 handle_partition_view_req(#httpd{method='GET',
         path_parts=[_, _, _, _, _, _, ViewName]} = Req, Db, DDoc, Partition) ->
     Keys = chttpd:qs_json_value(Req, "keys", undefined),


[couchdb] 01/02: Add /_partition/$partition/... endpoints

Posted by ga...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch partition-add-post
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit ec8b2037668e6d91a4a07b76b42afc4dbdb161d7
Author: Garren Smith <ga...@gmail.com>
AuthorDate: Wed Aug 29 13:59:48 2018 +0100

    Add /_partition/$partition/... endpoints
---
 src/chttpd/src/chttpd_db.erl               | 68 +++++++++++++++++++++---
 src/chttpd/src/chttpd_handlers.erl         | 10 +++-
 src/chttpd/src/chttpd_httpd_handlers.erl   |  6 ++-
 src/chttpd/src/chttpd_view.erl             | 17 +++++-
 src/couch_mrview/src/couch_mrview.erl      |  1 +
 src/couch_mrview/src/couch_mrview_util.erl | 14 +++++
 src/mango/src/mango_error.erl              |  7 +++
 src/mango/src/mango_httpd.erl              | 85 ++++++++++++++++++++++++++----
 src/mango/src/mango_httpd_handlers.erl     |  6 ++-
 9 files changed, 192 insertions(+), 22 deletions(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index d1f0b81..e020c5a 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_req/2]).
 
 -import(chttpd,
     [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
@@ -250,21 +251,72 @@ handle_view_cleanup_req(Req, Db) ->
     ok = fabric:cleanup_index_files_all_nodes(Db),
     send_json(Req, 202, {[{ok, true}]}).
 
+
+handle_partition_req(#httpd{
+        path_parts=[DbName, <<"_partition">>, Partition, _Design, Name, <<"_",_/binary>> = Action | _Rest]
+    }=Req, Db) ->
+
+    validate_partition_req(Req, Partition, DbName),
+    DDoc = get_design_doc(DbName, Name),
+    Partitioned = couch_mrview:get_partitioned_opt(DDoc#doc.body, true),
+
+    case Partitioned of
+        true ->
+            Handler = chttpd_handlers:partition_design_handler(Action, fun bad_action_partition_design_req/4),
+            Handler(Req, Db, DDoc, Partition);
+        false ->
+            throw({bad_request, <<"partition query is not supported in this design doc.">>})
+    end;
+
+handle_partition_req(#httpd{
+        path_parts=[DbName, <<"_partition">>, Partition, Action | _Rest]
+    }=Req, Db) ->
+        validate_partition_req(Req, Partition, DbName),
+        Handler = chttpd_handlers:partition_handler(Action, fun bad_action_partition_req/3),
+        Handler(Req, Db, Partition);
+
+handle_partition_req(_Req, _Db) ->
+    throw({bad_request, <<"missing partition key">>}).
+
+
+bad_action_partition_design_req(Req, _Db, _DDoc, _PartitionKey) ->
+    chttpd:send_error(Req, 404, <<"partition_error">>, <<"Invalid path.">>).
+
+
+bad_action_partition_req(Req, _Db, _PartitionKey) ->
+    chttpd:send_error(Req, 404, <<"partition_error">>, <<"Invalid path.">>).
+
+
+validate_partition_req(_Req, Partition, DbName) ->
+    validate_docid(Partition, DbName),
+
+    case mem3:is_partitioned(DbName) of
+        false -> throw({bad_request, <<"Database is not partitioned">>});
+        true -> ok
+    end.
+
+
 handle_design_req(#httpd{
         path_parts=[_DbName, _Design, Name, <<"_",_/binary>> = Action | _Rest]
     }=Req, Db) ->
     DbName = mem3:dbname(couch_db:name(Db)),
-    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);
-    Error ->
-        throw(Error)
-    end;
+    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} ->
+            DDoc;
+        Error ->
+            throw(Error)
+    end.
+
+
 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 9305632..f2098be 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -15,7 +15,9 @@
 -export([
     url_handler/2,
     db_handler/2,
-    design_handler/2
+    design_handler/2,
+    partition_handler/2,
+    partition_design_handler/2
 ]).
 
 -define(SERVICE_ID, chttpd_handlers).
@@ -35,6 +37,12 @@ db_handler(HandlerKey, DefaultFun) ->
 design_handler(HandlerKey, DefaultFun) ->
     select(collect(design_handler, [HandlerKey]), DefaultFun).
 
+partition_handler(HandlerKey, DefaultFun) ->
+        select(collect(partition_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 cb52e2c..2659d39 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_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 6b95706..627663c 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -14,7 +14,7 @@
 -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 +42,10 @@ 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, Args) ->
     couch_mrview_util:validate_args(Args, [view]),
     Max = chttpd:chunked_response_buffer_size(),
     VAcc = #vacc{db=Db, req=Req, threshold=Max},
@@ -102,6 +106,17 @@ 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, Partition) ->
+    Keys = chttpd:qs_json_value(Req, "keys", undefined),
+    Args = couch_mrview_http:parse_params(Req, Keys),
+    Args1 = couch_mrview_util:set_extra(Args, partition, Partition),
+    Args2 = couch_mrview_util:set_extra(Args1, partitioned, true),
+    design_doc_view_int(Req, Db, DDoc, ViewName, Args2);
+
+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.erl b/src/couch_mrview/src/couch_mrview.erl
index 7862afb..1b1a06b 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -24,6 +24,7 @@
 -export([refresh/2]).
 -export([compact/2, compact/3, cancel_compaction/2]).
 -export([cleanup/1]).
+-export([get_partitioned_opt/2]).
 
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 794b694..0fa5c1f 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -617,6 +617,20 @@ validate_args(Args, ValidateOptions) ->
             ok
     end,
 
+    case {Partitioned, Args#mrargs.conflicts} of
+        {true, true} ->
+            mrverror(<<"`conflicts=true` is not supported in this view.">>);
+        {_, _} ->
+            ok
+    end,
+
+    case {Partitioned, Args#mrargs.stable} of
+        {true, true} ->
+            mrverror(<<"`stable=true` is not supported in this view.">>);
+        {_, _} ->
+            ok
+    end,
+
     Args1 = case {Style, Partitioned, Partition} of
         {all_docs, true, undefined} ->
             Args;
diff --git a/src/mango/src/mango_error.erl b/src/mango/src/mango_error.erl
index b2bbb39..603fb5f 100644
--- a/src/mango/src/mango_error.erl
+++ b/src/mango/src/mango_error.erl
@@ -73,6 +73,13 @@ info(mango_fields, {invalid_field_json, BadField}) ->
         fmt("Invalid JSON for field spec: ~w", [BadField])
     };
 
+info(mango_httpd, partition_field_error) ->
+    {
+        400,
+        <<"bad request">>,
+        <<"`partition` is not a valid parameter.">>
+    };
+
 info(mango_httpd, error_saving_ddoc) ->
     {
         500,
diff --git a/src/mango/src/mango_httpd.erl b/src/mango/src/mango_httpd.erl
index 2e87771..9a5c266 100644
--- a/src/mango/src/mango_httpd.erl
+++ b/src/mango/src/mango_httpd.erl
@@ -14,7 +14,8 @@
 
 
 -export([
-    handle_req/2
+    handle_req/2,
+    handle_partition_req/3
 ]).
 
 
@@ -38,13 +39,7 @@ handle_req(#httpd{} = Req, Db0) ->
         handle_req_int(Req, Db)
     catch
         throw:{mango_error, Module, Reason} ->
-            case mango_error:info(Module, Reason) of
-            {500, ErrorStr, ReasonStr} ->
-                Stack = erlang:get_stacktrace(),
-                chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
-            {Code, ErrorStr, ReasonStr} ->
-                chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
-            end
+            handle_req_error(Req, Module, Reason)
     end.
 
 
@@ -58,6 +53,34 @@ handle_req_int(_, _) ->
     throw({not_found, missing}).
 
 
+handle_partition_req(#httpd{} = Req, Db0, Partition) ->
+        try
+            Db = set_user_ctx(Req, Db0),
+            handle_partition_req_int(Req, Db, Partition)
+        catch
+            throw:{mango_error, Module, Reason} ->
+                handle_req_error(Req, Module, Reason)
+        end.
+
+
+handle_partition_req_int(#httpd{path_parts=[_, _, _, <<"_explain">> | _]} = Req, Db, Partition) ->
+    handle_partition_explain_req(Req, Db, Partition);
+handle_partition_req_int(#httpd{path_parts=[_, _, _,<<"_find">> | _]} = Req, Db, Partition) ->
+    handle_partition_find_req(Req, Db, Partition);
+handle_partition_req_int(_, _, _) ->
+    throw({not_found, missing}).
+
+
+handle_req_error(Req, Module, Reason) ->
+    case mango_error:info(Module, Reason) of
+    {500, ErrorStr, ReasonStr} ->
+        Stack = erlang:get_stacktrace(),
+        chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
+    {Code, ErrorStr, ReasonStr} ->
+        chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
+    end.
+
+
 handle_index_req(#httpd{method='GET', path_parts=[_, _]}=Req, Db) ->
     Params = lists:flatmap(fun({K, V}) -> parse_index_param(K, V) end,
         chttpd:qs(Req)),
@@ -170,7 +193,9 @@ handle_index_req(#httpd{path_parts=[_, _, _DDocId0, _Type, _Name]}=Req, _Db) ->
 
 handle_explain_req(#httpd{method='POST'}=Req, Db) ->
     chttpd:validate_ctype(Req, "application/json"),
-    {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+    {Body0} = chttpd:json_body_obj(Req),
+    check_for_partition_param(Body0),
+    {ok, Opts0} = mango_opts:validate_find({Body0}),
     {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
     Resp = mango_crud:explain(Db, Sel, Opts),
     chttpd:send_json(Req, Resp);
@@ -179,9 +204,23 @@ handle_explain_req(Req, _Db) ->
     chttpd:send_method_not_allowed(Req, "POST").
 
 
+handle_partition_explain_req(#httpd{method='POST'}=Req, Db, Partition) ->
+    chttpd:validate_ctype(Req, "application/json"),
+    {ok, Body} = add_partition_to_query(Req, Partition),
+    {ok, Opts0} = mango_opts:validate_find(Body),
+    {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+    Resp = mango_crud:explain(Db, Sel, Opts),
+    chttpd:send_json(Req, Resp);
+
+handle_partition_explain_req(Req, _Db, _Partition) ->
+    chttpd:send_method_not_allowed(Req, "POST").
+
+
 handle_find_req(#httpd{method='POST'}=Req, Db) ->
     chttpd:validate_ctype(Req, "application/json"),
-    {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+    {Body0} = chttpd:json_body_obj(Req),
+    check_for_partition_param(Body0),
+    {ok, Opts0} = mango_opts:validate_find({Body0}),
     {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
     {ok, Resp0} = start_find_resp(Req),
     {ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
@@ -191,6 +230,32 @@ handle_find_req(Req, _Db) ->
     chttpd:send_method_not_allowed(Req, "POST").
 
 
+handle_partition_find_req(#httpd{method='POST'}=Req, Db, Partition) ->
+    chttpd:validate_ctype(Req, "application/json"),
+    {ok, Body} = add_partition_to_query(Req, Partition),
+    {ok, Opts0} = mango_opts:validate_find(Body),
+    {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+    {ok, Resp0} = start_find_resp(Req),
+    {ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
+    end_find_resp(AccOut);
+
+handle_partition_find_req(Req, _Db, _Partition) ->
+    chttpd:send_method_not_allowed(Req, "POST").
+
+check_for_partition_param(Body) ->
+    case lists:keyfind(<<"partition">>, 1, Body) of
+        false -> ok;
+        _ -> ?MANGO_ERROR(partition_field_error)
+    end.
+
+
+add_partition_to_query(Req, Partition) ->
+    {Body0} = chttpd:json_body_obj(Req),
+    check_for_partition_param(Body0),
+    Body1 = [{<<"partition">>, Partition} | Body0],
+    {ok, {Body1}}.
+
+
 set_user_ctx(#httpd{user_ctx=Ctx}, Db) ->
     {ok, NewDb} = couch_db:set_user_ctx(Db, Ctx),
     NewDb.
diff --git a/src/mango/src/mango_httpd_handlers.erl b/src/mango/src/mango_httpd_handlers.erl
index 80e5e27..8589b7e 100644
--- a/src/mango/src/mango_httpd_handlers.erl
+++ b/src/mango/src/mango_httpd_handlers.erl
@@ -12,7 +12,7 @@
 
 -module(mango_httpd_handlers).
 
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, partition_handler/1]).
 
 url_handler(_) -> no_match.
 
@@ -22,3 +22,7 @@ db_handler(<<"_find">>)         -> fun mango_httpd:handle_req/2;
 db_handler(_) -> no_match.
 
 design_handler(_) -> no_match.
+
+partition_handler(<<"_find">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(<<"_explain">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(_) -> no_match.