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

chewbranca pushed a commit to branch couch-stats-resource-tracker
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 715b524199cd2b1a4c35e26152c8d44d857db793
Author: Russell Branca <chewbra...@apache.org>
AuthorDate: Fri Nov 17 16:03:12 2023 -0800

    WIP: ugly but working HTTP API around groupings
---
 src/chttpd/src/chttpd_misc.erl                     | 92 +++++++++++++++++++++-
 .../src/couch_stats_resource_tracker.erl           | 13 ++-
 2 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/src/chttpd/src/chttpd_misc.erl b/src/chttpd/src/chttpd_misc.erl
index 195c8d828..28bbcbee0 100644
--- a/src/chttpd/src/chttpd_misc.erl
+++ b/src/chttpd/src/chttpd_misc.erl
@@ -37,8 +37,7 @@
     [
         send_json/2, send_json/3,
         send_method_not_allowed/2,
-        send_chunk/2,
-        start_chunked_response/3
+        send_chunk/2
     ]
 ).
 
@@ -231,6 +230,92 @@ handle_task_status_req(#httpd{method = 'GET'} = Req) ->
 handle_task_status_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
+handle_resource_status_req(#httpd{method = 'POST'} = Req) ->
+    ok = chttpd:verify_is_server_admin(Req),
+    chttpd:validate_ctype(Req, "application/json"),
+    {Props} = chttpd:json_body_obj(Req),
+    Action = proplists:get_value(<<"action">>, Props),
+    Key = proplists:get_value(<<"key">>, Props),
+    Val = proplists:get_value(<<"val">>, Props),
+
+    CountBy = fun couch_stats_resource_tracker:count_by/1,
+    GroupBy = fun couch_stats_resource_tracker:group_by/2,
+    SortedBy1 = fun couch_stats_resource_tracker:sorted_by/1,
+    SortedBy2 = fun couch_stats_resource_tracker:sorted_by/2,
+    ConvertEle = fun(K) -> list_to_existing_atom(binary_to_list(K)) end,
+    ConvertList = fun(L) -> [ConvertEle(E) || E <- L] end,
+    ToJson = fun couch_stats_resource_tracker:term_to_flat_json/1,
+    JsonKeys = fun(PL) -> [[ToJson(K), V] || {K, V} <- PL] end,
+
+    Fun = case {Action, Key, Val} of
+        {<<"count_by">>, Keys, undefined} when is_list(Keys) ->
+            Keys1 = [ConvertEle(K) || K <- Keys],
+            fun() -> CountBy(Keys1) end;
+        {<<"count_by">>, Key, undefined} ->
+            Key1 = ConvertEle(Key),
+            fun() -> CountBy(Key1) end;
+        {<<"group_by">>, Keys, Vals} when is_list(Keys) andalso is_list(Vals) 
->
+            Keys1 = ConvertList(Keys),
+            Vals1 = ConvertList(Vals),
+            fun() -> GroupBy(Keys1, Vals1) end;
+        {<<"group_by">>, Key, Vals} when is_list(Vals) ->
+            Key1 = ConvertEle(Key),
+            Vals1 = ConvertList(Vals),
+            fun() -> GroupBy(Key1, Vals1) end;
+        {<<"group_by">>, Keys, Val} when is_list(Keys) ->
+            Keys1 = ConvertList(Keys),
+            Val1 = ConvertEle(Val),
+            fun() -> GroupBy(Keys1, Val1) end;
+        {<<"group_by">>, Key, Val} ->
+            Key1 = ConvertEle(Key),
+            Val1 = ConvertList(Val),
+            fun() -> GroupBy(Key1, Val1) end;
+
+        {<<"sorted_by">>, Key, undefined} ->
+            Key1 = ConvertEle(Key),
+            fun() -> JsonKeys(SortedBy1(Key1)) end;
+        {<<"sorted_by">>, Keys, undefined} when is_list(Keys) ->
+            Keys1 = [ConvertEle(K) || K <- Keys],
+            fun() -> JsonKeys(SortedBy1(Keys1)) end;
+        {<<"sorted_by">>, Keys, Vals} when is_list(Keys) andalso is_list(Vals) 
->
+            Keys1 = ConvertList(Keys),
+            Vals1 = ConvertList(Vals),
+            fun() -> JsonKeys(SortedBy2(Keys1, Vals1)) end;
+        {<<"sorted_by">>, Key, Vals} when is_list(Vals) ->
+            Key1 = ConvertEle(Key),
+            Vals1 = ConvertList(Vals),
+            fun() -> JsonKeys(SortedBy2(Key1, Vals1)) end;
+        {<<"sorted_by">>, Keys, Val} when is_list(Keys) ->
+            Keys1 = ConvertList(Keys),
+            Val1 = ConvertEle(Val),
+            fun() -> JsonKeys(SortedBy2(Keys1, Val1)) end;
+        {<<"sorted_by">>, Key, Val} ->
+            Key1 = ConvertEle(Key),
+            Val1 = ConvertList(Val),
+            fun() -> JsonKeys(SortedBy2(Key1, Val1)) end;
+        _ ->
+            throw({badrequest, invalid_resource_request})
+    end,
+
+    Fun1 = fun() ->
+        case Fun() of
+            Map when is_map(Map) ->
+                {maps:fold(
+                    fun(K,V,A) -> [{ToJson(K), V} | A] end,
+                    [], Map)};
+            List when is_list(List) ->
+                List
+        end
+    end,
+
+    {Resp, _Bad} = rpc:multicall(erlang, apply, [
+        fun() ->
+            {node(), Fun1()}
+        end,
+        []
+    ]),
+    io:format("{CSRT}***** GOT RESP: ~p~n", [Resp]),
+    send_json(Req, {Resp});
 handle_resource_status_req(#httpd{method = 'GET'} = Req) ->
     ok = chttpd:verify_is_server_admin(Req),
     {Resp, Bad} = rpc:multicall(erlang, apply, [
@@ -243,7 +328,8 @@ handle_resource_status_req(#httpd{method = 'GET'} = Req) ->
     io:format("ACTIVE RESP: ~p~nBAD RESP: ~p~n", [Resp, Bad]),
     send_json(Req, {Resp});
 handle_resource_status_req(Req) ->
-    send_method_not_allowed(Req, "GET,HEAD").
+    ok = chttpd:verify_is_server_admin(Req),
+    send_method_not_allowed(Req, "GET,HEAD,POST").
 
 handle_replicate_req(#httpd{method = 'POST', user_ctx = Ctx, req_body = 
PostBody} = Req) ->
     chttpd:validate_ctype(Req, "application/json"),
diff --git a/src/couch_stats/src/couch_stats_resource_tracker.erl 
b/src/couch_stats/src/couch_stats_resource_tracker.erl
index d2dd4406c..d5fcd92ae 100644
--- a/src/couch_stats/src/couch_stats_resource_tracker.erl
+++ b/src/couch_stats/src/couch_stats_resource_tracker.erl
@@ -59,7 +59,9 @@
     sorted_by/2,
     sorted_by/3,
 
-    unsafe_foldl/3
+    unsafe_foldl/3,
+
+    term_to_flat_json/1
 ]).
 
 -export([
@@ -424,6 +426,7 @@ group_by(KeyFun, ValFun, AggFun, Fold) ->
     Fold(FoldFun, #{}, ?MODULE).
 
 
+%% Sorts largest first
 sorted(Map) when is_map(Map) ->
     lists:sort(fun({_K1, A}, {_K2, B}) -> B < A end, maps:to_list(Map)).
 
@@ -523,6 +526,8 @@ term_to_json({type, {coordinator, _, _} = Type}) ->
     ?l2b(io_lib:format("~p", [Type]));
 term_to_json({A, B, C}) ->
     [A, B, C];
+term_to_json(Tuple) when is_tuple(Tuple) ->
+    ?l2b(io_lib:format("~w", [Tuple]));
 term_to_json(undefined) ->
     null;
 term_to_json(null) ->
@@ -530,11 +535,13 @@ term_to_json(null) ->
 term_to_json(T) ->
     T.
 
-term_to_flat_json({type, {coordinator, _, _} = Type}) ->
+term_to_flat_json({type, {coordinator, _, _}}=Type) ->
     %%io:format("SETTING FLAT JSON TYPE: ~p~n", [Type]),
     ?l2b(io_lib:format("~p", [Type]));
+term_to_flat_json({coordinator, _, _}=Type) ->
+    ?l2b(io_lib:format("~p", [Type]));
 term_to_flat_json(Tuple) when is_tuple(Tuple) ->
-    ?l2b(io_lib:format("~w", [Tuple]));
+    ?l2b(io_lib:format("~p", [Tuple]));
 term_to_flat_json(undefined) ->
     null;
 term_to_flat_json(null) ->

Reply via email to