Packages

Gleam SDK for Rockbox Zig — pipe-friendly client for the rockboxd GraphQL API

Current section

Files

Jump to
rockbox src rockbox@smart_playlists@rules.erl
Raw

src/rockbox@smart_playlists@rules.erl

-module(rockbox@smart_playlists@rules).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/rockbox/smart_playlists/rules.gleam").
-export([int/1, string/1, bool/1, float/1, null/0, raw/1, all_of/0, any_of/0, where/4, where_group/2, sort/3, limit/2, to_json/1, to_string/1]).
-export_type([rules/0, group_op/0, op/0, sort_dir/0, value/0, sort/0, node_/0]).
-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(
" Composable builder for smart-playlist rule sets. Pipe-friendly.\n"
"\n"
" ```gleam\n"
" import rockbox/smart_playlists\n"
" import rockbox/smart_playlists/rules\n"
"\n"
" let r =\n"
" rules.all_of()\n"
" |> rules.where(\"play_count\", rules.Gte, rules.int(10))\n"
" |> rules.where(\"last_played\", rules.Within, rules.string(\"30d\"))\n"
" |> rules.sort(\"play_count\", rules.Desc)\n"
" |> rules.limit(50)\n"
"\n"
" let input = smart_playlists.new(\"Most played\", rules.to_string(r))\n"
" let assert Ok(_) = smart_playlists.create(client, input)\n"
" ```\n"
"\n"
" `any_of()` swaps the top-level operator from `AND` to `OR`. Mix the two by\n"
" nesting builders with `where_group`:\n"
"\n"
" ```gleam\n"
" let r =\n"
" rules.all_of()\n"
" |> rules.where(\"genre\", rules.Eq, rules.string(\"Rock\"))\n"
" |> rules.where_group(\n"
" rules.any_of()\n"
" |> rules.where(\"year\", rules.Gte, rules.int(2000))\n"
" |> rules.where(\"year\", rules.Lte, rules.int(2010)),\n"
" )\n"
" ```\n"
).
-opaque rules() :: {rules,
group_op(),
list(node_()),
gleam@option:option(sort()),
gleam@option:option(integer())}.
-type group_op() :: 'and' | 'or'.
-type op() :: eq | neq | gt | gte | lt | lte | contains | within.
-type sort_dir() :: asc | desc.
-opaque value() :: {value, gleam@json:json()}.
-type sort() :: {sort, binary(), sort_dir()}.
-type node_() :: {leaf, binary(), op(), gleam@json:json()} | {group, rules()}.
-file("src/rockbox/smart_playlists/rules.gleam", 107).
?DOC(" Wrap an integer (e.g. play counts, years, durations in ms).\n").
-spec int(integer()) -> value().
int(Value) ->
{value, gleam@json:int(Value)}.
-file("src/rockbox/smart_playlists/rules.gleam", 112).
?DOC(" Wrap a string (e.g. titles, artists, genres, duration windows).\n").
-spec string(binary()) -> value().
string(Value) ->
{value, gleam@json:string(Value)}.
-file("src/rockbox/smart_playlists/rules.gleam", 117).
?DOC(" Wrap a boolean.\n").
-spec bool(boolean()) -> value().
bool(Value) ->
{value, gleam@json:bool(Value)}.
-file("src/rockbox/smart_playlists/rules.gleam", 122).
?DOC(" Wrap a float.\n").
-spec float(float()) -> value().
float(Value) ->
{value, gleam@json:float(Value)}.
-file("src/rockbox/smart_playlists/rules.gleam", 127).
?DOC(" JSON `null`.\n").
-spec null() -> value().
null() ->
{value, gleam@json:null()}.
-file("src/rockbox/smart_playlists/rules.gleam", 132).
?DOC(" Escape hatch for arbitrary JSON values (arrays, nested objects, etc.).\n").
-spec raw(gleam@json:json()) -> value().
raw(Value) ->
{value, Value}.
-file("src/rockbox/smart_playlists/rules.gleam", 141).
?DOC(" Start a builder where every rule must match (logical AND).\n").
-spec all_of() -> rules().
all_of() ->
{rules, 'and', [], none, none}.
-file("src/rockbox/smart_playlists/rules.gleam", 146).
?DOC(" Start a builder where any single rule must match (logical OR).\n").
-spec any_of() -> rules().
any_of() ->
{rules, 'or', [], none, none}.
-file("src/rockbox/smart_playlists/rules.gleam", 151).
?DOC(" Append a rule to the current group.\n").
-spec where(rules(), binary(), op(), value()) -> rules().
where(Builder, Field, Op, Value) ->
{value, Json_value} = Value,
Leaf = {leaf, Field, Op, Json_value},
{rules,
erlang:element(2, Builder),
lists:append(erlang:element(3, Builder), [Leaf]),
erlang:element(4, Builder),
erlang:element(5, Builder)}.
-file("src/rockbox/smart_playlists/rules.gleam", 163).
?DOC(" Nest another builder underneath this one. Useful for mixing AND / OR.\n").
-spec where_group(rules(), rules()) -> rules().
where_group(Parent, Child) ->
{rules,
erlang:element(2, Parent),
lists:append(erlang:element(3, Parent), [{group, Child}]),
erlang:element(4, Parent),
erlang:element(5, Parent)}.
-file("src/rockbox/smart_playlists/rules.gleam", 168).
?DOC(" Set the result ordering.\n").
-spec sort(rules(), binary(), sort_dir()) -> rules().
sort(Builder, Field, Direction) ->
{rules,
erlang:element(2, Builder),
erlang:element(3, Builder),
{some, {sort, Field, Direction}},
erlang:element(5, Builder)}.
-file("src/rockbox/smart_playlists/rules.gleam", 173).
?DOC(" Cap the result count.\n").
-spec limit(rules(), integer()) -> rules().
limit(Builder, Count) ->
{rules,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
{some, Count}}.
-file("src/rockbox/smart_playlists/rules.gleam", 252).
-spec sort_dir_to_string(sort_dir()) -> binary().
sort_dir_to_string(Dir) ->
case Dir of
asc ->
<<"asc"/utf8>>;
desc ->
<<"desc"/utf8>>
end.
-file("src/rockbox/smart_playlists/rules.gleam", 239).
-spec op_to_string(op()) -> binary().
op_to_string(Op) ->
case Op of
eq ->
<<"eq"/utf8>>;
neq ->
<<"neq"/utf8>>;
gt ->
<<"gt"/utf8>>;
gte ->
<<"gte"/utf8>>;
lt ->
<<"lt"/utf8>>;
lte ->
<<"lte"/utf8>>;
contains ->
<<"contains"/utf8>>;
within ->
<<"within"/utf8>>
end.
-file("src/rockbox/smart_playlists/rules.gleam", 232).
-spec group_op_to_string(group_op()) -> binary().
group_op_to_string(Op) ->
case Op of
'and' ->
<<"AND"/utf8>>;
'or' ->
<<"OR"/utf8>>
end.
-file("src/rockbox/smart_playlists/rules.gleam", 220).
-spec node_to_json(node_()) -> gleam@json:json().
node_to_json(Node) ->
case Node of
{leaf, Field, Op, Value} ->
gleam@json:object(
[{<<"field"/utf8>>, gleam@json:string(Field)},
{<<"op"/utf8>>, gleam@json:string(op_to_string(Op))},
{<<"value"/utf8>>, Value}]
);
{group, Child} ->
to_json(Child)
end.
-file("src/rockbox/smart_playlists/rules.gleam", 183).
?DOC(
" Encode the builder as a `Json` value — useful if you're already working\n"
" with JSON values.\n"
).
-spec to_json(rules()) -> gleam@json:json().
to_json(Builder) ->
Base = [{<<"operator"/utf8>>,
gleam@json:string(group_op_to_string(erlang:element(2, Builder)))},
{<<"rules"/utf8>>,
gleam@json:array(erlang:element(3, Builder), fun node_to_json/1)}],
With_sort = case erlang:element(4, Builder) of
{some, {sort, Field, Dir}} ->
lists:append(
Base,
[{<<"sort"/utf8>>,
gleam@json:object(
[{<<"field"/utf8>>, gleam@json:string(Field)},
{<<"dir"/utf8>>,
gleam@json:string(sort_dir_to_string(Dir))}]
)}]
);
none ->
Base
end,
With_limit = case erlang:element(5, Builder) of
{some, N} ->
lists:append(With_sort, [{<<"limit"/utf8>>, gleam@json:int(N)}]);
none ->
With_sort
end,
gleam@json:object(With_limit).
-file("src/rockbox/smart_playlists/rules.gleam", 212).
?DOC(" Encode the builder as a JSON string ready for the smart-playlist mutation.\n").
-spec to_string(rules()) -> binary().
to_string(Builder) ->
gleam@json:to_string(to_json(Builder)).