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

iilyak pushed a commit to branch couch-stats-resource-tracker-v3-rebase-http-2
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e21c455e120791183d96a0c36ab0daa63df7c5d3
Author: ILYA Khlopotov <[email protected]>
AuthorDate: Wed Jun 25 07:03:48 2025 -0700

    Add typespecs to sort_by/group_by/count_by
---
 .../src/couch_stats_resource_tracker.hrl           |  6 +++-
 src/couch_stats/src/csrt_query.erl                 | 40 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/src/couch_stats/src/couch_stats_resource_tracker.hrl 
b/src/couch_stats/src/couch_stats_resource_tracker.hrl
index 819e97375..bf03a88b4 100644
--- a/src/couch_stats/src/couch_stats_resource_tracker.hrl
+++ b/src/couch_stats/src/couch_stats_resource_tracker.hrl
@@ -188,6 +188,10 @@
 %% valid #rctx record field names, however, a clean solution is not obvious.
 -type counter_updates_list() :: [{non_neg_integer(), pos_integer()}] | [].
 
+-type tuple_of_field_values() :: tuple().
+-type tuple_of_field_names() :: tuple().
+
 -type query_options() :: #{aggregation => group_by | sort_by | count_by, limit 
=> pos_integer()}.
--type aggregation_key() :: tuple().
+-type aggregation_key() :: tuple_of_field_names().
+-type aggregation_values() :: tuple_of_field_values().
 -type query_result() :: #{aggregation_key() => non_neg_integer()}.
diff --git a/src/couch_stats/src/csrt_query.erl 
b/src/couch_stats/src/csrt_query.erl
index 717b44de7..97a0be751 100644
--- a/src/couch_stats/src/csrt_query.erl
+++ b/src/couch_stats/src/csrt_query.erl
@@ -122,15 +122,35 @@ curry_field(Field) ->
 count_by(KeyFun) ->
     csrt_query:count_by(all(), KeyFun).
 
+-spec count_by(Matcher :: matcher(), KeyFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()).
 count_by(Matcher, KeyFun) ->
     group_by(Matcher, KeyFun, fun(_) -> 1 end).
 
+-spec group_by(KeyFun, ValFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()),
+    ValFun :: fun((Ele :: #rctx{}) -> aggregation_values()).
 group_by(KeyFun, ValFun) ->
     csrt_query:group_by(all(), KeyFun, ValFun).
 
+-spec group_by(Matcher :: matcher(), KeyFun, ValFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()),
+    ValFun :: fun((Ele :: #rctx{}) -> aggregation_values()).
 group_by(Matcher, KeyFun, ValFun) ->
     group_by(Matcher, KeyFun, ValFun, fun erlang:'+'/2).
 
+-spec group_by(Matcher :: matcher(), KeyFun, ValFun, AggFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()),
+    ValFun :: fun((Ele :: #rctx{}) -> aggregation_values()),
+    AggFun :: fun((FieldValue :: pos_integer()) -> pos_integer()).
 group_by(Matcher, KeyFun, ValFun, AggFun) ->
     group_by(Matcher, KeyFun, ValFun, AggFun, ?QUERY_CARDINALITY_LIMIT).
 
@@ -232,13 +252,33 @@ topK(Results, K) ->
     TopK = maps:fold(fun update_topK/3, new_topK(K), Results),
     get_topK(TopK).
 
+-spec sort_by(KeyFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()).
+
 %% eg: sort_by([username, dbname, type], ioq_calls)
 %% eg: sort_by([dbname, type], doc_reads)
 sort_by(KeyFun) ->
     topK(count_by(KeyFun), 10).
+
+-spec sort_by(ValFun, AggFun) ->
+    query_result()
+when
+    ValFun :: fun((Ele :: #rctx{}) -> aggregation_values()),
+    AggFun :: fun((FieldValue :: pos_integer()) -> pos_integer()).
+
 sort_by(KeyFun, ValFun) ->
     {Result, Acc} = group_by(KeyFun, ValFun),
     {Result, topK(Acc, 10)}.
+
+-spec sort_by(KeyFun, ValFun, AggFun) ->
+    query_result()
+when
+    KeyFun :: fun((Ele :: #rctx{}) -> aggregation_key()),
+    ValFun :: fun((Ele :: #rctx{}) -> aggregation_values()),
+    AggFun :: fun((FieldValue :: pos_integer()) -> pos_integer()).
+
 sort_by(KeyFun, ValFun, AggFun) ->
     {Result, Acc} = group_by(KeyFun, ValFun, AggFun),
     {Result, topK(Acc, 10)}.

Reply via email to