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)}.
