iilyak commented on code in PR #5602:
URL: https://github.com/apache/couchdb/pull/5602#discussion_r2236536174


##########
src/couch_srt/src/couch_srt_httpd.erl:
##########
@@ -0,0 +1,157 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_srt_httpd).
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch_srt.hrl").
+
+-export([handle_resource_status_req/1]).
+
+-import(
+    chttpd,
+    [
+        send_json/2, send_json/3,
+        send_method_not_allowed/2
+    ]
+).
+
+handle_resource_status_req(
+    #httpd{method = 'POST', path_parts = [<<"_active_resources">>, 
<<"_match">>, MatcherNameBin]} =
+        Req
+) ->
+    chttpd:validate_ctype(Req, "application/json"),
+    {JsonProps} = chttpd:json_body_obj(Req),
+    GroupBy = couch_util:get_value(<<"group_by">>, JsonProps),
+    SortBy = couch_util:get_value(<<"sort_by">>, JsonProps),
+    CountBy = couch_util:get_value(<<"count_by">>, JsonProps),
+    MatcherName = binary_to_list(MatcherNameBin),
+    {AggregationKeys, Query} =
+        case {GroupBy, SortBy, CountBy} of
+            {undefined, undefined, {Props}} ->
+                Keys = couch_util:get_value(<<"aggregate_keys">>, Props),
+                {Keys, couch_srt:query([couch_srt:from(MatcherName), 
couch_srt:count_by(Keys)])};
+            {undefined, {Props}, undefined} ->
+                Keys = couch_util:get_value(<<"aggregate_keys">>, Props),
+                CounterKey = couch_util:get_value(<<"counter_key">>, Props),
+                {Keys,
+                    couch_srt:query([
+                        couch_srt:from(MatcherName), couch_srt:sort_by(Keys, 
CounterKey)
+                    ])};
+            {{Props}, undefined, undefined} ->
+                Keys = couch_util:get_value(<<"aggregate_keys">>, Props),
+                CounterKey = couch_util:get_value(<<"counter_key">>, Props),
+                {Keys,
+                    couch_srt:query([
+                        couch_srt:from(MatcherName), couch_srt:group_by(Keys, 
CounterKey)
+                    ])};
+            {_, _, _} ->
+                throw({bad_request, <<"Multiple aggregations are not 
supported">>})
+        end,
+    case Query of
+        {error, Reason} ->
+            send_error(Req, Reason);
+        Q ->
+            JSON = to_json(AggregationKeys, couch_srt:rpc_run(Q)),
+            send_json(Req, JSON)
+    end;
+handle_resource_status_req(#httpd{path_parts = [<<"_active_resources">>]} = 
Req) ->
+    ok = chttpd:verify_is_server_admin(Req),
+    send_method_not_allowed(Req, "GET,HEAD");
+handle_resource_status_req(Req) ->
+    ok = chttpd:verify_is_server_admin(Req),
+    send_method_not_allowed(Req, "GET,HEAD,POST").
+
+to_json(AggregationKeys, Results) ->
+    lists:map(fun(E) -> node_reply_to_json(AggregationKeys, E) end, Results).
+
+node_reply_to_json(_AggregationKeys, #{node := Node, result := none, errors := 
Errors}) ->
+    #{
+        node => atom_to_binary(Node),
+        result => none,
+        errors => lists:map(fun erlang:atom_to_list/1, Errors)
+    };
+node_reply_to_json(AggregationKeys, #{node := Node, result := Result, errors 
:= Errors}) ->
+    #{
+        node => atom_to_binary(Node),
+        result => aggregation_result_to_json(AggregationKeys, Result),
+        errors => lists:map(fun erlang:atom_to_list/1, Errors)
+    }.
+
+encode_key(AggregationKeys, Key) ->
+    maps:from_list(lists:zip(AggregationKeys, tuple_to_list(Key))).
+
+-spec aggregation_result_to_json(AggregationKeys :: binary() | [binary()], Map 
:: query_result()) ->
+    json_spec(#{
+        value => non_neg_integer(),
+        key => #{
+            username => string(),

Review Comment:
   I see now that it is confusing. Here is how I came about this spec. The 
query_result function return JSON as expected by `jiffy:encode/1` 
(`jiffy:json_value()`). However `jiffy:json_value()` is opaque and cannot serve 
as a documentation. So my first idea was to have a comment which shows the 
structure of the result. However maintaining the comment is harder because 
compiler doesn't check the comments. So I invented `-type json_spec(_Spec) :: 
term().` This type *ignores* what's inside. It is meant for documenting JSON 
structure. I thought it would be great to use across codebase to provide 
example of the data structures used by functions. So I used the types which 
make sense to document JSON. I.e. `string()` in this context refer to the JSON 
string. I could change it to `jiffy:json_string().` although I need to check 
whether compiler would like it or not (the problem might be that `jiffy` 
doesn't export its types).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@couchdb.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to