Current section
Files
Jump to
Current section
Files
src/tql_compare.erl
-module(tql_compare).
%% API exports
-export([ by/1
, by/2
, by_prop/1
, by_prop/2
, by_prop/3
, concat/1
, reverse/1
]).
-type comparator(T) :: fun ((T, T) -> boolean()).
-type order() :: ascending | descending.
-export_types([ comparator/1
, order/0
]).
%%%---------------------------------------------------------------------
%%% API
%%%---------------------------------------------------------------------
%% @equiv by(F, ascending)
-spec by(fun ((A) -> B)) -> comparator(A) when
A :: term(),
B :: term().
by(F) ->
by(F, ascending).
%% @doc Creates a comparison function (`comparator(A)') compatible with
%% `lists:sort/2', using the extracted term to sort in the given
%% direction.
-spec by(fun ((A) -> B), order()) -> comparator(A) when
A :: term(),
B :: term().
by(Extractor, ascending) ->
fun (X, Y) -> Extractor(X) =< Extractor(Y) end;
by(Extractor, descending) ->
fun (X, Y) -> Extractor(Y) =< Extractor(X) end.
%% @doc Reverses the order in which elements are sorted by a comparator.
-spec reverse(comparator(T)) -> comparator(T) when T :: term().
reverse(Comparator) ->
fun (X, Y) -> Comparator(Y, X) end.
%% @equiv by_prop(Key, ascending)
-spec by_prop(Key :: term()) -> comparator(map()).
by_prop(Key) ->
by_prop(Key, ascending).
%% @doc Creates a comparator for maps, sorting by a given property, in
%% the given direction.
-spec by_prop(Key :: term(), order()) -> comparator(map()).
by_prop(Key, Order) ->
by(fun (Map) -> maps:get(Key, Map) end, Order).
%% @doc Creates a comparator for maps, sorting by the given property and
%% using the `Default' as fallback value, to sort in the provided
%% direction.
-spec by_prop(Key, Default, order()) -> comparator(map()) when
Key :: term(),
Default :: term().
by_prop(Key, Default, Order) ->
by(fun (Map) -> maps:get(Key, Map, Default) end, Order).
%% @doc Composes multiple comparators together.
%%
%% Fallthrough happens when 2 items are considered equivalent _according
%% to the comparators_. Specifically, this means when `Compare(A, B) ==
%% Compare(B, A)'.
-spec concat([Comp, ...]) -> Comp when
Comp :: comparator(T :: term()).
concat(Comparators) ->
fun (X, Y) ->
concat_help(X, Y, Comparators)
end.
%%%---------------------------------------------------------------------
%%% Internal functions
%%%---------------------------------------------------------------------
-spec concat_help(X, Y, [Comp, ...]) -> boolean() when
X :: T,
Y :: T,
Comp :: comparator(T),
T :: term().
concat_help(X, Y, [Comp]) ->
Comp(X, Y);
concat_help(X, Y, [Comp | Rest]) ->
OtherDir = Comp(Y, X),
case Comp(X, Y) of
OtherDir -> concat_help(X, Y, Rest);
Res -> Res
end.
%% Local variables:
%% mode: erlang
%% erlang-indent-level: 2
%% indent-tabs-mode: nil
%% fill-column: 72
%% coding: latin-1
%% End: