From 64f3729d0ca5a56d10b5abf83c751fb247ff4503 Mon Sep 17 00:00:00 2001 From: Lily Rose Date: Tue, 17 Jun 2025 19:04:29 +1000 Subject: [PATCH] Refactoring and general tidying up --- src/endpoints/accounts.gleam | 28 +- src/endpoints/agents.gleam | 52 +- src/endpoints/contracts.gleam | 83 ++- src/endpoints/data.gleam | 17 +- src/endpoints/factions.gleam | 39 +- src/endpoints/fleet.gleam | 561 ++++++++---------- src/endpoints/global.gleam | 34 +- src/endpoints/systems.gleam | 130 ++-- src/models/account.gleam | 24 +- src/models/account_id.gleam | 33 ++ src/models/activity_level.gleam | 34 +- src/models/agent.gleam | 18 +- src/models/agent_event.gleam | 18 +- src/models/agent_event_id.gleam | 33 ++ src/models/agent_symbol.gleam | 31 +- src/models/chart.gleam | 6 +- src/models/chart_transaction.gleam | 6 +- src/models/constellation.gleam | 33 ++ src/models/construction.gleam | 5 +- src/models/contract.gleam | 25 +- src/models/contract_deliver_good.gleam | 13 +- src/models/contract_id.gleam | 33 ++ src/models/contract_terms.gleam | 12 +- src/models/contract_type.gleam | 37 ++ src/models/cooldown.gleam | 10 +- src/models/crew_rotation.gleam | 30 +- src/models/engine_symbol.gleam | 34 +- src/models/faction.gleam | 9 +- src/models/faction_symbol.gleam | 68 ++- src/models/faction_trait_symbol.gleam | 150 ++--- src/models/frame_symbol.gleam | 58 +- src/models/jump_gate.gleam | 7 +- src/models/market.gleam | 13 +- src/models/market_symbol.gleam | 31 +- src/models/market_trade_good.gleam | 6 +- src/models/market_transaction.gleam | 8 +- src/models/meta.gleam | 8 +- src/models/module_symbol.gleam | 66 ++- src/models/mount_deposit.gleam | 54 +- src/models/mount_symbol.gleam | 56 +- src/models/public_agent.gleam | 18 +- src/models/reactor_symbol.gleam | 36 +- src/models/refinement_produce.gleam | 46 +- src/models/repair_transaction.gleam | 6 +- src/models/scanned_ship.gleam | 18 +- src/models/scanned_system.gleam | 7 +- src/models/scrap_transaction.gleam | 6 +- src/models/sector_symbol.gleam | 33 ++ src/models/ship.gleam | 2 +- src/models/ship_component.gleam | 32 +- src/models/ship_component_condition.gleam | 33 +- src/models/ship_component_integrity.gleam | 33 +- src/models/ship_component_quality.gleam | 26 +- src/models/ship_condition_event_symbol.gleam | 83 +-- src/models/ship_crew.gleam | 12 +- src/models/ship_fuel.gleam | 6 +- src/models/ship_fuel_consumed.gleam | 6 +- .../ship_modification_transaction.gleam | 6 +- src/models/ship_module.gleam | 13 +- src/models/ship_mount.gleam | 12 +- src/models/ship_nav_flight_mode.gleam | 36 +- src/models/ship_nav_route.gleam | 10 +- src/models/ship_nav_status.gleam | 34 +- src/models/ship_requirements.gleam | 19 +- src/models/ship_role.gleam | 54 +- src/models/ship_symbol.gleam | 31 +- src/models/ship_type.gleam | 36 +- src/models/shipyard.gleam | 13 +- src/models/shipyard_ship.gleam | 6 +- src/models/shipyard_symbol.gleam | 31 +- src/models/shipyard_transaction.gleam | 6 +- src/models/supply_level.gleam | 36 +- src/models/survey.gleam | 26 +- src/models/survey_deposit.gleam | 8 +- src/models/survey_signature.gleam | 31 +- src/models/survey_size.gleam | 31 +- src/models/system.gleam | 19 +- src/models/system_symbol.gleam | 31 +- src/models/system_type.gleam | 46 +- src/models/system_waypoint.gleam | 9 +- src/models/trade_good_type.gleam | 34 +- src/models/trade_symbol.gleam | 319 +++++----- src/models/transaction_type.gleam | 32 +- src/models/waypoint.gleam | 25 +- src/models/waypoint_modifier_symbol.gleam | 38 +- src/models/waypoint_symbol.gleam | 31 +- src/models/waypoint_trait_symbol.gleam | 166 +++--- src/models/waypoint_type.gleam | 54 +- src/spacetraders_sdk.gleam | 139 ++++- src/utils/{request.gleam => api.gleam} | 107 +++- src/utils/auth.gleam | 26 +- src/utils/decode.gleam | 68 --- src/utils/jwt.gleam | 36 +- src/utils/response.gleam | 29 - src/utils/types.gleam | 28 - 95 files changed, 2362 insertions(+), 1630 deletions(-) create mode 100644 src/models/account_id.gleam create mode 100644 src/models/agent_event_id.gleam create mode 100644 src/models/constellation.gleam create mode 100644 src/models/contract_id.gleam create mode 100644 src/models/contract_type.gleam create mode 100644 src/models/sector_symbol.gleam rename src/utils/{request.gleam => api.gleam} (56%) delete mode 100644 src/utils/decode.gleam delete mode 100644 src/utils/response.gleam delete mode 100644 src/utils/types.gleam diff --git a/src/endpoints/accounts.gleam b/src/endpoints/accounts.gleam index df58383..4d722b5 100644 --- a/src/endpoints/accounts.gleam +++ b/src/endpoints/accounts.gleam @@ -7,10 +7,8 @@ import models/contract.{type Contract} import models/faction.{type Faction} import models/faction_symbol.{type FactionSymbol} import models/ship.{type Ship} +import utils/api.{type ApiResponse} import utils/auth.{type AccountToken, type AgentToken, AccountAuth, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse} pub type GetAccountResponse { GetAccountResponse(account: Account) @@ -22,12 +20,11 @@ fn get_account_response_decoder() -> Decoder(GetAccountResponse) { } pub fn get_account(token: AgentToken) -> ApiResponse(GetAccountResponse) { - let request = request_utils.get(AgentAuth(token), "/my/account") - use response <- request_utils.try_send(request) + let request = api.get(AgentAuth(token), "/my/account") + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_account_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_account_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -62,21 +59,18 @@ pub fn register_new_agent( faction_symbol: FactionSymbol, ) -> ApiResponse(RegisterNewAgentResponse) { let request = - request_utils.post_json( + api.post_json( AccountAuth(token), "/register", json.object([ - #("symbol", json.string(agent_symbol)), - #("faction", json.string(faction_symbol.to_string(faction_symbol))), + #("symbol", agent_symbol.encode(agent_symbol)), + #("faction", faction_symbol.encode(faction_symbol)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - register_new_agent_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, register_new_agent_response_decoder()) + _ -> api.parse_error_response(response) } } diff --git a/src/endpoints/agents.gleam b/src/endpoints/agents.gleam index dab1b81..53f0d9f 100644 --- a/src/endpoints/agents.gleam +++ b/src/endpoints/agents.gleam @@ -1,11 +1,10 @@ import gleam/dynamic/decode.{type Decoder} import models/agent.{type Agent} import models/agent_event.{type AgentEvent} +import models/agent_symbol.{type AgentSymbol} import models/public_agent.{type PublicAgent} +import utils/api.{type ApiResponse, type PagedData} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse, type PagedData} pub type ListPublicAgentsResponse { ListPublicAgentsResponse(agents: List(PublicAgent)) @@ -21,15 +20,15 @@ pub fn list_public_agents( page: Int, limit: Int, ) -> ApiResponse(PagedData(ListPublicAgentsResponse)) { - let request = request_utils.get_page(AgentAuth(token), "/agents", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/agents", page, limit) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, + api.parse_paged_data_response( + response, list_public_agents_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -44,17 +43,18 @@ fn get_public_agent_response_decoder() -> Decoder(GetPublicAgentResponse) { pub fn get_public_agent( token: AgentToken, - agent_symbol: String, + agent_symbol: AgentSymbol, ) -> ApiResponse(GetPublicAgentResponse) { - let request = request_utils.get(AgentAuth(token), "/agents/" <> agent_symbol) - use response <- request_utils.try_send(request) + let request = + api.get( + AgentAuth(token), + "/agents/" <> agent_symbol.to_string(agent_symbol), + ) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - get_public_agent_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, get_public_agent_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -68,12 +68,11 @@ fn get_agent_response_decoder() -> decode.Decoder(GetAgentResponse) { } pub fn get_agent(token: AgentToken) -> ApiResponse(GetAgentResponse) { - let request = request_utils.get(AgentAuth(token), "/my/account") - use response <- request_utils.try_send(request) + let request = api.get(AgentAuth(token), "/my/agent") + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_agent_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_agent_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -89,14 +88,11 @@ fn get_agent_events_response_decoder() -> Decoder(GetAgentEventsResponse) { pub fn get_agent_events( token: AgentToken, ) -> ApiResponse(GetAgentEventsResponse) { - let request = request_utils.get(AgentAuth(token), "/my/agent/events") - use response <- request_utils.try_send(request) + let request = api.get(AgentAuth(token), "/my/agent/events") + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - get_agent_events_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, get_agent_events_response_decoder()) + _ -> api.parse_error_response(response) } } diff --git a/src/endpoints/contracts.gleam b/src/endpoints/contracts.gleam index 0c62866..e74c0e1 100644 --- a/src/endpoints/contracts.gleam +++ b/src/endpoints/contracts.gleam @@ -1,14 +1,14 @@ +import endpoints/fleet import gleam/dynamic/decode.{type Decoder} import gleam/json import models/agent.{type Agent} import models/contract.{type Contract} +import models/contract_id.{type ContractId} import models/ship_cargo.{type ShipCargo} import models/ship_symbol.{type ShipSymbol} import models/trade_symbol.{type TradeSymbol} +import utils/api.{type ApiResponse, type PagedData} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse, type PagedData} pub type ListContractsResponse { ListContractsResponse(contracts: List(Contract)) @@ -24,16 +24,12 @@ pub fn list_contracts( page: Int, limit: Int, ) -> ApiResponse(PagedData(ListContractsResponse)) { - let request = - request_utils.get_page(AgentAuth(token), "/my/contracts", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/my/contracts", page, limit) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, - list_contracts_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_paged_data_response(response, list_contracts_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -48,15 +44,17 @@ fn get_contract_response_decoder() -> Decoder(GetContractResponse) { pub fn get_contract( token: AgentToken, - contract_id: String, + contract_id: ContractId, ) -> ApiResponse(GetContractResponse) { let request = - request_utils.get(AgentAuth(token), "/my/contracts/" <> contract_id) - use response <- request_utils.try_send(request) + api.get( + AgentAuth(token), + "/my/contracts/" <> contract_id.to_string(contract_id), + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_contract_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_contract_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -72,21 +70,17 @@ fn accept_contract_response_decoder() -> Decoder(AcceptContractResponse) { pub fn accept_contract( token: AgentToken, - contract_id: String, + contract_id: ContractId, ) -> ApiResponse(AcceptContractResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/contracts/" <> contract_id <> "/accept", + "/my/contracts/" <> contract_id.to_string(contract_id) <> "/accept", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - accept_contract_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, accept_contract_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -102,21 +96,18 @@ fn fulfill_contract_response_decoder() -> Decoder(FulfillContractResponse) { pub fn fulfill_contract( token: AgentToken, - contract_id, + contract_id: ContractId, ) -> ApiResponse(FulfillContractResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/contracts/" <> contract_id <> "/fulfill", + "/my/contracts/" <> contract_id.to_string(contract_id) <> "/fulfill", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - fulfill_contract_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, fulfill_contract_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -134,28 +125,30 @@ fn deliver_contract_cargo_response_decoder() -> Decoder( pub fn deliver_contract_cargo( token: AgentToken, - contract_id: String, + contract_id: ContractId, ship_symbol: ShipSymbol, trade_symbol: TradeSymbol, units: Int, ) -> ApiResponse(DeliverContractCargoResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/contracts/" <> contract_id <> "/deliver", + "/my/contracts/" <> contract_id.to_string(contract_id) <> "/deliver", json.object([ - #("shipSymbol", json.string(ship_symbol)), - #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("shipSymbol", ship_symbol.encode(ship_symbol)), + #("tradeSymbol", trade_symbol.encode(trade_symbol)), #("units", json.int(units)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, + api.parse_data_response( + response, deliver_contract_cargo_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } + +pub const negotiate_contract = fleet.negotiate_contract diff --git a/src/endpoints/data.gleam b/src/endpoints/data.gleam index 5d245a7..27b1621 100644 --- a/src/endpoints/data.gleam +++ b/src/endpoints/data.gleam @@ -5,10 +5,8 @@ import gleam/http/request import gleam/option import gleam/otp/actor import stratus +import utils/api.{type ApiResponse} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse} pub type GetSupplyChainResponse { GetSupplyChainResponse(export_to_import_map: Dict(String, String)) @@ -25,15 +23,12 @@ fn get_supply_chain_response_decoder() -> Decoder(GetSupplyChainResponse) { pub fn get_supply_chain( token: AgentToken, ) -> ApiResponse(GetSupplyChainResponse) { - let request = request_utils.get(AgentAuth(token), "/market/supply-chain") - use response <- request_utils.try_send(request) + let request = api.get(AgentAuth(token), "/market/supply-chain") + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - get_supply_chain_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, get_supply_chain_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -45,7 +40,7 @@ pub fn get_departure_events( on_close: fn(state) -> Nil, ) -> Result(Subject(stratus.InternalMessage(user)), actor.StartError) { stratus.websocket( - request: request_utils.get(AgentAuth(token), "/my/socket.io") + request: api.get(AgentAuth(token), "/my/socket.io") |> request.set_body(""), init: fn() { #(initial_state, option.None) }, loop: fn(msg, state, conn) { diff --git a/src/endpoints/factions.gleam b/src/endpoints/factions.gleam index 6f51d92..6a48fa7 100644 --- a/src/endpoints/factions.gleam +++ b/src/endpoints/factions.gleam @@ -1,10 +1,8 @@ import gleam/dynamic/decode.{type Decoder} import models/faction.{type Faction} import models/faction_symbol.{type FactionSymbol} +import utils/api.{type ApiResponse, type PagedData} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse, type PagedData} pub type ListFactionsResponse { ListFactionsResponse(factions: List(Faction)) @@ -20,16 +18,12 @@ pub fn list_factions( page: Int, limit: Int, ) -> ApiResponse(PagedData(ListFactionsResponse)) { - let request = - request_utils.get_page(AgentAuth(token), "/factions", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/factions", page, limit) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, - list_factions_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_paged_data_response(response, list_factions_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -47,15 +41,11 @@ pub fn get_faction( symbol: FactionSymbol, ) -> ApiResponse(GetFactionResponse) { let request = - request_utils.get( - AgentAuth(token), - "/factions/" <> faction_symbol.to_string(symbol), - ) - use response <- request_utils.try_send(request) + api.get(AgentAuth(token), "/factions/" <> faction_symbol.to_string(symbol)) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_faction_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_faction_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -85,15 +75,14 @@ pub fn get_my_factions( page: Int, limit: Int, ) -> ApiResponse(PagedData(GetMyFactionsResponse)) { - let request = - request_utils.get_page(AgentAuth(token), "/my/factions", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/my/factions", page, limit) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, + api.parse_paged_data_response( + response, get_my_factions_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } diff --git a/src/endpoints/fleet.gleam b/src/endpoints/fleet.gleam index 0a48033..6feb289 100644 --- a/src/endpoints/fleet.gleam +++ b/src/endpoints/fleet.gleam @@ -35,10 +35,8 @@ import models/trade_symbol.{type TradeSymbol} import models/waypoint.{type Waypoint} import models/waypoint_modifier.{type WaypointModifier} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api.{type ApiResponse, type PagedData} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse, type PagedData} pub type ListShipsResponse { ListShipsResponse(ships: List(Ship)) @@ -54,12 +52,11 @@ pub fn list_ships( page: Int, limit: Int, ) -> ApiResponse(PagedData(ListShipsResponse)) { - let request = - request_utils.get_page(AgentAuth(token), "/my/ships", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/my/ships", page, limit) + use response <- api.try_send(request) case response.status { - 200 -> response_utils.paged_data_parser(response.body, list_ships_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_paged_data_response(response, list_ships_decoder()) + _ -> api.parse_error_response(response) } } @@ -84,18 +81,18 @@ pub fn purchase_ship( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(PurchaseShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), "/my/ships", json.object([ - #("shipType", json.string(ship_type.to_string(ship_type))), - #("waypointSymbol", json.string(waypoint_symbol)), + #("shipType", ship_type.encode(ship_type)), + #("waypointSymbol", waypoint_symbol.encode(waypoint_symbol)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> response_utils.data_parser(response.body, purchase_ship_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, purchase_ship_decoder()) + _ -> api.parse_error_response(response) } } @@ -112,11 +109,15 @@ pub fn get_ship( token: AgentToken, ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipResponse) { - let request = request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol) - use response <- request_utils.try_send(request) + let request = + api.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol.to_string(ship_symbol), + ) + use response <- api.try_send(request) case response.status { - 200 -> response_utils.data_parser(response.body, get_ship_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_ship_decoder()) + _ -> api.parse_error_response(response) } } @@ -142,15 +143,14 @@ pub fn create_chart( ship_symbol: ShipSymbol, ) -> ApiResponse(CreateChartResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/chart", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/chart", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser(response.body, create_chart_response_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, create_chart_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -168,18 +168,15 @@ pub fn negotiate_contract( ship_symbol: String, ) -> ApiResponse(NegotiateContractResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), "/my/ships/" <> ship_symbol <> "/negotiate/contract", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - negotiate_contract_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, negotiate_contract_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -189,7 +186,8 @@ pub type GetShipCooldownResponse { fn get_ship_cooldown_response_decoder() -> Decoder(GetShipCooldownResponse) { use cooldown <- decode.field("cooldown", cooldown.decoder()) - decode.success(GetShipCooldownResponse(cooldown: option.Some(cooldown))) + let cooldown = option.Some(cooldown) + decode.success(GetShipCooldownResponse(cooldown:)) } pub fn get_ship_cooldown( @@ -197,19 +195,16 @@ pub fn get_ship_cooldown( ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipCooldownResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/cooldown", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/cooldown", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - get_ship_cooldown_response_decoder(), - ) + api.parse_data_response(response, get_ship_cooldown_response_decoder()) 204 -> Ok(GetShipCooldownResponse(option.None)) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -227,12 +222,14 @@ pub fn dock_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(DockShipResponse) { let request = - request_utils.post(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/dock") - use response <- request_utils.try_send(request) + api.post( + AgentAuth(token), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/dock", + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, dock_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, dock_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -272,18 +269,15 @@ pub fn extract_resources( ship_symbol: ShipSymbol, ) -> ApiResponse(ExtractResourcesResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/extract", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/extract", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - extract_resources_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, extract_resources_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -326,19 +320,19 @@ pub fn extract_resources_with_survey( survey: Survey, ) -> ApiResponse(ExtractResourcesWithSurveyResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/extract/survey", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/extract/survey", survey.encode(survey), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, + api.parse_data_response( + response, extract_resources_with_survey_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -358,22 +352,18 @@ pub fn jettison_cargo( units: Int, ) -> ApiResponse(JettisonCargoResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/jettison", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/jettison", json.object([ - #("symbol", json.string(trade_symbol.to_string(trade_symbol))), + #("symbol", trade_symbol.encode(trade_symbol)), #("units", json.int(units)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - jettison_cargo_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, jettison_cargo_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -400,103 +390,96 @@ pub fn jump_ship( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(JumpShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/jump", - json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/jump", + json.object([#("waypointSymbol", waypoint_symbol.encode(waypoint_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, jump_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, jump_ship_response_decoder()) + _ -> api.parse_error_response(response) } } -pub type SystemScanResponse { - SystemScanResponse(cooldown: Cooldown, systems: List(ScannedSystem)) +pub type ScanSystemsResponse { + ScanSystemsResponse(cooldown: Cooldown, systems: List(ScannedSystem)) } -fn system_scan_response_decoder() -> Decoder(SystemScanResponse) { +fn scan_systems_response_decoder() -> Decoder(ScanSystemsResponse) { use cooldown <- decode.field("cooldown", cooldown.decoder()) use systems <- decode.field("systems", decode.list(scanned_system.decoder())) - decode.success(SystemScanResponse(cooldown:, systems:)) + decode.success(ScanSystemsResponse(cooldown:, systems:)) } -pub fn system_scan( +pub fn scan_systems( token: AgentToken, ship_symbol: ShipSymbol, -) -> ApiResponse(SystemScanResponse) { +) -> ApiResponse(ScanSystemsResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/scan/systems", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/scan/systems", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser(response.body, system_scan_response_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, scan_systems_response_decoder()) + _ -> api.parse_error_response(response) } } -pub type WaypointScanResponse { - WaypointScanResponse(cooldown: Cooldown, waypoints: List(ScannedWaypoint)) +pub type ScanWaypointsResponse { + ScanWaypointsResponse(cooldown: Cooldown, waypoints: List(ScannedWaypoint)) } -fn waypoint_scan_response_decoder() -> Decoder(WaypointScanResponse) { +fn scan_waypoints_response_decoder() -> Decoder(ScanWaypointsResponse) { use cooldown <- decode.field("cooldown", cooldown.decoder()) use waypoints <- decode.field( "waypoints", decode.list(scanned_waypoint.decoder()), ) - decode.success(WaypointScanResponse(cooldown:, waypoints:)) + decode.success(ScanWaypointsResponse(cooldown:, waypoints:)) } -pub fn waypoint_scan( +pub fn scan_waypoints( token: AgentToken, ship_symbol: ShipSymbol, -) -> ApiResponse(WaypointScanResponse) { +) -> ApiResponse(ScanWaypointsResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/scan/waypoints", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/scan/waypoints", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser( - response.body, - waypoint_scan_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, scan_waypoints_response_decoder()) + _ -> api.parse_error_response(response) } } -pub type ShipScanResponse { - ShipScanResponse(cooldown: Cooldown, ships: List(ScannedShip)) +pub type ScanShipsResponse { + ScanShipsResponse(cooldown: Cooldown, ships: List(ScannedShip)) } -fn ship_scan_response_decoder() -> Decoder(ShipScanResponse) { +fn scan_ships_response_decoder() -> Decoder(ScanShipsResponse) { use cooldown <- decode.field("cooldown", cooldown.decoder()) use ships <- decode.field("ships", decode.list(scanned_ship.decoder())) - decode.success(ShipScanResponse(cooldown:, ships:)) + decode.success(ScanShipsResponse(cooldown:, ships:)) } pub fn scan_ships( token: AgentToken, ship_symbol: ShipSymbol, -) -> ApiResponse(ShipScanResponse) { +) -> ApiResponse(ScanShipsResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/scan/ships", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/scan/ships", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser(response.body, ship_scan_response_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, scan_ships_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -515,15 +498,14 @@ pub fn scrap_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(ScrapShipResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/scrap", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/scrap", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, scrap_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, scrap_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -541,15 +523,14 @@ pub fn get_scrap_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(GetScrapShipResponse) { let request = - request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/scrap") - use response <- request_utils.try_send(request) + api.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/scrap", + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - get_scrap_ship_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_scrap_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -577,19 +558,15 @@ pub fn navigate_ship( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(NavigateShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/navigate", - json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/navigate", + json.object([#("waypointSymbol", waypoint_symbol.encode(waypoint_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - navigate_ship_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, navigate_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -617,16 +594,15 @@ pub fn warp_ship( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(WarpShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/warp", - json.object([#("waypointSymbol", json.string(waypoint_symbol))]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/warp", + json.object([#("waypointSymbol", waypoint_symbol.encode(waypoint_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, warp_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, warp_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -644,15 +620,14 @@ pub fn orbit_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(OrbitShipResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/orbit", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/orbit", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, orbit_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, orbit_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -677,26 +652,20 @@ pub fn purchase_cargo( trade_symbol: TradeSymbol, ) -> ApiResponse(PurchaseCargoResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/purchase", - json.object([ - #("symbol", json.string(trade_symbol.to_string(trade_symbol))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/purchase", + json.object([#("symbol", trade_symbol.encode(trade_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser( - response.body, - purchase_cargo_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, purchase_cargo_response_decoder()) + _ -> api.parse_error_response(response) } } -pub type ShipRefineResponse { - ShipRefineResponse( +pub type RefineShipResponse { + RefineShipResponse( cargo: ShipCargo, cooldown: Cooldown, produced: List(RefinementYield), @@ -704,7 +673,7 @@ pub type ShipRefineResponse { ) } -fn ship_refine_response_decoder() -> Decoder(ShipRefineResponse) { +fn refine_ship_response_decoder() -> Decoder(RefineShipResponse) { use cargo <- decode.field("cargo", ship_cargo.decoder()) use cooldown <- decode.field("cooldown", cooldown.decoder()) use produced <- decode.field( @@ -715,27 +684,24 @@ fn ship_refine_response_decoder() -> Decoder(ShipRefineResponse) { "consumed", decode.list(refinement_yield.decoder()), ) - decode.success(ShipRefineResponse(cargo:, cooldown:, produced:, consumed:)) + decode.success(RefineShipResponse(cargo:, cooldown:, produced:, consumed:)) } -pub fn ship_refine( +pub fn refine_ship( token: AgentToken, ship_symbol: ShipSymbol, produce: RefinementProduce, -) -> ApiResponse(ShipRefineResponse) { +) -> ApiResponse(RefineShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/refine", - json.object([ - #("produce", json.string(refinement_produce.to_string(produce))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/refine", + json.object([#("produce", refinement_produce.encode(produce))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser(response.body, ship_refine_response_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, refine_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -763,19 +729,18 @@ pub fn refuel_ship( from_cargo: Option(Bool), ) -> ApiResponse(RefuelShipResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/refuel", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/refuel", json.object([ #("units", json.nullable(units, json.int)), #("fromCargo", json.nullable(from_cargo, json.bool)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, refuel_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, refuel_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -795,15 +760,14 @@ pub fn repair_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(RepairShipResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/repair", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/repair", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, repair_ship_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, repair_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -821,18 +785,14 @@ pub fn get_repair_ship( ship_symbol: ShipSymbol, ) -> ApiResponse(GetRepairShipResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/repair", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/repair", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - get_repair_ship_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_repair_ship_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -858,19 +818,18 @@ pub fn sell_cargo( units: Int, ) -> ApiResponse(SellCargoResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/sell", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/sell", json.object([ - #("symbol", json.string(trade_symbol.to_string(trade_symbol))), + #("symbol", trade_symbol.encode(trade_symbol)), #("units", json.int(units)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser(response.body, sell_cargo_response_decoder()) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, sell_cargo_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -899,18 +858,15 @@ pub fn siphon_resources( ship_symbol: ShipSymbol, ) -> ApiResponse(SiphonResourcesResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/siphon", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/siphon", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - siphon_resources_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, siphon_resources_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -929,18 +885,14 @@ pub fn create_survey( ship_symbol: ShipSymbol, ) -> ApiResponse(CreateSurveyResponse) { let request = - request_utils.post( + api.post( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/survey", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/survey", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 201 -> - response_utils.data_parser( - response.body, - create_survey_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 201 -> api.parse_data_response(response, create_survey_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -962,23 +914,19 @@ pub fn transfer_cargo( target_ship_symbol: ShipSymbol, ) -> ApiResponse(TransferCargoResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/transfer", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/transfer", json.object([ - #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("tradeSymbol", trade_symbol.encode(trade_symbol)), #("units", json.int(units)), - #("shipSymbol", json.string(target_ship_symbol)), + #("shipSymbol", ship_symbol.encode(target_ship_symbol)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - transfer_cargo_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, transfer_cargo_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -991,20 +939,19 @@ pub fn get_ship_cargo_response_decoder() -> Decoder(GetShipCargoResponse) { decode.success(GetShipCargoResponse(cargo:)) } -pub fn get_my_ship_cargo( +pub fn get_ship_cargo( token: AgentToken, ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipCargoResponse) { let request = - request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/cargo") - use response <- request_utils.try_send(request) + api.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/cargo", + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - get_ship_cargo_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_ship_cargo_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1022,18 +969,15 @@ pub fn get_ship_modules( ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipModulesResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/modules", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/modules", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, - get_ship_modules_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, get_ship_modules_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1070,21 +1014,16 @@ pub fn install_ship_module( module_symbol: ModuleSymbol, ) -> ApiResponse(InstallShipModuleResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/modules/install", - json.object([ - #("symbol", json.string(module_symbol.to_string(module_symbol))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/modules/install", + json.object([#("symbol", module_symbol.encode(module_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - install_ship_module_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, install_ship_module_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1121,21 +1060,16 @@ pub fn remove_ship_module( module_symbol: ModuleSymbol, ) -> ApiResponse(RemoveShipModuleResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/modules/remove", - json.object([ - #("symbol", json.string(module_symbol.to_string(module_symbol))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/modules/remove", + json.object([#("symbol", module_symbol.encode(module_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - remove_ship_module_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, remove_ship_module_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1153,18 +1087,14 @@ pub fn get_ship_mounts( ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipMountsResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/mounts", + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/mounts", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - get_ship_mounts_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_ship_mounts_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1196,21 +1126,16 @@ pub fn install_ship_mount( mount_symbol: MountSymbol, ) -> ApiResponse(InstallShipMountResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/mounts/install", - json.object([ - #("symbol", json.string(mount_symbol.to_string(mount_symbol))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/mounts/install", + json.object([#("symbol", mount_symbol.encode(mount_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - install_ship_mount_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, install_ship_mount_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1240,21 +1165,16 @@ pub fn remove_ship_mount( mount_symbol: MountSymbol, ) -> ApiResponse(RemoveShipMountResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/mounts/remove", - json.object([ - #("symbol", json.string(mount_symbol.to_string(mount_symbol))), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/mounts/remove", + json.object([#("symbol", mount_symbol.encode(mount_symbol))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, - remove_ship_mount_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_data_response(response, remove_ship_mount_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1272,12 +1192,14 @@ pub fn get_ship_nav( ship_symbol: ShipSymbol, ) -> ApiResponse(GetShipNavResponse) { let request = - request_utils.get(AgentAuth(token), "/my/ships/" <> ship_symbol <> "/nav") - use response <- request_utils.try_send(request) + api.get( + AgentAuth(token), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/nav", + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_ship_nav_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_ship_nav_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -1305,23 +1227,14 @@ pub fn patch_ship_nav( flight_mode: ShipNavFlightMode, ) -> ApiResponse(PatchShipNavResponse) { let request = - request_utils.patch_json( + api.patch_json( AgentAuth(token), - "/my/ships/" <> ship_symbol <> "/nav", - json.object([ - #( - "flightMode", - json.string(ship_nav_flight_mode.to_string(flight_mode)), - ), - ]), + "/my/ships/" <> ship_symbol.to_string(ship_symbol) <> "/nav", + json.object([#("flightMode", ship_nav_flight_mode.encode(flight_mode))]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - patch_ship_nav_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, patch_ship_nav_response_decoder()) + _ -> api.parse_error_response(response) } } diff --git a/src/endpoints/global.gleam b/src/endpoints/global.gleam index 5a17d37..840dca2 100644 --- a/src/endpoints/global.gleam +++ b/src/endpoints/global.gleam @@ -1,10 +1,7 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} +import utils/api.{type ApiResponse} import utils/auth.{NoAuth} -import utils/decode as decode_utils -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse} pub type Stats { Stats( @@ -17,7 +14,11 @@ pub type Stats { } fn stats_decoder() -> Decoder(Stats) { - use accounts <- decode_utils.field_key_value_optional("accounts", decode.int) + use accounts <- decode.optional_field( + "accounts", + option.None, + decode.optional(decode.int), + ) use agents <- decode.field("agents", decode.int) use ships <- decode.field("ships", decode.int) use systems <- decode.field("systems", decode.int) @@ -30,9 +31,10 @@ pub type Health { } fn health_decoder() -> Decoder(Health) { - use last_market_update <- decode_utils.field_key_value_optional( + use last_market_update <- decode.optional_field( "lastMarketUpdate", - decode.string, + option.None, + decode.optional(decode.string), ) decode.success(Health(last_market_update:)) } @@ -150,12 +152,11 @@ fn get_server_status_response_decoder() -> Decoder(GetServerStatusResponse) { } pub fn get_server_status() -> ApiResponse(GetServerStatusResponse) { - let request = request_utils.get(NoAuth, "/") - use response <- request_utils.try_send(request) + let request = api.get(NoAuth, "/") + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.parser(response.body, get_server_status_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_response(response, get_server_status_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -182,11 +183,10 @@ fn list_error_codes_response_decoder() -> Decoder(ListErrorCodesResponse) { } pub fn list_error_codes() -> ApiResponse(ListErrorCodesResponse) { - let request = request_utils.get(NoAuth, "/error-codes") - use response <- request_utils.try_send(request) + let request = api.get(NoAuth, "/error-codes") + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.parser(response.body, list_error_codes_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_response(response, list_error_codes_response_decoder()) + _ -> api.parse_error_response(response) } } diff --git a/src/endpoints/systems.gleam b/src/endpoints/systems.gleam index fe346d4..643f490 100644 --- a/src/endpoints/systems.gleam +++ b/src/endpoints/systems.gleam @@ -15,10 +15,8 @@ import models/waypoint.{type Waypoint} import models/waypoint_symbol.{type WaypointSymbol} import models/waypoint_trait_symbol.{type WaypointTraitSymbol} import models/waypoint_type.{type WaypointType} +import utils/api.{type ApiResponse, type PagedData} import utils/auth.{type AgentToken, AgentAuth} -import utils/request as request_utils -import utils/response as response_utils -import utils/types.{type ApiResponse, type PagedData} pub type ListSystemsResponse { ListSystemsResponse(systems: List(System)) @@ -34,16 +32,12 @@ pub fn list_systems( page: Int, limit: Int, ) -> ApiResponse(PagedData(ListSystemsResponse)) { - let request = - request_utils.get_page(AgentAuth(token), "/systems", page, limit) - use response <- request_utils.try_send(request) + let request = api.get_page(AgentAuth(token), "/systems", page, limit) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, - list_systems_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + api.parse_paged_data_response(response, list_systems_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -61,12 +55,14 @@ pub fn get_system( system_symbol: SystemSymbol, ) -> ApiResponse(GetSystemResponse) { let request = - request_utils.get(AgentAuth(token), "/systems/" <> system_symbol) - use response <- request_utils.try_send(request) + api.get( + AgentAuth(token), + "/systems/" <> system_symbol.to_string(system_symbol), + ) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_system_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_system_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -102,21 +98,21 @@ pub fn list_system_waypoints( option.None -> traits_query } let request = - request_utils.get_page_query( + api.get_page_query( AgentAuth(token), - "/systems/" <> system_symbol <> "/waypoints", + "/systems/" <> system_symbol.to_string(system_symbol) <> "/waypoints", page, limit, query, ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.paged_data_parser( - response.body, + api.parse_paged_data_response( + response, list_system_waypoints_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -135,15 +131,17 @@ pub fn get_waypoint( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(GetWaypointResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), - "/systems/" <> system_symbol <> "/waypoints/" <> waypoint_symbol, + "/systems/" + <> system_symbol.to_string(system_symbol) + <> "/waypoints/" + <> waypoint_symbol.to_string(waypoint_symbol), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_waypoint_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_waypoint_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -164,22 +162,22 @@ pub fn get_construction_site( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(GetConstructionSiteResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), "/systems/" - <> system_symbol + <> system_symbol.to_string(system_symbol) <> "/waypoints/" - <> waypoint_symbol + <> waypoint_symbol.to_string(waypoint_symbol) <> "/construction", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 200 -> - response_utils.data_parser( - response.body, + api.parse_data_response( + response, get_construction_site_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -204,27 +202,27 @@ pub fn supply_construction_site( units: Int, ) -> ApiResponse(SupplyConstructionSiteResponse) { let request = - request_utils.post_json( + api.post_json( AgentAuth(token), "/systems/" - <> system_symbol + <> system_symbol.to_string(system_symbol) <> "/waypoints/" - <> waypoint_symbol + <> waypoint_symbol.to_string(waypoint_symbol) <> "/construction/supply", json.object([ - #("shipSymbol", json.string(ship_symbol)), - #("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))), + #("shipSymbol", ship_symbol.encode(ship_symbol)), + #("tradeSymbol", trade_symbol.encode(trade_symbol)), #("units", json.int(units)), ]), ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { 201 -> - response_utils.data_parser( - response.body, + api.parse_data_response( + response, supply_construction_site_response_decoder(), ) - _ -> response_utils.error_parser(response.body) + _ -> api.parse_error_response(response) } } @@ -243,19 +241,18 @@ pub fn get_market( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(GetMarketResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), "/systems/" - <> system_symbol + <> system_symbol.to_string(system_symbol) <> "/waypoints/" - <> waypoint_symbol + <> waypoint_symbol.to_string(waypoint_symbol) <> "/market", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_market_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_market_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -274,22 +271,18 @@ pub fn get_jump_gate( waypoint_symbol: WaypointSymbol, ) -> ApiResponse(GetJumpGateResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), "/systems/" - <> system_symbol + <> system_symbol.to_string(system_symbol) <> "/waypoints/" - <> waypoint_symbol + <> waypoint_symbol.to_string(waypoint_symbol) <> "/jump-gate", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser( - response.body, - get_jump_gate_response_decoder(), - ) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_jump_gate_response_decoder()) + _ -> api.parse_error_response(response) } } @@ -302,9 +295,13 @@ fn get_shipyard_response_decoder() -> Decoder(GetShipyardResponse) { decode.success(GetShipyardResponse(shipyard:)) } -pub fn get_shipyard(token, system_symbol, waypoint_symbol) { +pub fn get_shipyard( + token, + system_symbol, + waypoint_symbol, +) -> ApiResponse(GetShipyardResponse) { let request = - request_utils.get( + api.get( AgentAuth(token), "/systems/" <> system_symbol @@ -312,10 +309,9 @@ pub fn get_shipyard(token, system_symbol, waypoint_symbol) { <> waypoint_symbol <> "/shipyard", ) - use response <- request_utils.try_send(request) + use response <- api.try_send(request) case response.status { - 200 -> - response_utils.data_parser(response.body, get_shipyard_response_decoder()) - _ -> response_utils.error_parser(response.body) + 200 -> api.parse_data_response(response, get_shipyard_response_decoder()) + _ -> api.parse_error_response(response) } } diff --git a/src/models/account.gleam b/src/models/account.gleam index 2313575..e6aa690 100644 --- a/src/models/account.gleam +++ b/src/models/account.gleam @@ -1,20 +1,30 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} -import utils/decode as decode_utils +import models/account_id.{type AccountId} +import utils/api pub type Account { Account( - id: String, + id: AccountId, email: Option(String), token: Option(String), - created_at: String, + created_at: Time, ) } pub fn decoder() -> Decoder(Account) { - use id <- decode.field("id", decode.string) - use email <- decode_utils.field_value_optional("email", decode.string) - use token <- decode_utils.field_key_value_optional("token", decode.string) - use created_at <- decode.field("createdAt", decode.string) + use id <- decode.field("id", account_id.decoder()) + use email <- decode.optional_field( + "email", + option.None, + decode.optional(decode.string), + ) + use token <- decode.optional_field( + "token", + option.None, + decode.optional(decode.string), + ) + use created_at <- decode.field("createdAt", api.time_decoder()) decode.success(Account(id:, email:, token:, created_at:)) } diff --git a/src/models/account_id.gleam b/src/models/account_id.gleam new file mode 100644 index 0000000..94f6dfb --- /dev/null +++ b/src/models/account_id.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string + +pub opaque type AccountId { + AccountId(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(AccountId, Nil) { + case string.length(value) >= min_length { + True -> Ok(AccountId(value)) + False -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(AccountId) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(account_id) -> decode.success(account_id) + Error(Nil) -> decode.failure(AccountId("invalid"), "AccountId") + } +} + +pub fn to_string(account_id: AccountId) -> String { + let AccountId(symbol) = account_id + symbol +} + +pub fn encode(account_id: AccountId) -> Json { + json.string(to_string(account_id)) +} diff --git a/src/models/activity_level.gleam b/src/models/activity_level.gleam index 220be75..45481a6 100644 --- a/src/models/activity_level.gleam +++ b/src/models/activity_level.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ActivityLevel { Weak @@ -8,6 +8,24 @@ pub type ActivityLevel { Restricted } +pub fn parse(value: String) -> Result(ActivityLevel, Nil) { + case value { + "WEAK" -> Ok(Weak) + "GROWING" -> Ok(Growing) + "STRONG" -> Ok(Strong) + "RESTRICTED" -> Ok(Restricted) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ActivityLevel) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(activity_level) -> decode.success(activity_level) + Error(Nil) -> decode.failure(Weak, "ActivityLevel") + } +} + pub fn to_string(activity_level: ActivityLevel) -> String { case activity_level { Weak -> "WEAK" @@ -17,16 +35,6 @@ pub fn to_string(activity_level: ActivityLevel) -> String { } } -pub fn parse(activity_level_str: String) -> Result(ActivityLevel, ActivityLevel) { - case activity_level_str { - "WEAK" -> Ok(Weak) - "GROWING" -> Ok(Growing) - "STRONG" -> Ok(Strong) - "RESTRICTED" -> Ok(Restricted) - _ -> Error(Weak) - } -} - -pub fn decoder() -> Decoder(ActivityLevel) { - decode_utils.enum_decoder(parse, "ActivityLevel") +pub fn encode(activity_level: ActivityLevel) -> Json { + json.string(to_string(activity_level)) } diff --git a/src/models/agent.gleam b/src/models/agent.gleam index b145f76..07fc5c1 100644 --- a/src/models/agent.gleam +++ b/src/models/agent.gleam @@ -1,23 +1,29 @@ import gleam/dynamic/decode.{type Decoder} +import models/account_id.{type AccountId} import models/agent_symbol.{type AgentSymbol} +import models/faction_symbol.{type FactionSymbol} +import models/waypoint_symbol.{type WaypointSymbol} pub type Agent { Agent( - account_id: String, + account_id: AccountId, symbol: AgentSymbol, - headquarters: String, + headquarters: WaypointSymbol, credits: Int, - starting_faction: String, + starting_faction: FactionSymbol, ship_count: Int, ) } pub fn decoder() -> Decoder(Agent) { - use account_id <- decode.field("accountId", decode.string) + use account_id <- decode.field("accountId", account_id.decoder()) use symbol <- decode.field("symbol", agent_symbol.decoder()) - use headquarters <- decode.field("headquarters", decode.string) + use headquarters <- decode.field("headquarters", waypoint_symbol.decoder()) use credits <- decode.field("credits", decode.int) - use starting_faction <- decode.field("startingFaction", decode.string) + use starting_faction <- decode.field( + "startingFaction", + faction_symbol.decoder(), + ) use ship_count <- decode.field("shipCount", decode.int) decode.success(Agent( account_id:, diff --git a/src/models/agent_event.gleam b/src/models/agent_event.gleam index 7bc0296..f575900 100644 --- a/src/models/agent_event.gleam +++ b/src/models/agent_event.gleam @@ -1,23 +1,29 @@ +import birl.{type Time} import gleam/dynamic.{type Dynamic} import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} -import utils/decode as decode_utils +import models/agent_event_id.{type AgentEventId} +import utils/api pub type AgentEvent { AgentEvent( - id: String, + id: AgentEventId, type_: String, message: String, data: Option(Dynamic), - created_at: String, + created_at: Time, ) } pub fn decoder() -> Decoder(AgentEvent) { - use id <- decode.field("id", decode.string) + use id <- decode.field("id", agent_event_id.decoder()) use type_ <- decode.field("type", decode.string) use message <- decode.field("message", decode.string) - use data <- decode_utils.field_key_value_optional("data", decode.dynamic) - use created_at <- decode.field("createdAt", decode.string) + use data <- decode.optional_field( + "data", + option.None, + decode.optional(decode.dynamic), + ) + use created_at <- decode.field("createdAt", api.time_decoder()) decode.success(AgentEvent(id:, type_:, message:, data:, created_at:)) } diff --git a/src/models/agent_event_id.gleam b/src/models/agent_event_id.gleam new file mode 100644 index 0000000..1fb391c --- /dev/null +++ b/src/models/agent_event_id.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string + +pub opaque type AgentEventId { + AgentEventId(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(AgentEventId, Nil) { + case string.length(value) >= min_length { + True -> Ok(AgentEventId(value)) + False -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(AgentEventId) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(agent_event_id) -> decode.success(agent_event_id) + Error(Nil) -> decode.failure(AgentEventId("invalid"), "AgentEventId") + } +} + +pub fn to_string(agent_event_id: AgentEventId) -> String { + let AgentEventId(symbol) = agent_event_id + symbol +} + +pub fn encode(agent_event_id: AgentEventId) -> Json { + json.string(to_string(agent_event_id)) +} diff --git a/src/models/agent_symbol.gleam b/src/models/agent_symbol.gleam index f7df3d0..3d5f9d2 100644 --- a/src/models/agent_symbol.gleam +++ b/src/models/agent_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type AgentSymbol = - String +pub opaque type AgentSymbol { + AgentSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(AgentSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(AgentSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(AgentSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(agent_symbol) -> decode.success(agent_symbol) + Error(Nil) -> decode.failure(AgentSymbol("invalid"), "AgentSymbol") + } +} + +pub fn to_string(agent_symbol: AgentSymbol) -> String { + let AgentSymbol(symbol) = agent_symbol + symbol +} + +pub fn encode(agent_symbol: AgentSymbol) -> Json { + json.string(to_string(agent_symbol)) } diff --git a/src/models/chart.gleam b/src/models/chart.gleam index d697249..d7c776c 100644 --- a/src/models/chart.gleam +++ b/src/models/chart.gleam @@ -1,12 +1,14 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/agent_symbol.{type AgentSymbol} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type Chart { Chart( waypoint_symbol: WaypointSymbol, submitted_by: AgentSymbol, - submitted_on: String, + submitted_on: Time, ) } @@ -16,6 +18,6 @@ pub fn decoder() -> Decoder(Chart) { waypoint_symbol.decoder(), ) use submitted_by <- decode.field("submittedBy", agent_symbol.decoder()) - use submitted_on <- decode.field("submittedOn", decode.string) + use submitted_on <- decode.field("submittedOn", api.time_decoder()) decode.success(Chart(waypoint_symbol:, submitted_by:, submitted_on:)) } diff --git a/src/models/chart_transaction.gleam b/src/models/chart_transaction.gleam index 14c98ea..61619d3 100644 --- a/src/models/chart_transaction.gleam +++ b/src/models/chart_transaction.gleam @@ -1,13 +1,15 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_symbol.{type ShipSymbol} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type ChartTransaction { ChartTransaction( waypoint_symbol: WaypointSymbol, ship_symbol: ShipSymbol, total_price: Int, - timestamp: String, + timestamp: Time, ) } @@ -18,7 +20,7 @@ pub fn decoder() -> Decoder(ChartTransaction) { ) use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use total_price <- decode.field("totalPrice", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(ChartTransaction( waypoint_symbol:, ship_symbol:, diff --git a/src/models/constellation.gleam b/src/models/constellation.gleam new file mode 100644 index 0000000..bd60953 --- /dev/null +++ b/src/models/constellation.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string + +pub opaque type Constellation { + Constellation(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(Constellation, Nil) { + case string.length(value) >= min_length { + True -> Ok(Constellation(value)) + False -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(Constellation) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(constellation) -> decode.success(constellation) + Error(Nil) -> decode.failure(Constellation("invalid"), "Constellation") + } +} + +pub fn to_string(constellation: Constellation) -> String { + let Constellation(value) = constellation + value +} + +pub fn encode(constellation: Constellation) -> Json { + json.string(to_string(constellation)) +} diff --git a/src/models/construction.gleam b/src/models/construction.gleam index 5538e06..60aadd0 100644 --- a/src/models/construction.gleam +++ b/src/models/construction.gleam @@ -1,16 +1,17 @@ import gleam/dynamic/decode.{type Decoder} import models/construction_material.{type ConstructionMaterial} +import models/waypoint_symbol.{type WaypointSymbol} pub type Construction { Construction( - symbol: String, + symbol: WaypointSymbol, materials: List(ConstructionMaterial), is_complete: Bool, ) } pub fn decoder() -> Decoder(Construction) { - use symbol <- decode.field("symbol", decode.string) + use symbol <- decode.field("symbol", waypoint_symbol.decoder()) use materials <- decode.field( "materials", decode.list(construction_material.decoder()), diff --git a/src/models/contract.gleam b/src/models/contract.gleam index 19357c5..b02f417 100644 --- a/src/models/contract.gleam +++ b/src/models/contract.gleam @@ -1,30 +1,35 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} +import models/contract_id.{type ContractId} import models/contract_terms.{type ContractTerms} -import utils/decode as decode_utils +import models/contract_type.{type ContractType} +import models/faction_symbol.{type FactionSymbol} +import utils/api pub type Contract { Contract( - id: String, - faction_symbol: String, - type_: String, + id: ContractId, + faction_symbol: FactionSymbol, + type_: ContractType, terms: ContractTerms, accepted: Bool, fulfilled: Bool, - deadline_to_accept: Option(String), + deadline_to_accept: Option(Time), ) } pub fn decoder() -> Decoder(Contract) { - use id <- decode.field("id", decode.string) - use faction_symbol <- decode.field("factionSymbol", decode.string) - use type_ <- decode.field("type", decode.string) + use id <- decode.field("id", contract_id.decoder()) + use faction_symbol <- decode.field("factionSymbol", faction_symbol.decoder()) + use type_ <- decode.field("type", contract_type.decoder()) use terms <- decode.field("terms", contract_terms.decoder()) use accepted <- decode.field("accepted", decode.bool) use fulfilled <- decode.field("fulfilled", decode.bool) - use deadline_to_accept <- decode_utils.field_key_value_optional( + use deadline_to_accept <- decode.optional_field( "deadlineToAccept", - decode.string, + option.None, + decode.optional(api.time_decoder()), ) decode.success(Contract( id:, diff --git a/src/models/contract_deliver_good.gleam b/src/models/contract_deliver_good.gleam index d31cc09..3846859 100644 --- a/src/models/contract_deliver_good.gleam +++ b/src/models/contract_deliver_good.gleam @@ -1,17 +1,22 @@ import gleam/dynamic/decode.{type Decoder} +import models/trade_symbol.{type TradeSymbol} +import models/waypoint_symbol.{type WaypointSymbol} pub type ContractDeliverGood { ContractDeliverGood( - trade_symbol: String, - destination_symbol: String, + trade_symbol: TradeSymbol, + destination_symbol: WaypointSymbol, units_required: Int, units_fulfilled: Int, ) } pub fn decoder() -> Decoder(ContractDeliverGood) { - use trade_symbol <- decode.field("tradeSymbol", decode.string) - use destination_symbol <- decode.field("destinationSymbol", decode.string) + use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) + use destination_symbol <- decode.field( + "destinationSymbol", + waypoint_symbol.decoder(), + ) use units_required <- decode.field("unitsRequired", decode.int) use units_fulfilled <- decode.field("unitsFulfilled", decode.int) decode.success(ContractDeliverGood( diff --git a/src/models/contract_id.gleam b/src/models/contract_id.gleam new file mode 100644 index 0000000..1e37156 --- /dev/null +++ b/src/models/contract_id.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string + +pub opaque type ContractId { + ContractId(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(ContractId, Nil) { + case string.length(value) >= min_length { + True -> Ok(ContractId(value)) + False -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ContractId) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(contract_id) -> decode.success(contract_id) + Error(Nil) -> decode.failure(ContractId("invalid"), "ContractId") + } +} + +pub fn to_string(contract_id: ContractId) -> String { + let ContractId(symbol) = contract_id + symbol +} + +pub fn encode(contract_id: ContractId) -> Json { + json.string(to_string(contract_id)) +} diff --git a/src/models/contract_terms.gleam b/src/models/contract_terms.gleam index 4fde256..e45a22d 100644 --- a/src/models/contract_terms.gleam +++ b/src/models/contract_terms.gleam @@ -1,23 +1,25 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} import models/contract_deliver_good.{type ContractDeliverGood} import models/contract_payment.{type ContractPayment} -import utils/decode as decode_utils +import utils/api pub type ContractTerms { ContractTerms( - deadline: String, + deadline: Time, payment: ContractPayment, deliver: Option(List(ContractDeliverGood)), ) } pub fn decoder() -> Decoder(ContractTerms) { - use deadline <- decode.field("deadline", decode.string) + use deadline <- decode.field("deadline", api.time_decoder()) use payment <- decode.field("payment", contract_payment.decoder()) - use deliver <- decode_utils.field_key_value_optional( + use deliver <- decode.optional_field( "deliver", - decode.list(contract_deliver_good.decoder()), + option.None, + decode.optional(decode.list(contract_deliver_good.decoder())), ) decode.success(ContractTerms(deadline:, payment:, deliver:)) } diff --git a/src/models/contract_type.gleam b/src/models/contract_type.gleam new file mode 100644 index 0000000..4d459a7 --- /dev/null +++ b/src/models/contract_type.gleam @@ -0,0 +1,37 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} + +pub type ContractType { + Procurement + Transport + Shuttle +} + +pub fn parse(value: String) -> Result(ContractType, Nil) { + case value { + "PROCUREMENT" -> Ok(Procurement) + "TRANSPORT" -> Ok(Transport) + "SHUTTLE" -> Ok(Shuttle) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ContractType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(contract_type) -> decode.success(contract_type) + Error(Nil) -> decode.failure(Procurement, "ContractType") + } +} + +pub fn to_string(contract_type: ContractType) -> String { + case contract_type { + Procurement -> "PROCUREMENT" + Transport -> "TRANSPORT" + Shuttle -> "SHUTTLE" + } +} + +pub fn encode(contract_type: ContractType) -> Json { + json.string(to_string(contract_type)) +} diff --git a/src/models/cooldown.gleam b/src/models/cooldown.gleam index 9fb94c4..9bc60c3 100644 --- a/src/models/cooldown.gleam +++ b/src/models/cooldown.gleam @@ -1,14 +1,15 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} import models/ship_symbol.{type ShipSymbol} -import utils/decode as decode_utils +import utils/api pub type Cooldown { Cooldown( ship_symbol: ShipSymbol, total_seconds: Int, remaining_seconds: Int, - expiration: Option(String), + expiration: Option(Time), ) } @@ -16,9 +17,10 @@ pub fn decoder() -> Decoder(Cooldown) { use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use total_seconds <- decode.field("totalSeconds", decode.int) use remaining_seconds <- decode.field("remainingSeconds", decode.int) - use expiration <- decode_utils.field_key_value_optional( + use expiration <- decode.optional_field( "expiration", - decode.string, + option.None, + decode.optional(api.time_decoder()), ) decode.success(Cooldown( ship_symbol:, diff --git a/src/models/crew_rotation.gleam b/src/models/crew_rotation.gleam index 75dd328..963b8c5 100644 --- a/src/models/crew_rotation.gleam +++ b/src/models/crew_rotation.gleam @@ -1,11 +1,27 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type CrewRotation { Strict Relaxed } +pub fn parse(value: String) -> Result(CrewRotation, Nil) { + case value { + "STRICT" -> Ok(Strict) + "RELAXED" -> Ok(Relaxed) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(CrewRotation) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(crew_rotation) -> decode.success(crew_rotation) + Error(Nil) -> decode.failure(Strict, "CrewRotation") + } +} + pub fn to_string(crew_rotation: CrewRotation) -> String { case crew_rotation { Strict -> "STRICT" @@ -13,14 +29,6 @@ pub fn to_string(crew_rotation: CrewRotation) -> String { } } -pub fn parse(crew_rotation_str: String) -> Result(CrewRotation, CrewRotation) { - case crew_rotation_str { - "STRICT" -> Ok(Strict) - "RELAXED" -> Ok(Relaxed) - _ -> Error(Strict) - } -} - -pub fn decoder() -> Decoder(CrewRotation) { - decode_utils.enum_decoder(parse, "CrewRotation") +pub fn encode(crew_rotation: CrewRotation) -> Json { + json.string(to_string(crew_rotation)) } diff --git a/src/models/engine_symbol.gleam b/src/models/engine_symbol.gleam index cdee27d..1441a0f 100644 --- a/src/models/engine_symbol.gleam +++ b/src/models/engine_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type EngineSymbol { EngineImpulseDriveI @@ -8,6 +8,24 @@ pub type EngineSymbol { EngineHyperDriveI } +pub fn parse(value: String) -> Result(EngineSymbol, Nil) { + case value { + "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) + "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) + "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveII) + "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(EngineSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(engine_symbol) -> decode.success(engine_symbol) + Error(Nil) -> decode.failure(EngineImpulseDriveI, "EngineSymbol") + } +} + pub fn to_string(engine_symbol: EngineSymbol) -> String { case engine_symbol { EngineImpulseDriveI -> "ENGINE_IMPULSE_DRIVE_I" @@ -17,16 +35,6 @@ pub fn to_string(engine_symbol: EngineSymbol) -> String { } } -pub fn parse(engine_symbol_str: String) -> Result(EngineSymbol, EngineSymbol) { - case engine_symbol_str { - "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) - "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) - "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveII) - "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) - _ -> Error(EngineImpulseDriveI) - } -} - -pub fn decoder() -> Decoder(EngineSymbol) { - decode_utils.enum_decoder(parse, "EngineSymbol") +pub fn encode(engine_symbol: EngineSymbol) -> Json { + json.string(to_string(engine_symbol)) } diff --git a/src/models/faction.gleam b/src/models/faction.gleam index 7443c32..df24c2e 100644 --- a/src/models/faction.gleam +++ b/src/models/faction.gleam @@ -2,14 +2,14 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} import models/faction_symbol.{type FactionSymbol} import models/faction_trait.{type FactionTrait} -import utils/decode as decode_utils +import models/waypoint_symbol.{type WaypointSymbol} pub type Faction { Faction( symbol: FactionSymbol, name: String, description: String, - headquarters: Option(String), + headquarters: Option(WaypointSymbol), traits: List(FactionTrait), is_recruiting: Bool, ) @@ -19,9 +19,10 @@ pub fn decoder() -> Decoder(Faction) { use symbol <- decode.field("symbol", faction_symbol.decoder()) use name <- decode.field("name", decode.string) use description <- decode.field("description", decode.string) - use headquarters <- decode_utils.field_key_value_optional( + use headquarters <- decode.optional_field( "headquarters", - decode.string, + option.None, + decode.optional(waypoint_symbol.decoder()), ) use traits <- decode.field("traits", decode.list(faction_trait.decoder())) use is_recruiting <- decode.field("isRecruiting", decode.bool) diff --git a/src/models/faction_symbol.gleam b/src/models/faction_symbol.gleam index 4b9029b..583de57 100644 --- a/src/models/faction_symbol.gleam +++ b/src/models/faction_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type FactionSymbol { Cosmic @@ -23,8 +23,41 @@ pub type FactionSymbol { Ethereal } -pub fn to_string(symbol: FactionSymbol) -> String { - case symbol { +pub fn parse(value: String) -> Result(FactionSymbol, Nil) { + case value { + "COSMIC" -> Ok(Cosmic) + "VOID" -> Ok(Void) + "GALACTIC" -> Ok(Galactic) + "QUANTUM" -> Ok(Quantum) + "DOMINION" -> Ok(Dominion) + "ASTRO" -> Ok(Astro) + "CORSAIRS" -> Ok(Corsairs) + "OBSIDIAN" -> Ok(Obsidian) + "AEGIS" -> Ok(Aegis) + "UNITED" -> Ok(United) + "SOLITARY" -> Ok(Solitary) + "COBALT" -> Ok(Cobalt) + "OMEGA" -> Ok(Omega) + "ECHO" -> Ok(Echo) + "LORDS" -> Ok(Lord) + "CULT" -> Ok(Cult) + "ANCIENTS" -> Ok(Ancients) + "SHADOW" -> Ok(Shadow) + "ETHEREAL" -> Ok(Ethereal) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(FactionSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(faction_symbol) -> decode.success(faction_symbol) + Error(Nil) -> decode.failure(Cosmic, "FactionSymbol") + } +} + +pub fn to_string(faction_symbol: FactionSymbol) -> String { + case faction_symbol { Cosmic -> "COSMIC" Void -> "VOID" Galactic -> "GALACTIC" @@ -47,31 +80,6 @@ pub fn to_string(symbol: FactionSymbol) -> String { } } -pub fn parse(symbol_str: String) -> Result(FactionSymbol, FactionSymbol) { - case symbol_str { - "COSMIC" -> Ok(Cosmic) - "VOID" -> Ok(Void) - "GALACTIC" -> Ok(Galactic) - "QUANTUM" -> Ok(Quantum) - "DOMINION" -> Ok(Dominion) - "ASTRO" -> Ok(Astro) - "CORSAIRS" -> Ok(Corsairs) - "OBSIDIAN" -> Ok(Obsidian) - "AEGIS" -> Ok(Aegis) - "UNITED" -> Ok(United) - "SOLITARY" -> Ok(Solitary) - "COBALT" -> Ok(Cobalt) - "OMEGA" -> Ok(Omega) - "ECHO" -> Ok(Echo) - "LORDS" -> Ok(Lord) - "CULT" -> Ok(Cult) - "ANCIENTS" -> Ok(Ancients) - "SHADOW" -> Ok(Shadow) - "ETHEREAL" -> Ok(Ethereal) - _ -> Error(Cosmic) - } -} - -pub fn decoder() -> Decoder(FactionSymbol) { - decode_utils.enum_decoder(parse, "FactionSymbol") +pub fn encode(faction_symbol: FactionSymbol) -> Json { + json.string(to_string(faction_symbol)) } diff --git a/src/models/faction_trait_symbol.gleam b/src/models/faction_trait_symbol.gleam index 899c4e2..0bdfbf0 100644 --- a/src/models/faction_trait_symbol.gleam +++ b/src/models/faction_trait_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type FactionTraitSymbol { Bureaucratic @@ -63,8 +63,81 @@ pub type FactionTraitSymbol { Entrepreneurial } -pub fn to_string(trait_symbol: FactionTraitSymbol) -> String { - case trait_symbol { +pub fn parse(value: String) -> Result(FactionTraitSymbol, Nil) { + case value { + "BUREAUCRATIC" -> Ok(Bureaucratic) + "SECRETIVE" -> Ok(Secretive) + "CAPITALISTIC" -> Ok(Capitalistic) + "INDUSTRIOUS" -> Ok(Industrious) + "PEACEFUL" -> Ok(Peaceful) + "DISTRUSTFUL" -> Ok(Distrustful) + "WELCOMING" -> Ok(Welcoming) + "SMUGGLERS" -> Ok(Smugglers) + "SCAVENGERS" -> Ok(Scavengers) + "REBELLIOUS" -> Ok(Rebellious) + "EXILES" -> Ok(Exiles) + "PIRATES" -> Ok(Pirates) + "RAIDERS" -> Ok(Raiders) + "CLAN" -> Ok(Clan) + "GUILD" -> Ok(Guild) + "DOMINION" -> Ok(Dominion) + "FRINGE" -> Ok(Fringe) + "FORSAKEN" -> Ok(Forsaken) + "ISOLATED" -> Ok(Isolated) + "LOCALIZED" -> Ok(Localized) + "ESTABLISHED" -> Ok(Established) + "NOTABLE" -> Ok(Notable) + "DOMINANT" -> Ok(Dominant) + "INESCAPABLE" -> Ok(Inescapable) + "INNOVATIVE" -> Ok(Innovative) + "BOLD" -> Ok(Bold) + "VISIONARY" -> Ok(Visionary) + "CURIOUS" -> Ok(Curious) + "DARING" -> Ok(Daring) + "EXPLORATORY" -> Ok(Exploratory) + "RESOURCEFUL" -> Ok(Resourceful) + "FLEXIBLE" -> Ok(Flexible) + "COOPERATIVE" -> Ok(Cooperative) + "UNITED" -> Ok(United) + "STRATEGIC" -> Ok(Strategic) + "INTELLIGENT" -> Ok(Intelligent) + "RESEARCH_FOCUSED" -> Ok(ResearchFocused) + "COLLABORATIVE" -> Ok(Collaborative) + "PROGRESSIVE" -> Ok(Progressive) + "MILITARISTIC" -> Ok(Militaristic) + "TECHNOLOGICALLY_ADVANCED" -> Ok(TechnologicallyAdvanced) + "AGGRESSIVE" -> Ok(Aggressive) + "IMPERIALISTIC" -> Ok(Imperialistic) + "TREASURE_HUNTERS" -> Ok(TreasureHunters) + "DEXTEROUS" -> Ok(Dexterous) + "UNPREDICTABLE" -> Ok(Unpredictable) + "BRUTAL" -> Ok(Brutal) + "FLEETING" -> Ok(Fleeting) + "ADAPTABLE" -> Ok(Adaptable) + "SELF_SUFFICIENT" -> Ok(SelfSufficient) + "DEFENSIVE" -> Ok(Defensive) + "PROUD" -> Ok(Proud) + "DIVERSE" -> Ok(Diverse) + "INDEPENDENT" -> Ok(Independent) + "SELF_INTERESTED" -> Ok(SelfInterested) + "FRAGMENTED" -> Ok(Fragmented) + "COMMERCIAL" -> Ok(Commercial) + "FREE_MARKETS" -> Ok(FreeMarkets) + "ENTREPRENEURIAL" -> Ok(Entrepreneurial) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(FactionTraitSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(faction_trait_symbol) -> decode.success(faction_trait_symbol) + Error(Nil) -> decode.failure(Bureaucratic, "FactionTraitSymbol") + } +} + +pub fn to_string(faction_trait_symbol: FactionTraitSymbol) -> String { + case faction_trait_symbol { Bureaucratic -> "BUREAUCRATIC" Secretive -> "SECRETIVE" Capitalistic -> "CAPITALISTIC" @@ -127,73 +200,6 @@ pub fn to_string(trait_symbol: FactionTraitSymbol) -> String { } } -pub fn parse( - trait_symbol_str: String, -) -> Result(FactionTraitSymbol, FactionTraitSymbol) { - case trait_symbol_str { - "BUREAUCRATIC" -> Ok(Bureaucratic) - "SECRETIVE" -> Ok(Secretive) - "CAPITALISTIC" -> Ok(Capitalistic) - "INDUSTRIOUS" -> Ok(Industrious) - "PEACEFUL" -> Ok(Peaceful) - "DISTRUSTFUL" -> Ok(Distrustful) - "WELCOMING" -> Ok(Welcoming) - "SMUGGLERS" -> Ok(Smugglers) - "SCAVENGERS" -> Ok(Scavengers) - "REBELLIOUS" -> Ok(Rebellious) - "EXILES" -> Ok(Exiles) - "PIRATES" -> Ok(Pirates) - "RAIDERS" -> Ok(Raiders) - "CLAN" -> Ok(Clan) - "GUILD" -> Ok(Guild) - "DOMINION" -> Ok(Dominion) - "FRINGE" -> Ok(Fringe) - "FORSAKEN" -> Ok(Forsaken) - "ISOLATED" -> Ok(Isolated) - "LOCALIZED" -> Ok(Localized) - "ESTABLISHED" -> Ok(Established) - "NOTABLE" -> Ok(Notable) - "DOMINANT" -> Ok(Dominant) - "INESCAPABLE" -> Ok(Inescapable) - "INNOVATIVE" -> Ok(Innovative) - "BOLD" -> Ok(Bold) - "VISIONARY" -> Ok(Visionary) - "CURIOUS" -> Ok(Curious) - "DARING" -> Ok(Daring) - "EXPLORATORY" -> Ok(Exploratory) - "RESOURCEFUL" -> Ok(Resourceful) - "FLEXIBLE" -> Ok(Flexible) - "COOPERATIVE" -> Ok(Cooperative) - "UNITED" -> Ok(United) - "STRATEGIC" -> Ok(Strategic) - "INTELLIGENT" -> Ok(Intelligent) - "RESEARCH_FOCUSED" -> Ok(ResearchFocused) - "COLLABORATIVE" -> Ok(Collaborative) - "PROGRESSIVE" -> Ok(Progressive) - "MILITARISTIC" -> Ok(Militaristic) - "TECHNOLOGICALLY_ADVANCED" -> Ok(TechnologicallyAdvanced) - "AGGRESSIVE" -> Ok(Aggressive) - "IMPERIALISTIC" -> Ok(Imperialistic) - "TREASURE_HUNTERS" -> Ok(TreasureHunters) - "DEXTEROUS" -> Ok(Dexterous) - "UNPREDICTABLE" -> Ok(Unpredictable) - "BRUTAL" -> Ok(Brutal) - "FLEETING" -> Ok(Fleeting) - "ADAPTABLE" -> Ok(Adaptable) - "SELF_SUFFICIENT" -> Ok(SelfSufficient) - "DEFENSIVE" -> Ok(Defensive) - "PROUD" -> Ok(Proud) - "DIVERSE" -> Ok(Diverse) - "INDEPENDENT" -> Ok(Independent) - "SELF_INTERESTED" -> Ok(SelfInterested) - "FRAGMENTED" -> Ok(Fragmented) - "COMMERCIAL" -> Ok(Commercial) - "FREE_MARKETS" -> Ok(FreeMarkets) - "ENTREPRENEURIAL" -> Ok(Entrepreneurial) - _ -> Error(Bureaucratic) - } -} - -pub fn decoder() -> Decoder(FactionTraitSymbol) { - decode_utils.enum_decoder(parse, "FactionTraitSymbol") +pub fn encode(faction_trait_symbol: FactionTraitSymbol) -> Json { + json.string(to_string(faction_trait_symbol)) } diff --git a/src/models/frame_symbol.gleam b/src/models/frame_symbol.gleam index 30b39c1..25332c8 100644 --- a/src/models/frame_symbol.gleam +++ b/src/models/frame_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type FrameSymbol { FrameProbe @@ -20,6 +20,36 @@ pub type FrameSymbol { FrameBulkFreighter } +pub fn parse(value: String) -> Result(FrameSymbol, Nil) { + case value { + "FRAME_PROBE" -> Ok(FrameProbe) + "FRAME_DRONE" -> Ok(FrameDrone) + "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) + "FRAME_RACER" -> Ok(FrameRacer) + "FRAME_FIGHTER" -> Ok(FrameFighter) + "FRAME_FRIGATE" -> Ok(FrameFrigate) + "FRAME_SHUTTLE" -> Ok(FrameShuttle) + "FRAME_EXPLORER" -> Ok(FrameExplorer) + "FRAME_MINER" -> Ok(FrameMiner) + "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) + "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) + "FRAME_TRANSPORT" -> Ok(FrameTransport) + "FRAME_DESTROYER" -> Ok(FrameDestroyer) + "FRAME_CRUISER" -> Ok(FrameCruiser) + "FRAME_CARRIER" -> Ok(FrameCarrier) + "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(FrameSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(frame_symbol) -> decode.success(frame_symbol) + Error(Nil) -> decode.failure(FrameProbe, "FrameSymbol") + } +} + pub fn to_string(frame_symbol: FrameSymbol) -> String { case frame_symbol { FrameProbe -> "FRAME_PROBE" @@ -41,28 +71,6 @@ pub fn to_string(frame_symbol: FrameSymbol) -> String { } } -pub fn parse(frame_symbol_str: String) -> Result(FrameSymbol, FrameSymbol) { - case frame_symbol_str { - "FRAME_PROBE" -> Ok(FrameProbe) - "FRAME_DRONE" -> Ok(FrameDrone) - "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) - "FRAME_RACER" -> Ok(FrameRacer) - "FRAME_FIGHTER" -> Ok(FrameFighter) - "FRAME_FRIGATE" -> Ok(FrameFrigate) - "FRAME_SHUTTLE" -> Ok(FrameShuttle) - "FRAME_EXPLORER" -> Ok(FrameExplorer) - "FRAME_MINER" -> Ok(FrameMiner) - "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) - "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) - "FRAME_TRANSPORT" -> Ok(FrameTransport) - "FRAME_DESTROYER" -> Ok(FrameDestroyer) - "FRAME_CRUISER" -> Ok(FrameCruiser) - "FRAME_CARRIER" -> Ok(FrameCarrier) - "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) - _ -> Error(FrameProbe) - } -} - -pub fn decoder() -> Decoder(FrameSymbol) { - decode_utils.enum_decoder(parse, "FrameSymbol") +pub fn encode(frame_symbol: FrameSymbol) -> Json { + json.string(to_string(frame_symbol)) } diff --git a/src/models/jump_gate.gleam b/src/models/jump_gate.gleam index c2beeee..26613be 100644 --- a/src/models/jump_gate.gleam +++ b/src/models/jump_gate.gleam @@ -2,11 +2,14 @@ import gleam/dynamic/decode.{type Decoder} import models/waypoint_symbol.{type WaypointSymbol} pub type JumpGate { - JumpGate(symbol: WaypointSymbol, connections: List(String)) + JumpGate(symbol: WaypointSymbol, connections: List(WaypointSymbol)) } pub fn decoder() -> Decoder(JumpGate) { use symbol <- decode.field("symbol", waypoint_symbol.decoder()) - use connections <- decode.field("connections", decode.list(decode.string)) + use connections <- decode.field( + "connections", + decode.list(waypoint_symbol.decoder()), + ) decode.success(JumpGate(symbol:, connections:)) } diff --git a/src/models/market.gleam b/src/models/market.gleam index f9fb635..dd1f343 100644 --- a/src/models/market.gleam +++ b/src/models/market.gleam @@ -4,7 +4,6 @@ import models/market_symbol.{type MarketSymbol} import models/market_trade_good.{type MarketTradeGood} import models/market_transaction.{type MarketTransaction} import models/trade_good.{type TradeGood} -import utils/decode as decode_utils pub type Market { Market( @@ -18,17 +17,19 @@ pub type Market { } pub fn decoder() -> Decoder(Market) { - use symbol <- decode.field("symbol", decode.string) + use symbol <- decode.field("symbol", market_symbol.decoder()) use exports <- decode.field("exports", decode.list(trade_good.decoder())) use imports <- decode.field("imports", decode.list(trade_good.decoder())) use exchange <- decode.field("exchange", decode.list(trade_good.decoder())) - use transactions <- decode_utils.field_key_value_optional( + use transactions <- decode.optional_field( "transactions", - decode.list(market_transaction.decoder()), + option.None, + decode.optional(decode.list(market_transaction.decoder())), ) - use trade_goods <- decode_utils.field_key_value_optional( + use trade_goods <- decode.optional_field( "tradeGoods", - decode.list(market_trade_good.decoder()), + option.None, + decode.optional(decode.list(market_trade_good.decoder())), ) decode.success(Market( symbol:, diff --git a/src/models/market_symbol.gleam b/src/models/market_symbol.gleam index 47d4d5d..cc437d8 100644 --- a/src/models/market_symbol.gleam +++ b/src/models/market_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type MarketSymbol = - String +pub opaque type MarketSymbol { + MarketSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(MarketSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(MarketSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(MarketSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(market_symbol) -> decode.success(market_symbol) + Error(Nil) -> decode.failure(MarketSymbol("invalid"), "MarketSymbol") + } +} + +pub fn to_string(market_symbol: MarketSymbol) -> String { + let MarketSymbol(symbol) = market_symbol + symbol +} + +pub fn encode(market_symbol: MarketSymbol) -> Json { + json.string(to_string(market_symbol)) } diff --git a/src/models/market_trade_good.gleam b/src/models/market_trade_good.gleam index 7581274..0755a1c 100644 --- a/src/models/market_trade_good.gleam +++ b/src/models/market_trade_good.gleam @@ -4,7 +4,6 @@ import models/activity_level.{type ActivityLevel} import models/supply_level.{type SupplyLevel} import models/trade_good_type.{type TradeGoodType} import models/trade_symbol.{type TradeSymbol} -import utils/decode as decode_utils pub type MarketTradeGood { MarketTradeGood( @@ -23,9 +22,10 @@ pub fn decoder() -> Decoder(MarketTradeGood) { use type_ <- decode.field("type", trade_good_type.decoder()) use trade_volume <- decode.field("tradeVolume", decode.int) use supply <- decode.field("supply", supply_level.decoder()) - use activity <- decode_utils.field_key_value_optional( + use activity <- decode.optional_field( "activity", - activity_level.decoder(), + option.None, + decode.optional(activity_level.decoder()), ) use purchase_price <- decode.field("purchasePrice", decode.int) use sell_price <- decode.field("sellPrice", decode.int) diff --git a/src/models/market_transaction.gleam b/src/models/market_transaction.gleam index 1c5f185..531505c 100644 --- a/src/models/market_transaction.gleam +++ b/src/models/market_transaction.gleam @@ -1,8 +1,10 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_symbol.{type ShipSymbol} import models/trade_symbol.{type TradeSymbol} import models/transaction_type.{type TransactionType} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type MarketTransaction { MarketTransaction( @@ -13,7 +15,7 @@ pub type MarketTransaction { units: Int, price_per_unit: Int, total_price: Int, - timestamp: String, + timestamp: Time, ) } @@ -22,13 +24,13 @@ pub fn decoder() -> Decoder(MarketTransaction) { "waypointSymbol", waypoint_symbol.decoder(), ) - use ship_symbol <- decode.field("shipSymbol", decode.string) + use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) use type_ <- decode.field("type", transaction_type.decoder()) use units <- decode.field("units", decode.int) use price_per_unit <- decode.field("pricePerUnit", decode.int) use total_price <- decode.field("totalPrice", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(MarketTransaction( waypoint_symbol:, ship_symbol:, diff --git a/src/models/meta.gleam b/src/models/meta.gleam index 87fdb7e..9c00ca7 100644 --- a/src/models/meta.gleam +++ b/src/models/meta.gleam @@ -1,12 +1,12 @@ import gleam/dynamic/decode.{type Decoder} pub type Meta { - Meta(limit: Int, page: Int, total: Int) + Meta(total: Int, page: Int, limit: Int) } pub fn decoder() -> Decoder(Meta) { - use limit <- decode.field("limit", decode.int) - use page <- decode.field("page", decode.int) use total <- decode.field("total", decode.int) - decode.success(Meta(limit: limit, page: page, total: total)) + use page <- decode.field("page", decode.int) + use limit <- decode.field("limit", decode.int) + decode.success(Meta(total:, page:, limit:)) } diff --git a/src/models/module_symbol.gleam b/src/models/module_symbol.gleam index 106f4e2..e51cc0b 100644 --- a/src/models/module_symbol.gleam +++ b/src/models/module_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ModuleSymbol { ModuleMineralProcessorI @@ -24,6 +24,40 @@ pub type ModuleSymbol { ModuleShieldGeneratorII } +pub fn parse(value: String) -> Result(ModuleSymbol, Nil) { + case value { + "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) + "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) + "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) + "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) + "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) + "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) + "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) + "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) + "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) + "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) + "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) + "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) + "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) + "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) + "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) + "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) + "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) + "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) + "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) + "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ModuleSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(module_symbol) -> decode.success(module_symbol) + Error(Nil) -> decode.failure(ModuleMineralProcessorI, "ModuleSymbol") + } +} + pub fn to_string(module_symbol: ModuleSymbol) -> String { case module_symbol { ModuleMineralProcessorI -> "MODULE_MINERAL_PROCESSOR_I" @@ -49,32 +83,6 @@ pub fn to_string(module_symbol: ModuleSymbol) -> String { } } -pub fn parse(module_symbol_str: String) -> Result(ModuleSymbol, ModuleSymbol) { - case module_symbol_str { - "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) - "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) - "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) - "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) - "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) - "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) - "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) - "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) - "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) - "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) - "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) - "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) - "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) - "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) - "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) - "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) - "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) - "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) - "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) - "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) - _ -> Error(ModuleMineralProcessorI) - } -} - -pub fn decoder() -> Decoder(ModuleSymbol) { - decode_utils.enum_decoder(parse, "ModuleSymbol") +pub fn encode(module_symbol: ModuleSymbol) -> Json { + json.string(to_string(module_symbol)) } diff --git a/src/models/mount_deposit.gleam b/src/models/mount_deposit.gleam index 53aa879..8afc095 100644 --- a/src/models/mount_deposit.gleam +++ b/src/models/mount_deposit.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type MountDeposit { QuartzSand @@ -18,6 +18,34 @@ pub type MountDeposit { MeritiumOre } +pub fn parse(value: String) -> Result(MountDeposit, Nil) { + case value { + "QUARTZ_SAND" -> Ok(QuartzSand) + "SILICON_CRYSTALS" -> Ok(SiliconCrystals) + "PRECIOUS_STONES" -> Ok(PreciousStones) + "ICE_WATER" -> Ok(IceWater) + "AMMONIA_ICE" -> Ok(AmmoniaIce) + "IRON_ORE" -> Ok(IronOre) + "COPPER_ORE" -> Ok(CopperOre) + "SILVER_ORE" -> Ok(SilverOre) + "ALUMINUM_ORE" -> Ok(AluminumOre) + "GOLD_ORE" -> Ok(GoldOre) + "PLATINUM_ORE" -> Ok(PlatinumOre) + "DIAMONDS" -> Ok(Diamonds) + "URANITE_ORE" -> Ok(UraniteOre) + "MERITIUM_ORE" -> Ok(MeritiumOre) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(MountDeposit) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(mount_deposit) -> decode.success(mount_deposit) + Error(Nil) -> decode.failure(QuartzSand, "MountDeposit") + } +} + pub fn to_string(mount_deposit: MountDeposit) -> String { case mount_deposit { QuartzSand -> "QUARTZ_SAND" @@ -37,26 +65,6 @@ pub fn to_string(mount_deposit: MountDeposit) -> String { } } -pub fn parse(mount_deposit_str: String) -> Result(MountDeposit, MountDeposit) { - case mount_deposit_str { - "QUARTZ_SAND" -> Ok(QuartzSand) - "SILICON_CRYSTALS" -> Ok(SiliconCrystals) - "PRECIOUS_STONES" -> Ok(PreciousStones) - "ICE_WATER" -> Ok(IceWater) - "AMMONIA_ICE" -> Ok(AmmoniaIce) - "IRON_ORE" -> Ok(IronOre) - "COPPER_ORE" -> Ok(CopperOre) - "SILVER_ORE" -> Ok(SilverOre) - "ALUMINUM_ORE" -> Ok(AluminumOre) - "GOLD_ORE" -> Ok(GoldOre) - "PLATINUM_ORE" -> Ok(PlatinumOre) - "DIAMONDS" -> Ok(Diamonds) - "URANITE_ORE" -> Ok(UraniteOre) - "MERITIUM_ORE" -> Ok(MeritiumOre) - _ -> Error(QuartzSand) - } -} - -pub fn decoder() -> Decoder(MountDeposit) { - decode_utils.enum_decoder(parse, "MountDeposit") +pub fn encode(mount_deposit: MountDeposit) -> Json { + json.string(to_string(mount_deposit)) } diff --git a/src/models/mount_symbol.gleam b/src/models/mount_symbol.gleam index b948d70..29278e8 100644 --- a/src/models/mount_symbol.gleam +++ b/src/models/mount_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type MountSymbol { MountGasSiphonI @@ -19,6 +19,35 @@ pub type MountSymbol { MountTurretI } +pub fn parse(value: String) -> Result(MountSymbol, Nil) { + case value { + "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) + "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) + "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) + "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) + "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) + "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) + "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) + "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) + "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) + "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) + "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) + "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) + "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) + "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) + "MOUNT_TURRET_I" -> Ok(MountTurretI) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(MountSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(mount_symbol) -> decode.success(mount_symbol) + Error(Nil) -> decode.failure(MountGasSiphonI, "MountSymbol") + } +} + pub fn to_string(mount_symbol: MountSymbol) -> String { case mount_symbol { MountGasSiphonI -> "MOUNT_GAS_SIPHON_I" @@ -39,27 +68,6 @@ pub fn to_string(mount_symbol: MountSymbol) -> String { } } -pub fn parse(mount_symbol_str: String) -> Result(MountSymbol, MountSymbol) { - case mount_symbol_str { - "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) - "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) - "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) - "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) - "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) - "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) - "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) - "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) - "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) - "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) - "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) - "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) - "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) - "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) - "MOUNT_TURRET_I" -> Ok(MountTurretI) - _ -> Error(MountGasSiphonI) - } -} - -pub fn decoder() -> Decoder(MountSymbol) { - decode_utils.enum_decoder(parse, "MountSymbol") +pub fn encode(mount_symbol: MountSymbol) -> Json { + json.string(to_string(mount_symbol)) } diff --git a/src/models/public_agent.gleam b/src/models/public_agent.gleam index 64090e5..952b6e6 100644 --- a/src/models/public_agent.gleam +++ b/src/models/public_agent.gleam @@ -1,20 +1,26 @@ import gleam/dynamic/decode.{type Decoder} +import models/agent_symbol.{type AgentSymbol} +import models/faction_symbol.{type FactionSymbol} +import models/waypoint_symbol.{type WaypointSymbol} pub type PublicAgent { PublicAgent( - symbol: String, - headquarters: String, + symbol: AgentSymbol, + headquarters: WaypointSymbol, credits: Int, - starting_faction: String, + starting_faction: FactionSymbol, ship_count: Int, ) } pub fn decoder() -> Decoder(PublicAgent) { - use symbol <- decode.field("symbol", decode.string) - use headquarters <- decode.field("headquarters", decode.string) + use symbol <- decode.field("symbol", agent_symbol.decoder()) + use headquarters <- decode.field("headquarters", waypoint_symbol.decoder()) use credits <- decode.field("credits", decode.int) - use starting_faction <- decode.field("startingFaction", decode.string) + use starting_faction <- decode.field( + "startingFaction", + faction_symbol.decoder(), + ) use ship_count <- decode.field("shipCount", decode.int) decode.success(PublicAgent( symbol:, diff --git a/src/models/reactor_symbol.gleam b/src/models/reactor_symbol.gleam index 48903a4..60c37f6 100644 --- a/src/models/reactor_symbol.gleam +++ b/src/models/reactor_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ReactorSymbol { ReactorSolarI @@ -9,6 +9,25 @@ pub type ReactorSymbol { ReactorAntimatterI } +pub fn parse(value: String) -> Result(ReactorSymbol, Nil) { + case value { + "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) + "REACTOR_FUSION_I" -> Ok(ReactorFusionI) + "REACTOR_FISSION_I" -> Ok(ReactorFissionI) + "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) + "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ReactorSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(reactor_symbol) -> decode.success(reactor_symbol) + Error(Nil) -> decode.failure(ReactorSolarI, "ReactorSymbol") + } +} + pub fn to_string(reactor_symbol: ReactorSymbol) -> String { case reactor_symbol { ReactorSolarI -> "REACTOR_SOLAR_I" @@ -19,17 +38,6 @@ pub fn to_string(reactor_symbol: ReactorSymbol) -> String { } } -pub fn parse(reactor_symbol_str: String) -> Result(ReactorSymbol, ReactorSymbol) { - case reactor_symbol_str { - "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) - "REACTOR_FUSION_I" -> Ok(ReactorFusionI) - "REACTOR_FISSION_I" -> Ok(ReactorFissionI) - "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) - "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) - _ -> Error(ReactorSolarI) - } -} - -pub fn decoder() -> Decoder(ReactorSymbol) { - decode_utils.enum_decoder(parse, "ReactorSymbol") +pub fn encode(reactor_symbol: ReactorSymbol) -> Json { + json.string(to_string(reactor_symbol)) } diff --git a/src/models/refinement_produce.gleam b/src/models/refinement_produce.gleam index 510b54d..4ac3a23 100644 --- a/src/models/refinement_produce.gleam +++ b/src/models/refinement_produce.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type RefinementProduce { Iron @@ -13,6 +13,29 @@ pub type RefinementProduce { Fuel } +pub fn parse(value: String) -> Result(RefinementProduce, Nil) { + case value { + "IRON" -> Ok(Iron) + "COPPER" -> Ok(Copper) + "SILVER" -> Ok(Silver) + "GOLD" -> Ok(Gold) + "ALUMINUM" -> Ok(Aluminum) + "PLATINUM" -> Ok(Platinum) + "URANITE" -> Ok(Uranite) + "MERITIUM" -> Ok(Meritium) + "FUEL" -> Ok(Fuel) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(RefinementProduce) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(refinement_produce) -> decode.success(refinement_produce) + Error(Nil) -> decode.failure(Iron, "RefinementProduce") + } +} + pub fn to_string(refinement_produce: RefinementProduce) -> String { case refinement_produce { Iron -> "IRON" @@ -27,23 +50,6 @@ pub fn to_string(refinement_produce: RefinementProduce) -> String { } } -pub fn parse( - refinement_produce_str: String, -) -> Result(RefinementProduce, RefinementProduce) { - case refinement_produce_str { - "IRON" -> Ok(Iron) - "COPPER" -> Ok(Copper) - "SILVER" -> Ok(Silver) - "GOLD" -> Ok(Gold) - "ALUMINUM" -> Ok(Aluminum) - "PLATINUM" -> Ok(Platinum) - "URANITE" -> Ok(Uranite) - "MERITIUM" -> Ok(Meritium) - "FUEL" -> Ok(Fuel) - _ -> Error(Iron) - } -} - -pub fn decoder() -> Decoder(RefinementProduce) { - decode_utils.enum_decoder(parse, "RefinementProduce") +pub fn encode(refinement_produce: RefinementProduce) -> Json { + json.string(to_string(refinement_produce)) } diff --git a/src/models/repair_transaction.gleam b/src/models/repair_transaction.gleam index 121b85f..4d25e5f 100644 --- a/src/models/repair_transaction.gleam +++ b/src/models/repair_transaction.gleam @@ -1,13 +1,15 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_symbol.{type ShipSymbol} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type RepairTransaction { RepairTransaction( waypoint_symbol: WaypointSymbol, ship_symbol: ShipSymbol, total_price: Int, - timestamp: String, + timestamp: Time, ) } @@ -18,7 +20,7 @@ pub fn decoder() -> Decoder(RepairTransaction) { ) use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use total_price <- decode.field("totalPrice", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(RepairTransaction( waypoint_symbol:, ship_symbol:, diff --git a/src/models/scanned_ship.gleam b/src/models/scanned_ship.gleam index 11f693a..1dca015 100644 --- a/src/models/scanned_ship.gleam +++ b/src/models/scanned_ship.gleam @@ -7,7 +7,6 @@ import models/scanned_ship_reactor.{type ScannedShipReactor} import models/ship_nav.{type ShipNav} import models/ship_registration.{type ShipRegistration} import models/ship_symbol.{type ShipSymbol} -import utils/decode as decode_utils pub type ScannedShip { ScannedShip( @@ -22,21 +21,24 @@ pub type ScannedShip { } pub fn decoder() -> Decoder(ScannedShip) { - use symbol <- decode.field("symbol", decode.string) + use symbol <- decode.field("symbol", ship_symbol.decoder()) use registration <- decode.field("registration", ship_registration.decoder()) use nav <- decode.field("nav", ship_nav.decoder()) - use frame <- decode_utils.field_key_value_optional( + use frame <- decode.optional_field( "frame", - scanned_ship_frame.decoder(), + option.None, + decode.optional(scanned_ship_frame.decoder()), ) - use reactor <- decode_utils.field_key_value_optional( + use reactor <- decode.optional_field( "reactor", - scanned_ship_reactor.decoder(), + option.None, + decode.optional(scanned_ship_reactor.decoder()), ) use engine <- decode.field("engine", scanned_ship_engine.decoder()) - use mounts <- decode_utils.field_key_value_optional( + use mounts <- decode.optional_field( "mounts", - decode.list(scanned_ship_mount.decoder()), + option.None, + decode.optional(decode.list(scanned_ship_mount.decoder())), ) decode.success(ScannedShip( symbol:, diff --git a/src/models/scanned_system.gleam b/src/models/scanned_system.gleam index a6ad9a3..4853f52 100644 --- a/src/models/scanned_system.gleam +++ b/src/models/scanned_system.gleam @@ -1,11 +1,12 @@ import gleam/dynamic/decode.{type Decoder} +import models/sector_symbol.{type SectorSymbol} import models/system_symbol.{type SystemSymbol} import models/system_type.{type SystemType} pub type ScannedSystem { ScannedSystem( symbol: SystemSymbol, - sector_symbol: String, + sector_symbol: SectorSymbol, type_: SystemType, x: Int, y: Int, @@ -14,8 +15,8 @@ pub type ScannedSystem { } pub fn decoder() -> Decoder(ScannedSystem) { - use symbol <- decode.field("symbol", decode.string) - use sector_symbol <- decode.field("sectorSymbol", decode.string) + use symbol <- decode.field("symbol", system_symbol.decoder()) + use sector_symbol <- decode.field("sectorSymbol", sector_symbol.decoder()) use type_ <- decode.field("type", system_type.decoder()) use x <- decode.field("x", decode.int) use y <- decode.field("y", decode.int) diff --git a/src/models/scrap_transaction.gleam b/src/models/scrap_transaction.gleam index 39b85c5..1aee4fb 100644 --- a/src/models/scrap_transaction.gleam +++ b/src/models/scrap_transaction.gleam @@ -1,13 +1,15 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_symbol.{type ShipSymbol} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type ScrapTransaction { ScrapTransaction( waypoint_symbol: WaypointSymbol, ship_symbol: ShipSymbol, total_price: Int, - timestamp: String, + timestamp: Time, ) } @@ -18,7 +20,7 @@ pub fn decoder() -> Decoder(ScrapTransaction) { ) use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use total_price <- decode.field("totalPrice", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(ScrapTransaction( waypoint_symbol:, ship_symbol:, diff --git a/src/models/sector_symbol.gleam b/src/models/sector_symbol.gleam new file mode 100644 index 0000000..1b7ec0c --- /dev/null +++ b/src/models/sector_symbol.gleam @@ -0,0 +1,33 @@ +import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string + +pub opaque type SectorSymbol { + SectorSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(SectorSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(SectorSymbol(value)) + False -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(SectorSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(sector_symbol) -> decode.success(sector_symbol) + Error(Nil) -> decode.failure(SectorSymbol("invalid"), "SectorSymbol") + } +} + +pub fn to_string(sector_symbol: SectorSymbol) -> String { + let SectorSymbol(value) = sector_symbol + value +} + +pub fn encode(sector_symbol: SectorSymbol) -> Json { + json.string(to_string(sector_symbol)) +} diff --git a/src/models/ship.gleam b/src/models/ship.gleam index 5c8b085..ae6f10d 100644 --- a/src/models/ship.gleam +++ b/src/models/ship.gleam @@ -30,7 +30,7 @@ pub type Ship { } pub fn decoder() -> Decoder(Ship) { - use symbol <- decode.field("symbol", decode.string) + use symbol <- decode.field("symbol", ship_symbol.decoder()) use registration <- decode.field("registration", ship_registration.decoder()) use nav <- decode.field("nav", ship_nav.decoder()) use crew <- decode.field("crew", ship_crew.decoder()) diff --git a/src/models/ship_component.gleam b/src/models/ship_component.gleam index 32cb697..b1d534d 100644 --- a/src/models/ship_component.gleam +++ b/src/models/ship_component.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipComponent { Frame @@ -7,6 +7,23 @@ pub type ShipComponent { Engine } +pub fn parse(value: String) -> Result(ShipComponent, Nil) { + case value { + "FRAME" -> Ok(Frame) + "REACTOR" -> Ok(Reactor) + "ENGINE" -> Ok(Engine) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipComponent) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_component) -> decode.success(ship_component) + Error(Nil) -> decode.failure(Frame, "ShipComponent") + } +} + pub fn to_string(ship_component: ShipComponent) -> String { case ship_component { Frame -> "FRAME" @@ -15,15 +32,6 @@ pub fn to_string(ship_component: ShipComponent) -> String { } } -pub fn parse(ship_component_str: String) -> Result(ShipComponent, ShipComponent) { - case ship_component_str { - "FRAME" -> Ok(Frame) - "REACTOR" -> Ok(Reactor) - "ENGINE" -> Ok(Engine) - _ -> Error(Frame) - } -} - -pub fn decoder() -> Decoder(ShipComponent) { - decode_utils.enum_decoder(parse, "ShipComponent") +pub fn encode(ship_component: ShipComponent) -> Json { + json.string(to_string(ship_component)) } diff --git a/src/models/ship_component_condition.gleam b/src/models/ship_component_condition.gleam index 2b72921..2e88624 100644 --- a/src/models/ship_component_condition.gleam +++ b/src/models/ship_component_condition.gleam @@ -1,8 +1,35 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} -pub type ShipComponentCondition = - Float +pub opaque type ShipComponentCondition { + ShipComponentCondition(Float) +} + +pub const min: Float = 0.0 + +pub const max: Float = 1.0 + +pub fn parse(value: Float) -> Result(ShipComponentCondition, Nil) { + case value >=. min && value <=. max { + True -> Ok(ShipComponentCondition(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(ShipComponentCondition) { - decode.float + use value <- decode.then(decode.float) + case parse(value) { + Ok(ship_component_condition) -> decode.success(ship_component_condition) + Error(Nil) -> + decode.failure(ShipComponentCondition(0.0), "ShipComponentCondition") + } +} + +pub fn to_float(ship_component_condition: ShipComponentCondition) -> Float { + let ShipComponentCondition(value) = ship_component_condition + value +} + +pub fn encode(ship_component_condition: ShipComponentCondition) -> Json { + json.float(to_float(ship_component_condition)) } diff --git a/src/models/ship_component_integrity.gleam b/src/models/ship_component_integrity.gleam index d909bc5..e56efb6 100644 --- a/src/models/ship_component_integrity.gleam +++ b/src/models/ship_component_integrity.gleam @@ -1,8 +1,35 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} -pub type ShipComponentIntegrity = - Float +pub opaque type ShipComponentIntegrity { + ShipComponentIntegrity(Float) +} + +pub const min: Float = 0.0 + +pub const max: Float = 1.0 + +pub fn parse(value: Float) -> Result(ShipComponentIntegrity, Nil) { + case value >=. min && value <=. max { + True -> Ok(ShipComponentIntegrity(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(ShipComponentIntegrity) { - decode.float + use value <- decode.then(decode.float) + case parse(value) { + Ok(ship_component_integrity) -> decode.success(ship_component_integrity) + Error(Nil) -> + decode.failure(ShipComponentIntegrity(0.0), "ShipComponentIntegrity") + } +} + +pub fn to_float(ship_component_integrity: ShipComponentIntegrity) -> Float { + let ShipComponentIntegrity(value) = ship_component_integrity + value +} + +pub fn encode(ship_component_integrity: ShipComponentIntegrity) -> Json { + json.float(to_float(ship_component_integrity)) } diff --git a/src/models/ship_component_quality.gleam b/src/models/ship_component_quality.gleam index c8f7ea5..24633af 100644 --- a/src/models/ship_component_quality.gleam +++ b/src/models/ship_component_quality.gleam @@ -1,8 +1,28 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} -pub type ShipComponentQuality = - Float +pub opaque type ShipComponentQuality { + ShipComponentQuality(Int) +} + +pub fn parse(value: Int) -> Result(ShipComponentQuality, Nil) { + Ok(ShipComponentQuality(value)) +} pub fn decoder() -> Decoder(ShipComponentQuality) { - decode.float + use value <- decode.then(decode.int) + case parse(value) { + Ok(ship_component_quality) -> decode.success(ship_component_quality) + Error(Nil) -> + decode.failure(ShipComponentQuality(0), "ShipComponentQuality") + } +} + +pub fn to_int(ship_component_quality: ShipComponentQuality) -> Int { + let ShipComponentQuality(value) = ship_component_quality + value +} + +pub fn encode(ship_component_quality: ShipComponentQuality) -> Json { + json.int(to_int(ship_component_quality)) } diff --git a/src/models/ship_condition_event_symbol.gleam b/src/models/ship_condition_event_symbol.gleam index 4788d13..7b8cf87 100644 --- a/src/models/ship_condition_event_symbol.gleam +++ b/src/models/ship_condition_event_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipConditionEventSymbol { ReactorOverload @@ -31,6 +31,48 @@ pub type ShipConditionEventSymbol { AtmosphericEntryHeat } +pub fn parse(value: String) -> Result(ShipConditionEventSymbol, Nil) { + case value { + "REACTOR_OVERLOAD" -> Ok(ReactorOverload) + "ENERGY_SPIKE_FROM_MINERAL" -> Ok(EnergySpikeFromMineral) + "SOLAR_FLARE_INTERFERENCE" -> Ok(SolarFlareInterference) + "COOLANT_LEAK" -> Ok(CoolantLeak) + "POWER_DISTRIBUTION_FLUCTUATION" -> Ok(PowerDistributionFluctuation) + "MAGNETIC_FIELD_DISRUPTION" -> Ok(MagneticFieldDisruption) + "HULL_MICROMETEORITE_STRIKES" -> Ok(HullMicrometeoriteStrikes) + "STRUCTURAL_STRESS_FRACTURES" -> Ok(StructuralStressFractures) + "CORROSIVE_MINERAL_CONTAMINATION" -> Ok(CorrosiveMineralContamination) + "THERMAL_EXPANSION_MISMATCH" -> Ok(ThermalExpansionMismatch) + "VIBRATION_DAMAGE_FROM_DRILLING" -> Ok(VibrationDamageFromDrilling) + "ELECTROMAGNETIC_FIELD_INTERFERENCE" -> Ok(ElectromagneticFieldInterference) + "IMPACT_WITH_EXTRACTED_DEBRIS" -> Ok(ImpactWithExtractedDebris) + "FUEL_EFFICIENCY_DEGRADATION" -> Ok(FuelEfficiencyDegradation) + "COOLANT_SYSTEM_AGEING" -> Ok(CoolantSystemAgeing) + "DUST_MICROABRASIONS" -> Ok(DustMicroabrasions) + "THRUSTER_NOZZLE_WEAR" -> Ok(ThrusterNozzleWear) + "EXHAUST_PORT_CLOGGING" -> Ok(ExhaustPortClogging) + "BEARING_LUBRICATION_FADE" -> Ok(BearingLubricationFade) + "SENSOR_CALIBRATION_DRIFT" -> Ok(SensorCalibrationDrift) + "HULL_MICROMETEORITE_DAMAGE" -> Ok(HullMicrometeoriteDamage) + "SPACE_DEBRIS_COLLISION" -> Ok(SpaceDebrisCollision) + "THERMAL_STRESS" -> Ok(ThermalStress) + "VIBRATION_OVERLOAD" -> Ok(VibrationOverload) + "PRESSURE_DIFFERENTIAL_STRESS" -> Ok(PressureDifferentialStress) + "ELECTROMAGNETIC_SURGE_EFFECTS" -> Ok(ElectromagneticSurgeEffects) + "ATMOSPHERIC_ENTRY_HEAT" -> Ok(AtmosphericEntryHeat) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipConditionEventSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_condition_event_symbol) -> + decode.success(ship_condition_event_symbol) + Error(Nil) -> decode.failure(ReactorOverload, "ShipConditionEventSymbol") + } +} + pub fn to_string( ship_condition_event_symbol: ShipConditionEventSymbol, ) -> String { @@ -65,41 +107,6 @@ pub fn to_string( } } -pub fn parse( - ship_condition_event_symbol_str: String, -) -> Result(ShipConditionEventSymbol, ShipConditionEventSymbol) { - case ship_condition_event_symbol_str { - "REACTOR_OVERLOAD" -> Ok(ReactorOverload) - "ENERGY_SPIKE_FROM_MINERAL" -> Ok(EnergySpikeFromMineral) - "SOLAR_FLARE_INTERFERENCE" -> Ok(SolarFlareInterference) - "COOLANT_LEAK" -> Ok(CoolantLeak) - "POWER_DISTRIBUTION_FLUCTUATION" -> Ok(PowerDistributionFluctuation) - "MAGNETIC_FIELD_DISRUPTION" -> Ok(MagneticFieldDisruption) - "HULL_MICROMETEORITE_STRIKES" -> Ok(HullMicrometeoriteStrikes) - "STRUCTURAL_STRESS_FRACTURES" -> Ok(StructuralStressFractures) - "CORROSIVE_MINERAL_CONTAMINATION" -> Ok(CorrosiveMineralContamination) - "THERMAL_EXPANSION_MISMATCH" -> Ok(ThermalExpansionMismatch) - "VIBRATION_DAMAGE_FROM_DRILLING" -> Ok(VibrationDamageFromDrilling) - "ELECTROMAGNETIC_FIELD_INTERFERENCE" -> Ok(ElectromagneticFieldInterference) - "IMPACT_WITH_EXTRACTED_DEBRIS" -> Ok(ImpactWithExtractedDebris) - "FUEL_EFFICIENCY_DEGRADATION" -> Ok(FuelEfficiencyDegradation) - "COOLANT_SYSTEM_AGEING" -> Ok(CoolantSystemAgeing) - "DUST_MICROABRASIONS" -> Ok(DustMicroabrasions) - "THRUSTER_NOZZLE_WEAR" -> Ok(ThrusterNozzleWear) - "EXHAUST_PORT_CLOGGING" -> Ok(ExhaustPortClogging) - "BEARING_LUBRICATION_FADE" -> Ok(BearingLubricationFade) - "SENSOR_CALIBRATION_DRIFT" -> Ok(SensorCalibrationDrift) - "HULL_MICROMETEORITE_DAMAGE" -> Ok(HullMicrometeoriteDamage) - "SPACE_DEBRIS_COLLISION" -> Ok(SpaceDebrisCollision) - "THERMAL_STRESS" -> Ok(ThermalStress) - "VIBRATION_OVERLOAD" -> Ok(VibrationOverload) - "PRESSURE_DIFFERENTIAL_STRESS" -> Ok(PressureDifferentialStress) - "ELECTROMAGNETIC_SURGE_EFFECTS" -> Ok(ElectromagneticSurgeEffects) - "ATMOSPHERIC_ENTRY_HEAT" -> Ok(AtmosphericEntryHeat) - _ -> Error(ReactorOverload) - } -} - -pub fn decoder() -> Decoder(ShipConditionEventSymbol) { - decode_utils.enum_decoder(parse, "ShipConditionEventSymbol") +pub fn encode(ship_condition_event_symbol: ShipConditionEventSymbol) -> Json { + json.string(to_string(ship_condition_event_symbol)) } diff --git a/src/models/ship_crew.gleam b/src/models/ship_crew.gleam index 889d6e0..a6783ee 100644 --- a/src/models/ship_crew.gleam +++ b/src/models/ship_crew.gleam @@ -20,11 +20,11 @@ pub fn decoder() -> Decoder(ShipCrew) { use morale <- decode.field("morale", decode.int) use wages <- decode.field("wages", decode.int) decode.success(ShipCrew( - current: current, - required: required, - capacity: capacity, - rotation: rotation, - morale: morale, - wages: wages, + current:, + required:, + capacity:, + rotation:, + morale:, + wages:, )) } diff --git a/src/models/ship_fuel.gleam b/src/models/ship_fuel.gleam index 784ca81..be4f962 100644 --- a/src/models/ship_fuel.gleam +++ b/src/models/ship_fuel.gleam @@ -1,7 +1,6 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} import models/ship_fuel_consumed.{type ShipFuelConsumed} -import utils/decode as decode_utils pub type ShipFuel { ShipFuel(current: Int, capacity: Int, consumed: Option(ShipFuelConsumed)) @@ -10,9 +9,10 @@ pub type ShipFuel { pub fn decoder() -> Decoder(ShipFuel) { use current <- decode.field("current", decode.int) use capacity <- decode.field("capacity", decode.int) - use consumed <- decode_utils.field_key_value_optional( + use consumed <- decode.optional_field( "consumed", - ship_fuel_consumed.decoder(), + option.None, + decode.optional(ship_fuel_consumed.decoder()), ) decode.success(ShipFuel(current:, capacity:, consumed:)) } diff --git a/src/models/ship_fuel_consumed.gleam b/src/models/ship_fuel_consumed.gleam index 673d019..3d4784e 100644 --- a/src/models/ship_fuel_consumed.gleam +++ b/src/models/ship_fuel_consumed.gleam @@ -1,11 +1,13 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} +import utils/api pub type ShipFuelConsumed { - ShipFuelConsumed(amount: Int, timestamp: String) + ShipFuelConsumed(amount: Int, timestamp: Time) } pub fn decoder() -> Decoder(ShipFuelConsumed) { use amount <- decode.field("amount", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(ShipFuelConsumed(amount:, timestamp:)) } diff --git a/src/models/ship_modification_transaction.gleam b/src/models/ship_modification_transaction.gleam index 74bbd5c..fbd3fc1 100644 --- a/src/models/ship_modification_transaction.gleam +++ b/src/models/ship_modification_transaction.gleam @@ -1,7 +1,9 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_symbol.{type ShipSymbol} import models/trade_symbol.{type TradeSymbol} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type ShipModificationTransaction { ShipModificationTransaction( @@ -9,7 +11,7 @@ pub type ShipModificationTransaction { ship_symbol: ShipSymbol, trade_symbol: TradeSymbol, total_price: Int, - timestamp: String, + timestamp: Time, ) } @@ -21,7 +23,7 @@ pub fn decoder() -> Decoder(ShipModificationTransaction) { use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder()) use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder()) use total_price <- decode.field("totalPrice", decode.int) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(ShipModificationTransaction( waypoint_symbol:, ship_symbol:, diff --git a/src/models/ship_module.gleam b/src/models/ship_module.gleam index 8ad1201..e8505a0 100644 --- a/src/models/ship_module.gleam +++ b/src/models/ship_module.gleam @@ -2,7 +2,6 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} import models/module_symbol.{type ModuleSymbol} import models/ship_requirements.{type ShipRequirements} -import utils/decode as decode_utils pub type ShipModule { ShipModule( @@ -19,8 +18,16 @@ pub fn decoder() -> Decoder(ShipModule) { use symbol <- decode.field("symbol", module_symbol.decoder()) use name <- decode.field("name", decode.string) use description <- decode.field("description", decode.string) - use capacity <- decode_utils.field_key_value_optional("capacity", decode.int) - use range <- decode_utils.field_key_value_optional("range", decode.int) + use capacity <- decode.optional_field( + "capacity", + option.None, + decode.optional(decode.int), + ) + use range <- decode.optional_field( + "range", + option.None, + decode.optional(decode.int), + ) use requirements <- decode.field("requirements", ship_requirements.decoder()) decode.success(ShipModule( symbol:, diff --git a/src/models/ship_mount.gleam b/src/models/ship_mount.gleam index ee3afc3..8475d9b 100644 --- a/src/models/ship_mount.gleam +++ b/src/models/ship_mount.gleam @@ -3,7 +3,6 @@ import gleam/option.{type Option} import models/mount_deposit.{type MountDeposit} import models/mount_symbol.{type MountSymbol} import models/ship_requirements.{type ShipRequirements} -import utils/decode as decode_utils pub type ShipMount { ShipMount( @@ -20,10 +19,15 @@ pub fn decoder() -> Decoder(ShipMount) { use symbol <- decode.field("symbol", mount_symbol.decoder()) use name <- decode.field("name", decode.string) use description <- decode.field("description", decode.string) - use strength <- decode_utils.field_key_value_optional("strength", decode.int) - use deposits <- decode_utils.field_key_value_optional( + use strength <- decode.optional_field( + "strength", + option.None, + decode.optional(decode.int), + ) + use deposits <- decode.optional_field( "deposits", - decode.list(mount_deposit.decoder()), + option.None, + decode.optional(decode.list(mount_deposit.decoder())), ) use requirements <- decode.field("requirements", ship_requirements.decoder()) decode.success(ShipMount( diff --git a/src/models/ship_nav_flight_mode.gleam b/src/models/ship_nav_flight_mode.gleam index f5281d3..a540507 100644 --- a/src/models/ship_nav_flight_mode.gleam +++ b/src/models/ship_nav_flight_mode.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipNavFlightMode { Drift @@ -8,6 +8,24 @@ pub type ShipNavFlightMode { Burn } +pub fn parse(value: String) -> Result(ShipNavFlightMode, Nil) { + case value { + "DRIFT" -> Ok(Drift) + "STEALTH" -> Ok(Stealth) + "CRUISE" -> Ok(Cruise) + "BURN" -> Ok(Burn) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipNavFlightMode) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_nav_flight_mode) -> decode.success(ship_nav_flight_mode) + Error(Nil) -> decode.failure(Drift, "ShipNavFlightMode") + } +} + pub fn to_string(ship_nav_flight_mode: ShipNavFlightMode) -> String { case ship_nav_flight_mode { Drift -> "DRIFT" @@ -17,18 +35,6 @@ pub fn to_string(ship_nav_flight_mode: ShipNavFlightMode) -> String { } } -pub fn parse( - ship_nav_flight_mode_str: String, -) -> Result(ShipNavFlightMode, ShipNavFlightMode) { - case ship_nav_flight_mode_str { - "DRIFT" -> Ok(Drift) - "STEALTH" -> Ok(Stealth) - "CRUISE" -> Ok(Cruise) - "BURN" -> Ok(Burn) - _ -> Error(Drift) - } -} - -pub fn decoder() -> Decoder(ShipNavFlightMode) { - decode_utils.enum_decoder(parse, "ShipNavFlightMode") +pub fn encode(ship_nav_flight_mode: ShipNavFlightMode) -> Json { + json.string(to_string(ship_nav_flight_mode)) } diff --git a/src/models/ship_nav_route.gleam b/src/models/ship_nav_route.gleam index d94caa1..cc931a1 100644 --- a/src/models/ship_nav_route.gleam +++ b/src/models/ship_nav_route.gleam @@ -1,12 +1,14 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/ship_nav_route_waypoint.{type ShipNavRouteWaypoint} +import utils/api pub type ShipNavRoute { ShipNavRoute( destination: ShipNavRouteWaypoint, origin: ShipNavRouteWaypoint, - departure_time: String, - arrival: String, + departure_time: Time, + arrival: Time, ) } @@ -16,7 +18,7 @@ pub fn decoder() -> Decoder(ShipNavRoute) { ship_nav_route_waypoint.decoder(), ) use origin <- decode.field("origin", ship_nav_route_waypoint.decoder()) - use departure_time <- decode.field("departureTime", decode.string) - use arrival <- decode.field("arrival", decode.string) + use departure_time <- decode.field("departureTime", api.time_decoder()) + use arrival <- decode.field("arrival", api.time_decoder()) decode.success(ShipNavRoute(destination:, origin:, departure_time:, arrival:)) } diff --git a/src/models/ship_nav_status.gleam b/src/models/ship_nav_status.gleam index ce8a274..3e7cb7a 100644 --- a/src/models/ship_nav_status.gleam +++ b/src/models/ship_nav_status.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipNavStatus { InTransit @@ -7,6 +7,23 @@ pub type ShipNavStatus { Docked } +pub fn parse(value: String) -> Result(ShipNavStatus, Nil) { + case value { + "IN_TRANSIT" -> Ok(InTransit) + "IN_ORBIT" -> Ok(InOrbit) + "DOCKED" -> Ok(Docked) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipNavStatus) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_nav_status) -> decode.success(ship_nav_status) + Error(Nil) -> decode.failure(InTransit, "ShipNavStatus") + } +} + pub fn to_string(ship_nav_status: ShipNavStatus) -> String { case ship_nav_status { InTransit -> "IN_TRANSIT" @@ -15,17 +32,6 @@ pub fn to_string(ship_nav_status: ShipNavStatus) -> String { } } -pub fn parse( - ship_nav_status_str: String, -) -> Result(ShipNavStatus, ShipNavStatus) { - case ship_nav_status_str { - "IN_TRANSIT" -> Ok(InTransit) - "IN_ORBIT" -> Ok(InOrbit) - "DOCKED" -> Ok(Docked) - _ -> Error(InTransit) - } -} - -pub fn decoder() -> Decoder(ShipNavStatus) { - decode_utils.enum_decoder(parse, "ShipNavStatus") +pub fn encode(ship_nav_status: ShipNavStatus) -> Json { + json.string(to_string(ship_nav_status)) } diff --git a/src/models/ship_requirements.gleam b/src/models/ship_requirements.gleam index 3b2326b..1c10fa6 100644 --- a/src/models/ship_requirements.gleam +++ b/src/models/ship_requirements.gleam @@ -1,14 +1,25 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} -import utils/decode as decode_utils pub type ShipRequirements { ShipRequirements(power: Option(Int), crew: Option(Int), slots: Option(Int)) } pub fn decoder() -> Decoder(ShipRequirements) { - use power <- decode_utils.field_key_value_optional("power", decode.int) - use crew <- decode_utils.field_key_value_optional("crew", decode.int) - use slots <- decode_utils.field_key_value_optional("slots", decode.int) + use power <- decode.optional_field( + "power", + option.None, + decode.optional(decode.int), + ) + use crew <- decode.optional_field( + "crew", + option.None, + decode.optional(decode.int), + ) + use slots <- decode.optional_field( + "slots", + option.None, + decode.optional(decode.int), + ) decode.success(ShipRequirements(power:, crew:, slots:)) } diff --git a/src/models/ship_role.gleam b/src/models/ship_role.gleam index 6f7c56c..3d287f6 100644 --- a/src/models/ship_role.gleam +++ b/src/models/ship_role.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipRole { Fabricator @@ -18,6 +18,34 @@ pub type ShipRole { Refinery } +pub fn parse(value: String) -> Result(ShipRole, Nil) { + case value { + "FABRICATOR" -> Ok(Fabricator) + "HARVESTER" -> Ok(Harvester) + "HAULER" -> Ok(Hauler) + "INTERCEPTOR" -> Ok(Interceptor) + "EXCAVATOR" -> Ok(Excavator) + "TRANSPORT" -> Ok(Transport) + "REPAIR" -> Ok(Repair) + "SURVEYOR" -> Ok(Surveyor) + "COMMAND" -> Ok(Command) + "CARRIER" -> Ok(Carrier) + "PATROL" -> Ok(Patrol) + "SATELLITE" -> Ok(Satellite) + "EXPLORER" -> Ok(Explorer) + "REFINERY" -> Ok(Refinery) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipRole) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_role) -> decode.success(ship_role) + Error(Nil) -> decode.failure(Fabricator, "ShipRole") + } +} + pub fn to_string(ship_role: ShipRole) -> String { case ship_role { Fabricator -> "FABRICATOR" @@ -37,26 +65,6 @@ pub fn to_string(ship_role: ShipRole) -> String { } } -pub fn parse(ship_role_str: String) -> Result(ShipRole, ShipRole) { - case ship_role_str { - "FABRICATOR" -> Ok(Fabricator) - "HARVESTER" -> Ok(Harvester) - "HAULER" -> Ok(Hauler) - "INTERCEPTOR" -> Ok(Interceptor) - "EXCAVATOR" -> Ok(Excavator) - "TRANSPORT" -> Ok(Transport) - "REPAIR" -> Ok(Repair) - "SURVEYOR" -> Ok(Surveyor) - "COMMAND" -> Ok(Command) - "CARRIER" -> Ok(Carrier) - "PATROL" -> Ok(Patrol) - "SATELLITE" -> Ok(Satellite) - "EXPLORER" -> Ok(Explorer) - "REFINERY" -> Ok(Refinery) - _ -> Error(Fabricator) - } -} - -pub fn decoder() -> Decoder(ShipRole) { - decode_utils.enum_decoder(parse, "ShipRole") +pub fn encode(ship_role: ShipRole) -> Json { + json.string(to_string(ship_role)) } diff --git a/src/models/ship_symbol.gleam b/src/models/ship_symbol.gleam index 40610db..7b03b11 100644 --- a/src/models/ship_symbol.gleam +++ b/src/models/ship_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type ShipSymbol = - String +pub opaque type ShipSymbol { + ShipSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(ShipSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(ShipSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(ShipSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_symbol) -> decode.success(ship_symbol) + Error(Nil) -> decode.failure(ShipSymbol("invalid"), "ShipSymbol") + } +} + +pub fn to_string(ship_symbol: ShipSymbol) -> String { + let ShipSymbol(symbol) = ship_symbol + symbol +} + +pub fn encode(ship_symbol: ShipSymbol) -> Json { + json.string(to_string(ship_symbol)) } diff --git a/src/models/ship_type.gleam b/src/models/ship_type.gleam index a23919f..b38f5f9 100644 --- a/src/models/ship_type.gleam +++ b/src/models/ship_type.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type ShipType { ShipProbe @@ -9,6 +9,25 @@ pub type ShipType { ShipLightHauler } +pub fn parse(value: String) -> Result(ShipType, Nil) { + case value { + "SHIP_PROBE" -> Ok(ShipProbe) + "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) + "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) + "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) + "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(ShipType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(ship_type) -> decode.success(ship_type) + Error(Nil) -> decode.failure(ShipProbe, "ShipType") + } +} + pub fn to_string(ship_type: ShipType) -> String { case ship_type { ShipProbe -> "SHIP_PROBE" @@ -19,17 +38,6 @@ pub fn to_string(ship_type: ShipType) -> String { } } -pub fn parse(ship_type_str: String) -> Result(ShipType, ShipType) { - case ship_type_str { - "SHIP_PROBE" -> Ok(ShipProbe) - "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) - "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) - "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) - "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) - _ -> Error(ShipProbe) - } -} - -pub fn decoder() -> Decoder(ShipType) { - decode_utils.enum_decoder(parse, "ShipType") +pub fn encode(ship_type: ShipType) -> Json { + json.string(to_string(ship_type)) } diff --git a/src/models/shipyard.gleam b/src/models/shipyard.gleam index 132f09b..b3c8313 100644 --- a/src/models/shipyard.gleam +++ b/src/models/shipyard.gleam @@ -4,7 +4,6 @@ import models/ship_type.{type ShipType} import models/shipyard_ship.{type ShipyardShip} import models/shipyard_symbol.{type ShipyardSymbol} import models/shipyard_transaction.{type ShipyardTransaction} -import utils/decode as decode_utils pub type Shipyard { Shipyard( @@ -17,15 +16,17 @@ pub type Shipyard { } pub fn decoder() -> Decoder(Shipyard) { - use symbol <- decode.field("symbol", decode.string) + use symbol <- decode.field("symbol", shipyard_symbol.decoder()) use ship_types <- decode.field("shipTypes", decode.list(ship_type.decoder())) - use transactions <- decode_utils.field_key_value_optional( + use transactions <- decode.optional_field( "transactions", - decode.list(shipyard_transaction.decoder()), + option.None, + decode.optional(decode.list(shipyard_transaction.decoder())), ) - use ships <- decode_utils.field_key_value_optional( + use ships <- decode.optional_field( "ships", - decode.list(shipyard_ship.decoder()), + option.None, + decode.optional(decode.list(shipyard_ship.decoder())), ) use modifications_fee <- decode.field("modificationsFee", decode.int) decode.success(Shipyard( diff --git a/src/models/shipyard_ship.gleam b/src/models/shipyard_ship.gleam index 2836056..cdad68c 100644 --- a/src/models/shipyard_ship.gleam +++ b/src/models/shipyard_ship.gleam @@ -9,7 +9,6 @@ import models/ship_reactor.{type ShipReactor} import models/ship_type.{type ShipType} import models/shipyard_ship_crew.{type ShipyardShipCrew} import models/supply_level.{type SupplyLevel} -import utils/decode as decode_utils pub type ShipyardShip { ShipyardShip( @@ -32,9 +31,10 @@ pub fn decoder() -> Decoder(ShipyardShip) { use type_ <- decode.field("type", ship_type.decoder()) use name <- decode.field("name", decode.string) use description <- decode.field("description", decode.string) - use activity <- decode_utils.field_key_value_optional( + use activity <- decode.optional_field( "activity", - activity_level.decoder(), + option.None, + decode.optional(activity_level.decoder()), ) use supply <- decode.field("supply", supply_level.decoder()) use purchase_price <- decode.field("purchasePrice", decode.int) diff --git a/src/models/shipyard_symbol.gleam b/src/models/shipyard_symbol.gleam index b6e48f7..f3d3219 100644 --- a/src/models/shipyard_symbol.gleam +++ b/src/models/shipyard_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type ShipyardSymbol = - String +pub opaque type ShipyardSymbol { + ShipyardSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(ShipyardSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(ShipyardSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(ShipyardSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(shipyard_symbol) -> decode.success(shipyard_symbol) + Error(Nil) -> decode.failure(ShipyardSymbol("invalid"), "ShipyardSymbol") + } +} + +pub fn to_string(shipyard_symbol: ShipyardSymbol) -> String { + let ShipyardSymbol(symbol) = shipyard_symbol + symbol +} + +pub fn encode(shipyard_symbol: ShipyardSymbol) -> Json { + json.string(to_string(shipyard_symbol)) } diff --git a/src/models/shipyard_transaction.gleam b/src/models/shipyard_transaction.gleam index 77948e0..cf8d2f4 100644 --- a/src/models/shipyard_transaction.gleam +++ b/src/models/shipyard_transaction.gleam @@ -1,7 +1,9 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import models/agent_symbol.{type AgentSymbol} import models/ship_type.{type ShipType} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type ShipyardTransaction { ShipyardTransaction( @@ -9,7 +11,7 @@ pub type ShipyardTransaction { ship_type: ShipType, price: Int, agent_symbol: AgentSymbol, - timestamp: String, + timestamp: Time, ) } @@ -21,7 +23,7 @@ pub fn decoder() -> Decoder(ShipyardTransaction) { use ship_type <- decode.field("shipType", ship_type.decoder()) use price <- decode.field("price", decode.int) use agent_symbol <- decode.field("agentSymbol", agent_symbol.decoder()) - use timestamp <- decode.field("timestamp", decode.string) + use timestamp <- decode.field("timestamp", api.time_decoder()) decode.success(ShipyardTransaction( waypoint_symbol:, ship_type:, diff --git a/src/models/supply_level.gleam b/src/models/supply_level.gleam index 8d4aae9..b5c68e9 100644 --- a/src/models/supply_level.gleam +++ b/src/models/supply_level.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type SupplyLevel { Scarce @@ -9,6 +9,25 @@ pub type SupplyLevel { Abundant } +pub fn parse(value: String) -> Result(SupplyLevel, Nil) { + case value { + "SCARCE" -> Ok(Scarce) + "LIMITED" -> Ok(Limited) + "MODERATE" -> Ok(Moderate) + "HIGH" -> Ok(High) + "ABUNDANT" -> Ok(Abundant) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(SupplyLevel) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(supply_level) -> decode.success(supply_level) + Error(Nil) -> decode.failure(Scarce, "SupplyLevel") + } +} + pub fn to_string(supply_level: SupplyLevel) -> String { case supply_level { Scarce -> "SCARCE" @@ -19,17 +38,6 @@ pub fn to_string(supply_level: SupplyLevel) -> String { } } -pub fn parse(supply_level_str: String) -> Result(SupplyLevel, SupplyLevel) { - case supply_level_str { - "SCARCE" -> Ok(Scarce) - "LIMITED" -> Ok(Limited) - "MODERATE" -> Ok(Moderate) - "HIGH" -> Ok(High) - "ABUNDANT" -> Ok(Abundant) - _ -> Error(Scarce) - } -} - -pub fn decoder() -> Decoder(SupplyLevel) { - decode_utils.enum_decoder(parse, "SupplyLevel") +pub fn encode(supply_level: SupplyLevel) -> Json { + json.string(to_string(supply_level)) } diff --git a/src/models/survey.gleam b/src/models/survey.gleam index 6c41dc3..6306376 100644 --- a/src/models/survey.gleam +++ b/src/models/survey.gleam @@ -1,30 +1,22 @@ +import birl.{type Time} import gleam/dynamic/decode.{type Decoder} import gleam/json.{type Json} import models/survey_deposit.{type SurveyDeposit} import models/survey_signature.{type SurveySignature} import models/survey_size.{type SurveySize} import models/waypoint_symbol.{type WaypointSymbol} +import utils/api pub type Survey { Survey( signature: SurveySignature, symbol: WaypointSymbol, deposits: List(SurveyDeposit), - expiration: String, + expiration: Time, size: SurveySize, ) } -pub fn encode(data: Survey) -> Json { - json.object([ - #("signature", json.string(data.signature)), - #("symbol", json.string(data.symbol)), - #("deposits", json.array(data.deposits, survey_deposit.encode)), - #("expiration", json.string(data.expiration)), - #("size", survey_size.encode(data.size)), - ]) -} - pub fn decoder() -> Decoder(Survey) { use signature <- decode.field("signature", survey_signature.decoder()) use symbol <- decode.field("symbol", waypoint_symbol.decoder()) @@ -32,7 +24,17 @@ pub fn decoder() -> Decoder(Survey) { "deposits", decode.list(survey_deposit.decoder()), ) - use expiration <- decode.field("expiration", decode.string) + use expiration <- decode.field("expiration", api.time_decoder()) use size <- decode.field("size", survey_size.decoder()) decode.success(Survey(signature:, symbol:, deposits:, expiration:, size:)) } + +pub fn encode(data: Survey) -> Json { + json.object([ + #("signature", survey_signature.encode(data.signature)), + #("symbol", waypoint_symbol.encode(data.symbol)), + #("deposits", json.array(data.deposits, survey_deposit.encode)), + #("expiration", json.string(birl.to_iso8601(data.expiration))), + #("size", survey_size.encode(data.size)), + ]) +} diff --git a/src/models/survey_deposit.gleam b/src/models/survey_deposit.gleam index a97f5c2..a0c042b 100644 --- a/src/models/survey_deposit.gleam +++ b/src/models/survey_deposit.gleam @@ -6,11 +6,11 @@ pub type SurveyDeposit { SurveyDeposit(symbol: TradeSymbol) } -pub fn encode(survey_deposit: SurveyDeposit) -> Json { - json.object([#("symbol", trade_symbol.encode(survey_deposit.symbol))]) -} - pub fn decoder() -> Decoder(SurveyDeposit) { use symbol <- decode.field("symbol", trade_symbol.decoder()) decode.success(SurveyDeposit(symbol:)) } + +pub fn encode(survey_deposit: SurveyDeposit) -> Json { + json.object([#("symbol", trade_symbol.encode(survey_deposit.symbol))]) +} diff --git a/src/models/survey_signature.gleam b/src/models/survey_signature.gleam index 5c2793e..41a329e 100644 --- a/src/models/survey_signature.gleam +++ b/src/models/survey_signature.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type SurveySignature = - String +pub opaque type SurveySignature { + SurveySignature(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(SurveySignature, Nil) { + case string.length(value) >= min_length { + True -> Ok(SurveySignature(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(SurveySignature) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(survey_signature) -> decode.success(survey_signature) + Error(Nil) -> decode.failure(SurveySignature("invalid"), "SurveySignature") + } +} + +pub fn to_string(survey_signature: SurveySignature) -> String { + let SurveySignature(value) = survey_signature + value +} + +pub fn encode(survey_signature: SurveySignature) -> Json { + json.string(to_string(survey_signature)) } diff --git a/src/models/survey_size.gleam b/src/models/survey_size.gleam index afdde04..097f2a2 100644 --- a/src/models/survey_size.gleam +++ b/src/models/survey_size.gleam @@ -1,6 +1,5 @@ import gleam/dynamic/decode.{type Decoder} import gleam/json.{type Json} -import utils/decode as decode_utils pub type SurveySize { Small @@ -8,6 +7,23 @@ pub type SurveySize { Large } +pub fn parse(value: String) -> Result(SurveySize, Nil) { + case value { + "SMALL" -> Ok(Small) + "MODERATE" -> Ok(Moderate) + "LARGE" -> Ok(Large) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(SurveySize) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(survey_size) -> decode.success(survey_size) + Error(Nil) -> decode.failure(Small, "SurveySize") + } +} + pub fn to_string(survey_size: SurveySize) -> String { case survey_size { Small -> "SMALL" @@ -16,19 +32,6 @@ pub fn to_string(survey_size: SurveySize) -> String { } } -pub fn parse(survey_size_str: String) -> Result(SurveySize, SurveySize) { - case survey_size_str { - "SMALL" -> Ok(Small) - "MODERATE" -> Ok(Moderate) - "LARGE" -> Ok(Large) - _ -> Error(Small) - } -} - pub fn encode(survey_size: SurveySize) -> Json { json.string(to_string(survey_size)) } - -pub fn decoder() -> Decoder(SurveySize) { - decode_utils.enum_decoder(parse, "SurveySize") -} diff --git a/src/models/system.gleam b/src/models/system.gleam index 1aa39d7..aa0d229 100644 --- a/src/models/system.gleam +++ b/src/models/system.gleam @@ -1,16 +1,17 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option.{type Option} +import models/constellation.{type Constellation} +import models/sector_symbol.{type SectorSymbol} import models/system_faction.{type SystemFaction} import models/system_symbol.{type SystemSymbol} import models/system_type.{type SystemType} import models/system_waypoint.{type SystemWaypoint} -import utils/decode as decode_utils pub type System { System( - constellation: Option(String), + constellation: Option(Constellation), symbol: SystemSymbol, - sector_symbol: String, + sector_symbol: SectorSymbol, type_: SystemType, x: Int, y: Int, @@ -24,10 +25,10 @@ pub fn decoder() -> Decoder(System) { use constellation <- decode.optional_field( "constellation", option.None, - decode.optional(decode.string), + decode.optional(constellation.decoder()), ) - use symbol <- decode.field("symbol", decode.string) - use sector_symbol <- decode.field("sectorSymbol", decode.string) + use symbol <- decode.field("symbol", system_symbol.decoder()) + use sector_symbol <- decode.field("sectorSymbol", sector_symbol.decoder()) use type_ <- decode.field("type", system_type.decoder()) use x <- decode.field("x", decode.int) use y <- decode.field("y", decode.int) @@ -39,7 +40,11 @@ pub fn decoder() -> Decoder(System) { "factions", decode.list(system_faction.decoder()), ) - use name <- decode_utils.field_key_value_optional("name", decode.string) + use name <- decode.optional_field( + "name", + option.None, + decode.optional(decode.string), + ) decode.success(System( constellation:, symbol:, diff --git a/src/models/system_symbol.gleam b/src/models/system_symbol.gleam index b93eced..79a0a6a 100644 --- a/src/models/system_symbol.gleam +++ b/src/models/system_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type SystemSymbol = - String +pub opaque type SystemSymbol { + SystemSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(SystemSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(SystemSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(SystemSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(system_symbol) -> decode.success(system_symbol) + Error(Nil) -> decode.failure(SystemSymbol("invalid"), "SystemSymbol") + } +} + +pub fn to_string(system_symbol: SystemSymbol) -> String { + let SystemSymbol(symbol) = system_symbol + symbol +} + +pub fn encode(system_symbol: SystemSymbol) -> Json { + json.string(to_string(system_symbol)) } diff --git a/src/models/system_type.gleam b/src/models/system_type.gleam index 608f224..3060089 100644 --- a/src/models/system_type.gleam +++ b/src/models/system_type.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type SystemType { NeutronStar @@ -14,6 +14,30 @@ pub type SystemType { Unstable } +pub fn parse(value: String) -> Result(SystemType, Nil) { + case value { + "NEUTRON_STAR" -> Ok(NeutronStar) + "RED_STAR" -> Ok(RedStar) + "ORANGE_STAR" -> Ok(OrangeStar) + "BLUE_STAR" -> Ok(BlueStar) + "YOUNG_STAR" -> Ok(YoungStar) + "WHITE_DWARF" -> Ok(WhiteDwarf) + "BLACK_HOLE" -> Ok(BlackHole) + "HYPERGIANT" -> Ok(Hypergiant) + "NEBULA" -> Ok(Nebula) + "UNSTABLE" -> Ok(Unstable) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(SystemType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(system_type) -> decode.success(system_type) + Error(Nil) -> decode.failure(NeutronStar, "SystemType") + } +} + pub fn to_string(system_type: SystemType) -> String { case system_type { NeutronStar -> "NEUTRON_STAR" @@ -29,22 +53,6 @@ pub fn to_string(system_type: SystemType) -> String { } } -pub fn parse(system_type_str: String) -> Result(SystemType, SystemType) { - case system_type_str { - "NEUTRON_STAR" -> Ok(NeutronStar) - "RED_STAR" -> Ok(RedStar) - "ORANGE_STAR" -> Ok(OrangeStar) - "BLUE_STAR" -> Ok(BlueStar) - "YOUNG_STAR" -> Ok(YoungStar) - "WHITE_DWARF" -> Ok(WhiteDwarf) - "BLACK_HOLE" -> Ok(BlackHole) - "HYPERGIANT" -> Ok(Hypergiant) - "NEBULA" -> Ok(Nebula) - "UNSTABLE" -> Ok(Unstable) - _ -> Ok(NeutronStar) - } -} - -pub fn decoder() -> Decoder(SystemType) { - decode_utils.enum_decoder(parse, "SystemType") +pub fn encode(system_type: SystemType) -> Json { + json.string(to_string(system_type)) } diff --git a/src/models/system_waypoint.gleam b/src/models/system_waypoint.gleam index 7d9844f..27b771a 100644 --- a/src/models/system_waypoint.gleam +++ b/src/models/system_waypoint.gleam @@ -3,7 +3,6 @@ import gleam/option.{type Option} import models/waypoint_orbital.{type WaypointOrbital} import models/waypoint_symbol.{type WaypointSymbol} import models/waypoint_type.{type WaypointType} -import utils/decode as decode_utils pub type SystemWaypoint { SystemWaypoint( @@ -12,7 +11,7 @@ pub type SystemWaypoint { x: Int, y: Int, orbitals: List(WaypointOrbital), - orbits: Option(String), + orbits: Option(WaypointSymbol), ) } @@ -25,6 +24,10 @@ pub fn decoder() -> Decoder(SystemWaypoint) { "orbitals", decode.list(waypoint_orbital.decoder()), ) - use orbits <- decode_utils.field_key_value_optional("orbits", decode.string) + use orbits <- decode.optional_field( + "orbits", + option.None, + decode.optional(waypoint_symbol.decoder()), + ) decode.success(SystemWaypoint(symbol:, type_:, x:, y:, orbitals:, orbits:)) } diff --git a/src/models/trade_good_type.gleam b/src/models/trade_good_type.gleam index 4c5f84b..21fcc30 100644 --- a/src/models/trade_good_type.gleam +++ b/src/models/trade_good_type.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type TradeGoodType { Import @@ -7,6 +7,23 @@ pub type TradeGoodType { Exchange } +pub fn parse(value: String) -> Result(TradeGoodType, Nil) { + case value { + "IMPORT" -> Ok(Import) + "EXPORT" -> Ok(Export) + "EXCHANGE" -> Ok(Exchange) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(TradeGoodType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(trade_good_type) -> decode.success(trade_good_type) + Error(Nil) -> decode.failure(Import, "TradeGoodType") + } +} + pub fn to_string(trade_good_type: TradeGoodType) -> String { case trade_good_type { Import -> "IMPORT" @@ -15,17 +32,6 @@ pub fn to_string(trade_good_type: TradeGoodType) -> String { } } -pub fn parse( - trade_good_type_str: String, -) -> Result(TradeGoodType, TradeGoodType) { - case trade_good_type_str { - "IMPORT" -> Ok(Import) - "EXPORT" -> Ok(Export) - "EXCHANGE" -> Ok(Exchange) - _ -> Error(Import) - } -} - -pub fn decoder() -> Decoder(TradeGoodType) { - decode_utils.enum_decoder(parse, "TradeGoodType") +pub fn encode(trade_good_type: TradeGoodType) -> Json { + json.string(to_string(trade_good_type)) } diff --git a/src/models/trade_symbol.gleam b/src/models/trade_symbol.gleam index 7807e93..05719a1 100644 --- a/src/models/trade_symbol.gleam +++ b/src/models/trade_symbol.gleam @@ -1,6 +1,5 @@ import gleam/dynamic/decode.{type Decoder} import gleam/json.{type Json} -import utils/decode as decode_utils pub type TradeSymbol { PreciousStones @@ -98,7 +97,7 @@ pub type TradeSymbol { ReactorAntimatterI EngineImpulseDriveI EngineIonDriveI - EngineIonDriveIi + EngineIonDriveII EngineHyperDriveI ModuleMineralProcessorI ModuleGasProcessorI @@ -150,6 +149,165 @@ pub type TradeSymbol { ShipBulkFreighter } +pub fn parse(value: String) -> Result(TradeSymbol, Nil) { + case value { + "PRECIOUS_STONES" -> Ok(PreciousStones) + "QUARTZ_SAND" -> Ok(QuartzSand) + "SILICON_CRYSTALS" -> Ok(SiliconCrystals) + "AMMONIA_ICE" -> Ok(AmmoniaIce) + "LIQUID_HYDROGEN" -> Ok(LiquidHydrogen) + "LIQUID_NITROGEN" -> Ok(LiquidNitrogen) + "ICE_WATER" -> Ok(IceWater) + "EXOTIC_MATTER" -> Ok(ExoticMatter) + "ADVANCED_CIRCUITRY" -> Ok(AdvancedCircuitry) + "GRAVITON_EMITTERS" -> Ok(GravitonEmitters) + "IRON" -> Ok(Iron) + "IRON_ORE" -> Ok(IronOre) + "COPPER" -> Ok(Copper) + "COPPER_ORE" -> Ok(CopperOre) + "ALUMINUM" -> Ok(Aluminum) + "ALUMINUM_ORE" -> Ok(AluminumOre) + "SILVER" -> Ok(Silver) + "SILVER_ORE" -> Ok(SilverOre) + "GOLD" -> Ok(Gold) + "GOLD_ORE" -> Ok(GoldOre) + "PLATINUM" -> Ok(Platinum) + "PLATINUM_ORE" -> Ok(PlatinumOre) + "DIAMONDS" -> Ok(Diamonds) + "URANITE" -> Ok(Uranite) + "URANITE_ORE" -> Ok(UraniteOre) + "MERITIUM" -> Ok(Meritium) + "MERITIUM_ORE" -> Ok(MeritiumOre) + "HYDROCARBON" -> Ok(Hydrocarbon) + "ANTIMATTER" -> Ok(Antimatter) + "FAB_MATS" -> Ok(FabMats) + "FERTILIZERS" -> Ok(Fertilizers) + "FABRICS" -> Ok(Fabrics) + "FOOD" -> Ok(Food) + "JEWELRY" -> Ok(Jewelry) + "MACHINERY" -> Ok(Machinery) + "FIREARMS" -> Ok(Firearms) + "ASSAULT_RIFLES" -> Ok(AssaultRifles) + "MILITARY_EQUIPMENT" -> Ok(MilitaryEquipment) + "EXPLOSIVES" -> Ok(Explosives) + "LAB_INSTRUMENTS" -> Ok(LabInstruments) + "AMMUNITION" -> Ok(Ammunition) + "ELECTRONICS" -> Ok(Electronics) + "SHIP_PLATING" -> Ok(ShipPlating) + "SHIP_PARTS" -> Ok(ShipParts) + "EQUIPMENT" -> Ok(Equipment) + "FUEL" -> Ok(Fuel) + "MEDICINE" -> Ok(Medicine) + "DRUGS" -> Ok(Drugs) + "CLOTHING" -> Ok(Clothing) + "MICROPROCESSORS" -> Ok(Microprocessors) + "PLASTICS" -> Ok(Plastics) + "POLYNUCLEOTIDES" -> Ok(Polynucleotides) + "BIOCOMPOSITES" -> Ok(Biocomposites) + "QUANTUM_STABILIZERS" -> Ok(QuantumStabilizers) + "NANOBOTS" -> Ok(Nanobots) + "AI_MAINFRAMES" -> Ok(AiMainframes) + "QUANTUM_DRIVES" -> Ok(QuantumDrives) + "ROBOTIC_DRONES" -> Ok(RoboticDrones) + "CYBER_IMPLANTS" -> Ok(CyberImplants) + "GENE_THERAPEUTICS" -> Ok(GeneTherapeutics) + "NEURAL_CHIPS" -> Ok(NeuralChips) + "MOOD_REGULATORS" -> Ok(MoodRegulators) + "VIRAL_AGENTS" -> Ok(ViralAgents) + "MICRO_FUSION_GENERATORS" -> Ok(MicroFusionGenerators) + "SUPERGRAINS" -> Ok(Supergrains) + "LASER_RIFLES" -> Ok(LaserRifles) + "HOLOGRAPHICS" -> Ok(Holographics) + "SHIP_SALVAGE" -> Ok(ShipSalvage) + "RELIC_TECH" -> Ok(RelicTech) + "NOVEL_LIFEFORMS" -> Ok(NovelLifeforms) + "BOTANICAL_SPECIMENS" -> Ok(BotanicalSpecimens) + "CULTURAL_ARTIFACTS" -> Ok(CulturalArtifacts) + "FRAME_PROBE" -> Ok(FrameProbe) + "FRAME_DRONE" -> Ok(FrameDrone) + "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) + "FRAME_RACER" -> Ok(FrameRacer) + "FRAME_FIGHTER" -> Ok(FrameFighter) + "FRAME_FRIGATE" -> Ok(FrameFrigate) + "FRAME_SHUTTLE" -> Ok(FrameShuttle) + "FRAME_EXPLORER" -> Ok(FrameExplorer) + "FRAME_MINER" -> Ok(FrameMiner) + "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) + "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) + "FRAME_TRANSPORT" -> Ok(FrameTransport) + "FRAME_DESTROYER" -> Ok(FrameDestroyer) + "FRAME_CRUISER" -> Ok(FrameCruiser) + "FRAME_CARRIER" -> Ok(FrameCarrier) + "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) + "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) + "REACTOR_FUSION_I" -> Ok(ReactorFusionI) + "REACTOR_FISSION_I" -> Ok(ReactorFissionI) + "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) + "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) + "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) + "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) + "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveII) + "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) + "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) + "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) + "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) + "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) + "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) + "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) + "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) + "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) + "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) + "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) + "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) + "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) + "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) + "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) + "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) + "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) + "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) + "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) + "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) + "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) + "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) + "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) + "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) + "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) + "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) + "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) + "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) + "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) + "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) + "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) + "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) + "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) + "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) + "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) + "MOUNT_TURRET_I" -> Ok(MountTurretI) + "SHIP_PROBE" -> Ok(ShipProbe) + "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) + "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) + "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) + "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) + "SHIP_COMMAND_FRIGATE" -> Ok(ShipCommandFrigate) + "SHIP_EXPLORER" -> Ok(ShipExplorer) + "SHIP_HEAVY_FREIGHTER" -> Ok(ShipHeavyFreighter) + "SHIP_LIGHT_SHUTTLE" -> Ok(ShipLightShuttle) + "SHIP_ORE_HOUND" -> Ok(ShipOreHound) + "SHIP_REFINING_FREIGHTER" -> Ok(ShipRefiningFreighter) + "SHIP_SURVEYOR" -> Ok(ShipSurveyor) + "SHIP_BULK_FREIGHTER" -> Ok(ShipBulkFreighter) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(TradeSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(trade_symbol) -> decode.success(trade_symbol) + Error(Nil) -> decode.failure(PreciousStones, "TradeSymbol") + } +} + pub fn to_string(trade_symbol: TradeSymbol) -> String { case trade_symbol { PreciousStones -> "PRECIOUS_STONES" @@ -247,7 +405,7 @@ pub fn to_string(trade_symbol: TradeSymbol) -> String { ReactorAntimatterI -> "REACTOR_ANTIMATTER_I" EngineImpulseDriveI -> "ENGINE_IMPULSE_DRIVE_I" EngineIonDriveI -> "ENGINE_ION_DRIVE_I" - EngineIonDriveIi -> "ENGINE_ION_DRIVE_II" + EngineIonDriveII -> "ENGINE_ION_DRIVE_II" EngineHyperDriveI -> "ENGINE_HYPER_DRIVE_I" ModuleMineralProcessorI -> "MODULE_MINERAL_PROCESSOR_I" ModuleGasProcessorI -> "MODULE_GAS_PROCESSOR_I" @@ -300,161 +458,6 @@ pub fn to_string(trade_symbol: TradeSymbol) -> String { } } -pub fn parse(trade_symbol_str: String) -> Result(TradeSymbol, TradeSymbol) { - case trade_symbol_str { - "PRECIOUS_STONES" -> Ok(PreciousStones) - "QUARTZ_SAND" -> Ok(QuartzSand) - "SILICON_CRYSTALS" -> Ok(SiliconCrystals) - "AMMONIA_ICE" -> Ok(AmmoniaIce) - "LIQUID_HYDROGEN" -> Ok(LiquidHydrogen) - "LIQUID_NITROGEN" -> Ok(LiquidNitrogen) - "ICE_WATER" -> Ok(IceWater) - "EXOTIC_MATTER" -> Ok(ExoticMatter) - "ADVANCED_CIRCUITRY" -> Ok(AdvancedCircuitry) - "GRAVITON_EMITTERS" -> Ok(GravitonEmitters) - "IRON" -> Ok(Iron) - "IRON_ORE" -> Ok(IronOre) - "COPPER" -> Ok(Copper) - "COPPER_ORE" -> Ok(CopperOre) - "ALUMINUM" -> Ok(Aluminum) - "ALUMINUM_ORE" -> Ok(AluminumOre) - "SILVER" -> Ok(Silver) - "SILVER_ORE" -> Ok(SilverOre) - "GOLD" -> Ok(Gold) - "GOLD_ORE" -> Ok(GoldOre) - "PLATINUM" -> Ok(Platinum) - "PLATINUM_ORE" -> Ok(PlatinumOre) - "DIAMONDS" -> Ok(Diamonds) - "URANITE" -> Ok(Uranite) - "URANITE_ORE" -> Ok(UraniteOre) - "MERITIUM" -> Ok(Meritium) - "MERITIUM_ORE" -> Ok(MeritiumOre) - "HYDROCARBON" -> Ok(Hydrocarbon) - "ANTIMATTER" -> Ok(Antimatter) - "FAB_MATS" -> Ok(FabMats) - "FERTILIZERS" -> Ok(Fertilizers) - "FABRICS" -> Ok(Fabrics) - "FOOD" -> Ok(Food) - "JEWELRY" -> Ok(Jewelry) - "MACHINERY" -> Ok(Machinery) - "FIREARMS" -> Ok(Firearms) - "ASSAULT_RIFLES" -> Ok(AssaultRifles) - "MILITARY_EQUIPMENT" -> Ok(MilitaryEquipment) - "EXPLOSIVES" -> Ok(Explosives) - "LAB_INSTRUMENTS" -> Ok(LabInstruments) - "AMMUNITION" -> Ok(Ammunition) - "ELECTRONICS" -> Ok(Electronics) - "SHIP_PLATING" -> Ok(ShipPlating) - "SHIP_PARTS" -> Ok(ShipParts) - "EQUIPMENT" -> Ok(Equipment) - "FUEL" -> Ok(Fuel) - "MEDICINE" -> Ok(Medicine) - "DRUGS" -> Ok(Drugs) - "CLOTHING" -> Ok(Clothing) - "MICROPROCESSORS" -> Ok(Microprocessors) - "PLASTICS" -> Ok(Plastics) - "POLYNUCLEOTIDES" -> Ok(Polynucleotides) - "BIOCOMPOSITES" -> Ok(Biocomposites) - "QUANTUM_STABILIZERS" -> Ok(QuantumStabilizers) - "NANOBOTS" -> Ok(Nanobots) - "AI_MAINFRAMES" -> Ok(AiMainframes) - "QUANTUM_DRIVES" -> Ok(QuantumDrives) - "ROBOTIC_DRONES" -> Ok(RoboticDrones) - "CYBER_IMPLANTS" -> Ok(CyberImplants) - "GENE_THERAPEUTICS" -> Ok(GeneTherapeutics) - "NEURAL_CHIPS" -> Ok(NeuralChips) - "MOOD_REGULATORS" -> Ok(MoodRegulators) - "VIRAL_AGENTS" -> Ok(ViralAgents) - "MICRO_FUSION_GENERATORS" -> Ok(MicroFusionGenerators) - "SUPERGRAINS" -> Ok(Supergrains) - "LASER_RIFLES" -> Ok(LaserRifles) - "HOLOGRAPHICS" -> Ok(Holographics) - "SHIP_SALVAGE" -> Ok(ShipSalvage) - "RELIC_TECH" -> Ok(RelicTech) - "NOVEL_LIFEFORMS" -> Ok(NovelLifeforms) - "BOTANICAL_SPECIMENS" -> Ok(BotanicalSpecimens) - "CULTURAL_ARTIFACTS" -> Ok(CulturalArtifacts) - "FRAME_PROBE" -> Ok(FrameProbe) - "FRAME_DRONE" -> Ok(FrameDrone) - "FRAME_INTERCEPTOR" -> Ok(FrameInterceptor) - "FRAME_RACER" -> Ok(FrameRacer) - "FRAME_FIGHTER" -> Ok(FrameFighter) - "FRAME_FRIGATE" -> Ok(FrameFrigate) - "FRAME_SHUTTLE" -> Ok(FrameShuttle) - "FRAME_EXPLORER" -> Ok(FrameExplorer) - "FRAME_MINER" -> Ok(FrameMiner) - "FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter) - "FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter) - "FRAME_TRANSPORT" -> Ok(FrameTransport) - "FRAME_DESTROYER" -> Ok(FrameDestroyer) - "FRAME_CRUISER" -> Ok(FrameCruiser) - "FRAME_CARRIER" -> Ok(FrameCarrier) - "FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter) - "REACTOR_SOLAR_I" -> Ok(ReactorSolarI) - "REACTOR_FUSION_I" -> Ok(ReactorFusionI) - "REACTOR_FISSION_I" -> Ok(ReactorFissionI) - "REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI) - "REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI) - "ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI) - "ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI) - "ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveIi) - "ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI) - "MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI) - "MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI) - "MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI) - "MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII) - "MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII) - "MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI) - "MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI) - "MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI) - "MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI) - "MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI) - "MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI) - "MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII) - "MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII) - "MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI) - "MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII) - "MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII) - "MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI) - "MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII) - "MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI) - "MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI) - "MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI) - "MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII) - "MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII) - "MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI) - "MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII) - "MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII) - "MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI) - "MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII) - "MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII) - "MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI) - "MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII) - "MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII) - "MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI) - "MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI) - "MOUNT_TURRET_I" -> Ok(MountTurretI) - "SHIP_PROBE" -> Ok(ShipProbe) - "SHIP_MINING_DRONE" -> Ok(ShipMiningDrone) - "SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone) - "SHIP_INTERCEPTOR" -> Ok(ShipInterceptor) - "SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler) - "SHIP_COMMAND_FRIGATE" -> Ok(ShipCommandFrigate) - "SHIP_EXPLORER" -> Ok(ShipExplorer) - "SHIP_HEAVY_FREIGHTER" -> Ok(ShipHeavyFreighter) - "SHIP_LIGHT_SHUTTLE" -> Ok(ShipLightShuttle) - "SHIP_ORE_HOUND" -> Ok(ShipOreHound) - "SHIP_REFINING_FREIGHTER" -> Ok(ShipRefiningFreighter) - "SHIP_SURVEYOR" -> Ok(ShipSurveyor) - "SHIP_BULK_FREIGHTER" -> Ok(ShipBulkFreighter) - _ -> Error(PreciousStones) - } -} - pub fn encode(trade_symbol: TradeSymbol) -> Json { json.string(to_string(trade_symbol)) } - -pub fn decoder() -> Decoder(TradeSymbol) { - decode_utils.enum_decoder(parse, "TradeSymbol") -} diff --git a/src/models/transaction_type.gleam b/src/models/transaction_type.gleam index b449d2b..b2d8abb 100644 --- a/src/models/transaction_type.gleam +++ b/src/models/transaction_type.gleam @@ -1,11 +1,27 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type TransactionType { Purchase Sell } +pub fn parse(value: String) -> Result(TransactionType, Nil) { + case value { + "PURCHASE" -> Ok(Purchase) + "SELL" -> Ok(Sell) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(TransactionType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(transaction_type) -> decode.success(transaction_type) + Error(Nil) -> decode.failure(Purchase, "TransactionType") + } +} + pub fn to_string(transaction_type: TransactionType) -> String { case transaction_type { Purchase -> "PURCHASE" @@ -13,16 +29,6 @@ pub fn to_string(transaction_type: TransactionType) -> String { } } -pub fn parse( - transaction_type_str: String, -) -> Result(TransactionType, TransactionType) { - case transaction_type_str { - "PURCHASE" -> Ok(Purchase) - "SELL" -> Ok(Sell) - _ -> Error(Purchase) - } -} - -pub fn decoder() -> Decoder(TransactionType) { - decode_utils.enum_decoder(parse, "TransactionType") +pub fn encode(transaction_type: TransactionType) -> Json { + json.string(to_string(transaction_type)) } diff --git a/src/models/waypoint.gleam b/src/models/waypoint.gleam index 069960d..a3b29b3 100644 --- a/src/models/waypoint.gleam +++ b/src/models/waypoint.gleam @@ -8,7 +8,6 @@ import models/waypoint_orbital.{type WaypointOrbital} import models/waypoint_symbol.{type WaypointSymbol} import models/waypoint_trait.{type WaypointTrait} import models/waypoint_type.{type WaypointType} -import utils/decode as decode_utils pub type Waypoint { Waypoint( @@ -18,7 +17,7 @@ pub type Waypoint { x: Int, y: Int, orbitals: List(WaypointOrbital), - orbits: Option(String), + orbits: Option(WaypointSymbol), faction: Option(WaypointFaction), traits: List(WaypointTrait), modifiers: Option(List(WaypointModifier)), @@ -37,16 +36,26 @@ pub fn decoder() -> Decoder(Waypoint) { "orbitals", decode.list(waypoint_orbital.decoder()), ) - use orbits <- decode_utils.field_key_value_optional("orbits", decode.string) - use chart <- decode_utils.field_key_value_optional("chart", chart.decoder()) - use faction <- decode_utils.field_key_value_optional( + use orbits <- decode.optional_field( + "orbits", + option.None, + decode.optional(waypoint_symbol.decoder()), + ) + use chart <- decode.optional_field( + "chart", + option.None, + decode.optional(chart.decoder()), + ) + use faction <- decode.optional_field( "faction", - waypoint_faction.decoder(), + option.None, + decode.optional(waypoint_faction.decoder()), ) use traits <- decode.field("traits", decode.list(waypoint_trait.decoder())) - use modifiers <- decode_utils.field_key_value_optional( + use modifiers <- decode.optional_field( "modifiers", - decode.list(waypoint_modifier.decoder()), + option.None, + decode.optional(decode.list(waypoint_modifier.decoder())), ) use is_under_construction <- decode.field("isUnderConstruction", decode.bool) decode.success(Waypoint( diff --git a/src/models/waypoint_modifier_symbol.gleam b/src/models/waypoint_modifier_symbol.gleam index b8257d3..f75da52 100644 --- a/src/models/waypoint_modifier_symbol.gleam +++ b/src/models/waypoint_modifier_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type WaypointModifierSymbol { Stripped @@ -9,6 +9,25 @@ pub type WaypointModifierSymbol { CivilUnrest } +pub fn parse(value: String) -> Result(WaypointModifierSymbol, Nil) { + case value { + "STRIPPED" -> Ok(Stripped) + "UNSTABLE" -> Ok(Unstable) + "RADIATION_LEAK" -> Ok(RadiationLeak) + "CRITICAL_LIMIT" -> Ok(CriticalLimit) + "CIVIL_UNREST" -> Ok(CivilUnrest) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(WaypointModifierSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(waypoint_modifier_symbol) -> decode.success(waypoint_modifier_symbol) + Error(Nil) -> decode.failure(Stripped, "WaypointModifierSymbol") + } +} + pub fn to_string(waypoint_modifier_symbol: WaypointModifierSymbol) -> String { case waypoint_modifier_symbol { Stripped -> "STRIPPED" @@ -19,19 +38,6 @@ pub fn to_string(waypoint_modifier_symbol: WaypointModifierSymbol) -> String { } } -pub fn parse( - waypoint_modifier_symbol_str: String, -) -> Result(WaypointModifierSymbol, WaypointModifierSymbol) { - case waypoint_modifier_symbol_str { - "STRIPPED" -> Ok(Stripped) - "UNSTABLE" -> Ok(Unstable) - "RADIATION_LEAK" -> Ok(RadiationLeak) - "CRITICAL_LIMIT" -> Ok(CriticalLimit) - "CIVIL_UNREST" -> Ok(CivilUnrest) - _ -> Error(Stripped) - } -} - -pub fn decoder() -> Decoder(WaypointModifierSymbol) { - decode_utils.enum_decoder(parse, "WaypointModifierSymbol") +pub fn encode(waypoint_modifier_symbol: WaypointModifierSymbol) -> Json { + json.string(to_string(waypoint_modifier_symbol)) } diff --git a/src/models/waypoint_symbol.gleam b/src/models/waypoint_symbol.gleam index 7482cd0..30279c1 100644 --- a/src/models/waypoint_symbol.gleam +++ b/src/models/waypoint_symbol.gleam @@ -1,8 +1,33 @@ import gleam/dynamic/decode.{type Decoder} +import gleam/json.{type Json} +import gleam/string -pub type WaypointSymbol = - String +pub opaque type WaypointSymbol { + WaypointSymbol(String) +} + +pub const min_length: Int = 1 + +pub fn parse(value: String) -> Result(WaypointSymbol, Nil) { + case string.length(value) >= min_length { + True -> Ok(WaypointSymbol(value)) + False -> Error(Nil) + } +} pub fn decoder() -> Decoder(WaypointSymbol) { - decode.string + use value <- decode.then(decode.string) + case parse(value) { + Ok(waypoint_symbol) -> decode.success(waypoint_symbol) + Error(Nil) -> decode.failure(WaypointSymbol("invalid"), "WaypointSymbol") + } +} + +pub fn to_string(waypoint_symbol: WaypointSymbol) -> String { + let WaypointSymbol(symbol) = waypoint_symbol + symbol +} + +pub fn encode(waypoint_symbol: WaypointSymbol) -> Json { + json.string(to_string(waypoint_symbol)) } diff --git a/src/models/waypoint_trait_symbol.gleam b/src/models/waypoint_trait_symbol.gleam index bc570e6..9ba5723 100644 --- a/src/models/waypoint_trait_symbol.gleam +++ b/src/models/waypoint_trait_symbol.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type WaypointTraitSymbol { Uncharted @@ -73,6 +73,89 @@ pub type WaypointTraitSymbol { Stripped } +pub fn parse(value: String) -> Result(WaypointTraitSymbol, Nil) { + case value { + "UNCHARTED" -> Ok(Uncharted) + "UNDER_CONSTRUCTION" -> Ok(UnderConstruction) + "MARKETPLACE" -> Ok(Marketplace) + "SHIPYARD" -> Ok(Shipyard) + "OUTPOST" -> Ok(Outpost) + "SCATTERED_SETTLEMENTS" -> Ok(ScatteredSettlements) + "SPRAWLING_CITIES" -> Ok(SprawlingCities) + "MEGA_STRUCTURES" -> Ok(MegaStructures) + "PIRATE_BASE" -> Ok(PirateBase) + "OVERCROWDED" -> Ok(Overcrowded) + "HIGH_TECH" -> Ok(HighTech) + "CORRUPT" -> Ok(Corrupt) + "BUREAUCRATIC" -> Ok(Bureaucratic) + "TRADING_HUB" -> Ok(TradingHub) + "INDUSTRIAL" -> Ok(Industrial) + "BLACK_MARKET" -> Ok(BlackMarket) + "RESEARCH_FACILITY" -> Ok(ResearchFacility) + "MILITARY_BASE" -> Ok(MilitaryBase) + "SURVEILLANCE_OUTPOST" -> Ok(SurveillanceOutpost) + "EXPLORATION_OUTPOST" -> Ok(ExplorationOutpost) + "MINERAL_DEPOSITS" -> Ok(MineralDeposits) + "COMMON_METAL_DEPOSITS" -> Ok(CommonMetalDeposits) + "PRECIOUS_METAL_DEPOSITS" -> Ok(PreciousMetalDeposits) + "RARE_METAL_DEPOSITS" -> Ok(RareMetalDeposits) + "METHANE_POOLS" -> Ok(MethanePools) + "ICE_CRYSTALS" -> Ok(IceCrystals) + "EXPLOSIVE_GASES" -> Ok(ExplosiveGases) + "STRONG_MAGNETOSPHERE" -> Ok(StrongMagnetosphere) + "VIBRANT_AURORAS" -> Ok(VibrantAuroras) + "SALT_FLATS" -> Ok(SaltFlats) + "CANYONS" -> Ok(Canyons) + "PERPETUAL_DAYLIGHT" -> Ok(PerpetualDaylight) + "PERPETUAL_OVERCAST" -> Ok(PerpetualOvercast) + "DRY_SEABEDS" -> Ok(DrySeabeds) + "MAGMA_SEAS" -> Ok(MagmaSeas) + "SUPERVOLCANOES" -> Ok(Supervolcanoes) + "ASH_CLOUDS" -> Ok(AshClouds) + "VAST_RUINS" -> Ok(VastRuins) + "MUTATED_FLORA" -> Ok(MutatedFlora) + "TERRAFORMED" -> Ok(Terraformed) + "EXTREME_TEMPERATURES" -> Ok(ExtremeTemperatures) + "EXTREME_PRESSURE" -> Ok(ExtremePressure) + "DIVERSE_LIFE" -> Ok(DiverseLife) + "SCARCE_LIFE" -> Ok(ScarceLife) + "FOSSILS" -> Ok(Fossils) + "WEAK_GRAVITY" -> Ok(WeakGravity) + "STRONG_GRAVITY" -> Ok(StrongGravity) + "CRUSHING_GRAVITY" -> Ok(CrushingGravity) + "TOXIC_ATMOSPHERE" -> Ok(ToxicAtmosphere) + "CORROSIVE_ATMOSPHERE" -> Ok(CorrosiveAtmosphere) + "BREATHABLE_ATMOSPHERE" -> Ok(BreathableAtmosphere) + "THIN_ATMOSPHERE" -> Ok(ThinAtmosphere) + "JOVIAN" -> Ok(Jovian) + "ROCKY" -> Ok(Rocky) + "VOLCANIC" -> Ok(Volcanic) + "FROZEN" -> Ok(Frozen) + "SWAMP" -> Ok(Swamp) + "BARREN" -> Ok(Barren) + "TEMPERATE" -> Ok(Temperate) + "JUNGLE" -> Ok(Jungle) + "OCEAN" -> Ok(Ocean) + "RADIOACTIVE" -> Ok(Radioactive) + "MICRO_GRAVITY_ANOMALIES" -> Ok(MicroGravityAnomalies) + "DEBRIS_CLUSTER" -> Ok(DebrisCluster) + "DEEP_CRATERS" -> Ok(DeepCraters) + "SHALLOW_CRATERS" -> Ok(ShallowCraters) + "UNSTABLE_COMPOSITION" -> Ok(UnstableComposition) + "HOLLOWED_INTERIOR" -> Ok(HollowedInterior) + "STRIPPED" -> Ok(Stripped) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(WaypointTraitSymbol) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(waypoint_trait_symbol) -> decode.success(waypoint_trait_symbol) + Error(Nil) -> decode.failure(Uncharted, "WaypointTraitSymbol") + } +} + pub fn to_string(waypoint_trait_symbol: WaypointTraitSymbol) -> String { case waypoint_trait_symbol { Uncharted -> "UNCHARTED" @@ -147,83 +230,6 @@ pub fn to_string(waypoint_trait_symbol: WaypointTraitSymbol) -> String { } } -pub fn parse( - waypoint_trait_symbol_str: String, -) -> Result(WaypointTraitSymbol, WaypointTraitSymbol) { - case waypoint_trait_symbol_str { - "UNCHARTED" -> Ok(Uncharted) - "UNDER_CONSTRUCTION" -> Ok(UnderConstruction) - "MARKETPLACE" -> Ok(Marketplace) - "SHIPYARD" -> Ok(Shipyard) - "OUTPOST" -> Ok(Outpost) - "SCATTERED_SETTLEMENTS" -> Ok(ScatteredSettlements) - "SPRAWLING_CITIES" -> Ok(SprawlingCities) - "MEGA_STRUCTURES" -> Ok(MegaStructures) - "PIRATE_BASE" -> Ok(PirateBase) - "OVERCROWDED" -> Ok(Overcrowded) - "HIGH_TECH" -> Ok(HighTech) - "CORRUPT" -> Ok(Corrupt) - "BUREAUCRATIC" -> Ok(Bureaucratic) - "TRADING_HUB" -> Ok(TradingHub) - "INDUSTRIAL" -> Ok(Industrial) - "BLACK_MARKET" -> Ok(BlackMarket) - "RESEARCH_FACILITY" -> Ok(ResearchFacility) - "MILITARY_BASE" -> Ok(MilitaryBase) - "SURVEILLANCE_OUTPOST" -> Ok(SurveillanceOutpost) - "EXPLORATION_OUTPOST" -> Ok(ExplorationOutpost) - "MINERAL_DEPOSITS" -> Ok(MineralDeposits) - "COMMON_METAL_DEPOSITS" -> Ok(CommonMetalDeposits) - "PRECIOUS_METAL_DEPOSITS" -> Ok(PreciousMetalDeposits) - "RARE_METAL_DEPOSITS" -> Ok(RareMetalDeposits) - "METHANE_POOLS" -> Ok(MethanePools) - "ICE_CRYSTALS" -> Ok(IceCrystals) - "EXPLOSIVE_GASES" -> Ok(ExplosiveGases) - "STRONG_MAGNETOSPHERE" -> Ok(StrongMagnetosphere) - "VIBRANT_AURORAS" -> Ok(VibrantAuroras) - "SALT_FLATS" -> Ok(SaltFlats) - "CANYONS" -> Ok(Canyons) - "PERPETUAL_DAYLIGHT" -> Ok(PerpetualDaylight) - "PERPETUAL_OVERCAST" -> Ok(PerpetualOvercast) - "DRY_SEABEDS" -> Ok(DrySeabeds) - "MAGMA_SEAS" -> Ok(MagmaSeas) - "SUPERVOLCANOES" -> Ok(Supervolcanoes) - "ASH_CLOUDS" -> Ok(AshClouds) - "VAST_RUINS" -> Ok(VastRuins) - "MUTATED_FLORA" -> Ok(MutatedFlora) - "TERRAFORMED" -> Ok(Terraformed) - "EXTREME_TEMPERATURES" -> Ok(ExtremeTemperatures) - "EXTREME_PRESSURE" -> Ok(ExtremePressure) - "DIVERSE_LIFE" -> Ok(DiverseLife) - "SCARCE_LIFE" -> Ok(ScarceLife) - "FOSSILS" -> Ok(Fossils) - "WEAK_GRAVITY" -> Ok(WeakGravity) - "STRONG_GRAVITY" -> Ok(StrongGravity) - "CRUSHING_GRAVITY" -> Ok(CrushingGravity) - "TOXIC_ATMOSPHERE" -> Ok(ToxicAtmosphere) - "CORROSIVE_ATMOSPHERE" -> Ok(CorrosiveAtmosphere) - "BREATHABLE_ATMOSPHERE" -> Ok(BreathableAtmosphere) - "THIN_ATMOSPHERE" -> Ok(ThinAtmosphere) - "JOVIAN" -> Ok(Jovian) - "ROCKY" -> Ok(Rocky) - "VOLCANIC" -> Ok(Volcanic) - "FROZEN" -> Ok(Frozen) - "SWAMP" -> Ok(Swamp) - "BARREN" -> Ok(Barren) - "TEMPERATE" -> Ok(Temperate) - "JUNGLE" -> Ok(Jungle) - "OCEAN" -> Ok(Ocean) - "RADIOACTIVE" -> Ok(Radioactive) - "MICRO_GRAVITY_ANOMALIES" -> Ok(MicroGravityAnomalies) - "DEBRIS_CLUSTER" -> Ok(DebrisCluster) - "DEEP_CRATERS" -> Ok(DeepCraters) - "SHALLOW_CRATERS" -> Ok(ShallowCraters) - "UNSTABLE_COMPOSITION" -> Ok(UnstableComposition) - "HOLLOWED_INTERIOR" -> Ok(HollowedInterior) - "STRIPPED" -> Ok(Stripped) - _ -> Error(Uncharted) - } -} - -pub fn decoder() -> Decoder(WaypointTraitSymbol) { - decode_utils.enum_decoder(parse, "WaypointTraitSymbol") +pub fn encode(waypoint_trait_symbol: WaypointTraitSymbol) -> Json { + json.string(to_string(waypoint_trait_symbol)) } diff --git a/src/models/waypoint_type.gleam b/src/models/waypoint_type.gleam index 9f0e2f7..4d9143c 100644 --- a/src/models/waypoint_type.gleam +++ b/src/models/waypoint_type.gleam @@ -1,5 +1,5 @@ import gleam/dynamic/decode.{type Decoder} -import utils/decode as decode_utils +import gleam/json.{type Json} pub type WaypointType { Planet @@ -18,6 +18,34 @@ pub type WaypointType { FuelStation } +pub fn parse(value: String) -> Result(WaypointType, Nil) { + case value { + "PLANET" -> Ok(Planet) + "GAS_GIANT" -> Ok(GasGiant) + "MOON" -> Ok(Moon) + "ORBITAL_STATION" -> Ok(OrbitalStation) + "JUMP_GATE" -> Ok(JumpGate) + "ASTEROID_FIELD" -> Ok(AsteroidField) + "ASTEROID" -> Ok(Asteroid) + "ENGINEERED_ASTEROID" -> Ok(EngineeredAsteroid) + "ASTEROID_BASE" -> Ok(AsteroidBase) + "NEBULA" -> Ok(Nebula) + "DEBRIS_FIELD" -> Ok(DebrisField) + "GRAVITY_WELL" -> Ok(GravityWell) + "ARTIFICIAL_GRAVITY_WELL" -> Ok(ArtificialGravityWell) + "FUEL_STATION" -> Ok(FuelStation) + _ -> Error(Nil) + } +} + +pub fn decoder() -> Decoder(WaypointType) { + use value <- decode.then(decode.string) + case parse(value) { + Ok(waypoint_type) -> decode.success(waypoint_type) + Error(Nil) -> decode.failure(Planet, "WaypointType") + } +} + pub fn to_string(waypoint_type: WaypointType) -> String { case waypoint_type { Planet -> "PLANET" @@ -37,26 +65,6 @@ pub fn to_string(waypoint_type: WaypointType) -> String { } } -pub fn parse(waypoint_type_str: String) -> Result(WaypointType, WaypointType) { - case waypoint_type_str { - "PLANET" -> Ok(Planet) - "GAS_GIANT" -> Ok(GasGiant) - "MOON" -> Ok(Moon) - "ORBITAL_STATION" -> Ok(OrbitalStation) - "JUMP_GATE" -> Ok(JumpGate) - "ASTEROID_FIELD" -> Ok(AsteroidField) - "ASTEROID" -> Ok(Asteroid) - "ENGINEERED_ASTEROID" -> Ok(EngineeredAsteroid) - "ASTEROID_BASE" -> Ok(AsteroidBase) - "NEBULA" -> Ok(Nebula) - "DEBRIS_FIELD" -> Ok(DebrisField) - "GRAVITY_WELL" -> Ok(GravityWell) - "ARTIFICIAL_GRAVITY_WELL" -> Ok(ArtificialGravityWell) - "FUEL_STATION" -> Ok(FuelStation) - _ -> Error(Planet) - } -} - -pub fn decoder() -> Decoder(WaypointType) { - decode_utils.enum_decoder(parse, "WaypointType") +pub fn encode(waypoint_type: WaypointType) -> Json { + json.string(to_string(waypoint_type)) } diff --git a/src/spacetraders_sdk.gleam b/src/spacetraders_sdk.gleam index 7669d34..f77825b 100644 --- a/src/spacetraders_sdk.gleam +++ b/src/spacetraders_sdk.gleam @@ -1,5 +1,140 @@ -import gleam/io +import endpoints/accounts +import endpoints/agents +import endpoints/contracts +import endpoints/data +import endpoints/factions +import endpoints/fleet +import endpoints/global +import endpoints/systems pub fn main() -> Nil { - io.println("Hello from spacetraders_sdk!") + Nil } + +pub const get_account = accounts.get_account + +pub const register_new_agent = accounts.register_new_agent + +pub const list_public_agents = agents.list_public_agents + +pub const get_public_agent = agents.get_public_agent + +pub const get_agent = agents.get_agent + +pub const get_agent_events = agents.get_agent_events + +pub const list_contracts = contracts.list_contracts + +pub const get_contract = contracts.get_contract + +pub const accept_contract = contracts.accept_contract + +pub const fulfill_contract = contracts.fulfill_contract + +pub const deliver_contract_cargo = contracts.deliver_contract_cargo + +pub const list_factions = factions.list_factions + +pub const get_faction = factions.get_faction + +pub const get_my_factions = factions.get_my_factions + +pub const list_ships = fleet.list_ships + +pub const purchase_ship = fleet.purchase_ship + +pub const get_ship = fleet.get_ship + +pub const create_chart = fleet.create_chart + +pub const negotiate_contract = fleet.negotiate_contract + +pub const get_ship_cooldown = fleet.get_ship_cooldown + +pub const dock_ship = fleet.dock_ship + +pub const extract_resources = fleet.extract_resources + +pub const extract_resources_with_survey = fleet.extract_resources_with_survey + +pub const jettison_cargo = fleet.jettison_cargo + +pub const jump_ship = fleet.jump_ship + +pub const scan_systems = fleet.scan_systems + +pub const scan_waypoints = fleet.scan_waypoints + +pub const scan_ships = fleet.scan_ships + +pub const scrap_ship = fleet.scrap_ship + +pub const get_scrap_ship = fleet.get_scrap_ship + +pub const navigate_ship = fleet.navigate_ship + +pub const warp_ship = fleet.warp_ship + +pub const orbit_ship = fleet.orbit_ship + +pub const purchase_cargo = fleet.purchase_cargo + +pub const refine_ship = fleet.refine_ship + +pub const refuel_ship = fleet.refuel_ship + +pub const repair_ship = fleet.repair_ship + +pub const get_repair_ship = fleet.repair_ship + +pub const sell_cargo = fleet.sell_cargo + +pub const siphon_resources = fleet.siphon_resources + +pub const create_survey = fleet.create_survey + +pub const transfer_cargo = fleet.transfer_cargo + +pub const get_ship_cargo = fleet.get_ship_cargo + +pub const get_ship_modules = fleet.get_ship_modules + +pub const install_ship_module = fleet.install_ship_module + +pub const remove_ship_module = fleet.remove_ship_module + +pub const get_ship_mounts = fleet.get_ship_mounts + +pub const install_ship_mount = fleet.install_ship_mount + +pub const remove_ship_mount = fleet.remove_ship_mount + +pub const get_ship_nav = fleet.get_ship_nav + +pub const patch_ship_nav = fleet.patch_ship_nav + +pub const list_systems = systems.list_systems + +pub const get_system = systems.get_system + +pub const list_system_waypoints = systems.list_system_waypoints + +pub const get_waypoint = systems.get_waypoint + +pub const get_construction_site = systems.get_construction_site + +pub const supply_construction_site = systems.supply_construction_site + +pub const get_market = systems.get_market + +pub const get_jump_gate = systems.get_jump_gate + +pub const get_shipyard = systems.get_shipyard + +pub const get_supply_chain = data.get_supply_chain + +pub const get_departure_events = data.get_departure_events + +pub const get_server_status = global.get_server_status + +pub const list_error_codes = global.list_error_codes diff --git a/src/utils/request.gleam b/src/utils/api.gleam similarity index 56% rename from src/utils/request.gleam rename to src/utils/api.gleam index 78bbfce..36fb2c7 100644 --- a/src/utils/request.gleam +++ b/src/utils/api.gleam @@ -1,15 +1,41 @@ +import birl.{type Time} import gleam/bit_array +import gleam/dynamic.{type Dynamic} +import gleam/dynamic/decode.{type Decoder} import gleam/http.{type Method} import gleam/http/request.{type Request} import gleam/http/response.{type Response} -import gleam/httpc +import gleam/httpc.{type HttpError} import gleam/int -import gleam/json.{type Json} -import gleam/option +import gleam/json.{type DecodeError, type Json} +import gleam/option.{type Option} import gleam/result import gleam/string_tree +import models/meta.{type Meta} import utils/auth.{type AuthMethod} -import utils/types.{type ApiResponse} + +pub type PagedData(data) { + PagedData(data: data, meta: Meta) +} + +pub type ErrorResponse { + ErrorResponse( + code: Int, + message: String, + data: Option(Dynamic), + request_id: Option(String), + ) +} + +pub type ApiError { + HttpcError(HttpError) + JsonDecodeError(DecodeError) + ResponseError(ErrorResponse) + UnknownError +} + +pub type ApiResponse(a) = + Result(a, ApiError) const base_request = request.Request( method: http.Get, @@ -132,7 +158,7 @@ pub fn delete(auth_method: AuthMethod, path: String) { pub fn send(request: Request(BitArray)) { case httpc.send_bits(request) { Ok(res) -> Ok(res) - Error(err) -> Error(types.HttpcError(err)) + Error(err) -> Error(HttpcError(err)) } } @@ -142,3 +168,74 @@ pub fn try_send( ) { result.try(send(request), fun) } + +pub fn parse_response( + response: Response(BitArray), + decoder: Decoder(data), +) -> ApiResponse(data) { + case json.parse_bits(response.body, decoder) { + Ok(data) -> Ok(data) + Error(err) -> Error(JsonDecodeError(err)) + } +} + +pub fn data_decoder(decoder: Decoder(data)) -> Decoder(data) { + use data <- decode.field("data", decoder) + decode.success(data) +} + +pub fn parse_data_response( + response: Response(BitArray), + decoder: Decoder(data), +) -> ApiResponse(data) { + parse_response(response, data_decoder(decoder)) +} + +pub fn paged_data_decoder(decoder: Decoder(data)) -> Decoder(PagedData(data)) { + use data <- decode.field("data", decoder) + use meta <- decode.field("meta", meta.decoder()) + decode.success(PagedData(data:, meta:)) +} + +pub fn parse_paged_data_response( + response: Response(BitArray), + decoder: Decoder(data), +) -> ApiResponse(PagedData(data)) { + parse_response(response, paged_data_decoder(decoder)) +} + +pub fn error_response_decoder() -> Decoder(ErrorResponse) { + use code <- decode.field("code", decode.int) + use message <- decode.field("message", decode.string) + use data <- decode.optional_field( + "data", + option.None, + decode.optional(decode.dynamic), + ) + use request_id <- decode.optional_field( + "requestId", + option.None, + decode.optional(decode.string), + ) + decode.success(ErrorResponse(code:, message:, data:, request_id:)) +} + +pub fn error_decoder() -> Decoder(ErrorResponse) { + use data <- decode.field("error", error_response_decoder()) + decode.success(data) +} + +pub fn parse_error_response(response: Response(BitArray)) -> ApiResponse(data) { + Error(case parse_response(response, error_decoder()) { + Ok(err) -> ResponseError(err) + Error(err) -> err + }) +} + +pub fn time_decoder() -> Decoder(Time) { + use value <- decode.then(decode.string) + case birl.parse(value) { + Ok(time) -> decode.success(time) + Error(Nil) -> decode.failure(birl.now(), "Time") + } +} diff --git a/src/utils/auth.gleam b/src/utils/auth.gleam index 6624afc..8fb0447 100644 --- a/src/utils/auth.gleam +++ b/src/utils/auth.gleam @@ -17,40 +17,34 @@ pub type TokenParseError { } pub fn parse_account_token( - token_str: String, + value: String, ) -> Result(AccountToken, TokenParseError) { - use jwt <- result.try( - jwt.parse(token_str) |> result.replace_error(InvalidToken), - ) + use jwt <- result.try(jwt.parse(value) |> result.replace_error(InvalidToken)) case jwt.payload.subject { - "account-token" -> Ok(AccountToken(token_str)) + "account-token" -> Ok(AccountToken(value)) _ -> Error(IncorrectType) } } pub fn account_token_decoder() -> Decoder(AccountToken) { - use token_str <- decode.then(decode.string) - case parse_account_token(token_str) { + use value <- decode.then(decode.string) + case parse_account_token(value) { Ok(token) -> decode.success(token) Error(_) -> decode.failure(AccountToken("invalid"), "AccountToken") } } -pub fn parse_agent_token( - token_str: String, -) -> Result(AgentToken, TokenParseError) { - use jwt <- result.try( - jwt.parse(token_str) |> result.replace_error(InvalidToken), - ) +pub fn parse_agent_token(value: String) -> Result(AgentToken, TokenParseError) { + use jwt <- result.try(jwt.parse(value) |> result.replace_error(InvalidToken)) case jwt.payload.subject { - "agent-token" -> Ok(AgentToken(token_str)) + "agent-token" -> Ok(AgentToken(value)) _ -> Error(IncorrectType) } } pub fn agent_token_decoder() -> Decoder(AgentToken) { - use token_str <- decode.then(decode.string) - case parse_agent_token(token_str) { + use value <- decode.then(decode.string) + case parse_agent_token(value) { Ok(token) -> decode.success(token) Error(_) -> decode.failure(AgentToken("invalid"), "AgentToken") } diff --git a/src/utils/decode.gleam b/src/utils/decode.gleam deleted file mode 100644 index e55741d..0000000 --- a/src/utils/decode.gleam +++ /dev/null @@ -1,68 +0,0 @@ -import gleam/dynamic/decode.{type Decoder} -import gleam/option.{type Option} -import models/meta -import utils/types.{type ErrorResponse, type PagedData, ErrorResponse, PagedData} - -pub fn data_decoder(decoder: Decoder(data)) -> Decoder(data) { - use data <- decode.field("data", decoder) - decode.success(data) -} - -pub fn paged_data_decoder(decoder: Decoder(data)) -> Decoder(PagedData(data)) { - use data <- decode.field("data", decoder) - use meta <- decode.field("meta", meta.decoder()) - decode.success(PagedData(data:, meta:)) -} - -pub fn error_response_decoder() -> Decoder(ErrorResponse) { - use code <- decode.field("code", decode.int) - use message <- decode.field("message", decode.string) - use data <- field_key_value_optional("data", decode.dynamic) - use request_id <- field_key_value_optional("requestId", decode.string) - decode.success(ErrorResponse(code:, message:, data:, request_id:)) -} - -pub fn error_decoder() -> Decoder(ErrorResponse) { - use data <- decode.field("error", error_response_decoder()) - decode.success(data) -} - -pub fn enum_decoder( - parse_enum: fn(String) -> Result(enum, enum), - expected: String, -) -> Decoder(enum) { - use enum_str <- decode.then(decode.string) - case parse_enum(enum_str) { - Ok(enum) -> decode.success(enum) - Error(enum) -> decode.failure(enum, expected) - } -} - -pub fn field_value_optional( - field: String, - decoder: Decoder(a), - next: fn(Option(a)) -> Decoder(b), -) { - decode.field(field, decode.optional(decoder), next) -} - -pub fn field_key_optional( - field: String, - decoder: Decoder(a), - next: fn(Option(a)) -> Decoder(b), -) { - decode.optional_field( - field, - option.None, - decode.map(decoder, option.Some), - next, - ) -} - -pub fn field_key_value_optional( - field: String, - decoder: Decoder(a), - next: fn(Option(a)) -> Decoder(b), -) { - decode.optional_field(field, option.None, decode.optional(decoder), next) -} diff --git a/src/utils/jwt.gleam b/src/utils/jwt.gleam index a352d77..20817a3 100644 --- a/src/utils/jwt.gleam +++ b/src/utils/jwt.gleam @@ -1,10 +1,10 @@ +import birl.{type Time} import gleam/bit_array import gleam/dynamic/decode.{type Decoder} import gleam/json import gleam/option.{type Option} import gleam/result import gleam/string -import utils/decode as decode_utils pub type JwtDecodeError { MissingHeader @@ -36,10 +36,8 @@ pub type JwtAlgorithm { None } -pub fn parse_jwt_algorithm( - jwt_algorithm_str: String, -) -> Result(JwtAlgorithm, JwtAlgorithm) { - case jwt_algorithm_str { +pub fn parse_jwt_algorithm(value: String) -> Result(JwtAlgorithm, Nil) { + case value { "HS256" -> Ok(HS256) "HS384" -> Ok(HS384) "HS512" -> Ok(HS512) @@ -53,12 +51,16 @@ pub fn parse_jwt_algorithm( "PS384" -> Ok(PS384) "PS512" -> Ok(PS512) "none" -> Ok(None) - _ -> Error(None) + _ -> Error(Nil) } } pub fn jwt_algorithm_decoder() -> Decoder(JwtAlgorithm) { - decode_utils.enum_decoder(parse_jwt_algorithm, "JwtAlgorithm") + use value <- decode.then(decode.string) + case parse_jwt_algorithm(value) { + Ok(jwt_algorithm) -> decode.success(jwt_algorithm) + Error(Nil) -> decode.failure(None, "JwtAlgorithm") + } } pub type JwtHeader { @@ -75,20 +77,30 @@ pub type JwtPayload { JwtPayload( identifier: String, version: String, - reset_date: Option(String), - issued_at: Int, + reset_date: Option(Time), + issued_at: Time, subject: String, ) } +fn reset_date_decoder() -> Decoder(Time) { + use value <- decode.then(decode.string) + case birl.from_naive(value) { + Ok(time) -> decode.success(time) + Error(Nil) -> decode.failure(birl.now(), "Time") + } +} + fn jwt_payload_decoder() -> Decoder(JwtPayload) { use identifier <- decode.field("identifier", decode.string) use version <- decode.field("version", decode.string) - use reset_date <- decode_utils.field_key_value_optional( + use reset_date <- decode.optional_field( "reset_date", - decode.string, + option.None, + decode.optional(reset_date_decoder()), ) - use issued_at <- decode.field("iat", decode.int) + use issued_at_int <- decode.field("iat", decode.int) + let issued_at = birl.from_unix(issued_at_int) use subject <- decode.field("sub", decode.string) decode.success(JwtPayload( identifier:, diff --git a/src/utils/response.gleam b/src/utils/response.gleam deleted file mode 100644 index cce69f6..0000000 --- a/src/utils/response.gleam +++ /dev/null @@ -1,29 +0,0 @@ -import gleam/dynamic/decode.{type Decoder} -import gleam/json -import utils/decode as decode_utils -import utils/types.{type ApiResponse} - -pub fn parser(body: BitArray, decoder: Decoder(data)) -> ApiResponse(data) { - case json.parse_bits(body, decoder) { - Ok(data) -> Ok(data) - Error(err) -> Error(types.JsonDecodeError(err)) - } -} - -pub fn data_parser(body: BitArray, decoder: Decoder(data)) -> ApiResponse(data) { - parser(body, decode_utils.data_decoder(decoder)) -} - -pub fn paged_data_parser( - body: BitArray, - decoder: Decoder(data), -) -> ApiResponse(types.PagedData(data)) { - parser(body, decode_utils.paged_data_decoder(decoder)) -} - -pub fn error_parser(body: BitArray) -> ApiResponse(data) { - Error(case parser(body, decode_utils.error_decoder()) { - Ok(err) -> types.ResponseError(err) - Error(err) -> err - }) -} diff --git a/src/utils/types.gleam b/src/utils/types.gleam deleted file mode 100644 index 0d5fa4a..0000000 --- a/src/utils/types.gleam +++ /dev/null @@ -1,28 +0,0 @@ -import gleam/dynamic.{type Dynamic} -import gleam/httpc.{type HttpError} -import gleam/json.{type DecodeError} -import gleam/option.{type Option} -import models/meta.{type Meta} - -pub type PagedData(data) { - PagedData(data: data, meta: Meta) -} - -pub type ErrorResponse { - ErrorResponse( - code: Int, - message: String, - data: Option(Dynamic), - request_id: Option(String), - ) -} - -pub type ApiError { - HttpcError(HttpError) - JsonDecodeError(DecodeError) - ResponseError(ErrorResponse) - UnknownError -} - -pub type ApiResponse(a) = - Result(a, ApiError)