-module(qs_adv). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([scheme_rails_like/0, default_config/0, with_scheme/2, serialize/2, default_serialize/1, empty/0, parse/2, default_parse/1, get/2, get_as_string/2, get_as_int/2, get_as_float/2, has_key/2, insert/3, insert_one/3, insert_list/3, merge/2, delete/2, maybe_get_as_list/2, get_as_list/2, get_as_list_of_int/2, get_as_list_of_float/2, get_as_bool/2, get_as_list_of_bool/2]). -export_type([one_or_many/0, scheme/0, config/0]). -type one_or_many() :: {one, binary()} | {many, list(binary())}. -type scheme() :: {scheme_list_as_multiple_values, binary()} | {scheme_list_as_single_value, binary(), binary()}. -type config() :: {config, boolean(), scheme()}. -spec map_one_or_many(one_or_many(), fun((binary()) -> binary())) -> one_or_many(). map_one_or_many(One_or_many, Mapper) -> case One_or_many of {one, Value} -> {one, Mapper(Value)}; {many, Values} -> {many, gleam@list:map(Values, Mapper)} end. -spec scheme_rails_like() -> scheme(). scheme_rails_like() -> {scheme_list_as_multiple_values, <<"[]"/utf8>>}. -spec default_config() -> config(). default_config() -> {config, false, scheme_rails_like()}. -spec with_scheme(config(), scheme()) -> config(). with_scheme(Config, Scheme) -> erlang:setelement(3, Config, Scheme). -spec get_list_value(binary(), scheme()) -> list(binary()). get_list_value(Raw_value, Scheme) -> case Scheme of {scheme_list_as_single_value, _, Separator} -> gleam@string:split(Raw_value, Separator); {scheme_list_as_multiple_values, _} -> [Raw_value] end. -spec value_as_many(binary(), list(binary()), scheme()) -> one_or_many(). value_as_many(Raw_value, Existing_values, Scheme) -> Added_values = get_list_value(Raw_value, Scheme), Next_values = lists:append(Existing_values, Added_values), {many, Next_values}. -spec add_key_value( scheme(), gleam@dict:dict(binary(), one_or_many()), {binary(), binary()} ) -> gleam@dict:dict(binary(), one_or_many()). add_key_value(Scheme, Query, Key_value) -> {Raw_key, Raw_value} = Key_value, List_suffix = erlang:element(2, Scheme), Key_without_suffix = gleam@string:replace(Raw_key, List_suffix, <<""/utf8>>), Is_list = Raw_key /= Key_without_suffix, Updater = fun(Res) -> case {Is_list, Res} of {true, {some, Existing}} -> case Existing of {one, _} -> value_as_many(Raw_value, [], Scheme); {many, Existing_values} -> value_as_many(Raw_value, Existing_values, Scheme) end; {true, none} -> value_as_many(Raw_value, [], Scheme); {false, _} -> {one, Raw_value} end end, gleam@dict:upsert(Query, Key_without_suffix, Updater). -spec encode_key_and_values({binary(), one_or_many()}) -> {binary(), one_or_many()}. encode_key_and_values(Key_value) -> {Key, One_or_many} = Key_value, {qs:encode(Key), map_one_or_many(One_or_many, fun qs:encode/1)}. -spec add_list_suffix_or_key(binary(), scheme()) -> binary(). add_list_suffix_or_key(Key, Scheme) -> <>. -spec add_key_suffix({binary(), one_or_many()}, scheme()) -> {binary(), one_or_many()}. add_key_suffix(Key_value, Scheme) -> {Key, One_or_many} = Key_value, case One_or_many of {one, _} -> Key_value; {many, Values} -> {add_list_suffix_or_key(Key, Scheme), {many, Values}} end. -spec unfold_key_value_many(binary(), list(binary()), scheme()) -> list({binary(), binary()}). unfold_key_value_many(Key, Values, Scheme) -> case Scheme of {scheme_list_as_single_value, _, Separator} -> [{Key, gleam@string:join(Values, Separator)}]; {scheme_list_as_multiple_values, _} -> gleam@list:map(Values, fun(Value) -> {Key, Value} end) end. -spec unfold_values({binary(), one_or_many()}, scheme()) -> list({binary(), binary()}). unfold_values(Key_value, Scheme) -> {Key, One_or_many} = Key_value, case One_or_many of {one, Value} -> [{Key, Value}]; {many, Values} -> unfold_key_value_many(Key, Values, Scheme) end. -spec join_key_value({binary(), binary()}) -> binary(). join_key_value(Tuple) -> {Key, Value} = Tuple, <<<>), qs:add_question_mark(_pipe@6). -spec default_serialize(gleam@dict:dict(binary(), one_or_many())) -> binary(). default_serialize(Query) -> serialize(Query, default_config()). -spec empty() -> gleam@dict:dict(binary(), one_or_many()). empty() -> qs:empty(). -spec parse(binary(), config()) -> {ok, gleam@dict:dict(binary(), one_or_many())} | {error, binary()}. parse(Input, Config) -> gleam@result:then( qs:split_and_parse(Input, erlang:element(2, Config)), fun(Key_values) -> _pipe = gleam@list:fold( Key_values, empty(), fun(Query, Key_value) -> add_key_value(erlang:element(3, Config), Query, Key_value) end ), {ok, _pipe} end ). -spec default_parse(binary()) -> {ok, gleam@dict:dict(binary(), one_or_many())} | {error, binary()}. default_parse(Qs) -> parse(Qs, default_config()). -spec get(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, one_or_many()} | {error, binary()}. get(Query, Key) -> qs:get(Query, Key). -spec get_as_string(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, binary()} | {error, binary()}. get_as_string(Query, Key) -> gleam@result:then(get(Query, Key), fun(One_or_many) -> case One_or_many of {one, Value} -> {ok, Value}; {many, _} -> {error, begin _pipe = Key, gleam@string:append(_pipe, <<" is a list"/utf8>>) end} end end). -spec get_as_int(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, integer()} | {error, binary()}. get_as_int(Query, Key) -> gleam@result:then(get_as_string(Query, Key), fun(Value) -> _pipe = Value, _pipe@1 = gleam@int:parse(_pipe), gleam@result:replace_error( _pipe@1, begin _pipe@2 = <<"Invalid Int "/utf8>>, gleam@string:append(_pipe@2, Value) end ) end). -spec get_as_float(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, float()} | {error, binary()}. get_as_float(Query, Key) -> gleam@result:then(get_as_string(Query, Key), fun(Value) -> _pipe = Value, _pipe@1 = gleam@float:parse(_pipe), gleam@result:replace_error( _pipe@1, begin _pipe@2 = <<"Invalid Float "/utf8>>, gleam@string:append(_pipe@2, Value) end ) end). -spec has_key(gleam@dict:dict(binary(), one_or_many()), binary()) -> boolean(). has_key(Query, Key) -> qs:has_key(Query, Key). -spec insert(gleam@dict:dict(binary(), one_or_many()), binary(), one_or_many()) -> gleam@dict:dict(binary(), one_or_many()). insert(Query, Key, Value) -> qs:insert(Query, Key, Value). -spec insert_one(gleam@dict:dict(binary(), one_or_many()), binary(), binary()) -> gleam@dict:dict(binary(), one_or_many()). insert_one(Query, Key, Value) -> insert(Query, Key, {one, Value}). -spec insert_list( gleam@dict:dict(binary(), one_or_many()), binary(), list(binary()) ) -> gleam@dict:dict(binary(), one_or_many()). insert_list(Query, Key, Values) -> insert(Query, Key, {many, Values}). -spec merge( gleam@dict:dict(binary(), one_or_many()), gleam@dict:dict(binary(), one_or_many()) ) -> gleam@dict:dict(binary(), one_or_many()). merge(A, B) -> qs:merge(A, B). -spec delete(gleam@dict:dict(binary(), one_or_many()), binary()) -> gleam@dict:dict(binary(), one_or_many()). delete(Query, Key) -> qs:delete(Query, Key). -spec to_list(one_or_many()) -> list(binary()). to_list(One_or_many) -> case One_or_many of {one, Value} -> [Value]; {many, Values} -> Values end. -spec maybe_get_as_list(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, list(binary())} | {error, binary()}. maybe_get_as_list(Query, Key) -> _pipe = get(Query, Key), gleam@result:map(_pipe, fun to_list/1). -spec get_as_list(gleam@dict:dict(binary(), one_or_many()), binary()) -> list(binary()). get_as_list(Query, Key) -> _pipe = maybe_get_as_list(Query, Key), gleam@result:unwrap(_pipe, []). -spec get_as_list_of_int(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, list(integer())} | {error, binary()}. get_as_list_of_int(Query, Key) -> _pipe = get_as_list(Query, Key), _pipe@1 = gleam@list:map(_pipe, fun gleam@int:parse/1), _pipe@2 = gleam@result:all(_pipe@1), gleam@result:replace_error(_pipe@2, <<"Couldn't parse all values"/utf8>>). -spec get_as_list_of_float(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, list(float())} | {error, binary()}. get_as_list_of_float(Query, Key) -> _pipe = get_as_list(Query, Key), _pipe@1 = gleam@list:map(_pipe, fun gleam@float:parse/1), _pipe@2 = gleam@result:all(_pipe@1), gleam@result:replace_error(_pipe@2, <<"Couldn't parse all values"/utf8>>). -spec parse_bool(binary()) -> {ok, boolean()} | {error, binary()}. parse_bool(S) -> case S of <<"true"/utf8>> -> {ok, true}; <<"false"/utf8>> -> {ok, false}; _ -> {error, begin _pipe = <<"Invalid "/utf8>>, gleam@string:append(_pipe, S) end} end. -spec get_as_bool(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, boolean()} | {error, binary()}. get_as_bool(Query, Key) -> _pipe = get_as_string(Query, Key), gleam@result:then(_pipe, fun parse_bool/1). -spec get_as_list_of_bool(gleam@dict:dict(binary(), one_or_many()), binary()) -> {ok, list(boolean())} | {error, binary()}. get_as_list_of_bool(Query, Key) -> _pipe = get_as_list(Query, Key), _pipe@1 = gleam@list:map(_pipe, fun parse_bool/1), gleam@result:all(_pipe@1).