-module(sunny@api@geocoding). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([location_to_position/1, params/1, set_count/2, set_language/2, get_locations/2, get_first_location/2]). -export_type([language/0, location/0, geocoding_params/0, location_list/0]). -type language() :: english | german | french | spanish | italian | portuguese | russian | turkish | hindi. -type location() :: {location, float(), float(), integer(), binary(), float(), binary(), binary(), integer(), gleam@option:option(integer()), gleam@option:option(list(binary())), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(integer()), gleam@option:option(integer()), gleam@option:option(integer()), gleam@option:option(integer())}. -type geocoding_params() :: {geocoding_params, binary(), integer(), language()}. -type location_list() :: {location_list, gleam@option:option(list(location()))}. -spec location_to_position(location()) -> sunny@position:position(). location_to_position(Location) -> {position, erlang:element(2, Location), erlang:element(3, Location)}. -spec params(binary()) -> geocoding_params(). params(Name) -> {geocoding_params, Name, 10, english}. -spec set_count(geocoding_params(), integer()) -> geocoding_params(). set_count(Params, Count) -> erlang:setelement(3, Params, gleam@int:clamp(Count, 1, 100)). -spec set_language(geocoding_params(), language()) -> geocoding_params(). set_language(Params, Language) -> erlang:setelement(4, Params, Language). -spec language_to_country_code(language()) -> binary(). language_to_country_code(Lang) -> case Lang of english -> <<"en"/utf8>>; german -> <<"de"/utf8>>; french -> <<"fr"/utf8>>; spanish -> <<"es"/utf8>>; italian -> <<"it"/utf8>>; portuguese -> <<"pt"/utf8>>; russian -> <<"ru"/utf8>>; turkish -> <<"tr"/utf8>>; hindi -> <<"hi"/utf8>> end. -spec geocoding_params_to_params_list(geocoding_params()) -> list(sunny@internal@utils:request_parameter()). geocoding_params_to_params_list(Params) -> [{request_parameter, <<"name"/utf8>>, erlang:element(2, Params)}, {request_parameter, <<"count"/utf8>>, gleam@int:to_string(erlang:element(3, Params))}, {request_parameter, <<"language"/utf8>>, begin _pipe = erlang:element(4, Params), language_to_country_code(_pipe) end}, {request_parameter, <<"format"/utf8>>, <<"json"/utf8>>}]. -spec locations_from_json(binary()) -> {ok, list(location())} | {error, sunny@errors:sunny_error()}. locations_from_json(Json_string) -> Geocoding_decoder = gleam@dynamic:decode1( fun(Field@0) -> {location_list, Field@0} end, gleam@dynamic:optional_field( <<"results"/utf8>>, gleam@dynamic:list( sunny@internal@utils:decode18( fun(Field@0, Field@1, Field@2, Field@3, Field@4, Field@5, Field@6, Field@7, Field@8, Field@9, Field@10, Field@11, Field@12, Field@13, Field@14, Field@15, Field@16, Field@17) -> {location, Field@0, Field@1, Field@2, Field@3, Field@4, Field@5, Field@6, Field@7, Field@8, Field@9, Field@10, Field@11, Field@12, Field@13, Field@14, Field@15, Field@16, Field@17} end, gleam@dynamic:field( <<"latitude"/utf8>>, fun gleam@dynamic:float/1 ), gleam@dynamic:field( <<"longitude"/utf8>>, fun gleam@dynamic:float/1 ), gleam@dynamic:field(<<"id"/utf8>>, fun gleam@dynamic:int/1), gleam@dynamic:field( <<"name"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:field( <<"elevation"/utf8>>, fun gleam@dynamic:float/1 ), gleam@dynamic:field( <<"feature_code"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:field( <<"country_code"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:field( <<"country_id"/utf8>>, fun gleam@dynamic:int/1 ), gleam@dynamic:optional_field( <<"population"/utf8>>, fun gleam@dynamic:int/1 ), gleam@dynamic:optional_field( <<"postcodes"/utf8>>, gleam@dynamic:list(fun gleam@dynamic:string/1) ), gleam@dynamic:optional_field( <<"admin1"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:optional_field( <<"admin2"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:optional_field( <<"admin3"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:optional_field( <<"admin4"/utf8>>, fun gleam@dynamic:string/1 ), gleam@dynamic:optional_field( <<"admin1_id"/utf8>>, fun gleam@dynamic:int/1 ), gleam@dynamic:optional_field( <<"admin2_id"/utf8>>, fun gleam@dynamic:int/1 ), gleam@dynamic:optional_field( <<"admin3_id"/utf8>>, fun gleam@dynamic:int/1 ), gleam@dynamic:optional_field( <<"admin4_id"/utf8>>, fun gleam@dynamic:int/1 ) ) ) ) ), _pipe = gleam@json:decode(Json_string, Geocoding_decoder), _pipe@1 = gleam@result:map_error(_pipe, fun(X) -> {decode_error, X} end), _pipe@2 = gleam@result:map( _pipe@1, fun(Locations_maybe) -> case Locations_maybe of {location_list, {some, Locations}} -> {ok, Locations}; _ -> {error, {api_error, {no_results_error, <<"Geocoding search gave no results"/utf8>>}}} end end ), gleam@result:flatten(_pipe@2). -spec make_request(sunny@internal@client:client(), geocoding_params()) -> {ok, list(location())} | {error, sunny@errors:sunny_error()}. make_request(Client, Params) -> Params@1 = case erlang:element(3, Params) of C when (C > 100) orelse (C < 1) -> set_count(Params, C); _ -> Params end, case begin _pipe@1 = sunny@internal@utils:get_final_url( erlang:element(2, Client), <<"geocoding"/utf8>>, erlang:element(3, Client), <<"/search"/utf8>>, erlang:element(4, Client), begin _pipe = Params@1, geocoding_params_to_params_list(_pipe) end ), sunny@internal@utils:make_request(_pipe@1) end of {ok, Body} -> locations_from_json(Body); {error, Err} -> {error, {http_error, Err}} end. -spec get_locations(sunny@internal@client:client(), geocoding_params()) -> {ok, list(location())} | {error, sunny@errors:sunny_error()}. get_locations(Client, Params) -> make_request(Client, Params). -spec get_first_location(sunny@internal@client:client(), geocoding_params()) -> {ok, location()} | {error, sunny@errors:sunny_error()}. get_first_location(Client, Params) -> gleam@result:'try'( get_locations(Client, set_count(Params, 1)), fun(Locations) -> case Locations of [Head | _] -> {ok, Head}; [] -> {error, {sunny_internal_error, {internal_error, <<"`get_locations` gave empty list instead of error."/utf8>>}}} end end ). -spec decoding_helper( gleam@dict:dict(integer(), NBQ), integer(), list(NBQ), integer() ) -> list(NBQ). decoding_helper(D, N, L, Max) -> case N of N@1 when N@1 >= Max -> L; N@2 -> L@1 = lists:append(L, [case gleam@dict:get(D, N@2) of {ok, V} -> V; {error, _} -> erlang:error(#{gleam_error => panic, message => <<"This shouldn't happen."/utf8>>, module => <<"sunny/api/geocoding"/utf8>>, function => <<"decoding_helper"/utf8>>, line => 265}) end]), decoding_helper(D, N@2 + 1, L@1, Max) end.