-module(sturnidae). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([direction_to_string/1, transaction_status_to_string/1, string_to_transaction_status/1, decode_feed_item/1, get_feed_items_response/1, get_feed_items_request/4]). -export_type([starling_api_error/0, direction/0, currency_and_amount/0, transaction_status/0, feed_item/0]). -type starling_api_error() :: {starling_client_error, integer(), list(binary())} | {starling_server_error, integer(), binary()}. -type direction() :: in | out. -type currency_and_amount() :: {currency_and_amount, binary(), integer()}. -type transaction_status() :: upcoming | pending | reversed | settled | declined | refunded | retrying | account_check. -type feed_item() :: {feed_item, binary(), binary(), currency_and_amount(), currency_and_amount(), binary(), direction(), binary(), binary(), transaction_status(), gleam@option:option(binary()), gleam@option:option(binary()), binary(), gleam@option:option(integer()), gleam@option:option(currency_and_amount()), gleam@option:option(binary()), binary(), binary(), gleam@option:option(binary())}. -spec direction_to_string(direction()) -> binary(). direction_to_string(Direction) -> case Direction of in -> <<"IN"/utf8>>; out -> <<"OUT"/utf8>> end. -spec transaction_status_to_string(transaction_status()) -> binary(). transaction_status_to_string(Status) -> case Status of upcoming -> <<"UPCOMING"/utf8>>; pending -> <<"PENDING"/utf8>>; reversed -> <<"REVERSED"/utf8>>; settled -> <<"SETTLED"/utf8>>; declined -> <<"DECLINED"/utf8>>; refunded -> <<"REFUNDED"/utf8>>; retrying -> <<"RETRYING"/utf8>>; account_check -> <<"ACCOUNT_CHECK"/utf8>> end. -spec string_to_transaction_status(binary()) -> {ok, transaction_status()} | {error, nil}. string_to_transaction_status(Status) -> case Status of <<"UPCOMING"/utf8>> -> {ok, upcoming}; <<"PENDING"/utf8>> -> {ok, pending}; <<"REVERSED"/utf8>> -> {ok, reversed}; <<"SETTLED"/utf8>> -> {ok, settled}; <<"DECLINED"/utf8>> -> {ok, declined}; <<"REFUNDED"/utf8>> -> {ok, refunded}; <<"RETRYING"/utf8>> -> {ok, retrying}; <<"ACCOUNT_CHECK"/utf8>> -> {ok, account_check}; _ -> {error, nil} end. -spec decode_currency_and_amount(gleam@dynamic:dynamic_()) -> {ok, currency_and_amount()} | {error, list(gleam@dynamic:decode_error())}. decode_currency_and_amount(D) -> gleam@result:'try'( (gleam@dynamic:field(<<"currency"/utf8>>, fun gleam@dynamic:string/1))( D ), fun(Currency) -> gleam@result:'try'( (gleam@dynamic:field( <<"minorUnits"/utf8>>, fun gleam@dynamic:int/1 ))(D), fun(Minor_units) -> {ok, {currency_and_amount, Currency, Minor_units}} end ) end ). -spec decode_direction(gleam@dynamic:dynamic_()) -> {ok, direction()} | {error, list(gleam@dynamic:decode_error())}. decode_direction(D) -> gleam@result:'try'( gleam@dynamic:string(D), fun(Direction) -> case Direction of <<"IN"/utf8>> -> {ok, in}; <<"OUT"/utf8>> -> {ok, out}; _ -> {error, [{decode_error, <<"Direction"/utf8>>, <<"String"/utf8>>, []}]} end end ). -spec decode_transaction_status(gleam@dynamic:dynamic_()) -> {ok, transaction_status()} | {error, list(gleam@dynamic:decode_error())}. decode_transaction_status(D) -> gleam@result:'try'(gleam@dynamic:string(D), fun(Status) -> case Status of <<"UPCOMING"/utf8>> -> {ok, upcoming}; <<"PENDING"/utf8>> -> {ok, pending}; <<"REVERSED"/utf8>> -> {ok, reversed}; <<"SETTLED"/utf8>> -> {ok, settled}; <<"DECLINED"/utf8>> -> {ok, declined}; <<"REFUNDED"/utf8>> -> {ok, refunded}; <<"RETRYING"/utf8>> -> {ok, retrying}; <<"ACCOUNT_CHECK"/utf8>> -> {ok, account_check}; _ -> {error, [{decode_error, <<"TransactionStatus"/utf8>>, <<"String"/utf8>>, []}]} end end). -spec decode_feed_item(gleam@dynamic:dynamic_()) -> {ok, feed_item()} | {error, list(gleam@dynamic:decode_error())}. decode_feed_item(D) -> String_field = fun(Field) -> (gleam@dynamic:field(Field, fun gleam@dynamic:string/1))(D) end, gleam@result:'try'( String_field(<<"feedItemUid"/utf8>>), fun(Feed_item_uid) -> gleam@result:'try'( String_field(<<"categoryUid"/utf8>>), fun(Category_uid) -> gleam@result:'try'( (gleam@dynamic:field( <<"amount"/utf8>>, fun decode_currency_and_amount/1 ))(D), fun(Amount) -> gleam@result:'try'( (gleam@dynamic:field( <<"sourceAmount"/utf8>>, fun decode_currency_and_amount/1 ))(D), fun(Source_amount) -> gleam@result:'try'( String_field(<<"updatedAt"/utf8>>), fun(Updated_at) -> gleam@result:'try'( (gleam@dynamic:field( <<"direction"/utf8>>, fun decode_direction/1 ))(D), fun(Direction) -> gleam@result:'try'( String_field( <<"transactionTime"/utf8>> ), fun(Transaction_time) -> gleam@result:'try'( String_field( <<"source"/utf8>> ), fun(Source) -> gleam@result:'try'( (gleam@dynamic:field( <<"status"/utf8>>, fun decode_transaction_status/1 ))(D), fun( Status ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"counterPartyType"/utf8>>, fun gleam@dynamic:string/1 ))( D ), fun( Counter_party_type ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"counterPartyUid"/utf8>>, fun gleam@dynamic:string/1 ))( D ), fun( Counter_party_uid ) -> gleam@result:'try'( String_field( <<"counterPartyName"/utf8>> ), fun( Counter_party_name ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"totalFees"/utf8>>, fun gleam@dynamic:int/1 ))( D ), fun( Total_fees ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"totalFeeAmount"/utf8>>, fun decode_currency_and_amount/1 ))( D ), fun( Total_fee_amount ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"reference"/utf8>>, fun gleam@dynamic:string/1 ))( D ), fun( Reference ) -> gleam@result:'try'( String_field( <<"country"/utf8>> ), fun( Country ) -> gleam@result:'try'( String_field( <<"spendingCategory"/utf8>> ), fun( Spending_category ) -> gleam@result:'try'( (gleam@dynamic:optional_field( <<"userNote"/utf8>>, fun gleam@dynamic:string/1 ))( D ), fun( User_note ) -> {ok, {feed_item, Feed_item_uid, Category_uid, Amount, Source_amount, Updated_at, Direction, Transaction_time, Source, Status, Counter_party_type, Counter_party_uid, Counter_party_name, Total_fees, Total_fee_amount, Reference, Country, Spending_category, User_note}} end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -spec check_status(gleam@http@response:response(binary())) -> {ok, nil} | {error, starling_api_error()}. check_status(Response) -> Status = erlang:element(2, Response), case nil of _ when (Status >= 200) andalso (Status < 300) -> {ok, nil}; _ when (Status >= 400) andalso (Status < 500) -> Messages = [], {error, {starling_client_error, Status, Messages}}; _ -> {error, {starling_server_error, Status, erlang:element(4, Response)}} end. -spec decode_json_body( gleam@http@response:response(binary()), fun((gleam@dynamic:dynamic_()) -> {ok, GUJ} | {error, list(gleam@dynamic:decode_error())}) ) -> {ok, GUJ} | {error, starling_api_error()}. decode_json_body(Response, Decoder) -> case gleam@json:decode(erlang:element(4, Response), Decoder) of {ok, Json} -> {ok, Json}; {error, _} -> {error, {starling_server_error, erlang:element(2, Response), <<"Invalid JSON returned by server"/utf8>>}} end. -spec get_feed_items_response(gleam@http@response:response(binary())) -> {ok, list(feed_item())} | {error, starling_api_error()}. get_feed_items_response(Response) -> gleam@result:'try'( check_status(Response), fun(_) -> Decoder = gleam@dynamic:field( <<"feedItems"/utf8>>, gleam@dynamic:list(fun decode_feed_item/1) ), decode_json_body(Response, Decoder) end ). -spec get_feed_items_request(binary(), binary(), binary(), binary()) -> gleam@http@request:request(binary()). get_feed_items_request(Pat, Account, Category, Limit) -> Url = <<<<<<<<"https://api.starlingbank.com/api/v2"/utf8, "/feed/account/"/utf8>>/binary, Account/binary>>/binary, "/category/"/utf8>>/binary, Category/binary>>, Url@1 = <<<>, value => _assert_fail, module => <<"sturnidae"/utf8>>, function => <<"get_feed_items_request"/utf8>>, line => 233}) end, _pipe = Request, _pipe@1 = gleam@http@request:set_header( _pipe, <<"accept"/utf8>>, <<"application/json"/utf8>> ), gleam@http@request:set_header( _pipe@1, <<"authorization"/utf8>>, <<"Bearer "/utf8, Pat/binary>> ).