Packages

Native desktop GUI framework for Gleam, powered by Iced

Current section

Files

Jump to
plushie_gleam src plushie@data.erl
Raw

src/plushie@data.erl

-module(plushie@data).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/plushie/data.gleam").
-export(['query'/2]).
-export_type([query_result/1, sort_direction/0, query_opt/1, sort_spec/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Data query pipeline for filtering, searching, sorting, and\n"
" paginating in-memory record collections.\n"
"\n"
" Apply a chain of query options to transform a list:\n"
"\n"
" ```gleam\n"
" data.query(users, [\n"
" data.Filter(fn(u) { u.active }),\n"
" data.Search(fields: [fn(u) { u.name }], query: \"alice\"),\n"
" data.SortBy(direction: data.Asc, compare: fn(a, b) {\n"
" string.compare(a.name, b.name)\n"
" }),\n"
" data.Page(1),\n"
" data.PageSize(10),\n"
" ])\n"
" ```\n"
).
-type query_result(OFN) :: {query_result,
list(OFN),
integer(),
integer(),
integer(),
gleam@dict:dict(binary(), list(OFN))}.
-type sort_direction() :: asc | desc.
-type query_opt(OFO) :: {filter, fun((OFO) -> boolean())} |
{search, list(fun((OFO) -> binary())), binary()} |
{sort, sort_direction(), fun((OFO) -> binary())} |
{sort_by, sort_direction(), fun((OFO, OFO) -> gleam@order:order())} |
{page, integer()} |
{page_size, integer()} |
{group, fun((OFO) -> binary())}.
-type sort_spec(OFP) :: {sort_spec, fun((OFP, OFP) -> gleam@order:order())}.
-file("src/plushie/data.gleam", 107).
-spec paginate(list(OFV), integer(), integer()) -> list(OFV).
paginate(Items, Page, Page_size) ->
Skip = (Page - 1) * Page_size,
_pipe = Items,
_pipe@1 = gleam@list:drop(_pipe, Skip),
gleam@list:take(_pipe@1, Page_size).
-file("src/plushie/data.gleam", 114).
-spec find_filter(list(query_opt(OFY))) -> gleam@option:option(fun((OFY) -> boolean())).
find_filter(Opts) ->
_pipe = gleam@list:find_map(Opts, fun(Opt) -> case Opt of
{filter, F} ->
{ok, F};
_ ->
{error, nil}
end end),
gleam@option:from_result(_pipe).
-file("src/plushie/data.gleam", 124).
-spec find_search(list(query_opt(OGC))) -> gleam@option:option({list(fun((OGC) -> binary())),
binary()}).
find_search(Opts) ->
_pipe = gleam@list:find_map(Opts, fun(Opt) -> case Opt of
{search, Fields, Query} ->
{ok, {Fields, Query}};
_ ->
{error, nil}
end end),
gleam@option:from_result(_pipe).
-file("src/plushie/data.gleam", 143).
?DOC(
" Collect all Sort and SortBy opts (in order) into normalized comparators.\n"
" Multiple sort specs enable multi-column tiebreaking.\n"
).
-spec collect_sort_specs(list(query_opt(OGH))) -> list(sort_spec(OGH)).
collect_sort_specs(Opts) ->
gleam@list:filter_map(Opts, fun(Opt) -> case Opt of
{sort, Dir, Key_fn} ->
{ok,
{sort_spec,
fun(A, B) ->
Cmp = gleam@string:compare(Key_fn(A), Key_fn(B)),
case Dir of
asc ->
Cmp;
desc ->
gleam@order:negate(Cmp)
end
end}};
{sort_by, Dir@1, Cmp@1} ->
{ok, {sort_spec, fun(A@1, B@1) -> case Dir@1 of
asc ->
Cmp@1(A@1, B@1);
desc ->
gleam@order:negate(Cmp@1(A@1, B@1))
end end}};
_ ->
{error, nil}
end end).
-file("src/plushie/data.gleam", 171).
?DOC(" Multi-column tiebreaking: walk through sort specs until one breaks the tie.\n").
-spec compare_multi(OGM, OGM, list(sort_spec(OGM))) -> gleam@order:order().
compare_multi(A, B, Specs) ->
case Specs of
[] ->
eq;
[Spec | Rest] ->
case (erlang:element(2, Spec))(A, B) of
eq ->
compare_multi(A, B, Rest);
Result ->
Result
end
end.
-file("src/plushie/data.gleam", 182).
-spec find_page(list(query_opt(any()))) -> integer().
find_page(Opts) ->
_pipe = gleam@list:find_map(Opts, fun(Opt) -> case Opt of
{page, P} ->
{ok, P};
_ ->
{error, nil}
end end),
gleam@result:unwrap(_pipe, 1).
-file("src/plushie/data.gleam", 192).
-spec find_page_size(list(query_opt(any()))) -> integer().
find_page_size(Opts) ->
_pipe = gleam@list:find_map(Opts, fun(Opt) -> case Opt of
{page_size, Ps} ->
{ok, Ps};
_ ->
{error, nil}
end end),
gleam@result:unwrap(_pipe, 25).
-file("src/plushie/data.gleam", 202).
-spec find_group(list(query_opt(OGV))) -> gleam@option:option(fun((OGV) -> binary())).
find_group(Opts) ->
_pipe = gleam@list:find_map(Opts, fun(Opt) -> case Opt of
{group, F} ->
{ok, F};
_ ->
{error, nil}
end end),
gleam@option:from_result(_pipe).
-file("src/plushie/data.gleam", 61).
?DOC(" Run a query pipeline on a list of records.\n").
-spec 'query'(list(OFQ), list(query_opt(OFQ))) -> query_result(OFQ).
'query'(Records, Opts) ->
Filter_fn = find_filter(Opts),
Search = find_search(Opts),
Sort_specs = collect_sort_specs(Opts),
Page = find_page(Opts),
Page_size = find_page_size(Opts),
Result = Records,
Result@1 = case Filter_fn of
{some, F} ->
gleam@list:filter(Result, F);
none ->
Result
end,
Result@2 = case Search of
{some, {Fields, Q}} ->
Q_lower = string:lowercase(Q),
gleam@list:filter(
Result@1,
fun(Record) ->
gleam@list:any(
Fields,
fun(Field) ->
gleam_stdlib:contains_string(
string:lowercase(Field(Record)),
Q_lower
)
end
)
end
);
none ->
Result@1
end,
Result@3 = case Sort_specs of
[] ->
Result@2;
Specs ->
gleam@list:sort(
Result@2,
fun(A, B) -> compare_multi(A, B, Specs) end
)
end,
Total = erlang:length(Result@3),
Result@4 = paginate(Result@3, Page, Page_size),
Groups = case find_group(Opts) of
{some, Group_fn} ->
gleam@list:fold(
Result@4,
maps:new(),
fun(Acc, Item) ->
Key = Group_fn(Item),
Existing = case gleam_stdlib:map_get(Acc, Key) of
{ok, Items} ->
Items;
{error, _} ->
[]
end,
gleam@dict:insert(Acc, Key, lists:append(Existing, [Item]))
end
);
none ->
maps:new()
end,
{query_result, Result@4, Total, Page, Page_size, Groups}.