diff --git a/Cargo.toml b/Cargo.toml index bfa7970..b0663a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,13 +33,15 @@ once_cell = "1.20.2" query_map = "0.7.0" reqwest = "0.12.8" rstest = "0.23.0" -sea-orm = "1.1.0" -sea-orm-migration = "1.0.0" +sea-orm = "1.1.1" +sea-orm-macros = "1.1.1" +sea-orm-migration = "1.1.1" +sea-query = "0.32.1" serde = "1.0.214" serde_json = "1.0.132" serde_plain = "1.0.2" serde_with = "3.11.0" -thiserror = "2.0.3" +thiserror = "2.0.9" time = "0.3.37" tokio = "1.41.0" tower-http = "0.6.2" @@ -47,6 +49,9 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", default-features = false } url = "2.3.1" urlencoding = "2.1.3" +utoipa = "5.3.0" +utoipa-axum = "0.1.3" +utoipa-swagger-ui = "8.1.0" uuid = "1.11.0" [dependencies] diff --git a/bnaclient/src/lib.rs b/bnaclient/src/lib.rs index a935b5a..6c2aa4d 100644 --- a/bnaclient/src/lib.rs +++ b/bnaclient/src/lib.rs @@ -185,7 +185,7 @@ pub mod types { pub torn_down: ::std::option::Option, } - impl From<&Analysis> for Analysis { + impl ::std::convert::From<&Analysis> for Analysis { fn from(value: &Analysis) -> Self { value.clone() } @@ -323,12 +323,29 @@ pub mod types { pub torn_down: ::std::option::Option, } - impl From<&AnalysisPatch> for AnalysisPatch { + impl ::std::convert::From<&AnalysisPatch> for AnalysisPatch { fn from(value: &AnalysisPatch) -> Self { value.clone() } } + impl ::std::default::Default for AnalysisPatch { + fn default() -> Self { + Self { + cost: Default::default(), + end_time: Default::default(), + fargate_task_arn: Default::default(), + results_posted: Default::default(), + s3_bucket: Default::default(), + sqs_message: Default::default(), + start_time: Default::default(), + status: Default::default(), + step: Default::default(), + torn_down: Default::default(), + } + } + } + impl AnalysisPatch { pub fn builder() -> builder::AnalysisPatch { Default::default() @@ -473,12 +490,31 @@ pub mod types { pub torn_down: ::std::option::Option, } - impl From<&AnalysisPost> for AnalysisPost { + impl ::std::convert::From<&AnalysisPost> for AnalysisPost { fn from(value: &AnalysisPost) -> Self { value.clone() } } + impl ::std::default::Default for AnalysisPost { + fn default() -> Self { + Self { + cost: Default::default(), + end_time: Default::default(), + fargate_price_id: Default::default(), + fargate_task_arn: Default::default(), + result_posted: Default::default(), + s3_bucket: Default::default(), + sqs_message: Default::default(), + start_time: Default::default(), + state_machine_id: Default::default(), + status: Default::default(), + step: Default::default(), + torn_down: Default::default(), + } + } + } + impl AnalysisPost { pub fn builder() -> builder::AnalysisPost { Default::default() @@ -522,7 +558,7 @@ pub mod types { Processing, } - impl From<&AnalysisStatus> for AnalysisStatus { + impl ::std::convert::From<&AnalysisStatus> for AnalysisStatus { fn from(value: &AnalysisStatus) -> Self { value.clone() } @@ -538,7 +574,7 @@ pub mod types { } } - impl std::str::FromStr for AnalysisStatus { + impl ::std::str::FromStr for AnalysisStatus { type Err = self::error::ConversionError; fn from_str(value: &str) -> ::std::result::Result { match value { @@ -550,14 +586,14 @@ pub mod types { } } - impl std::convert::TryFrom<&str> for AnalysisStatus { + impl ::std::convert::TryFrom<&str> for AnalysisStatus { type Error = self::error::ConversionError; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&::std::string::String> for AnalysisStatus { + impl ::std::convert::TryFrom<&::std::string::String> for AnalysisStatus { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -566,7 +602,7 @@ pub mod types { } } - impl std::convert::TryFrom<::std::string::String> for AnalysisStatus { + impl ::std::convert::TryFrom<::std::string::String> for AnalysisStatus { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -608,19 +644,19 @@ pub mod types { } } - impl From for ::std::string::String { + impl ::std::convert::From for ::std::string::String { fn from(value: ApiGatewayId) -> Self { value.0 } } - impl From<&ApiGatewayId> for ApiGatewayId { + impl ::std::convert::From<&ApiGatewayId> for ApiGatewayId { fn from(value: &ApiGatewayId) -> Self { value.clone() } } - impl From<::std::string::String> for ApiGatewayId { + impl ::std::convert::From<::std::string::String> for ApiGatewayId { fn from(value: ::std::string::String) -> Self { Self(value) } @@ -986,7 +1022,7 @@ pub mod types { pub version: ::std::string::String, } - impl From<&Bna> for Bna { + impl ::std::convert::From<&Bna> for Bna { fn from(value: &Bna) -> Self { value.clone() } @@ -1056,7 +1092,7 @@ pub mod types { pub transit: Transit, } - impl From<&BnaPost> for BnaPost { + impl ::std::convert::From<&BnaPost> for BnaPost { fn from(value: &BnaPost) -> Self { value.clone() } @@ -1135,7 +1171,7 @@ pub mod types { pub version: ::std::string::String, } - impl From<&BnaSummary> for BnaSummary { + impl ::std::convert::From<&BnaSummary> for BnaSummary { fn from(value: &BnaSummary) -> Self { value.clone() } @@ -1176,19 +1212,19 @@ pub mod types { } } - impl From for ::std::vec::Vec { + impl ::std::convert::From for ::std::vec::Vec { fn from(value: BnaSummaryWithCity) -> Self { value.0 } } - impl From<&BnaSummaryWithCity> for BnaSummaryWithCity { + impl ::std::convert::From<&BnaSummaryWithCity> for BnaSummaryWithCity { fn from(value: &BnaSummaryWithCity) -> Self { value.clone() } } - impl From<::std::vec::Vec> for BnaSummaryWithCity { + impl ::std::convert::From<::std::vec::Vec> for BnaSummaryWithCity { fn from(value: ::std::vec::Vec) -> Self { Self(value) } @@ -1247,7 +1283,7 @@ pub mod types { pub version: ::std::string::String, } - impl From<&BnaSummaryWithCityItem> for BnaSummaryWithCityItem { + impl ::std::convert::From<&BnaSummaryWithCityItem> for BnaSummaryWithCityItem { fn from(value: &BnaSummaryWithCityItem) -> Self { value.clone() } @@ -1341,12 +1377,25 @@ pub mod types { pub population: ::std::option::Option, } - impl From<&Census> for Census { + impl ::std::convert::From<&Census> for Census { fn from(value: &Census) -> Self { value.clone() } } + impl ::std::default::Default for Census { + fn default() -> Self { + Self { + census_id: Default::default(), + city_id: Default::default(), + created_at: Default::default(), + fips_code: Default::default(), + pop_size: Default::default(), + population: Default::default(), + } + } + } + impl Census { pub fn builder() -> builder::Census { Default::default() @@ -1382,13 +1431,13 @@ pub mod types { } } - impl From for i64 { + impl ::std::convert::From for i64 { fn from(value: CensusPopSize) -> Self { value.0 } } - impl From<&CensusPopSize> for CensusPopSize { + impl ::std::convert::From<&CensusPopSize> for CensusPopSize { fn from(value: &CensusPopSize) -> Self { value.clone() } @@ -1469,12 +1518,22 @@ pub mod types { pub population: ::std::option::Option, } - impl From<&CensusPost> for CensusPost { + impl ::std::convert::From<&CensusPost> for CensusPost { fn from(value: &CensusPost) -> Self { value.clone() } } + impl ::std::default::Default for CensusPost { + fn default() -> Self { + Self { + fips_code: Default::default(), + pop_size: Default::default(), + population: Default::default(), + } + } + } + impl CensusPost { pub fn builder() -> builder::CensusPost { Default::default() @@ -1510,13 +1569,13 @@ pub mod types { } } - impl From for i64 { + impl ::std::convert::From for i64 { fn from(value: CensusPostPopSize) -> Self { value.0 } } - impl From<&CensusPostPopSize> for CensusPostPopSize { + impl ::std::convert::From<&CensusPostPopSize> for CensusPostPopSize { fn from(value: &CensusPostPopSize) -> Self { value.clone() } @@ -1667,7 +1726,7 @@ pub mod types { pub updated_at: ::std::option::Option>, } - impl From<&City> for City { + impl ::std::convert::From<&City> for City { fn from(value: &City) -> Self { value.clone() } @@ -1776,7 +1835,7 @@ pub mod types { pub state_abbrev: ::std::option::Option<::std::string::String>, } - impl From<&CityPost> for CityPost { + impl ::std::convert::From<&CityPost> for CityPost { fn from(value: &CityPost) -> Self { value.clone() } @@ -1869,12 +1928,26 @@ pub mod types { pub social_services: ::std::option::Option, } - impl From<&CoreServices> for CoreServices { + impl ::std::convert::From<&CoreServices> for CoreServices { fn from(value: &CoreServices) -> Self { value.clone() } } + impl ::std::default::Default for CoreServices { + fn default() -> Self { + Self { + dentists: Default::default(), + doctors: Default::default(), + grocery: Default::default(), + hospitals: Default::default(), + pharmacies: Default::default(), + score: Default::default(), + social_services: Default::default(), + } + } + } + impl CoreServices { pub fn builder() -> builder::CoreServices { Default::default() @@ -1965,7 +2038,7 @@ pub mod types { Wales, } - impl From<&Country> for Country { + impl ::std::convert::From<&Country> for Country { fn from(value: &Country) -> Self { value.clone() } @@ -2005,7 +2078,7 @@ pub mod types { } } - impl std::str::FromStr for Country { + impl ::std::str::FromStr for Country { type Err = self::error::ConversionError; fn from_str(value: &str) -> ::std::result::Result { match value { @@ -2041,14 +2114,14 @@ pub mod types { } } - impl std::convert::TryFrom<&str> for Country { + impl ::std::convert::TryFrom<&str> for Country { type Error = self::error::ConversionError; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&::std::string::String> for Country { + impl ::std::convert::TryFrom<&::std::string::String> for Country { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -2057,7 +2130,7 @@ pub mod types { } } - impl std::convert::TryFrom<::std::string::String> for Country { + impl ::std::convert::TryFrom<::std::string::String> for Country { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -2123,12 +2196,23 @@ pub mod types { pub region: ::std::option::Option<::std::string::String>, } - impl From<&Enqueue> for Enqueue { + impl ::std::convert::From<&Enqueue> for Enqueue { fn from(value: &Enqueue) -> Self { value.clone() } } + impl ::std::default::Default for Enqueue { + fn default() -> Self { + Self { + city: Default::default(), + country: Default::default(), + fips_code: Default::default(), + region: Default::default(), + } + } + } + impl Enqueue { pub fn builder() -> builder::Enqueue { Default::default() @@ -2192,12 +2276,23 @@ pub mod types { pub region: ::std::option::Option<::std::string::String>, } - impl From<&EnqueuePost> for EnqueuePost { + impl ::std::convert::From<&EnqueuePost> for EnqueuePost { fn from(value: &EnqueuePost) -> Self { value.clone() } } + impl ::std::default::Default for EnqueuePost { + fn default() -> Self { + Self { + city: Default::default(), + country: Default::default(), + fips_code: Default::default(), + region: Default::default(), + } + } + } + impl EnqueuePost { pub fn builder() -> builder::EnqueuePost { Default::default() @@ -2262,12 +2357,24 @@ pub mod types { pub title: ::std::option::Option<::std::string::String>, } - impl From<&Error> for Error { + impl ::std::convert::From<&Error> for Error { fn from(value: &Error) -> Self { value.clone() } } + impl ::std::default::Default for Error { + fn default() -> Self { + Self { + details: Default::default(), + id: Default::default(), + source: Default::default(), + status: Default::default(), + title: Default::default(), + } + } + } + impl Error { pub fn builder() -> builder::Error { Default::default() @@ -2297,19 +2404,19 @@ pub mod types { } } - impl From for ::std::vec::Vec { + impl ::std::convert::From for ::std::vec::Vec { fn from(value: Errors) -> Self { value.0 } } - impl From<&Errors> for Errors { + impl ::std::convert::From<&Errors> for Errors { fn from(value: &Errors) -> Self { value.clone() } } - impl From<::std::vec::Vec> for Errors { + impl ::std::convert::From<::std::vec::Vec> for Errors { fn from(value: ::std::vec::Vec) -> Self { Self(value) } @@ -2360,12 +2467,22 @@ pub mod types { pub per_second: ::std::option::Option<::std::string::String>, } - impl From<&FargatePrice> for FargatePrice { + impl ::std::convert::From<&FargatePrice> for FargatePrice { fn from(value: &FargatePrice) -> Self { value.clone() } } + impl ::std::default::Default for FargatePrice { + fn default() -> Self { + Self { + created_at: Default::default(), + fargate_price_id: Default::default(), + per_second: Default::default(), + } + } + } + impl FargatePrice { pub fn builder() -> builder::FargatePrice { Default::default() @@ -2396,19 +2513,19 @@ pub mod types { Census(Census), } - impl From<&GetCityCensusResponseItem> for GetCityCensusResponseItem { + impl ::std::convert::From<&GetCityCensusResponseItem> for GetCityCensusResponseItem { fn from(value: &GetCityCensusResponseItem) -> Self { value.clone() } } - impl From for GetCityCensusResponseItem { + impl ::std::convert::From for GetCityCensusResponseItem { fn from(value: City) -> Self { Self::City(value) } } - impl From for GetCityCensusResponseItem { + impl ::std::convert::From for GetCityCensusResponseItem { fn from(value: Census) -> Self { Self::Census(value) } @@ -2438,19 +2555,19 @@ pub mod types { BnaSummary(BnaSummary), } - impl From<&GetCityRatingsResponseItem> for GetCityRatingsResponseItem { + impl ::std::convert::From<&GetCityRatingsResponseItem> for GetCityRatingsResponseItem { fn from(value: &GetCityRatingsResponseItem) -> Self { value.clone() } } - impl From for GetCityRatingsResponseItem { + impl ::std::convert::From for GetCityRatingsResponseItem { fn from(value: City) -> Self { Self::City(value) } } - impl From for GetCityRatingsResponseItem { + impl ::std::convert::From for GetCityRatingsResponseItem { fn from(value: BnaSummary) -> Self { Self::BnaSummary(value) } @@ -2480,19 +2597,19 @@ pub mod types { City(City), } - impl From<&GetRatingCityResponseItem> for GetRatingCityResponseItem { + impl ::std::convert::From<&GetRatingCityResponseItem> for GetRatingCityResponseItem { fn from(value: &GetRatingCityResponseItem) -> Self { value.clone() } } - impl From for GetRatingCityResponseItem { + impl ::std::convert::From for GetRatingCityResponseItem { fn from(value: BnaSummaryWithCity) -> Self { Self::BnaSummaryWithCity(value) } } - impl From for GetRatingCityResponseItem { + impl ::std::convert::From for GetRatingCityResponseItem { fn from(value: City) -> Self { Self::City(value) } @@ -2546,7 +2663,7 @@ pub mod types { Transit, } - impl From<&GetRatingComponent> for GetRatingComponent { + impl ::std::convert::From<&GetRatingComponent> for GetRatingComponent { fn from(value: &GetRatingComponent) -> Self { value.clone() } @@ -2568,7 +2685,7 @@ pub mod types { } } - impl std::str::FromStr for GetRatingComponent { + impl ::std::str::FromStr for GetRatingComponent { type Err = self::error::ConversionError; fn from_str(value: &str) -> ::std::result::Result { match value { @@ -2586,14 +2703,14 @@ pub mod types { } } - impl std::convert::TryFrom<&str> for GetRatingComponent { + impl ::std::convert::TryFrom<&str> for GetRatingComponent { type Error = self::error::ConversionError; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&::std::string::String> for GetRatingComponent { + impl ::std::convert::TryFrom<&::std::string::String> for GetRatingComponent { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -2602,7 +2719,7 @@ pub mod types { } } - impl std::convert::TryFrom<::std::string::String> for GetRatingComponent { + impl ::std::convert::TryFrom<::std::string::String> for GetRatingComponent { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -2645,19 +2762,19 @@ pub mod types { } } - impl From
for ::std::string::String { + impl ::std::convert::From
for ::std::string::String { fn from(value: Header) -> Self { value.0 } } - impl From<&Header> for Header { + impl ::std::convert::From<&Header> for Header { fn from(value: &Header) -> Self { value.clone() } } - impl From<::std::string::String> for Header { + impl ::std::convert::From<::std::string::String> for Header { fn from(value: ::std::string::String) -> Self { Self(value) } @@ -2712,12 +2829,21 @@ pub mod types { pub low_stress_miles: ::std::option::Option, } - impl From<&Infrastructure> for Infrastructure { + impl ::std::convert::From<&Infrastructure> for Infrastructure { fn from(value: &Infrastructure) -> Self { value.clone() } } + impl ::std::default::Default for Infrastructure { + fn default() -> Self { + Self { + high_stress_miles: Default::default(), + low_stress_miles: Default::default(), + } + } + } + impl Infrastructure { pub fn builder() -> builder::Infrastructure { Default::default() @@ -2789,12 +2915,24 @@ pub mod types { pub technical_vocational_college: ::std::option::Option, } - impl From<&Opportunity> for Opportunity { + impl ::std::convert::From<&Opportunity> for Opportunity { fn from(value: &Opportunity) -> Self { value.clone() } } + impl ::std::default::Default for Opportunity { + fn default() -> Self { + Self { + employment: Default::default(), + higher_education: Default::default(), + k12_education: Default::default(), + score: Default::default(), + technical_vocational_college: Default::default(), + } + } + } + impl Opportunity { pub fn builder() -> builder::Opportunity { Default::default() @@ -2834,19 +2972,19 @@ pub mod types { } } - impl From for ::std::string::String { + impl ::std::convert::From for ::std::string::String { fn from(value: Parameter) -> Self { value.0 } } - impl From<&Parameter> for Parameter { + impl ::std::convert::From<&Parameter> for Parameter { fn from(value: &Parameter) -> Self { value.clone() } } - impl From<::std::string::String> for Parameter { + impl ::std::convert::From<::std::string::String> for Parameter { fn from(value: ::std::string::String) -> Self { Self(value) } @@ -2889,19 +3027,19 @@ pub mod types { Census(Census), } - impl From<&PatchCityCensusResponseItem> for PatchCityCensusResponseItem { + impl ::std::convert::From<&PatchCityCensusResponseItem> for PatchCityCensusResponseItem { fn from(value: &PatchCityCensusResponseItem) -> Self { value.clone() } } - impl From for PatchCityCensusResponseItem { + impl ::std::convert::From for PatchCityCensusResponseItem { fn from(value: City) -> Self { Self::City(value) } } - impl From for PatchCityCensusResponseItem { + impl ::std::convert::From for PatchCityCensusResponseItem { fn from(value: Census) -> Self { Self::Census(value) } @@ -2928,12 +3066,20 @@ pub mod types { pub score: ::std::option::Option, } - impl From<&People> for People { + impl ::std::convert::From<&People> for People { fn from(value: &People) -> Self { value.clone() } } + impl ::std::default::Default for People { + fn default() -> Self { + Self { + score: Default::default(), + } + } + } + impl People { pub fn builder() -> builder::People { Default::default() @@ -2973,19 +3119,19 @@ pub mod types { } } - impl From for ::std::string::String { + impl ::std::convert::From for ::std::string::String { fn from(value: Pointer) -> Self { value.0 } } - impl From<&Pointer> for Pointer { + impl ::std::convert::From<&Pointer> for Pointer { fn from(value: &Pointer) -> Self { value.clone() } } - impl From<::std::string::String> for Pointer { + impl ::std::convert::From<::std::string::String> for Pointer { fn from(value: ::std::string::String) -> Self { Self(value) } @@ -3058,12 +3204,23 @@ pub mod types { pub score: ::std::option::Option, } - impl From<&Recreation> for Recreation { + impl ::std::convert::From<&Recreation> for Recreation { fn from(value: &Recreation) -> Self { value.clone() } } + impl ::std::default::Default for Recreation { + fn default() -> Self { + Self { + community_centers: Default::default(), + parks: Default::default(), + recreation_trails: Default::default(), + score: Default::default(), + } + } + } + impl Recreation { pub fn builder() -> builder::Recreation { Default::default() @@ -3091,12 +3248,20 @@ pub mod types { pub score: ::std::option::Option, } - impl From<&Retail> for Retail { + impl ::std::convert::From<&Retail> for Retail { fn from(value: &Retail) -> Self { value.clone() } } + impl ::std::default::Default for Retail { + fn default() -> Self { + Self { + score: Default::default(), + } + } + } + impl Retail { pub fn builder() -> builder::Retail { Default::default() @@ -3140,13 +3305,13 @@ pub mod types { Header(Header), } - impl From<&Source> for Source { + impl ::std::convert::From<&Source> for Source { fn from(value: &Source) -> Self { value.clone() } } - impl std::str::FromStr for Source { + impl ::std::str::FromStr for Source { type Err = self::error::ConversionError; fn from_str(value: &str) -> ::std::result::Result { if let Ok(v) = value.parse() { @@ -3161,14 +3326,14 @@ pub mod types { } } - impl std::convert::TryFrom<&str> for Source { + impl ::std::convert::TryFrom<&str> for Source { type Error = self::error::ConversionError; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&::std::string::String> for Source { + impl ::std::convert::TryFrom<&::std::string::String> for Source { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -3177,7 +3342,7 @@ pub mod types { } } - impl std::convert::TryFrom<::std::string::String> for Source { + impl ::std::convert::TryFrom<::std::string::String> for Source { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -3196,19 +3361,19 @@ pub mod types { } } - impl From for Source { + impl ::std::convert::From for Source { fn from(value: Parameter) -> Self { Self::Parameter(value) } } - impl From for Source { + impl ::std::convert::From for Source { fn from(value: Pointer) -> Self { Self::Pointer(value) } } - impl From
for Source { + impl ::std::convert::From
for Source { fn from(value: Header) -> Self { Self::Header(value) } @@ -3239,46 +3404,46 @@ pub mod types { } } - impl From for uuid::Uuid { + impl ::std::convert::From for uuid::Uuid { fn from(value: StateMachineId) -> Self { value.0 } } - impl From<&StateMachineId> for StateMachineId { + impl ::std::convert::From<&StateMachineId> for StateMachineId { fn from(value: &StateMachineId) -> Self { value.clone() } } - impl From for StateMachineId { + impl ::std::convert::From for StateMachineId { fn from(value: uuid::Uuid) -> Self { Self(value) } } - impl std::str::FromStr for StateMachineId { + impl ::std::str::FromStr for StateMachineId { type Err = ::Err; fn from_str(value: &str) -> ::std::result::Result { Ok(Self(value.parse()?)) } } - impl std::convert::TryFrom<&str> for StateMachineId { + impl ::std::convert::TryFrom<&str> for StateMachineId { type Error = ::Err; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&String> for StateMachineId { + impl ::std::convert::TryFrom<&String> for StateMachineId { type Error = ::Err; fn try_from(value: &String) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom for StateMachineId { + impl ::std::convert::TryFrom for StateMachineId { type Error = ::Err; fn try_from(value: String) -> ::std::result::Result { value.parse() @@ -3331,7 +3496,7 @@ pub mod types { Cleanup, } - impl From<&Step> for Step { + impl ::std::convert::From<&Step> for Step { fn from(value: &Step) -> Self { value.clone() } @@ -3348,7 +3513,7 @@ pub mod types { } } - impl std::str::FromStr for Step { + impl ::std::str::FromStr for Step { type Err = self::error::ConversionError; fn from_str(value: &str) -> ::std::result::Result { match value { @@ -3361,14 +3526,14 @@ pub mod types { } } - impl std::convert::TryFrom<&str> for Step { + impl ::std::convert::TryFrom<&str> for Step { type Error = self::error::ConversionError; fn try_from(value: &str) -> ::std::result::Result { value.parse() } } - impl std::convert::TryFrom<&::std::string::String> for Step { + impl ::std::convert::TryFrom<&::std::string::String> for Step { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -3377,7 +3542,7 @@ pub mod types { } } - impl std::convert::TryFrom<::std::string::String> for Step { + impl ::std::convert::TryFrom<::std::string::String> for Step { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -3534,12 +3699,32 @@ pub mod types { pub submission_status: ::std::option::Option<::std::string::String>, } - impl From<&Submission> for Submission { + impl ::std::convert::From<&Submission> for Submission { fn from(value: &Submission) -> Self { value.clone() } } + impl ::std::default::Default for Submission { + fn default() -> Self { + Self { + city: Default::default(), + consent: Default::default(), + country: Default::default(), + created_at: Default::default(), + email: Default::default(), + fips_code: Default::default(), + first_name: Default::default(), + id: Default::default(), + last_name: Default::default(), + occupation: Default::default(), + organization: Default::default(), + region: Default::default(), + submission_status: Default::default(), + } + } + } + impl Submission { pub fn builder() -> builder::Submission { Default::default() @@ -3703,12 +3888,30 @@ pub mod types { pub submission_status: ::std::option::Option<::std::string::String>, } - impl From<&SubmissionPatch> for SubmissionPatch { + impl ::std::convert::From<&SubmissionPatch> for SubmissionPatch { fn from(value: &SubmissionPatch) -> Self { value.clone() } } + impl ::std::default::Default for SubmissionPatch { + fn default() -> Self { + Self { + city: Default::default(), + consent: Default::default(), + country: Default::default(), + email: Default::default(), + fips_code: Default::default(), + first_name: Default::default(), + last_name: Default::default(), + occupation: Default::default(), + organization: Default::default(), + region: Default::default(), + submission_status: Default::default(), + } + } + } + impl SubmissionPatch { pub fn builder() -> builder::SubmissionPatch { Default::default() @@ -3853,7 +4056,7 @@ pub mod types { pub submission_status: ::std::option::Option<::std::string::String>, } - impl From<&SubmissionPost> for SubmissionPost { + impl ::std::convert::From<&SubmissionPost> for SubmissionPost { fn from(value: &SubmissionPost) -> Self { value.clone() } @@ -3888,19 +4091,19 @@ pub mod types { } } - impl From for ::std::vec::Vec { + impl ::std::convert::From for ::std::vec::Vec { fn from(value: Submissions) -> Self { value.0 } } - impl From<&Submissions> for Submissions { + impl ::std::convert::From<&Submissions> for Submissions { fn from(value: &Submissions) -> Self { value.clone() } } - impl From<::std::vec::Vec> for Submissions { + impl ::std::convert::From<::std::vec::Vec> for Submissions { fn from(value: ::std::vec::Vec) -> Self { Self(value) } @@ -3927,12 +4130,20 @@ pub mod types { pub score: ::std::option::Option, } - impl From<&Transit> for Transit { + impl ::std::convert::From<&Transit> for Transit { fn from(value: &Transit) -> Self { value.clone() } } + impl ::std::default::Default for Transit { + fn default() -> Self { + Self { + score: Default::default(), + } + } + } + impl Transit { pub fn builder() -> builder::Transit { Default::default() @@ -3980,7 +4191,7 @@ pub mod types { torn_down: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Analysis { + impl ::std::default::Default for Analysis { fn default() -> Self { Self { cost: Ok(Default::default()), @@ -4002,8 +4213,8 @@ pub mod types { impl Analysis { pub fn cost(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.cost = value .try_into() @@ -4012,10 +4223,10 @@ pub mod types { } pub fn end_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.end_time = value .try_into() @@ -4024,8 +4235,8 @@ pub mod types { } pub fn fargate_price_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.fargate_price_id = value.try_into().map_err(|e| { format!( @@ -4037,8 +4248,8 @@ pub mod types { } pub fn fargate_task_arn(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fargate_task_arn = value.try_into().map_err(|e| { format!( @@ -4050,8 +4261,8 @@ pub mod types { } pub fn results_posted(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.results_posted = value.try_into().map_err(|e| { format!("error converting supplied value for results_posted: {}", e) @@ -4060,8 +4271,8 @@ pub mod types { } pub fn s3_bucket(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.s3_bucket = value .try_into() @@ -4070,8 +4281,8 @@ pub mod types { } pub fn sqs_message(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.sqs_message = value .try_into() @@ -4080,10 +4291,10 @@ pub mod types { } pub fn start_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.start_time = value .try_into() @@ -4092,8 +4303,8 @@ pub mod types { } pub fn state_machine_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.state_machine_id = value.try_into().map_err(|e| { format!( @@ -4105,8 +4316,8 @@ pub mod types { } pub fn status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.status = value .try_into() @@ -4115,8 +4326,8 @@ pub mod types { } pub fn step(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.step = value .try_into() @@ -4125,8 +4336,8 @@ pub mod types { } pub fn torn_down(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.torn_down = value .try_into() @@ -4157,7 +4368,7 @@ pub mod types { } } - impl From for Analysis { + impl ::std::convert::From for Analysis { fn from(value: super::Analysis) -> Self { Self { cost: Ok(value.cost), @@ -4209,7 +4420,7 @@ pub mod types { torn_down: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for AnalysisPatch { + impl ::std::default::Default for AnalysisPatch { fn default() -> Self { Self { cost: Ok(Default::default()), @@ -4229,8 +4440,8 @@ pub mod types { impl AnalysisPatch { pub fn cost(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.cost = value .try_into() @@ -4239,10 +4450,10 @@ pub mod types { } pub fn end_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.end_time = value .try_into() @@ -4251,8 +4462,8 @@ pub mod types { } pub fn fargate_task_arn(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fargate_task_arn = value.try_into().map_err(|e| { format!( @@ -4264,8 +4475,8 @@ pub mod types { } pub fn results_posted(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.results_posted = value.try_into().map_err(|e| { format!("error converting supplied value for results_posted: {}", e) @@ -4274,8 +4485,8 @@ pub mod types { } pub fn s3_bucket(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.s3_bucket = value .try_into() @@ -4284,8 +4495,8 @@ pub mod types { } pub fn sqs_message(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.sqs_message = value .try_into() @@ -4294,10 +4505,10 @@ pub mod types { } pub fn start_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.start_time = value .try_into() @@ -4306,8 +4517,8 @@ pub mod types { } pub fn status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.status = value .try_into() @@ -4316,8 +4527,8 @@ pub mod types { } pub fn step(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.step = value .try_into() @@ -4326,8 +4537,8 @@ pub mod types { } pub fn torn_down(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.torn_down = value .try_into() @@ -4356,7 +4567,7 @@ pub mod types { } } - impl From for AnalysisPatch { + impl ::std::convert::From for AnalysisPatch { fn from(value: super::AnalysisPatch) -> Self { Self { cost: Ok(value.cost), @@ -4412,7 +4623,7 @@ pub mod types { torn_down: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for AnalysisPost { + impl ::std::default::Default for AnalysisPost { fn default() -> Self { Self { cost: Ok(Default::default()), @@ -4434,8 +4645,8 @@ pub mod types { impl AnalysisPost { pub fn cost(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.cost = value .try_into() @@ -4444,10 +4655,10 @@ pub mod types { } pub fn end_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.end_time = value .try_into() @@ -4456,8 +4667,8 @@ pub mod types { } pub fn fargate_price_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.fargate_price_id = value.try_into().map_err(|e| { format!( @@ -4469,8 +4680,8 @@ pub mod types { } pub fn fargate_task_arn(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fargate_task_arn = value.try_into().map_err(|e| { format!( @@ -4482,8 +4693,8 @@ pub mod types { } pub fn result_posted(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.result_posted = value.try_into().map_err(|e| { format!("error converting supplied value for result_posted: {}", e) @@ -4492,8 +4703,8 @@ pub mod types { } pub fn s3_bucket(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.s3_bucket = value .try_into() @@ -4502,8 +4713,8 @@ pub mod types { } pub fn sqs_message(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.sqs_message = value .try_into() @@ -4512,10 +4723,10 @@ pub mod types { } pub fn start_time(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.start_time = value .try_into() @@ -4524,8 +4735,8 @@ pub mod types { } pub fn state_machine_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.state_machine_id = value.try_into().map_err(|e| { format!( @@ -4537,8 +4748,8 @@ pub mod types { } pub fn status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.status = value .try_into() @@ -4547,8 +4758,8 @@ pub mod types { } pub fn step(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.step = value .try_into() @@ -4557,8 +4768,8 @@ pub mod types { } pub fn torn_down(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.torn_down = value .try_into() @@ -4589,7 +4800,7 @@ pub mod types { } } - impl From for AnalysisPost { + impl ::std::convert::From for AnalysisPost { fn from(value: super::AnalysisPost) -> Self { Self { cost: Ok(value.cost), @@ -4647,7 +4858,7 @@ pub mod types { version: ::std::result::Result<::std::string::String, ::std::string::String>, } - impl Default for Bna { + impl ::std::default::Default for Bna { fn default() -> Self { Self { city_id: Err("no value supplied for city_id".to_string()), @@ -4682,8 +4893,8 @@ pub mod types { impl Bna { pub fn city_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.city_id = value .try_into() @@ -4692,8 +4903,8 @@ pub mod types { } pub fn community_centers(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.community_centers = value.try_into().map_err(|e| { format!( @@ -4705,8 +4916,8 @@ pub mod types { } pub fn coreservices_score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.coreservices_score = value.try_into().map_err(|e| { format!( @@ -4718,8 +4929,8 @@ pub mod types { } pub fn dentists(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.dentists = value .try_into() @@ -4728,8 +4939,8 @@ pub mod types { } pub fn doctors(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.doctors = value .try_into() @@ -4738,8 +4949,8 @@ pub mod types { } pub fn employment(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.employment = value .try_into() @@ -4748,8 +4959,8 @@ pub mod types { } pub fn grocery(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.grocery = value .try_into() @@ -4758,8 +4969,8 @@ pub mod types { } pub fn high_stress_miles(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.high_stress_miles = value.try_into().map_err(|e| { format!( @@ -4771,8 +4982,8 @@ pub mod types { } pub fn higher_education(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.higher_education = value.try_into().map_err(|e| { format!( @@ -4784,8 +4995,8 @@ pub mod types { } pub fn hospitals(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.hospitals = value .try_into() @@ -4794,8 +5005,8 @@ pub mod types { } pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.id = value .try_into() @@ -4804,8 +5015,8 @@ pub mod types { } pub fn k12_education(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.k12_education = value.try_into().map_err(|e| { format!("error converting supplied value for k12_education: {}", e) @@ -4814,8 +5025,8 @@ pub mod types { } pub fn low_stress_miles(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.low_stress_miles = value.try_into().map_err(|e| { format!( @@ -4827,8 +5038,8 @@ pub mod types { } pub fn opportunity_score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.opportunity_score = value.try_into().map_err(|e| { format!( @@ -4840,8 +5051,8 @@ pub mod types { } pub fn parks(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.parks = value .try_into() @@ -4850,8 +5061,8 @@ pub mod types { } pub fn people(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.people = value .try_into() @@ -4860,8 +5071,8 @@ pub mod types { } pub fn pharmacies(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.pharmacies = value .try_into() @@ -4870,8 +5081,8 @@ pub mod types { } pub fn recreation_score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.recreation_score = value.try_into().map_err(|e| { format!( @@ -4883,8 +5094,8 @@ pub mod types { } pub fn recreation_trails(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.recreation_trails = value.try_into().map_err(|e| { format!( @@ -4896,8 +5107,8 @@ pub mod types { } pub fn retail(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.retail = value .try_into() @@ -4906,8 +5117,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -4916,8 +5127,8 @@ pub mod types { } pub fn social_services(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.social_services = value.try_into().map_err(|e| { format!("error converting supplied value for social_services: {}", e) @@ -4926,8 +5137,8 @@ pub mod types { } pub fn technical_vocational_college(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.technical_vocational_college = value.try_into().map_err(|e| { format!( @@ -4939,8 +5150,8 @@ pub mod types { } pub fn transit(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.transit = value .try_into() @@ -4949,8 +5160,8 @@ pub mod types { } pub fn version(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.version = value .try_into() @@ -4992,7 +5203,7 @@ pub mod types { } } - impl From for Bna { + impl ::std::convert::From for Bna { fn from(value: super::Bna) -> Self { Self { city_id: Ok(value.city_id), @@ -5036,7 +5247,7 @@ pub mod types { transit: ::std::result::Result, } - impl Default for BnaPost { + impl ::std::default::Default for BnaPost { fn default() -> Self { Self { core_services: Err("no value supplied for core_services".to_string()), @@ -5054,8 +5265,8 @@ pub mod types { impl BnaPost { pub fn core_services(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.core_services = value.try_into().map_err(|e| { format!("error converting supplied value for core_services: {}", e) @@ -5064,8 +5275,8 @@ pub mod types { } pub fn infrastructure(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.infrastructure = value.try_into().map_err(|e| { format!("error converting supplied value for infrastructure: {}", e) @@ -5074,8 +5285,8 @@ pub mod types { } pub fn opportunity(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.opportunity = value .try_into() @@ -5084,8 +5295,8 @@ pub mod types { } pub fn people(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.people = value .try_into() @@ -5094,8 +5305,8 @@ pub mod types { } pub fn recreation(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.recreation = value .try_into() @@ -5104,8 +5315,8 @@ pub mod types { } pub fn retail(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.retail = value .try_into() @@ -5114,8 +5325,8 @@ pub mod types { } pub fn summary(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.summary = value .try_into() @@ -5124,8 +5335,8 @@ pub mod types { } pub fn transit(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.transit = value .try_into() @@ -5152,7 +5363,7 @@ pub mod types { } } - impl From for BnaPost { + impl ::std::convert::From for BnaPost { fn from(value: super::BnaPost) -> Self { Self { core_services: Ok(value.core_services), @@ -5179,7 +5390,7 @@ pub mod types { version: ::std::result::Result<::std::string::String, ::std::string::String>, } - impl Default for BnaSummary { + impl ::std::default::Default for BnaSummary { fn default() -> Self { Self { city_id: Err("no value supplied for city_id".to_string()), @@ -5194,8 +5405,8 @@ pub mod types { impl BnaSummary { pub fn city_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.city_id = value .try_into() @@ -5204,10 +5415,10 @@ pub mod types { } pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -5216,8 +5427,8 @@ pub mod types { } pub fn rating_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.rating_id = value .try_into() @@ -5226,8 +5437,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -5236,8 +5447,8 @@ pub mod types { } pub fn version(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.version = value .try_into() @@ -5261,7 +5472,7 @@ pub mod types { } } - impl From for BnaSummary { + impl ::std::convert::From for BnaSummary { fn from(value: super::BnaSummary) -> Self { Self { city_id: Ok(value.city_id), @@ -5302,7 +5513,7 @@ pub mod types { version: ::std::result::Result<::std::string::String, ::std::string::String>, } - impl Default for BnaSummaryWithCityItem { + impl ::std::default::Default for BnaSummaryWithCityItem { fn default() -> Self { Self { city_id: Err("no value supplied for city_id".to_string()), @@ -5327,8 +5538,8 @@ pub mod types { impl BnaSummaryWithCityItem { pub fn city_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.city_id = value .try_into() @@ -5337,8 +5548,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -5347,8 +5558,8 @@ pub mod types { } pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto>, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -5357,8 +5568,8 @@ pub mod types { } pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.id = value .try_into() @@ -5367,8 +5578,8 @@ pub mod types { } pub fn latitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.latitude = value .try_into() @@ -5377,8 +5588,8 @@ pub mod types { } pub fn longitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.longitude = value .try_into() @@ -5387,8 +5598,8 @@ pub mod types { } pub fn name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.name = value .try_into() @@ -5397,8 +5608,8 @@ pub mod types { } pub fn rating_id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.rating_id = value .try_into() @@ -5407,8 +5618,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -5417,8 +5628,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -5427,8 +5638,8 @@ pub mod types { } pub fn speed_limit(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.speed_limit = value .try_into() @@ -5437,8 +5648,8 @@ pub mod types { } pub fn state(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.state = value .try_into() @@ -5447,8 +5658,8 @@ pub mod types { } pub fn state_abbrev(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.state_abbrev = value.try_into().map_err(|e| { format!("error converting supplied value for state_abbrev: {}", e) @@ -5457,10 +5668,10 @@ pub mod types { } pub fn updated_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.updated_at = value .try_into() @@ -5469,8 +5680,8 @@ pub mod types { } pub fn version(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.version = value .try_into() @@ -5504,7 +5715,7 @@ pub mod types { } } - impl From for BnaSummaryWithCityItem { + impl ::std::convert::From for BnaSummaryWithCityItem { fn from(value: super::BnaSummaryWithCityItem) -> Self { Self { city_id: Ok(value.city_id), @@ -5546,7 +5757,7 @@ pub mod types { population: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Census { + impl ::std::default::Default for Census { fn default() -> Self { Self { census_id: Ok(Default::default()), @@ -5562,8 +5773,8 @@ pub mod types { impl Census { pub fn census_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.census_id = value .try_into() @@ -5572,8 +5783,8 @@ pub mod types { } pub fn city_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.city_id = value .try_into() @@ -5582,10 +5793,10 @@ pub mod types { } pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -5594,8 +5805,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -5604,8 +5815,8 @@ pub mod types { } pub fn pop_size(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.pop_size = value .try_into() @@ -5614,8 +5825,8 @@ pub mod types { } pub fn population(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.population = value .try_into() @@ -5640,7 +5851,7 @@ pub mod types { } } - impl From for Census { + impl ::std::convert::From for Census { fn from(value: super::Census) -> Self { Self { census_id: Ok(value.census_id), @@ -5666,7 +5877,7 @@ pub mod types { population: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for CensusPost { + impl ::std::default::Default for CensusPost { fn default() -> Self { Self { fips_code: Ok(Default::default()), @@ -5679,8 +5890,8 @@ pub mod types { impl CensusPost { pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -5689,8 +5900,8 @@ pub mod types { } pub fn pop_size(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.pop_size = value .try_into() @@ -5699,8 +5910,8 @@ pub mod types { } pub fn population(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.population = value .try_into() @@ -5722,7 +5933,7 @@ pub mod types { } } - impl From for CensusPost { + impl ::std::convert::From for CensusPost { fn from(value: super::CensusPost) -> Self { Self { fips_code: Ok(value.fips_code), @@ -5757,7 +5968,7 @@ pub mod types { >, } - impl Default for City { + impl ::std::default::Default for City { fn default() -> Self { Self { country: Err("no value supplied for country".to_string()), @@ -5778,8 +5989,8 @@ pub mod types { impl City { pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -5788,8 +5999,8 @@ pub mod types { } pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto>, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -5798,8 +6009,8 @@ pub mod types { } pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.id = value .try_into() @@ -5808,8 +6019,8 @@ pub mod types { } pub fn latitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.latitude = value .try_into() @@ -5818,8 +6029,8 @@ pub mod types { } pub fn longitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.longitude = value .try_into() @@ -5828,8 +6039,8 @@ pub mod types { } pub fn name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.name = value .try_into() @@ -5838,8 +6049,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -5848,8 +6059,8 @@ pub mod types { } pub fn speed_limit(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.speed_limit = value .try_into() @@ -5858,8 +6069,8 @@ pub mod types { } pub fn state(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.state = value .try_into() @@ -5868,8 +6079,8 @@ pub mod types { } pub fn state_abbrev(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.state_abbrev = value.try_into().map_err(|e| { format!("error converting supplied value for state_abbrev: {}", e) @@ -5878,10 +6089,10 @@ pub mod types { } pub fn updated_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.updated_at = value .try_into() @@ -5909,7 +6120,7 @@ pub mod types { } } - impl From for City { + impl ::std::convert::From for City { fn from(value: super::City) -> Self { Self { country: Ok(value.country), @@ -5944,7 +6155,7 @@ pub mod types { >, } - impl Default for CityPost { + impl ::std::default::Default for CityPost { fn default() -> Self { Self { country: Err("no value supplied for country".to_string()), @@ -5961,8 +6172,8 @@ pub mod types { impl CityPost { pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -5971,8 +6182,8 @@ pub mod types { } pub fn latitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.latitude = value .try_into() @@ -5981,8 +6192,8 @@ pub mod types { } pub fn longitude(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.longitude = value .try_into() @@ -5991,8 +6202,8 @@ pub mod types { } pub fn name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.name = value .try_into() @@ -6001,8 +6212,8 @@ pub mod types { } pub fn speed_limit(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.speed_limit = value .try_into() @@ -6011,8 +6222,8 @@ pub mod types { } pub fn state(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.state = value .try_into() @@ -6021,8 +6232,8 @@ pub mod types { } pub fn state_abbrev(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.state_abbrev = value.try_into().map_err(|e| { format!("error converting supplied value for state_abbrev: {}", e) @@ -6048,7 +6259,7 @@ pub mod types { } } - impl From for CityPost { + impl ::std::convert::From for CityPost { fn from(value: super::CityPost) -> Self { Self { country: Ok(value.country), @@ -6074,7 +6285,7 @@ pub mod types { ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for CoreServices { + impl ::std::default::Default for CoreServices { fn default() -> Self { Self { dentists: Ok(Default::default()), @@ -6091,8 +6302,8 @@ pub mod types { impl CoreServices { pub fn dentists(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.dentists = value .try_into() @@ -6101,8 +6312,8 @@ pub mod types { } pub fn doctors(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.doctors = value .try_into() @@ -6111,8 +6322,8 @@ pub mod types { } pub fn grocery(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.grocery = value .try_into() @@ -6121,8 +6332,8 @@ pub mod types { } pub fn hospitals(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.hospitals = value .try_into() @@ -6131,8 +6342,8 @@ pub mod types { } pub fn pharmacies(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.pharmacies = value .try_into() @@ -6141,8 +6352,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -6151,8 +6362,8 @@ pub mod types { } pub fn social_services(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.social_services = value.try_into().map_err(|e| { format!("error converting supplied value for social_services: {}", e) @@ -6178,7 +6389,7 @@ pub mod types { } } - impl From for CoreServices { + impl ::std::convert::From for CoreServices { fn from(value: super::CoreServices) -> Self { Self { dentists: Ok(value.dentists), @@ -6210,7 +6421,7 @@ pub mod types { >, } - impl Default for Enqueue { + impl ::std::default::Default for Enqueue { fn default() -> Self { Self { city: Ok(Default::default()), @@ -6224,8 +6435,8 @@ pub mod types { impl Enqueue { pub fn city(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.city = value .try_into() @@ -6234,8 +6445,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -6244,8 +6455,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -6254,8 +6465,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -6278,7 +6489,7 @@ pub mod types { } } - impl From for Enqueue { + impl ::std::convert::From for Enqueue { fn from(value: super::Enqueue) -> Self { Self { city: Ok(value.city), @@ -6307,7 +6518,7 @@ pub mod types { >, } - impl Default for EnqueuePost { + impl ::std::default::Default for EnqueuePost { fn default() -> Self { Self { city: Ok(Default::default()), @@ -6321,8 +6532,8 @@ pub mod types { impl EnqueuePost { pub fn city(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.city = value .try_into() @@ -6331,8 +6542,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -6341,8 +6552,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -6351,8 +6562,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -6375,7 +6586,7 @@ pub mod types { } } - impl From for EnqueuePost { + impl ::std::convert::From for EnqueuePost { fn from(value: super::EnqueuePost) -> Self { Self { city: Ok(value.city), @@ -6405,7 +6616,7 @@ pub mod types { >, } - impl Default for Error { + impl ::std::default::Default for Error { fn default() -> Self { Self { details: Ok(Default::default()), @@ -6420,8 +6631,8 @@ pub mod types { impl Error { pub fn details(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.details = value .try_into() @@ -6430,8 +6641,8 @@ pub mod types { } pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.id = value .try_into() @@ -6440,8 +6651,8 @@ pub mod types { } pub fn source(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.source = value .try_into() @@ -6450,8 +6661,8 @@ pub mod types { } pub fn status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.status = value .try_into() @@ -6460,8 +6671,8 @@ pub mod types { } pub fn title(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.title = value .try_into() @@ -6485,7 +6696,7 @@ pub mod types { } } - impl From for Error { + impl ::std::convert::From for Error { fn from(value: super::Error) -> Self { Self { details: Ok(value.details), @@ -6511,7 +6722,7 @@ pub mod types { >, } - impl Default for FargatePrice { + impl ::std::default::Default for FargatePrice { fn default() -> Self { Self { created_at: Ok(Default::default()), @@ -6524,10 +6735,10 @@ pub mod types { impl FargatePrice { pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -6536,8 +6747,8 @@ pub mod types { } pub fn fargate_price_id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.fargate_price_id = value.try_into().map_err(|e| { format!( @@ -6549,8 +6760,8 @@ pub mod types { } pub fn per_second(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.per_second = value .try_into() @@ -6572,7 +6783,7 @@ pub mod types { } } - impl From for FargatePrice { + impl ::std::convert::From for FargatePrice { fn from(value: super::FargatePrice) -> Self { Self { created_at: Ok(value.created_at), @@ -6590,7 +6801,7 @@ pub mod types { ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Infrastructure { + impl ::std::default::Default for Infrastructure { fn default() -> Self { Self { high_stress_miles: Ok(Default::default()), @@ -6602,8 +6813,8 @@ pub mod types { impl Infrastructure { pub fn high_stress_miles(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.high_stress_miles = value.try_into().map_err(|e| { format!( @@ -6615,8 +6826,8 @@ pub mod types { } pub fn low_stress_miles(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.low_stress_miles = value.try_into().map_err(|e| { format!( @@ -6640,7 +6851,7 @@ pub mod types { } } - impl From for Infrastructure { + impl ::std::convert::From for Infrastructure { fn from(value: super::Infrastructure) -> Self { Self { high_stress_miles: Ok(value.high_stress_miles), @@ -6660,7 +6871,7 @@ pub mod types { ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Opportunity { + impl ::std::default::Default for Opportunity { fn default() -> Self { Self { employment: Ok(Default::default()), @@ -6675,8 +6886,8 @@ pub mod types { impl Opportunity { pub fn employment(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.employment = value .try_into() @@ -6685,8 +6896,8 @@ pub mod types { } pub fn higher_education(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.higher_education = value.try_into().map_err(|e| { format!( @@ -6698,8 +6909,8 @@ pub mod types { } pub fn k12_education(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.k12_education = value.try_into().map_err(|e| { format!("error converting supplied value for k12_education: {}", e) @@ -6708,8 +6919,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -6718,8 +6929,8 @@ pub mod types { } pub fn technical_vocational_college(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.technical_vocational_college = value.try_into().map_err(|e| { format!( @@ -6746,7 +6957,7 @@ pub mod types { } } - impl From for Opportunity { + impl ::std::convert::From for Opportunity { fn from(value: super::Opportunity) -> Self { Self { employment: Ok(value.employment), @@ -6763,7 +6974,7 @@ pub mod types { score: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for People { + impl ::std::default::Default for People { fn default() -> Self { Self { score: Ok(Default::default()), @@ -6774,8 +6985,8 @@ pub mod types { impl People { pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -6795,7 +7006,7 @@ pub mod types { } } - impl From for People { + impl ::std::convert::From for People { fn from(value: super::People) -> Self { Self { score: Ok(value.score), @@ -6813,7 +7024,7 @@ pub mod types { score: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Recreation { + impl ::std::default::Default for Recreation { fn default() -> Self { Self { community_centers: Ok(Default::default()), @@ -6827,8 +7038,8 @@ pub mod types { impl Recreation { pub fn community_centers(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.community_centers = value.try_into().map_err(|e| { format!( @@ -6840,8 +7051,8 @@ pub mod types { } pub fn parks(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.parks = value .try_into() @@ -6850,8 +7061,8 @@ pub mod types { } pub fn recreation_trails(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.recreation_trails = value.try_into().map_err(|e| { format!( @@ -6863,8 +7074,8 @@ pub mod types { } pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -6887,7 +7098,7 @@ pub mod types { } } - impl From for Recreation { + impl ::std::convert::From for Recreation { fn from(value: super::Recreation) -> Self { Self { community_centers: Ok(value.community_centers), @@ -6903,7 +7114,7 @@ pub mod types { score: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Retail { + impl ::std::default::Default for Retail { fn default() -> Self { Self { score: Ok(Default::default()), @@ -6914,8 +7125,8 @@ pub mod types { impl Retail { pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -6935,7 +7146,7 @@ pub mod types { } } - impl From for Retail { + impl ::std::convert::From for Retail { fn from(value: super::Retail) -> Self { Self { score: Ok(value.score), @@ -6991,7 +7202,7 @@ pub mod types { >, } - impl Default for Submission { + impl ::std::default::Default for Submission { fn default() -> Self { Self { city: Ok(Default::default()), @@ -7014,8 +7225,8 @@ pub mod types { impl Submission { pub fn city(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.city = value .try_into() @@ -7024,8 +7235,8 @@ pub mod types { } pub fn consent(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.consent = value .try_into() @@ -7034,8 +7245,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -7044,10 +7255,10 @@ pub mod types { } pub fn created_at(mut self, value: T) -> Self where - T: std::convert::TryInto< + T: ::std::convert::TryInto< ::std::option::Option>, >, - T::Error: std::fmt::Display, + T::Error: ::std::fmt::Display, { self.created_at = value .try_into() @@ -7056,8 +7267,8 @@ pub mod types { } pub fn email(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.email = value .try_into() @@ -7066,8 +7277,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -7076,8 +7287,8 @@ pub mod types { } pub fn first_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.first_name = value .try_into() @@ -7086,8 +7297,8 @@ pub mod types { } pub fn id(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.id = value .try_into() @@ -7096,8 +7307,8 @@ pub mod types { } pub fn last_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.last_name = value .try_into() @@ -7106,8 +7317,8 @@ pub mod types { } pub fn occupation(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.occupation = value .try_into() @@ -7116,8 +7327,8 @@ pub mod types { } pub fn organization(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.organization = value.try_into().map_err(|e| { format!("error converting supplied value for organization: {}", e) @@ -7126,8 +7337,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -7136,8 +7347,8 @@ pub mod types { } pub fn submission_status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.submission_status = value.try_into().map_err(|e| { format!( @@ -7172,7 +7383,7 @@ pub mod types { } } - impl From for Submission { + impl ::std::convert::From for Submission { fn from(value: super::Submission) -> Self { Self { city: Ok(value.city), @@ -7235,7 +7446,7 @@ pub mod types { >, } - impl Default for SubmissionPatch { + impl ::std::default::Default for SubmissionPatch { fn default() -> Self { Self { city: Ok(Default::default()), @@ -7256,8 +7467,8 @@ pub mod types { impl SubmissionPatch { pub fn city(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.city = value .try_into() @@ -7266,8 +7477,8 @@ pub mod types { } pub fn consent(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.consent = value .try_into() @@ -7276,8 +7487,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -7286,8 +7497,8 @@ pub mod types { } pub fn email(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.email = value .try_into() @@ -7296,8 +7507,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -7306,8 +7517,8 @@ pub mod types { } pub fn first_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.first_name = value .try_into() @@ -7316,8 +7527,8 @@ pub mod types { } pub fn last_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.last_name = value .try_into() @@ -7326,8 +7537,8 @@ pub mod types { } pub fn occupation(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.occupation = value .try_into() @@ -7336,8 +7547,8 @@ pub mod types { } pub fn organization(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.organization = value.try_into().map_err(|e| { format!("error converting supplied value for organization: {}", e) @@ -7346,8 +7557,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -7356,8 +7567,8 @@ pub mod types { } pub fn submission_status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.submission_status = value.try_into().map_err(|e| { format!( @@ -7390,7 +7601,7 @@ pub mod types { } } - impl From for SubmissionPatch { + impl ::std::convert::From for SubmissionPatch { fn from(value: super::SubmissionPatch) -> Self { Self { city: Ok(value.city), @@ -7435,7 +7646,7 @@ pub mod types { >, } - impl Default for SubmissionPost { + impl ::std::default::Default for SubmissionPost { fn default() -> Self { Self { city: Err("no value supplied for city".to_string()), @@ -7456,8 +7667,8 @@ pub mod types { impl SubmissionPost { pub fn city(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.city = value .try_into() @@ -7466,8 +7677,8 @@ pub mod types { } pub fn consent(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.consent = value .try_into() @@ -7476,8 +7687,8 @@ pub mod types { } pub fn country(mut self, value: T) -> Self where - T: std::convert::TryInto, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, { self.country = value .try_into() @@ -7486,8 +7697,8 @@ pub mod types { } pub fn email(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.email = value .try_into() @@ -7496,8 +7707,8 @@ pub mod types { } pub fn fips_code(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.fips_code = value .try_into() @@ -7506,8 +7717,8 @@ pub mod types { } pub fn first_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.first_name = value .try_into() @@ -7516,8 +7727,8 @@ pub mod types { } pub fn last_name(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::string::String>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, { self.last_name = value .try_into() @@ -7526,8 +7737,8 @@ pub mod types { } pub fn occupation(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.occupation = value .try_into() @@ -7536,8 +7747,8 @@ pub mod types { } pub fn organization(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.organization = value.try_into().map_err(|e| { format!("error converting supplied value for organization: {}", e) @@ -7546,8 +7757,8 @@ pub mod types { } pub fn region(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.region = value .try_into() @@ -7556,8 +7767,8 @@ pub mod types { } pub fn submission_status(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, { self.submission_status = value.try_into().map_err(|e| { format!( @@ -7590,7 +7801,7 @@ pub mod types { } } - impl From for SubmissionPost { + impl ::std::convert::From for SubmissionPost { fn from(value: super::SubmissionPost) -> Self { Self { city: Ok(value.city), @@ -7613,7 +7824,7 @@ pub mod types { score: ::std::result::Result<::std::option::Option, ::std::string::String>, } - impl Default for Transit { + impl ::std::default::Default for Transit { fn default() -> Self { Self { score: Ok(Default::default()), @@ -7624,8 +7835,8 @@ pub mod types { impl Transit { pub fn score(mut self, value: T) -> Self where - T: std::convert::TryInto<::std::option::Option>, - T::Error: std::fmt::Display, + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, { self.score = value .try_into() @@ -7645,7 +7856,7 @@ pub mod types { } } - impl From for Transit { + impl ::std::convert::From for Transit { fn from(value: super::Transit) -> Self { Self { score: Ok(value.score), @@ -8168,8 +8379,8 @@ pub mod builder { #[derive(Debug, Clone)] pub struct GetRatings<'a> { client: &'a super::Client, - page: Result, String>, - page_size: Result, String>, + page: Result, String>, + page_size: Result, String>, } impl<'a> GetRatings<'a> { @@ -8183,23 +8394,21 @@ pub mod builder { pub fn page(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page failed".to_string()); + self.page = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page failed".to_string() + }); self } pub fn page_size(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page_size = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page_size failed".to_string()); + self.page_size = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page_size failed".to_string() + }); self } @@ -8313,8 +8522,8 @@ pub mod builder { #[derive(Debug, Clone)] pub struct GetRatingsAnalyses<'a> { client: &'a super::Client, - page: Result, String>, - page_size: Result, String>, + page: Result, String>, + page_size: Result, String>, } impl<'a> GetRatingsAnalyses<'a> { @@ -8328,23 +8537,21 @@ pub mod builder { pub fn page(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page failed".to_string()); + self.page = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page failed".to_string() + }); self } pub fn page_size(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page_size = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page_size failed".to_string()); + self.page_size = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page_size failed".to_string() + }); self } @@ -8768,8 +8975,8 @@ pub mod builder { #[derive(Debug, Clone)] pub struct GetCities<'a> { client: &'a super::Client, - page: Result, String>, - page_size: Result, String>, + page: Result, String>, + page_size: Result, String>, } impl<'a> GetCities<'a> { @@ -8783,23 +8990,21 @@ pub mod builder { pub fn page(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page failed".to_string()); + self.page = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page failed".to_string() + }); self } pub fn page_size(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page_size = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page_size failed".to_string()); + self.page_size = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page_size failed".to_string() + }); self } @@ -8845,8 +9050,8 @@ pub mod builder { #[derive(Debug, Clone)] pub struct PostCity<'a> { client: &'a super::Client, - page: Result, String>, - page_size: Result, String>, + page: Result, String>, + page_size: Result, String>, body: Result, } @@ -8862,23 +9067,21 @@ pub mod builder { pub fn page(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page failed".to_string()); + self.page = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page failed".to_string() + }); self } pub fn page_size(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page_size = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page_size failed".to_string()); + self.page_size = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page_size failed".to_string() + }); self } @@ -8952,8 +9155,8 @@ pub mod builder { #[derive(Debug, Clone)] pub struct GetCitySubmissions<'a> { client: &'a super::Client, - page: Result, String>, - page_size: Result, String>, + page: Result, String>, + page_size: Result, String>, } impl<'a> GetCitySubmissions<'a> { @@ -8967,23 +9170,21 @@ pub mod builder { pub fn page(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page failed".to_string()); + self.page = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page failed".to_string() + }); self } pub fn page_size(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.page_size = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `i64` for page_size failed".to_string()); + self.page_size = value.try_into().map(Some).map_err(|_| { + "conversion to `std :: num :: NonZeroU16` for page_size failed".to_string() + }); self } diff --git a/bnaclient/src/progenitor_client.rs b/bnaclient/src/progenitor_client.rs index 61b79eb..d36990c 100644 --- a/bnaclient/src/progenitor_client.rs +++ b/bnaclient/src/progenitor_client.rs @@ -12,12 +12,10 @@ use reqwest::RequestBuilder; use serde::{de::DeserializeOwned, Serialize}; #[cfg(not(target_arch = "wasm32"))] -type InnerByteStream = - std::pin::Pin> + Send + Sync>>; +type InnerByteStream = std::pin::Pin> + Send + Sync>>; #[cfg(target_arch = "wasm32")] -type InnerByteStream = - std::pin::Pin>>>; +type InnerByteStream = std::pin::Pin>>>; /// Untyped byte stream used for both success and error responses. pub struct ByteStream(InnerByteStream); @@ -63,14 +61,12 @@ pub struct ResponseValue { impl ResponseValue { #[doc(hidden)] - pub async fn from_response( - response: reqwest::Response, - ) -> Result> { + pub async fn from_response(response: reqwest::Response) -> Result> { let status = response.status(); let headers = response.headers().clone(); let full = response.bytes().await.map_err(Error::ResponseBodyError)?; - let inner = serde_json::from_slice(&full) - .map_err(|e| Error::InvalidResponsePayload(full, e))?; + let inner = + serde_json::from_slice(&full).map_err(|e| Error::InvalidResponsePayload(full, e))?; Ok(Self { inner, @@ -89,8 +85,7 @@ impl ResponseValue { let status = response.status(); let headers = response.headers().clone(); if status == reqwest::StatusCode::SWITCHING_PROTOCOLS { - let inner = - response.upgrade().await.map_err(Error::InvalidUpgrade)?; + let inner = response.upgrade().await.map_err(Error::InvalidUpgrade)?; Ok(Self { inner, @@ -135,11 +130,7 @@ impl ResponseValue { /// Creates a [`ResponseValue`] from the inner type, status, and headers. /// /// Useful for generating test fixtures. - pub fn new( - inner: T, - status: reqwest::StatusCode, - headers: reqwest::header::HeaderMap, - ) -> Self { + pub fn new(inner: T, status: reqwest::StatusCode, headers: reqwest::header::HeaderMap) -> Self { Self { inner, status, @@ -174,10 +165,7 @@ impl ResponseValue { } #[doc(hidden)] - pub fn map( - self, - f: F, - ) -> Result, E> + pub fn map(self, f: F) -> Result, E> where F: FnOnce(T) -> U, { @@ -300,9 +288,7 @@ impl Error { }), Error::InvalidUpgrade(e) => Error::InvalidUpgrade(e), Error::ResponseBodyError(e) => Error::ResponseBodyError(e), - Error::InvalidResponsePayload(b, e) => { - Error::InvalidResponsePayload(b, e) - } + Error::InvalidResponsePayload(b, e) => Error::InvalidResponsePayload(b, e), Error::UnexpectedResponse(r) => Error::UnexpectedResponse(r), } } @@ -441,26 +427,19 @@ pub fn encode_path(pc: &str) -> String { #[doc(hidden)] pub trait RequestBuilderExt { - fn form_urlencoded( - self, - body: &T, - ) -> Result>; + fn form_urlencoded(self, body: &T) -> Result>; } impl RequestBuilderExt for RequestBuilder { - fn form_urlencoded( - self, - body: &T, - ) -> Result> { + fn form_urlencoded(self, body: &T) -> Result> { Ok(self .header( reqwest::header::CONTENT_TYPE, - reqwest::header::HeaderValue::from_static( - "application/x-www-form-urlencoded", - ), + reqwest::header::HeaderValue::from_static("application/x-www-form-urlencoded"), ) - .body(serde_urlencoded::to_string(body).map_err(|_| { - Error::InvalidRequest("failed to serialize body".to_string()) - })?)) + .body( + serde_urlencoded::to_string(body) + .map_err(|_| Error::InvalidRequest("failed to serialize body".to_string()))?, + )) } } diff --git a/entity/src/entities/approval_status.rs b/entity/src/entities/approval_status.rs index 4a2c6bb..6329e84 100644 --- a/entity/src/entities/approval_status.rs +++ b/entity/src/entities/approval_status.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/bna_pipeline.rs b/entity/src/entities/bna_pipeline.rs index 91a8827..7b08256 100644 --- a/entity/src/entities/bna_pipeline.rs +++ b/entity/src/entities/bna_pipeline.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub state_machine_id: Uuid, - pub step: Option, + pub step: String, pub sqs_message: Option, pub fargate_price_id: Option, pub fargate_task_arn: Option, @@ -16,8 +16,6 @@ pub struct Model { pub status: String, pub start_time: DateTimeWithTimeZone, pub end_time: Option, - pub torn_down: Option, - pub results_posted: Option, pub cost: Option, } diff --git a/entity/src/entities/bna_pipeline_status.rs b/entity/src/entities/bna_pipeline_status.rs index 1526de3..68e7fa1 100644 --- a/entity/src/entities/bna_pipeline_status.rs +++ b/entity/src/entities/bna_pipeline_status.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/bna_pipeline_step.rs b/entity/src/entities/bna_pipeline_step.rs index 94d6cba..5589962 100644 --- a/entity/src/entities/bna_pipeline_step.rs +++ b/entity/src/entities/bna_pipeline_step.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/bna_region.rs b/entity/src/entities/bna_region.rs index 3c9bf09..65ec3ba 100644 --- a/entity/src/entities/bna_region.rs +++ b/entity/src/entities/bna_region.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/census.rs b/entity/src/entities/census.rs index 71bc261..f48fb12 100644 --- a/entity/src/entities/census.rs +++ b/entity/src/entities/census.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/city.rs b/entity/src/entities/city.rs index cf8e405..c6e5e03 100644 --- a/entity/src/entities/city.rs +++ b/entity/src/entities/city.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/core_services.rs b/entity/src/entities/core_services.rs index bd816e2..57962ad 100644 --- a/entity/src/entities/core_services.rs +++ b/entity/src/entities/core_services.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/country.rs b/entity/src/entities/country.rs index a383436..513f63b 100644 --- a/entity/src/entities/country.rs +++ b/entity/src/entities/country.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/fargate_price.rs b/entity/src/entities/fargate_price.rs index 6dde20c..29e965b 100644 --- a/entity/src/entities/fargate_price.rs +++ b/entity/src/entities/fargate_price.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/infrastructure.rs b/entity/src/entities/infrastructure.rs index 9ffd535..aefdaa6 100644 --- a/entity/src/entities/infrastructure.rs +++ b/entity/src/entities/infrastructure.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/mod.rs b/entity/src/entities/mod.rs index 5027ece..133eec1 100644 --- a/entity/src/entities/mod.rs +++ b/entity/src/entities/mod.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 pub mod prelude; diff --git a/entity/src/entities/opportunity.rs b/entity/src/entities/opportunity.rs index 93861c2..f57c221 100644 --- a/entity/src/entities/opportunity.rs +++ b/entity/src/entities/opportunity.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/people.rs b/entity/src/entities/people.rs index 9a42307..1e3ab66 100644 --- a/entity/src/entities/people.rs +++ b/entity/src/entities/people.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/prelude.rs b/entity/src/entities/prelude.rs index 61e43a0..03040e1 100644 --- a/entity/src/entities/prelude.rs +++ b/entity/src/entities/prelude.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 pub use super::approval_status::Entity as ApprovalStatus; pub use super::bna_pipeline::Entity as BnaPipeline; diff --git a/entity/src/entities/recreation.rs b/entity/src/entities/recreation.rs index f96bafb..370cbad 100644 --- a/entity/src/entities/recreation.rs +++ b/entity/src/entities/recreation.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/retail.rs b/entity/src/entities/retail.rs index cd83d3b..58a7157 100644 --- a/entity/src/entities/retail.rs +++ b/entity/src/entities/retail.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/speed_limit.rs b/entity/src/entities/speed_limit.rs index 512a0f9..77d8a54 100644 --- a/entity/src/entities/speed_limit.rs +++ b/entity/src/entities/speed_limit.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/state_region_crosswalk.rs b/entity/src/entities/state_region_crosswalk.rs index f9ea371..44b9ce7 100644 --- a/entity/src/entities/state_region_crosswalk.rs +++ b/entity/src/entities/state_region_crosswalk.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/submission.rs b/entity/src/entities/submission.rs index 4edd034..3374aad 100644 --- a/entity/src/entities/submission.rs +++ b/entity/src/entities/submission.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/summary.rs b/entity/src/entities/summary.rs index 0c41726..5a3e1fe 100644 --- a/entity/src/entities/summary.rs +++ b/entity/src/entities/summary.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/transit.rs b/entity/src/entities/transit.rs index 5e49306..c075ea2 100644 --- a/entity/src/entities/transit.rs +++ b/entity/src/entities/transit.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/entities/us_state.rs b/entity/src/entities/us_state.rs index 602176d..b697804 100644 --- a/entity/src/entities/us_state.rs +++ b/entity/src/entities/us_state.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.1 use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/entity/src/wrappers/bna_pipeline.rs b/entity/src/wrappers/bna_pipeline.rs index c9aec24..2a1ab5d 100644 --- a/entity/src/wrappers/bna_pipeline.rs +++ b/entity/src/wrappers/bna_pipeline.rs @@ -16,7 +16,7 @@ pub struct BNAPipelinePost { pub sqs_message: Option, pub start_time: DateTimeWithTimeZone, pub state_machine_id: Uuid, - pub step: Option, + pub step: String, pub torn_down: Option, } @@ -27,14 +27,12 @@ impl IntoActiveModel for BNAPipelinePost { end_time: ActiveValue::Set(self.end_time), fargate_price_id: ActiveValue::Set(self.fargate_price_id), fargate_task_arn: ActiveValue::Set(self.fargate_task_arn), - results_posted: ActiveValue::Set(self.result_posted), s3_bucket: ActiveValue::Set(self.s3_bucket), sqs_message: ActiveValue::Set(self.sqs_message), start_time: ActiveValue::Set(self.start_time), state_machine_id: ActiveValue::Set(self.state_machine_id), status: ActiveValue::Set("Pending".to_string()), step: ActiveValue::Set(self.step), - torn_down: ActiveValue::Set(self.torn_down), } } } @@ -50,7 +48,7 @@ pub struct BNAPipelinePatch { pub sqs_message: Option>, pub start_time: Option>, pub status: Option, - pub step: Option>, + pub step: Option, pub torn_down: Option>, } @@ -70,10 +68,6 @@ impl IntoActiveModel for BNAPipelinePatch { s3_bucket: self.s3_bucket.map_or(ActiveValue::NotSet, ActiveValue::Set), start_time: ActiveValue::NotSet, end_time: self.end_time.map_or(ActiveValue::NotSet, ActiveValue::Set), - torn_down: self.torn_down.map_or(ActiveValue::NotSet, ActiveValue::Set), - results_posted: self - .result_posted - .map_or(ActiveValue::NotSet, ActiveValue::Set), fargate_price_id: self .fargate_price_id .map_or(ActiveValue::NotSet, ActiveValue::Set), diff --git a/justfile b/justfile index 3eb6fb4..aa1ee2b 100644 --- a/justfile +++ b/justfile @@ -111,3 +111,16 @@ debug-axum: DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres \ cargo watch -x \ 'run -p lambdas --bin axumed' +# Generate the OAS 3.1.x from the Axum source code. +generate-oas-31: + BNA_API_GENERATE_ONLY=1 \ + cargo run \ + -p lambdas \ + --bin axumed + +# Generate the OAS 3.0.x from the OAS 3.1.x. +generate-oas-30: + openapi-down-convert --input openapi-3.1.yaml --output openapi-3.0.yaml + +# Regenerate the OpenAPI specifications and the client. +regenerate-all: generate-oas-31 generate-oas-30 generate-client diff --git a/lambdas/Cargo.toml b/lambdas/Cargo.toml index d21ca90..e53b876 100644 --- a/lambdas/Cargo.toml +++ b/lambdas/Cargo.toml @@ -11,6 +11,7 @@ aws-sdk-s3 = { workspace = true } aws-sdk-sqs = { workspace = true } aws_lambda_events = { workspace = true } bnacore = { workspace = true } +chrono = { workspace = true } dotenv = { workspace = true } effortless = { path = "../effortless" } entity = { path = "../entity" } @@ -29,12 +30,16 @@ sea-orm = { workspace = true, features = [ serde = { workspace = true } serde_json = { workspace = true } serde_plain = { workspace = true } +serde_with = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["macros"] } tower-http = { workspace = true, features = ["trace"] } tracing = { workspace = true, features = ["log"] } tracing-subscriber = { workspace = true, features = ["fmt"] } url = { workspace = true } +utoipa = { workspace = true, features = ["chrono", "decimal", "uuid", "yaml"] } +utoipa-axum = { workspace = true } +utoipa-swagger-ui = { workspace = true, features = ["axum"] } uuid = { workspace = true, features = ["v4", "serde"] } [lints.clippy] @@ -49,74 +54,6 @@ path = "src/lib.rs" name = "axumed" path = "src/main.rs" -[[bin]] -name = "get-ratings" -path = "src/bin/ratings/get-ratings.rs" - -[[bin]] -name = "post-ratings" -path = "src/bin/ratings/post-ratings.rs" - -# [[bin]] -# name = "patch-bnas" -# path = "src/bnas/patch-bnas.rs" - -[[bin]] -name = "get-ratings-cities" -path = "src/bin/ratings/get-ratings-cities.rs" - -[[bin]] -name = "get-ratings-analysis" -path = "src/bin/ratings/get-ratings-analysis.rs" - -[[bin]] -name = "get-cities" -path = "src/bin/cities/get-cities.rs" - -[[bin]] -name = "get-cities-ratings" -path = "src/bin/cities/get-cities-ratings.rs" - -[[bin]] -name = "get-cities-census" -path = "src/bin/cities/get-cities-census.rs" - -[[bin]] -name = "get-cities-submissions" -path = "src/bin/cities/get-cities-submissions.rs" - -[[bin]] -name = "get-price-fargate" -path = "src/bin/price-fargate/get-price-fargate.rs" - -[[bin]] -name = "patch-ratings-analysis" -path = "src/bin/ratings/patch-ratings-analysis.rs" - -[[bin]] -name = "patch-cities-submissions" -path = "src/bin/cities/patch-cities-submissions.rs" - -[[bin]] -name = "post-cities-submissions" -path = "src/bin/cities/post-cities-submissions.rs" - -[[bin]] -name = "post-ratings-analysis" -path = "src/bin/ratings/post-ratings-analysis.rs" - -[[bin]] -name = "post-ratings-enqueue" -path = "src/bin/ratings/post-ratings-enqueue.rs" - -[[bin]] -name = "get-ratings-results" -path = "src/bin/ratings/get-ratings-results.rs" - -[[bin]] -name = "post-cities" -path = "src/bin/cities/post-cities.rs" - [dev-dependencies] color-eyre = { workspace = true } rstest = { workspace = true } diff --git a/lambdas/src/bin/cities/get-cities-census.rs b/lambdas/src/bin/cities/get-cities-census.rs deleted file mode 100644 index e88bf2a..0000000 --- a/lambdas/src/bin/cities/get-cities-census.rs +++ /dev/null @@ -1,78 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::extract_pagination_parameters, error::APIErrors}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::core::resource::cities::{ - adaptor::get_cities_censuses_adaptor, extract_path_parameters, CitiesPathParameters, -}; -use tracing::info; - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract the path parameters. - let params: CitiesPathParameters = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - match get_cities_censuses_adaptor( - ¶ms.country, - ¶ms.region, - ¶ms.name, - pagination.page, - pagination.page_size(), - ) - .await - { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -// #[cfg(test)] -// mod tests { - -// use super::*; -// use aws_lambda_events::http; -// use lambda_http::RequestExt; -// use std::collections::HashMap; - -// #[tokio::test] -// async fn test_handler() { -// let event = http::Request::builder() -// .header(http::header::CONTENT_TYPE, "application/json") -// .body(Body::Empty) -// .expect("failed to build request") -// .with_path_parameters(HashMap::from([( -// "id".to_string(), -// "c49fa94e-542d-421f-9826-e233538be929".to_string(), // Santa Monica, CA -// )])) -// .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( -// lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), -// )); -// let r = function_handler(event).await.unwrap(); -// dbg!(r); -// } -// } diff --git a/lambdas/src/bin/cities/get-cities-ratings.rs b/lambdas/src/bin/cities/get-cities-ratings.rs deleted file mode 100644 index 6ffd2ed..0000000 --- a/lambdas/src/bin/cities/get-cities-ratings.rs +++ /dev/null @@ -1,96 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::extract_pagination_parameters, error::APIErrors, fragment::BnaRequestExt}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::cities::{ - adaptor::get_cities_ratings_adaptor, extract_path_parameters, CitiesPathParameters, - }, - Context, -}; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract the path parameters. - let params: CitiesPathParameters = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - - match get_cities_ratings_adaptor( - ¶ms.country, - ¶ms.region, - ¶ms.name, - pagination.page, - pagination.page_size(), - ctx, - ) - .await - { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -#[cfg(test)] -mod tests { - // use super::*; - // use lambda_http::{http, RequestExt}; - // use std::collections::HashMap; - - // #[tokio::test] - // async fn test_handler_opportunity() { - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::Empty) - // .expect("failed to build request") - // .with_path_parameters(HashMap::from([( - // "country".to_string(), - // "United%20States".to_string(), - // )])) - // .with_query_string_parameters(HashMap::from([( - // "region".to_string(), - // "Texas".to_string(), - // )])) - // .with_query_string_parameters(HashMap::from([( - // "name".to_string(), - // "Austin".to_string(), - // )])) - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } -} diff --git a/lambdas/src/bin/cities/get-cities-submissions.rs b/lambdas/src/bin/cities/get-cities-submissions.rs deleted file mode 100644 index 6d93ea5..0000000 --- a/lambdas/src/bin/cities/get-cities-submissions.rs +++ /dev/null @@ -1,79 +0,0 @@ -use dotenv::dotenv; -use effortless::{ - api::{extract_pagination_parameters, parse_path_parameter, parse_query_string_parameter}, - error::APIErrors, - fragment::BnaRequestExt, -}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::cities::adaptor::{ - get_cities_submission_adaptor, get_cities_submissions_adaptor, - }, - Context, -}; -use tracing::{debug, info}; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - // Retrieve the status parameter if available. - let query_param_key = "status"; - let status = match parse_query_string_parameter::(&event, query_param_key) { - Ok(status) => status, - Err(e) => return Ok(e.into()), - }; - - // Retrieve the ID of the Submission to get if any. - let submission_id = match parse_path_parameter::(&event, "id") { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - - // Retrieve all submissions or a specific one. - debug!("Processing the requests..."); - match submission_id { - Some(id) => match get_cities_submission_adaptor(id, status, ctx).await { - Ok(v) => Ok(v.into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - }, - None => { - match get_cities_submissions_adaptor(status, pagination.page, pagination.page_size()) - .await - { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } - } - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/cities/get-cities.rs b/lambdas/src/bin/cities/get-cities.rs deleted file mode 100644 index a03dfe5..0000000 --- a/lambdas/src/bin/cities/get-cities.rs +++ /dev/null @@ -1,116 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::extract_pagination_parameters, error::APIErrors, fragment::BnaRequestExt}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::cities::{ - adaptor::{get_cities_adaptor, get_city_adaptor}, - extract_path_parameters, CitiesPathParameters, - }, - Context, -}; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve a single city. - if event.has_path_parameters() { - let params: CitiesPathParameters = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - info!("{:#?}", params); - match get_city_adaptor(¶ms.country, ¶ms.region, ¶ms.name, ctx).await { - Ok(v) => return Ok(v.into_response().await), - Err(e) => return Ok(APIErrors::from(e).into()), - } - } - - // Extract pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - // Retrieve all cities. - match get_cities_adaptor(pagination.page, pagination.page_size()).await { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use lambda_http::{http, RequestExt}; - use std::collections::HashMap; - - #[test] - fn test_extract_path_parameters() { - let country: String = String::from("United States"); - let region: String = String::from("Texas"); - let name: String = String::from("Austin"); - let event = http::Request::builder() - .header(http::header::CONTENT_TYPE, "application/json") - .body(Body::Empty) - .expect("failed to build request") - .with_path_parameters(HashMap::from([ - ("country".to_string(), country.clone()), - ("region".to_string(), region.clone()), - ("name".to_string(), name.clone()), - ])) - .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - )); - let r = extract_path_parameters(&event).unwrap(); - assert_eq!(r.country, country); - assert_eq!(r.region, region); - assert_eq!(r.name, name); - } - - // #[tokio::test] - // async fn test_handler() { - // let country: String = String::from("United States"); - // let region: String = String::from("Texas"); - // let name: String = String::from("Austin"); - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::Empty) - // .expect("failed to build request") - // .with_path_parameters(HashMap::from([ - // ("country".to_string(), country.clone()), - // ("region".to_string(), region.clone()), - // ("name".to_string(), name.clone()), - // ])) - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - - // let res = function_handler(event).await.unwrap(); - // dbg!(res); - // } -} diff --git a/lambdas/src/bin/cities/patch-cities-submissions.rs b/lambdas/src/bin/cities/patch-cities-submissions.rs deleted file mode 100644 index 8f05edf..0000000 --- a/lambdas/src/bin/cities/patch-cities-submissions.rs +++ /dev/null @@ -1,73 +0,0 @@ -use dotenv::dotenv; -use effortless::{ - api::{missing_parameter, parse_path_parameter, parse_request_body}, - error::APIErrors, -}; -use entity::wrappers::submission::SubmissionPatch; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::core::resource::cities::adaptor::patch_cities_submission_adaptor; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve the ID of the Submission to update. - let parameter = "submission_id"; - let submission_id = match parse_path_parameter::(&event, parameter) { - Ok(id) => match id { - Some(id) => id, - None => return Ok(missing_parameter(&event, parameter).into()), - }, - Err(e) => return Ok(e.into()), - }; - - // Prepare the model to update. - let submission = match parse_request_body::(&event) { - Ok(v) => v, - Err(e) => return Ok(e.into()), - }; - - match patch_cities_submission_adaptor(submission_id, submission).await { - Ok(v) => Ok(v.into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -// #[cfg(test)] -// mod tests { -// use super::*; -// use aws_lambda_events::http; -// use lambda_http::RequestExt; -// use std::collections::HashMap; - -// #[test] -// fn test_prepare_active_model() { -// let event = http::Request::builder() -// .header(http::header::CONTENT_TYPE, "application/json") -// .body(Body::from(r#"{"city": "santa rosa","country": "usa","email": "jane.dpe@orgllc.com","fips_code": "3570670","first_name": "Jane","last_name": "Doe","organization": "Organization LLC","region": "new mexico","title": "CTO","consent": true}"#)) -// .expect("failed to build request") -// .with_path_parameters(HashMap::from([("submission_id".to_string(), "1".to_string())])) -// .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2(lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default())); -// let active_submission = prepare_active_model(&event).unwrap(); -// assert_eq!( -// active_submission.country, -// sea_orm::ActiveValue::Set("usa".to_string()) -// ) -// } -// } diff --git a/lambdas/src/bin/cities/post-cities-submissions.rs b/lambdas/src/bin/cities/post-cities-submissions.rs deleted file mode 100644 index f879d82..0000000 --- a/lambdas/src/bin/cities/post-cities-submissions.rs +++ /dev/null @@ -1,75 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::parse_request_body, error::APIErrors, response::make_json_created_response}; -use entity::wrappers::submission::SubmissionPost; -use lambda_http::{run, service_fn, Body, Error, Request, Response}; -use lambdas::core::resource::cities::adaptor::post_cities_submission_adaptor; -use serde_json::json; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract and serialize the data. - let wrapper = match parse_request_body::(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - // let country = wrapper.country.clone(); - - match post_cities_submission_adaptor(wrapper).await { - Ok(v) => Ok(make_json_created_response(json!(v).to_string()) - .expect("unable to build http::Response")), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -#[cfg(test)] -mod tests { - - // use super::*; - // use aws_lambda_events::http; - // use lambda_http::RequestExt; - - // #[tokio::test] - // async fn test_handler() { - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::Text( - // r#"{ - // "city": "santa rosa", - // "country": "United States", - // "email": "jane.dpe@orgllc.com", - // "fips_code": "3570670", - // "first_name": "Jane", - // "last_name": "Doe", - // "organization": "Organization LLC", - // "region": "new mexico", - // "occupation": "CTO", - // "consent": true - // }"# - // .to_string(), - // )) - // .expect("failed to build request") - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } -} diff --git a/lambdas/src/bin/cities/post-cities.rs b/lambdas/src/bin/cities/post-cities.rs deleted file mode 100644 index e592b58..0000000 --- a/lambdas/src/bin/cities/post-cities.rs +++ /dev/null @@ -1,55 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::parse_request_body, error::APIErrors}; -use entity::wrappers::city::CityPost; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::core::resource::cities::adaptor::post_cities_adaptor; -use tracing::info; - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract and serialize the data. - let wrapper = match parse_request_body::(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - match post_cities_adaptor(wrapper).await { - Ok(v) => Ok(v.into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[cfg(test)] -mod tests { - // use super::*; - // use lambda_http::{http, RequestExt}; - - // #[tokio::test] - // async fn test_handler() { - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::from(r#"{"name": "santa rosa 000","country": "united states","fips_code": "3570670","state": "new mexico", "state_abbrev": "NM"}"#)) - // .expect("failed to build request") - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2(lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default())); - - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } -} diff --git a/lambdas/src/bin/price-fargate/get-price-fargate.rs b/lambdas/src/bin/price-fargate/get-price-fargate.rs deleted file mode 100644 index 87c3993..0000000 --- a/lambdas/src/bin/price-fargate/get-price-fargate.rs +++ /dev/null @@ -1,117 +0,0 @@ -use dotenv::dotenv; -use effortless::{ - api::{extract_pagination_parameters, invalid_path_parameter, invalid_query_parameter}, - error::APIErrors, - fragment::BnaRequestExt, -}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::price::{ - adaptor::{get_price_fargate_adaptor, get_prices_fargate_adaptor}, - PriceParameters, - }, - Context, Sort, -}; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - // Retrieve price parameter. - let mut price_parameters = PriceParameters::default(); - let parameter = "sort"; - let sort = event.query_string_parameter::(parameter); - if let Some(sort) = sort { - match sort { - Ok(sort) => { - price_parameters.set_sort(Some(sort)); - } - Err(e) => { - let api_error = invalid_query_parameter( - &event, - parameter, - format!("failed to process the `{parameter}` parameter: {e}").as_str(), - ); - return Ok(APIErrors::new(&[api_error]).into()); - } - } - } - - let parameter = "latest"; - let latest = event.query_string_parameter::(parameter); - if let Some(latest) = latest { - match latest { - Ok(latest) => { - price_parameters.set_latest(latest); - } - Err(e) => { - let api_error = invalid_query_parameter( - &event, - parameter, - format!("failed to process the `{parameter}` parameter: {e}").as_str(), - ); - return Ok(APIErrors::new(&[api_error]).into()); - } - } - } - - // Retrieve the ID of the entry to retrieve. - let parameter = "price_id"; - let id = event.path_parameter::(parameter); - - // Retrieve a specific entry if an id was specified. - if let Some(id) = id { - let id = match id { - Ok(id) => id, - Err(e) => { - let api_error = invalid_path_parameter( - &event, - parameter, - format!("failed to process the `{parameter}` parameter: {e}").as_str(), - ); - return Ok(APIErrors::new(&[api_error]).into()); - } - }; - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - match get_price_fargate_adaptor(id, ctx).await { - Ok(v) => return Ok(v.into_response().await), - Err(e) => return Ok(APIErrors::from(e).into()), - }; - } - // Retrieve all entries. - match get_prices_fargate_adaptor(price_parameters, pagination.page, pagination.page_size()) - .await - { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/ratings/get-ratings-analysis.rs b/lambdas/src/bin/ratings/get-ratings-analysis.rs deleted file mode 100644 index ae18878..0000000 --- a/lambdas/src/bin/ratings/get-ratings-analysis.rs +++ /dev/null @@ -1,64 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::extract_pagination_parameters, error::APIErrors, fragment::BnaRequestExt}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::ratings::{ - adaptor::{get_ratings_analyses_adaptor, get_ratings_analysis_adaptor}, - extract_path_parameters, - }, - Context, -}; -use tracing::{debug, info}; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - if event.has_path_parameters() { - let params = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - - // Retrieve a specific entry. - debug!("Processing the requests..."); - match get_ratings_analysis_adaptor(params.rating_id, ctx).await { - Ok(v) => return Ok(v.into_response().await), - Err(e) => return Ok(APIErrors::from(e).into()), - } - } - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - match get_ratings_analyses_adaptor(pagination.page, pagination.page_size()).await { - Ok(v) => Ok(v.into()), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/ratings/get-ratings-cities.rs b/lambdas/src/bin/ratings/get-ratings-cities.rs deleted file mode 100644 index ed355de..0000000 --- a/lambdas/src/bin/ratings/get-ratings-cities.rs +++ /dev/null @@ -1,47 +0,0 @@ -use dotenv::dotenv; -use effortless::{error::APIErrors, fragment::BnaRequestExt}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::ratings::{adaptor::get_ratings_city_adaptor, extract_path_parameters}, - Context, -}; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve the parameters. - let params = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - let ctx = Context::new( - event.apigw_request_id(), - event - .uri() - .path_and_query() - .expect("to have a path and optional query parameters") - .to_string(), - ); - - match get_ratings_city_adaptor(params.rating_id, ctx).await { - Ok(v) => Ok(v.into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/ratings/get-ratings-results.rs b/lambdas/src/bin/ratings/get-ratings-results.rs deleted file mode 100644 index 758e75b..0000000 --- a/lambdas/src/bin/ratings/get-ratings-results.rs +++ /dev/null @@ -1,65 +0,0 @@ -use aws_config::BehaviorVersion; -use dotenv::dotenv; -use effortless::{error::APIError, fragment::get_apigw_request_id}; -use lambda_http::{ - http::StatusCode, run, service_fn, Body, Error, IntoResponse, Request, Response, -}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use tracing::info; - -const BUCKET_NAME: &str = "brokenspoke-analyzer"; - -#[derive(Deserialize, Serialize, Debug)] -pub struct BNAResults { - results: Vec, -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Configure the AWS S3 client. - let aws_config = aws_config::load_defaults(BehaviorVersion::latest()).await; - let s3_client = aws_sdk_s3::Client::new(&aws_config); - - // Collect the folders in the bucket. - let objects = s3_client.list_objects_v2().bucket(BUCKET_NAME).send().await; - match objects { - Ok(o) => { - let mut bna_results = o - .contents() - .iter() - .filter(|o| o.key.clone().unwrap().ends_with('/')) - .map(|o| o.key.clone().unwrap()) - .collect::>(); - bna_results.sort(); - Ok(json!(bna_results).into_response().await) - } - Err(e) => { - let api_error = APIError::new( - get_apigw_request_id(&event), - StatusCode::BAD_REQUEST, - "S3 Client Error", - format!("Cannot retrieve the content of the {BUCKET_NAME} bucket: {e}").as_str(), - None, - ); - Ok(api_error.into()) - } - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/ratings/get-ratings.rs b/lambdas/src/bin/ratings/get-ratings.rs deleted file mode 100644 index 2e1df62..0000000 --- a/lambdas/src/bin/ratings/get-ratings.rs +++ /dev/null @@ -1,324 +0,0 @@ -use dotenv::dotenv; -use effortless::{ - api::{entry_not_found, extract_pagination_parameters}, - error::APIErrors, - fragment::BnaRequestExt, -}; -use entity::{ - core_services, infrastructure, opportunity, people, prelude::*, recreation, retail, transit, -}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::{ - core::resource::ratings::{ - adaptor::get_ratings_summaries_adaptor, extract_path_parameters, extract_query_parameters, - BNAComponent, BNAPathParameters, BNAQueryParameters, - }, - database_connect, -}; -use sea_orm::{prelude::Uuid, EntityTrait, FromQueryResult, JoinType, QuerySelect, RelationTrait}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use tracing::{debug, info}; - -#[derive(FromQueryResult, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct BNA { - // BNA Summary - pub id: Uuid, - pub city_id: Uuid, - pub score: f64, - pub version: String, - - // BNAInfrastructure - pub low_stress_miles: Option, - pub high_stress_miles: Option, - - // BNA Recreation - pub community_centers: Option, - pub parks: Option, - pub recreation_trails: Option, - pub recreation_score: Option, - - // BNA Opportunity - pub employment: Option, - pub higher_education: Option, - pub k12_education: Option, - pub opportunity_score: Option, - pub technical_vocational_college: Option, - - // BNA Core Services - pub dentists: Option, - pub doctors: Option, - pub grocery: Option, - pub hospitals: Option, - pub pharmacies: Option, - pub coreservices_score: Option, - pub social_services: Option, - - // BNA People - pub people: Option, - - // BNA Retail - pub retail: Option, - - // BNA Transit - pub transit: Option, -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Get the database connection. - // let db = match api_database_connect(&event).await { - // Ok(db) => db, - // Err(e) => return Ok(e), - // }; - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // Retrieve all bnas or a specific one. - debug!("Processing the requests..."); - - // With params. - if event.has_path_parameters() { - let params: BNAPathParameters = match extract_path_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e.into()), - }; - - let queries: BNAQueryParameters = match extract_query_parameters(&event) { - Ok(a) => a, - Err(e) => return Ok(e.into()), - }; - - let select = Summary::find_by_id(params.rating_id); - let res = match queries.component { - BNAComponent::All => { - let model = select - .clone() - .columns([ - entity::core_services::Column::Dentists, - entity::core_services::Column::Doctors, - entity::core_services::Column::Grocery, - entity::core_services::Column::Hospitals, - entity::core_services::Column::Pharmacies, - entity::core_services::Column::SocialServices, - ]) - .column_as(entity::core_services::Column::Score, "coreservices_score") - .columns([ - entity::infrastructure::Column::HighStressMiles, - entity::infrastructure::Column::LowStressMiles, - ]) - .columns([ - entity::recreation::Column::CommunityCenters, - entity::recreation::Column::Parks, - entity::recreation::Column::RecreationTrails, - ]) - .column_as(entity::recreation::Column::Score, "recreation_score") - .columns([ - entity::opportunity::Column::Employment, - entity::opportunity::Column::HigherEducation, - entity::opportunity::Column::K12Education, - entity::opportunity::Column::TechnicalVocationalCollege, - ]) - .column_as(entity::opportunity::Column::Score, "opportunity_score") - .column_as(entity::people::Column::Score, "people_score") - .column_as(entity::retail::Column::Score, "retail_score") - .column_as(entity::transit::Column::Score, "transit_score") - .join( - JoinType::InnerJoin, - entity::summary::Relation::CoreServices.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Infrastructure.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Recreation.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Opportunity.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::People.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::Retail.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::Transit.def(), - ) - .into_model::() - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Summary => { - let model = select.clone().one(&db).await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Infratructure => { - let model = select - .clone() - .find_also_related(infrastructure::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Recreation => { - let model = select - .clone() - .find_also_related(recreation::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Opportunity => { - let model = select - .clone() - .find_also_related(opportunity::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::CoreServices => { - let model = select - .clone() - .find_also_related(core_services::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::People => { - let model = select - .clone() - .find_also_related(people::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Retail => { - let model = select - .clone() - .find_also_related(retail::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - BNAComponent::Transit => { - let model = select - .clone() - .find_also_related(transit::Entity) - .one(&db) - .await?; - match model { - Some(model) => json!(model).into_response().await, - None => entry_not_found(&event).into(), - } - } - }; - return Ok(res); - } - - // Retrieve pagination parameters if any. - let pagination = match extract_pagination_parameters(&event) { - Ok(p) => p, - Err(e) => return Ok(e), - }; - - // Retrieve entries. - match get_ratings_summaries_adaptor(pagination.page, pagination.page_size()).await { - Ok(v) => Ok(v.payload().into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -#[cfg(test)] -mod tests { - - // use super::*; - // use aws_lambda_events::http; - // use lambda_http::RequestExt; - // use std::collections::HashMap; - - // #[tokio::test] - // async fn test_handler_all() { - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::Empty) - // .expect("failed to build request") - // .with_path_parameters(HashMap::from([( - // "rating_id".to_string(), - // "837082b8-c8a0-469e-b310-c868d7f140a2".to_string(), // Santa Monica, CA - // )])) - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } - - // #[tokio::test] - // async fn test_handler_opportunity() { - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::Empty) - // .expect("failed to build request") - // .with_path_parameters(HashMap::from([( - // "id".to_string(), - // "837082b8-c8a0-469e-b310-c868d7f140a2".to_string(), // Santa Monica, CA - // )])) - // .with_query_string_parameters(HashMap::from([( - // "component".to_string(), - // "Opportunity".to_string(), - // )])) - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } -} diff --git a/lambdas/src/bin/ratings/patch-ratings.rs b/lambdas/src/bin/ratings/patch-ratings.rs deleted file mode 100644 index 784883a..0000000 --- a/lambdas/src/bin/ratings/patch-ratings.rs +++ /dev/null @@ -1,102 +0,0 @@ -use dotenv::dotenv; -use effortless::{ - api::{ - entry_not_found, invalid_path_parameter, missing_parameter, parse_path_parameter, - parse_request_body, - }, - fragment::BnaRequestExt, -}; -use entity::{ - core_services, features, infrastructure, opportunity, prelude, recreation, summary, - wrappers::bna::BNAPatch, -}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::database_connect; -use sea_orm::{prelude::Uuid, ActiveValue, EntityTrait}; -use serde_json::json; -use tracing::info; - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Retrieve the ID of the entry to update. - let parameter = "id"; - let id = event - .path_parameter::(parameter) - .ok_or(missing_parameter(&event, parameter))? - .map_err(|e| invalid_path_parameter(&event, parameter, e.to_string().as_str()))?; - - // Extract and deserialize the data. - let wrapper = match parse_request_body::(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - // Turn the model wrapper into active models. - let summary = summary::ActiveModel { - bna_uuid: ActiveValue::NotSet, - city_id: wrapper - .summary - .city_id - .map_or(ActiveValue::NotSet, ActiveValue::Set), - created_at: ActiveValue::NotSet, - score: ActiveValue::Set(wrapper.summary.score), - version: ActiveValue::Set(wrapper.summary.version), - }; - let core_services = core_services::ActiveModel { - bna_uuid: ActiveValue::NotSet, - dentists: ActiveValue::Set(wrapper.core_services.dentists), - doctors: ActiveValue::Set(wrapper.core_services.doctors), - grocery: ActiveValue::Set(wrapper.core_services.grocery), - hospitals: ActiveValue::Set(wrapper.core_services.hospitals), - pharmacies: ActiveValue::Set(wrapper.core_services.pharmacies), - score: ActiveValue::Set(wrapper.core_services.score), - social_services: ActiveValue::Set(wrapper.core_services.social_services), - }; - let features = features::ActiveModel { - bna_uuid: ActiveValue::NotSet, - people: ActiveValue::Set(wrapper.features.people), - retail: ActiveValue::Set(wrapper.features.retail), - transit: ActiveValue::Set(wrapper.features.transit), - }; - let infrastructure = infrastructure::ActiveModel { - bna_uuid: ActiveValue::NotSet, - low_stress_miles: ActiveValue::Set(wrapper.infrastructure.low_stress_miles), - high_stress_miles: ActiveValue::Set(wrapper.infrastructure.high_stress_miles), - }; - let opportunity = opportunity::ActiveModel { - bna_uuid: ActiveValue::NotSet, - employment: ActiveValue::Set(wrapper.opportunity.employment), - higher_education: ActiveValue::Set(wrapper.opportunity.higher_education), - k12_education: ActiveValue::Set(wrapper.opportunity.k12_education), - score: ActiveValue::Set(wrapper.opportunity.score), - technical_vocational_college: ActiveValue::Set( - wrapper.opportunity.technical_vocational_college, - ), - }; - let recreation = recreation::ActiveModel { - bna_uuid: ActiveValue::NotSet, - community_centers: ActiveValue::Set(wrapper.recreation.community_centers), - parks: ActiveValue::Set(wrapper.recreation.parks), - recreation_trails: ActiveValue::Set(wrapper.recreation.recreation_trails), - score: ActiveValue::Set(wrapper.recreation.score), - }; - - Ok(Body::Empty.into_response().await) -} diff --git a/lambdas/src/bin/ratings/post-ratings-analysis.rs b/lambdas/src/bin/ratings/post-ratings-analysis.rs deleted file mode 100644 index ed53303..0000000 --- a/lambdas/src/bin/ratings/post-ratings-analysis.rs +++ /dev/null @@ -1,84 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::parse_request_body, error::APIErrors}; -use entity::wrappers::bna_pipeline::BNAPipelinePost; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use lambdas::core::resource::ratings::adaptor::post_ratings_analysis_adaptor; -use tracing::info; - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract and serialize the data. - let wrapper = match parse_request_body::(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - match post_ratings_analysis_adaptor(wrapper).await { - Ok(v) => Ok(v.into_response().await), - Err(e) => Ok(APIErrors::from(e).into()), - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -#[cfg(test)] -mod tests { - - use super::*; - use aws_lambda_events::http; - use lambda_http::RequestExt; - - #[tokio::test] - async fn test_handler_all() { - let event = http::Request::builder() - .header(http::header::CONTENT_TYPE, "application/json") - .body(Body::Text( - r#"{ - "cost": null, - "end_time": null, - "fargate_price_id": null, - "fargate_task_arn": null, - "result_posted": null, - "s3_bucket": null, - "sqs_message": null, - "start_time": [ - 2024, - 247, - 13, - 7, - 29, - 922293000, - 0, - 0, - 0 - ], - "state_machine_id": "fc009967-c4d0-416b-baee-93708ac80cbc", - "status": null, - "step": "Analysis", - "torn_down": null - }"# - .to_string(), - )) - .expect("failed to build request") - .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - )); - let r = function_handler(event).await; - let _var_name = dbg!(r); - } -} diff --git a/lambdas/src/bin/ratings/post-ratings-enqueue.rs b/lambdas/src/bin/ratings/post-ratings-enqueue.rs deleted file mode 100644 index 155f3ff..0000000 --- a/lambdas/src/bin/ratings/post-ratings-enqueue.rs +++ /dev/null @@ -1,79 +0,0 @@ -use aws_config::BehaviorVersion; -use bnacore::aws::get_aws_parameter; -use dotenv::dotenv; -use effortless::api::{internal_error, invalid_body, parse_request_body}; -use lambda_http::{run, service_fn, Body, Error, IntoResponse, Request, Response}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use tracing::info; - -#[derive(Deserialize, Serialize, Debug)] -pub struct EnqueueCity { - pub country: String, - pub city: String, - pub region: String, - pub fips_code: String, -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract and deserialize the data. - let enqueued_cities = match parse_request_body::>(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - // Prepare the AWS client. - let aws_config = aws_config::load_defaults(BehaviorVersion::latest()).await; - let sqs_client = aws_sdk_sqs::Client::new(&aws_config); - let bna_sqs_queue = match get_aws_parameter("BNA_SQS_QUEUE_URL").await { - Ok(param) => param, - Err(e) => { - let message = format!("cannot retrieve the SQS Queue URL: {e}"); - info!(message); - return Ok(internal_error(&event, &message).into()); - } - }; - - // Enqueue the messages. - let mut count = 0; - for enqueued_city in enqueued_cities { - let enqueued_city_string = match serde_json::to_string(&enqueued_city) { - Ok(s) => s, - Err(e) => return Ok(invalid_body(&event, e.to_string().as_str()).into()), - }; - let send_message = sqs_client - .send_message() - .queue_url(&bna_sqs_queue.parameter.value) - .message_body(enqueued_city_string) - .send() - .await; - if send_message.is_err() { - let e = send_message.err().unwrap(); - let message = format!("cannot send the message to the SQS queue: {e}"); - info!(message); - return Ok(internal_error(&event, &message).into()); - } - count += 1; - } - - // Return the number of messages successfully processed.. - Ok(json!({"messages": count}).into_response().await) -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} diff --git a/lambdas/src/bin/ratings/post-ratings.rs b/lambdas/src/bin/ratings/post-ratings.rs deleted file mode 100644 index c90d075..0000000 --- a/lambdas/src/bin/ratings/post-ratings.rs +++ /dev/null @@ -1,201 +0,0 @@ -use dotenv::dotenv; -use effortless::{api::parse_request_body, response::make_json_created_response}; -use entity::{ - core_services, infrastructure, opportunity, people, recreation, retail, summary, transit, - wrappers::bna::BNAPost, -}; -use lambda_http::{run, service_fn, Body, Error, Request, Response}; -use lambdas::database_connect; -use sea_orm::{ActiveModelTrait, ActiveValue}; -use serde_json::json; -use tracing::info; - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disable printing the name of the module in every log line. - .with_target(false) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - run(service_fn(function_handler)).await.map_err(|e| { - info!("{e}"); - e - }) -} - -async fn function_handler(event: Request) -> Result, Error> { - dotenv().ok(); - - // Extract and serialize the data. - info!("Parsing body into BNAPost..."); - let wrapper = match parse_request_body::(&event) { - Ok(value) => value, - Err(e) => return Ok(e.into()), - }; - - // Note(rgreinho): We are note supposed to do that. The Brokenspoke-analyzer - // already computes the scores for us. - // Refresh the scores. - // wrapper.core_services.refresh_score(); - // wrapper.opportunity.refresh_score(); - // wrapper.recreation.refresh_score(); - // wrapper.refresh_score(); - - // Turn the model wrapper into active models. - let summary = summary::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - city_id: ActiveValue::Set(wrapper.summary.city_id), - created_at: ActiveValue::NotSet, - score: ActiveValue::Set(wrapper.summary.score), - version: ActiveValue::Set(wrapper.summary.version), - }; - info!("{:?}", summary); - let core_services = core_services::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - dentists: ActiveValue::Set(wrapper.core_services.dentists), - doctors: ActiveValue::Set(wrapper.core_services.doctors), - grocery: ActiveValue::Set(wrapper.core_services.grocery), - hospitals: ActiveValue::Set(wrapper.core_services.hospitals), - pharmacies: ActiveValue::Set(wrapper.core_services.pharmacies), - score: ActiveValue::Set(wrapper.core_services.score), - social_services: ActiveValue::Set(wrapper.core_services.social_services), - }; - info!("{:?}", core_services); - let people = people::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - score: ActiveValue::Set(wrapper.people.score), - }; - info!("{:?}", people); - let retail = retail::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - score: ActiveValue::Set(wrapper.retail.score), - }; - info!("{:?}", people); - let transit = transit::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - score: ActiveValue::Set(wrapper.transit.score), - }; - info!("{:?}", people); - let infrastructure = infrastructure::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - low_stress_miles: ActiveValue::Set(wrapper.infrastructure.low_stress_miles), - high_stress_miles: ActiveValue::Set(wrapper.infrastructure.high_stress_miles), - }; - info!("{:?}", infrastructure); - let opportunity = opportunity::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - employment: ActiveValue::Set(wrapper.opportunity.employment), - higher_education: ActiveValue::Set(wrapper.opportunity.higher_education), - k12_education: ActiveValue::Set(wrapper.opportunity.k12_education), - score: ActiveValue::Set(wrapper.opportunity.score), - technical_vocational_college: ActiveValue::Set( - wrapper.opportunity.technical_vocational_college, - ), - }; - info!("{:?}", opportunity); - let recreation = recreation::ActiveModel { - id: ActiveValue::Set(wrapper.summary.rating_id), - community_centers: ActiveValue::Set(wrapper.recreation.community_centers), - parks: ActiveValue::Set(wrapper.recreation.parks), - recreation_trails: ActiveValue::Set(wrapper.recreation.recreation_trails), - score: ActiveValue::Set(wrapper.recreation.score), - }; - info!("{:?}", recreation); - - // Get the database connection. - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // And insert a new entry for each model. - let summary_res = summary.insert(&db).await?; - let core_services_res = core_services.insert(&db).await?; - let people_res = people.insert(&db).await?; - let retail_res = retail.insert(&db).await?; - let transit_res = transit.insert(&db).await?; - let infrastructure_res = infrastructure.insert(&db).await?; - let opportunity_res = opportunity.insert(&db).await?; - let recreation_res = recreation.insert(&db).await?; - let res = ( - summary_res, - core_services_res, - people_res, - retail_res, - transit_res, - infrastructure_res, - opportunity_res, - recreation_res, - ); - info!("{:?}", res); - let response = - make_json_created_response(json!(res).to_string()).expect("unable to build http::Response"); - Ok(response) - - // Ok(Body::Empty.into_response().await) -} - -#[cfg(test)] -mod tests { - // use super::*; - // use entity::wrappers::bna::{ - // BNACoreServices, BNAFeatures, BNAInfrastructure, BNAOpportunity, BNARecreation, BNASummary, - // }; - // use lambda_http::{http, RequestExt}; - // use sea_orm::prelude::Uuid; - - // #[tokio::test] - // async fn test_post() { - // let bna_uuid = Uuid::new_v4(); - // dbg!(&bna_uuid); - // let bna_post = BNAPost { - // core_services: BNACoreServices { - // dentists: Some(0.0), - // doctors: Some(0.0), - // grocery: Some(1.69), - // hospitals: Some(5.18), - // pharmacies: Some(0.0), - // social_services: Some(0.0), - // score: Some(0.0), - // }, - // features: BNAFeatures { - // people: Some(19.17), - // retail: Some(0.0), - // transit: Some(0.0), - // }, - // infrastructure: BNAInfrastructure { - // low_stress_miles: Some(9.3), - // high_stress_miles: Some(64.5), - // }, - // opportunity: BNAOpportunity { - // employment: Some(8.26), - // higher_education: Some(0.0), - // k12_education: Some(8.31), - // technical_vocational_college: Some(0.0), - // score: Some(0.0), - // }, - // recreation: BNARecreation { - // community_centers: Some(0.0), - // parks: Some(7.13), - // recreation_trails: Some(0.0), - // score: Some(0.0), - // }, - // summary: BNASummary { - // bna_uuid, - // version: "24.05".to_string(), - // city_id: Uuid::parse_str("02fa7cef-bfb9-494e-9ae9-cdbaeb15f11f").unwrap(), - // score: 0.0, - // }, - // }; - // let body = serde_json::to_string(&bna_post).unwrap(); - // let event = http::Request::builder() - // .header(http::header::CONTENT_TYPE, "application/json") - // .body(Body::from(body)) - // .expect("failed to build request") - // .with_request_context(lambda_http::request::RequestContext::ApiGatewayV2( - // lambda_http::aws_lambda_events::apigw::ApiGatewayV2httpRequestContext::default(), - // )); - // let r = function_handler(event).await.unwrap(); - // dbg!(r); - // } -} diff --git a/lambdas/src/core/resource/cities/adaptor.rs b/lambdas/src/core/resource/cities/adaptor.rs index 76d7273..6cfb227 100644 --- a/lambdas/src/core/resource/cities/adaptor.rs +++ b/lambdas/src/core/resource/cities/adaptor.rs @@ -2,11 +2,14 @@ use super::db::{ fetch_cities, fetch_cities_censuses, fetch_cities_ratings, fetch_cities_submission, fetch_cities_submissions, fetch_city, fetch_country, fetch_state_region_crosswalk, }; -use crate::{database_connect, Context, ExecutionError, PageFlow, Paginatron}; -use entity::wrappers::{ - census::CensusFromCityPost, - city::CityPost, - submission::{SubmissionPatch, SubmissionPost}, +use crate::{database_connect, Context, ExecutionError}; +use entity::{ + census, city, summary, + wrappers::{ + census::CensusFromCityPost, + city::CityPost, + submission::{SubmissionPatch, SubmissionPost}, + }, }; use sea_orm::{ActiveModelTrait, ActiveValue, IntoActiveModel}; use serde_json::{json, Value}; @@ -18,7 +21,7 @@ pub async fn get_city_adaptor( region: &str, name: &str, ctx: Context, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -31,7 +34,7 @@ pub async fn get_city_adaptor( } }; match model { - Some(model) => Ok(json!(model)), + Some(model) => Ok(model), None => Err(ExecutionError::NotFound( ctx.request_id(), ctx.source(), @@ -40,18 +43,15 @@ pub async fn get_city_adaptor( } } -pub async fn get_cities_adaptor(page: u64, page_size: u64) -> Result { +pub async fn get_cities_adaptor( + page: u64, + page_size: u64, +) -> Result<(u64, Vec), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch a page of cities. - let (total_items, models) = fetch_cities(&db, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) + Ok(fetch_cities(&db, page, page_size).await?) } pub async fn get_cities_censuses_adaptor( @@ -60,19 +60,12 @@ pub async fn get_cities_censuses_adaptor( name: &str, page: u64, page_size: u64, -) -> Result { +) -> Result<(u64, Vec<(city::Model, Option)>), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch a page of city censuses. - let (total_items, models) = - fetch_cities_censuses(&db, country, region, name, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) + Ok(fetch_cities_censuses(&db, country, region, name, page, page_size).await?) } pub async fn post_cities_census_adaptor( @@ -80,7 +73,7 @@ pub async fn post_cities_census_adaptor( region: &str, name: &str, census: CensusFromCityPost, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -95,8 +88,7 @@ pub async fn post_cities_census_adaptor( // And insert a new entry. let model = active_model.insert(&db).await?; - let value = json!(model); - Ok(value) + Ok(model) } else { Err(ExecutionError::NotFound( Some(country.to_string()), @@ -113,7 +105,7 @@ pub async fn get_cities_ratings_adaptor( page: u64, page_size: u64, ctx: Context, -) -> Result { +) -> Result<(u64, Vec<(city::Model, Option)>), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -130,11 +122,7 @@ pub async fn get_cities_ratings_adaptor( )); } - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) + Ok((total_items, models)) } pub async fn post_cities_adaptor(city: CityPost) -> Result { @@ -173,7 +161,6 @@ pub async fn post_cities_adaptor(city: CityPost) -> Result, ctx: Context, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -190,7 +177,7 @@ pub async fn get_cities_submission_adaptor( let status_str = status.clone().unwrap_or("any".to_string()); let model = fetch_cities_submission(&db, submission_id, status).await?; match model { - Some(model) => Ok(json!(model)), + Some(model) => Ok(model), None => Err(ExecutionError::NotFound( ctx.request_id(), ctx.source(), @@ -203,24 +190,18 @@ pub async fn get_cities_submissions_adaptor( status: Option, page: u64, page_size: u64, -) -> Result { +) -> Result<(u64, Vec), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch the model. - let (total_items, models) = fetch_cities_submissions(&db, status, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) + Ok(fetch_cities_submissions(&db, status, page, page_size).await?) } pub async fn patch_cities_submission_adaptor( submission_id: i32, submission: SubmissionPatch, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -229,12 +210,12 @@ pub async fn patch_cities_submission_adaptor( active_model.id = ActiveValue::Unchanged(submission_id); let model = active_model.update(&db).await?; - Ok(json!(model)) + Ok(model) } pub async fn post_cities_submission_adaptor( submission: SubmissionPost, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -251,5 +232,5 @@ pub async fn post_cities_submission_adaptor( // And insert a new entry. let model = active_model.insert(&db).await?; - Ok(json!(model)) + Ok(model) } diff --git a/lambdas/src/core/resource/cities/db.rs b/lambdas/src/core/resource/cities/db.rs index 5f77873..ea8222b 100644 --- a/lambdas/src/core/resource/cities/db.rs +++ b/lambdas/src/core/resource/cities/db.rs @@ -42,7 +42,7 @@ pub async fn fetch_cities_censuses( let select = city::Entity::find_by_id((country.to_string(), region.to_string(), name.to_string())) .find_also_related(census::Entity); - let models = select + let models: Vec<(city::Model, Option)> = select .clone() .paginate(db, page_size) .fetch_page(page) diff --git a/lambdas/src/core/resource/cities/endpoint.rs b/lambdas/src/core/resource/cities/endpoint.rs index 620f24d..a53b804 100644 --- a/lambdas/src/core/resource/cities/endpoint.rs +++ b/lambdas/src/core/resource/cities/endpoint.rs @@ -1,86 +1,171 @@ -use super::adaptor::{ - get_cities_adaptor, get_cities_censuses_adaptor, get_cities_ratings_adaptor, - get_cities_submission_adaptor, get_cities_submissions_adaptor, get_city_adaptor, - patch_cities_submission_adaptor, post_cities_adaptor, post_cities_census_adaptor, - post_cities_submission_adaptor, +use super::{ + adaptor::{ + get_cities_adaptor, get_cities_censuses_adaptor, get_cities_ratings_adaptor, + get_cities_submission_adaptor, get_cities_submissions_adaptor, get_city_adaptor, + patch_cities_submission_adaptor, post_cities_adaptor, post_cities_census_adaptor, + post_cities_submission_adaptor, + }, + schema::{ + Census, CensusPost, Cities, CityCensuses, CityPost, CityRatings, RatingSummary, Submission, + SubmissionPatch, SubmissionPost, Submissions, + }, +}; +use crate::{ + core::resource::{ + cities::CitiesPathParameters, + schema::{City, Country, ErrorResponses}, + }, + Context, ExecutionError, PageFlow, Paginatron, }; -use crate::{core::resource::cities::CitiesPathParameters, Context, ExecutionError}; use axum::{ - debug_handler, extract::{Path, Query}, http::StatusCode, - response::IntoResponse, - routing::get, - Json, Router, + Json, }; use axum_extra::extract::OptionalQuery; use effortless::api::PaginationParameters; -use entity::wrappers::{ - census::CensusFromCityPost, - city::CityPost, - submission::{SubmissionPatch, SubmissionPost}, -}; -use serde::Deserialize; -use serde_json::{json, Value}; - -pub fn routes() -> Router { - Router::new() - .route("/cities", get(get_cities).post(post_cities)) - .route("/cities/:country/:region/:name", get(get_city)) - .route( - "/cities/:country/:region/:name/census", - get(get_city_censuses).post(post_city_census), - ) - .route( - "/cities/:country/:region/:name/ratings", - get(get_city_ratings), - ) - .route( - "/cities/submissions", - get(get_cities_submissions).post(post_cities_submissions), - ) - .route( - "/cities/submissions/:submission_id", - get(get_cities_submission).patch(patch_cities_submission), - ) +use entity::wrappers::{census::CensusFromCityPost, city, submission}; +use serde::{self, Deserialize}; +use serde_json::Value; +use utoipa_axum::{router::OpenApiRouter, routes}; + +const TAG: &str = "city"; + +pub fn routes() -> OpenApiRouter { + OpenApiRouter::new() + .routes(routes!(get_city)) + .routes(routes!(post_city)) + .routes(routes!(get_cities)) + .routes(routes!(get_city_censuses)) + .routes(routes!(post_city_census)) + .routes(routes!(get_city_ratings)) + .routes(routes!(get_cities_submission)) + .routes(routes!(post_cities_submission)) + .routes(routes!(patch_cities_submission)) + .routes(routes!(get_cities_submissions)) } +#[utoipa::path( + get, + path = "/cities/{country}/{region}/{name}", + description = "Get the details of a specific city where an BNA analysis was computed.", + tag = TAG, + params( + ("country" = Country, Path, description = "Country name", example = "Belgium"), + ("region" = str, Path, description = "Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used.", example = "Antwerp"), + ("name" = str, Path, description = "City name", example = "Antwerp"), + ), + responses( + (status = OK, description = "Fetches a city", body = City), + ErrorResponses, + ))] async fn get_city( Path(params): Path, ctx: Context, -) -> Result, ExecutionError> { +) -> Result, ExecutionError> { get_city_adaptor(¶ms.country, ¶ms.region, ¶ms.name, ctx) .await + .map(City::from) .map(Json) } -async fn get_cities(pagination: Option>) -> impl IntoResponse { +#[utoipa::path( + get, + path = "/cities", + description = "Get the details of all cities where an BNA analysis was performed.", + tag = TAG, + params( + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches cities", body = Cities), + ))] +async fn get_cities( + pagination: Option>, +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_cities_adaptor(pagination.page, pagination.page_size()).await + let payload = get_cities_adaptor(pagination.page, pagination.page_size()).await?; + Ok(PageFlow::new( + Paginatron::new(None, payload.0, pagination.page, pagination.page_size()), + payload.1.into(), + )) } +#[utoipa::path( + get, + path = "/cities/{country}/{region}/{name}/census", + description = "Get the details of a specific city with its associated census information.", + tag = TAG, + params( + ("country" = Country, Path, description = "Country name", example = "Belgium"), + ("region" = str, Path, description = "Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used.", example = "Antwerp"), + ("name" = str, Path, description = "City name", example = "Antwerp"), + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches city censuses", body = CityCensuses), + ErrorResponses, + ))] async fn get_city_censuses( Path(params): Path, pagination: Option>, -) -> impl IntoResponse { +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_cities_censuses_adaptor( + let city_censuses = get_cities_censuses_adaptor( ¶ms.country, ¶ms.region, ¶ms.name, pagination.page, pagination.page_size(), ) - .await + .await?; + let city = city_censuses.1.first().unwrap().0.clone(); + let censuses = city_censuses + .1 + .iter() + .filter_map(|e| e.1.clone()) + .map(Census::from) + .collect::>(); + let payload = CityCensuses { + city: city.into(), + censuses, + }; + Ok(PageFlow::new( + Paginatron::new( + None, + city_censuses.0, + pagination.page, + pagination.page_size(), + ), + payload, + )) } +#[utoipa::path( + get, + path = "/cities/{country}/{region}/{name}/ratings", + description = "Get the details of a specific city with all the analysis that were performed against it.", + tag = TAG, + params( + ("country" = Country, Path, description = "Country name", example = "Belgium"), + ("region" = str, Path, description = "Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used.", example = "Antwerp"), + ("name" = str, Path, description = "City name", example = "Antwerp"), + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches city ratings", body = CityRatings), + ErrorResponses, + ))] async fn get_city_ratings( Path(params): Path, pagination: Option>, ctx: Context, -) -> impl IntoResponse { +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_cities_ratings_adaptor( + let city_ratings = get_cities_ratings_adaptor( ¶ms.country, ¶ms.region, ¶ms.name, @@ -88,21 +173,64 @@ async fn get_city_ratings( pagination.page_size(), ctx, ) - .await + .await?; + let city = city_ratings.1.first().unwrap().0.clone(); + let ratings = city_ratings + .1 + .iter() + .filter_map(|e| e.1.clone()) + .map(RatingSummary::from) + .collect::>(); + let payload = CityRatings { + city: city.into(), + ratings, + }; + Ok(PageFlow::new( + Paginatron::new( + None, + city_ratings.0, + pagination.page, + pagination.page_size(), + ), + payload, + )) } -async fn post_cities(Json(city): Json) -> Result, ExecutionError> { +#[utoipa::path( + post, + path = "/cities", + description = "Create a new city.", + tag = TAG, + request_body = CityPost, + responses( + (status = CREATED, description = "Creates a new city", body = City), + ErrorResponses, + ))] +async fn post_city(Json(city): Json) -> Result, ExecutionError> { post_cities_adaptor(city).await.map(Json) } +#[utoipa::path( + get, + path = "/cities/submissions/{submission_id}", + description = "Get the details of a specific sumission.", + tag = TAG, + params( + ("submission_id" = i32, Path, description = "Submission identifier", example = "1"), + ("status" = Option, Query, description = "Filter for the submission status", example = "Pending"), + ), + responses( + (status = OK, description = "Fetches a submission", body = Submission), + ErrorResponses, + ))] async fn get_cities_submission( Path(submission_id): Path, OptionalQuery(status): OptionalQuery, ctx: Context, -) -> Result, ExecutionError> { - // let ctx = Context::new(request_id, source); +) -> Result, ExecutionError> { get_cities_submission_adaptor(submission_id, status, ctx) .await + .map(Submission::from) .map(Json) } @@ -111,45 +239,113 @@ struct SubmissionParameters { pub status: Option, } -#[debug_handler] +#[utoipa::path( + get, + path = "/cities/submissions", + description = "Get the submissions details.", + tag = TAG, + params( + ("status" = Option, Query, description = "Filter for the submission status", example = "Pending"), + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches submissions", body = Submissions), + ErrorResponses, + ))] async fn get_cities_submissions( Query(submission_params): Query, pagination: Option>, -) -> Result, ExecutionError> { +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_cities_submissions_adaptor( + let cities_submissions = get_cities_submissions_adaptor( submission_params.status, pagination.page, pagination.page_size(), ) - .await - .map(|v| Json(json!(v.payload()))) + .await?; + // .map(|v| Json(json!(v.payload()))) + let submissions = cities_submissions + .1 + .into_iter() + .map(Submission::from) + .collect::>(); + let payload = Submissions(submissions); + Ok(PageFlow::new( + Paginatron::new( + None, + cities_submissions.0, + pagination.page, + pagination.page_size(), + ), + payload, + )) } +#[utoipa::path( + post, + path = "/cities/submissions", + description = "Create a new city submission.", + tag = TAG, + request_body = SubmissionPost, + responses( + (status = CREATED, description = "Creates a new city submission", body = Submission), + ErrorResponses, + ))] +async fn post_cities_submission( + Json(submission): Json, +) -> Result<(StatusCode, Json), ExecutionError> { + post_cities_submission_adaptor(submission) + .await + .map(Submission::from) + .map(|v| (StatusCode::CREATED, Json(v))) +} + +#[utoipa::path( + patch, + path = "/cities/submissions/{submission_id}", + description = "Update a city submission.", + tag = TAG, + params( + ("submission_id" = i32, Path, description = "Submission identifier", example = "1"), + ), + request_body = SubmissionPatch, + responses( + (status = OK, description = "Updates a city submission", body = Submission), + ErrorResponses, + ))] async fn patch_cities_submission( Query(submission_id): Query, - Json(submission): Json, -) -> Result, ExecutionError> { + Json(submission): Json, +) -> Result, ExecutionError> { patch_cities_submission_adaptor(submission_id, submission) .await + .map(Submission::from) .map(Json) } -async fn post_cities_submissions( - Json(submission): Json, -) -> Result<(StatusCode, Json), ExecutionError> { - post_cities_submission_adaptor(submission) - .await - .map(|v| (StatusCode::CREATED, Json(v))) -} - -#[axum::debug_handler] +#[utoipa::path( + post, + path = "/cities/{country}/{region}/{name}/census", + description = "Create census information for a specific city.", + tag = TAG, + params( + ("country" = Country, Path, description = "Country name", example = "Belgium"), + ("region" = str, Path, description = "Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used.", example = "Antwerp"), + ("name" = str, Path, description = "City name", example = "Antwerp"), + ), + request_body = CensusPost, + responses( + (status = CREATED, description = "Creates a new census entry for a city", body = Census), + ErrorResponses, + ))] async fn post_city_census( Path(params): Path, Json(census): Json, -) -> Result<(StatusCode, Json), ExecutionError> { +) -> Result<(StatusCode, Json), ExecutionError> { post_cities_census_adaptor(¶ms.country, ¶ms.region, ¶ms.name, census) .await + .map(Census::from) .map(|v| (StatusCode::CREATED, Json(v))) } diff --git a/lambdas/src/core/resource/cities/mod.rs b/lambdas/src/core/resource/cities/mod.rs index 119db0e..61120da 100644 --- a/lambdas/src/core/resource/cities/mod.rs +++ b/lambdas/src/core/resource/cities/mod.rs @@ -2,6 +2,7 @@ pub mod adaptor; mod db; pub mod endpoint; +mod schema; use effortless::{api::parse_path_parameter, error::APIErrors}; use serde::Deserialize; diff --git a/lambdas/src/core/resource/cities/schema.rs b/lambdas/src/core/resource/cities/schema.rs new file mode 100644 index 0000000..97e501c --- /dev/null +++ b/lambdas/src/core/resource/cities/schema.rs @@ -0,0 +1,290 @@ +//! Describes the Citi schemas. +use crate::core::resource::schema::{City, Country}; +use chrono::DateTime; +use entity::{census, submission, summary}; +use serde::Serialize; +use utoipa::ToSchema; +use uuid::Uuid; + +#[derive(ToSchema, Serialize)] +pub(crate) struct Cities(Vec); + +impl From> for Cities { + fn from(value: Vec) -> Self { + let c = value.into_iter().map(City::from).collect::>(); + Cities(c) + } +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct CityPost { + /// Country name + #[schema(examples("Belgium"))] + country: Country, + /// Geographic coordinate that specifies the north-south position of a point + /// on the surface of the Earth. + #[schema(examples("51.260197"))] + latitude: Option, + /// Geographic coordinate that specifies the east–west position of a point + /// on the surface of the Earth. + #[schema(examples("4.402771"))] + longitude: Option, + /// City name + #[schema(examples("Antwerp"))] + name: String, + /// Region name. A region can be a state, a province, a community, or + /// something similar depending on the country. If a country does not have + /// this concept, then the country name is used. + #[schema(examples("Antwerp"))] + region: Option, + /// A short version of the state name, usually 2 or 3 character long + #[schema(examples("VAN"))] + state: String, + /// A short version of the state name, usually 2 or 3 character long + #[schema(examples("VAN"))] + state_abbrev: Option, + /// Speed limit in kilometer per hour (km/h). + #[schema(examples("50"))] + speed_limit: Option, +} + +#[derive(ToSchema, Serialize)] +#[schema(description = "Census information of a city")] +pub(crate) struct Census { + /// Census identifier + id: i32, + /// City identifier + city_id: Uuid, + /// Creation date + created_at: DateTime, + /// Numerical city identifier given by the U.S. census, or 0 for non-US cities + #[schema(examples("4805000"))] + fips_code: String, + /// City population size category (small (0), medium (1), large (2)) + #[schema(examples("1"))] + pop_size: i32, + /// City population + #[schema(examples("907779"))] + population: i32, +} + +impl From for Census { + fn from(value: census::Model) -> Self { + Self { + id: value.id, + city_id: value.city_id, + created_at: value.created_at, + fips_code: value.fips_code, + pop_size: value.pop_size, + population: value.population, + } + } +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct CensusPost { + /// Numerical city identifier given by the U.S. census, or 0 for non-US cities + #[schema(examples("4805000"))] + fips_code: String, + /// City population size category (small (0), medium (1), large (2)) + #[schema(examples("1"))] + pop_size: i32, + /// City population + #[schema(examples("907779"))] + population: i32, +} + +// This is the current version which does not seem to be valid OAS3.1 +// https://github.com/juhaku/utoipa/issues/901 +// https://github.com/juhaku/utoipa/pull/1103 +// https://json-schema.org/understanding-json-schema/reference/array#tupleValidation +// struct CityCensuses(Vec<(City, Option)>); +// So here is the new idea, which shounds more correct anyway +#[derive(ToSchema, Serialize)] +pub(crate) struct CityCensuses { + pub(crate) city: City, + pub(crate) censuses: Vec, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct RatingSummary { + /// Analysis identifier + id: Uuid, + /// City identifier + city_id: Uuid, + /// Creation date + created_at: DateTime, + /// BNA score + #[schema(examples("77.0"))] + score: f64, + /// Analysis version. The format follows the [calver](https://calver.org) + /// specification with the YY.0M[.Minor] scheme. + #[schema(examples("23.12"))] + version: String, +} + +impl From for RatingSummary { + fn from(value: summary::Model) -> Self { + Self { + id: value.id, + city_id: value.city_id, + created_at: value.created_at, + score: value.score, + version: value.version, + } + } +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct CityRatings { + pub(crate) city: City, + pub(crate) ratings: Vec, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Submission { + /// Submission identifier + id: i32, + /// First name + #[schema(examples("Jane"))] + first_name: String, + /// Last name + last_name: String, + #[schema(examples("Doe"))] + /// Job title or position + #[schema(examples("CTO"))] + occupation: Option, + /// Organization or company + #[schema(examples("Organization LLC"))] + organization: Option, + /// email address + #[schema(examples("jane.doe@orgllc.com"))] + email: String, + /// Country + #[schema(examples("Belgium"))] + country: Country, + /// City name + #[schema(examples("Antwerp"))] + city: String, + /// Region name. A region can be a state, a province, a community, or + /// something similar depending on the country. If a country does not have + /// this concept, then the country name is used. + #[schema(examples("Antwerp"))] + region: Option, + /// Numerical city identifier given by the U.S. census, or 0 for non-US cities + #[schema(examples("4805000"))] + fips_code: String, + /// Consent status + #[schema(examples("true"))] + consent: bool, + /// Submission status, e.g. "Pending" + #[schema(examples("Pending"))] + status: String, + /// Creation date + created_at: DateTime, +} + +impl From for Submission { + fn from(value: submission::Model) -> Self { + Self { + id: value.id, + first_name: value.first_name, + last_name: value.last_name, + occupation: value.occupation, + organization: value.organization, + email: value.email, + country: value.country.into(), + city: value.city, + region: value.region, + fips_code: value.fips_code, + consent: value.consent, + status: value.status, + created_at: value.created_at, + } + } +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct SubmissionPost { + /// First name + #[schema(examples("Jane"))] + first_name: String, + /// Last name + last_name: String, + #[schema(examples("Doe"))] + /// Job title or position + #[schema(examples("CTO"))] + occupation: Option, + /// Organization or company + #[schema(examples("Organization LLC"))] + organization: Option, + /// email address + #[schema(examples("jane.doe@orgllc.com"))] + email: String, + /// Country + #[schema(examples("Belgium"))] + country: Country, + /// City name + #[schema(examples("Antwerp"))] + city: String, + /// Region name. A region can be a state, a province, a community, or + /// something similar depending on the country. If a country does not have + /// this concept, then the country name is used. + #[schema(examples("Antwerp"))] + region: Option, + /// Numerical city identifier given by the U.S. census, or 0 for non-US cities + #[schema(examples("4805000"))] + fips_code: String, + /// Consent status + #[schema(examples("true"))] + consent: bool, + /// Submission status, e.g. "Pending" + #[schema(examples("Pending"))] + status: String, +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct SubmissionPatch { + /// First name + #[schema(examples("Jane"))] + first_name: String, + /// Last name + last_name: String, + #[schema(examples("Doe"))] + /// Job title or position + #[schema(examples("CTO"))] + occupation: Option, + /// Organization or company + #[schema(examples("Organization LLC"))] + organization: Option, + /// email address + #[schema(examples("jane.doe@orgllc.com"))] + email: String, + /// Country + #[schema(examples("Belgium"))] + country: Country, + /// City name + #[schema(examples("Antwerp"))] + city: String, + /// Region name. A region can be a state, a province, a community, or + /// something similar depending on the country. If a country does not have + /// this concept, then the country name is used. + #[schema(examples("Antwerp"))] + region: Option, + /// Numerical city identifier given by the U.S. census, or 0 for non-US cities + #[schema(examples("4805000"))] + fips_code: String, + /// Consent status + #[schema(examples("true"))] + consent: bool, + /// Submission status, e.g. "Pending" + #[schema(examples("Pending"))] + status: String, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Submissions(pub(crate) Vec); diff --git a/lambdas/src/core/resource/mod.rs b/lambdas/src/core/resource/mod.rs index 1d724ef..723f541 100644 --- a/lambdas/src/core/resource/mod.rs +++ b/lambdas/src/core/resource/mod.rs @@ -1,3 +1,5 @@ pub mod cities; +pub mod pipelines; pub mod price; pub mod ratings; +pub mod schema; diff --git a/lambdas/src/core/resource/pipelines/adaptor.rs b/lambdas/src/core/resource/pipelines/adaptor.rs new file mode 100644 index 0000000..0620e60 --- /dev/null +++ b/lambdas/src/core/resource/pipelines/adaptor.rs @@ -0,0 +1,79 @@ +use super::db::{fetch_bna_pipeline, fetch_bna_pipelines}; +use crate::{database_connect, Context, ExecutionError, PageFlow, Paginatron}; +use entity::{ + bna_pipeline, + wrappers::bna_pipeline::{BNAPipelinePatch, BNAPipelinePost}, +}; +use sea_orm::{ActiveModelTrait, ActiveValue, IntoActiveModel}; +use tracing::info; +use uuid::Uuid; + +pub async fn get_pipelines_bna_adaptor( + pipeline_id: Uuid, + ctx: Context, +) -> Result { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Fetch the model. + let model = fetch_bna_pipeline(&db, pipeline_id).await?; + match model { + Some(model) => Ok(model), + None => Err(ExecutionError::NotFound( + ctx.request_id(), + ctx.source(), + format!("cannot find a pipeline with the ID {pipeline_id}"), + )), + } +} + +pub async fn get_pipelines_bnas_adaptor( + page: u64, + page_size: u64, +) -> Result>, ExecutionError> { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Fetch a page of summary. + let (total_items, models) = fetch_bna_pipelines(&db, page, page_size).await?; + + // Return the paginated response. + Ok(PageFlow::new( + Paginatron::new(None, total_items, page, page_size), + models, + )) +} + +pub async fn post_pipelines_bna_adaptor( + bna_pipeline: BNAPipelinePost, +) -> Result { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Turn the post model into an active model. + let active_model = bna_pipeline.into_active_model(); + + // And insert a new entry. + info!( + "inserting Brokenspoke pipeline into database: {:?}", + active_model + ); + let model = active_model.insert(&db).await?; + Ok(model) +} + +pub async fn patch_pipelines_bna_adaptor( + bna_pipeline: BNAPipelinePatch, + analysis_id: Uuid, +) -> Result { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Turn the patch model into an active model. + let mut active_model = bna_pipeline.into_active_model(); + active_model.state_machine_id = ActiveValue::Unchanged(analysis_id); + + // Update the entry. + let model = active_model.update(&db).await?; + Ok(model) +} diff --git a/lambdas/src/core/resource/pipelines/db.rs b/lambdas/src/core/resource/pipelines/db.rs new file mode 100644 index 0000000..c922c53 --- /dev/null +++ b/lambdas/src/core/resource/pipelines/db.rs @@ -0,0 +1,25 @@ +use entity::bna_pipeline; +use sea_orm::{DatabaseConnection, EntityTrait, PaginatorTrait}; +use uuid::Uuid; + +pub async fn fetch_bna_pipeline( + db: &DatabaseConnection, + pipeline_id: Uuid, +) -> Result, sea_orm::DbErr> { + bna_pipeline::Entity::find_by_id(pipeline_id).one(db).await +} + +pub async fn fetch_bna_pipelines( + db: &DatabaseConnection, + page: u64, + page_size: u64, +) -> Result<(u64, Vec), sea_orm::DbErr> { + let select = bna_pipeline::Entity::find(); + let models = select + .clone() + .paginate(db, page_size) + .fetch_page(page) + .await?; + let count = select.count(db).await?; + Ok((count, models)) +} diff --git a/lambdas/src/core/resource/pipelines/endpoint.rs b/lambdas/src/core/resource/pipelines/endpoint.rs new file mode 100644 index 0000000..7c1a9cb --- /dev/null +++ b/lambdas/src/core/resource/pipelines/endpoint.rs @@ -0,0 +1,121 @@ +use super::adaptor::{ + get_pipelines_bna_adaptor, get_pipelines_bnas_adaptor, patch_pipelines_bna_adaptor, + post_pipelines_bna_adaptor, +}; +use super::schema::{BnaPipeline, BnaPipelinePatch, BnaPipelinePost, BnaPipelines}; +use crate::{core::resource::schema::ErrorResponses, Context, ExecutionError}; +use axum::{ + extract::{Path, Query}, + http::StatusCode, + Json, +}; +use effortless::api::PaginationParameters; +use entity::wrappers::bna_pipeline::{BNAPipelinePatch, BNAPipelinePost}; +use serde_json::{json, Value}; +use tracing::debug; +use utoipa_axum::{router::OpenApiRouter, routes}; +use uuid::Uuid; + +const TAG: &str = "pipeline"; + +pub fn routes() -> OpenApiRouter { + OpenApiRouter::new() + .routes(routes!(get_pipelines_bna)) + .routes(routes!(get_pipelines_bnas)) + .routes(routes!(post_pipelines_bna)) + .routes(routes!(patch_pipelines_bna)) +} + +#[utoipa::path( + get, + path = "/pipelines/bna/{pipeline_id}", + description = "Get the details of a specific BNA pipeline", + tag = TAG, + params( + ("pipeline_id" = Uuid, Path, description = "Pipeline identifier") + ), + responses( + (status = OK, description = "Fetches the details of a BNA pipeline", body = BnaPipeline), + ErrorResponses, + ))] +async fn get_pipelines_bna( + Path(pipeline_id): Path, + ctx: Context, +) -> Result, ExecutionError> { + get_pipelines_bna_adaptor(pipeline_id, ctx) + .await + .map(BnaPipeline::from) + .map(Json) +} + +#[utoipa::path( + get, + path = "/pipelines/bna", + description = "Get the details of all BNA pipelines", + tag = TAG, + params( + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches the details of all BNA pipelines", body = BnaPipelines), + ErrorResponses, + ))] +async fn get_pipelines_bnas( + pagination: Option>, +) -> Result, ExecutionError> { + let Query(pagination) = pagination.unwrap_or_default(); + get_pipelines_bnas_adaptor(pagination.page, pagination.page_size()) + .await + .map(|v| Json(json!(v.payload()))) +} + +#[utoipa::path( + post, + path = "/pipelines/bna", + description = "Create a new BNA pipeline", + tag = TAG, + request_body = BnaPipelinePost, + responses( + (status = CREATED, description = "Creates a new city submission", body = BnaPipeline), + ErrorResponses, + ))] +async fn post_pipelines_bna( + Json(bna_pipeline): Json, +) -> Result<(StatusCode, Json), ExecutionError> { + post_pipelines_bna_adaptor(bna_pipeline) + .await + .map_err(|e| { + debug!("{e}"); + e + }) + .map(BnaPipeline::from) + .map(|v| (StatusCode::CREATED, Json(v))) +} + +#[utoipa::path( + patch, + path = "/pipelines/bna/{pipeline_id}", + description = "Update the details of a specific BNA pipeline", + tag = TAG, + request_body = BnaPipelinePatch, + params( + ("pipeline_id" = Uuid, Path, description = "Pipeline identifier") + ), + responses( + (status = OK, description = "Updates the details of a BNA pipeline", body = BnaPipeline), + ErrorResponses, + ))] +async fn patch_pipelines_bna( + Path(analysis_id): Path, + Json(bna_pipeline): Json, +) -> Result, ExecutionError> { + patch_pipelines_bna_adaptor(bna_pipeline, analysis_id) + .await + .map_err(|e| { + debug!("{e}"); + e + }) + .map(BnaPipeline::from) + .map(Json) +} diff --git a/lambdas/src/core/resource/pipelines/mod.rs b/lambdas/src/core/resource/pipelines/mod.rs new file mode 100644 index 0000000..5c891fd --- /dev/null +++ b/lambdas/src/core/resource/pipelines/mod.rs @@ -0,0 +1,5 @@ +//! Module for the /pipeline enpoint. +pub mod adaptor; +mod db; +pub mod endpoint; +mod schema; diff --git a/lambdas/src/core/resource/pipelines/schema.rs b/lambdas/src/core/resource/pipelines/schema.rs new file mode 100644 index 0000000..ebd3a88 --- /dev/null +++ b/lambdas/src/core/resource/pipelines/schema.rs @@ -0,0 +1,161 @@ +//! Describes the Pipeline schemas. +use std::{fmt::Display, str::FromStr}; + +use chrono::DateTime; +use sea_orm::prelude::Decimal; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; +use uuid::Uuid; + +#[derive(ToSchema, Serialize, Deserialize)] +pub(crate) enum PipelineStatus { + Completed, + Pending, + Processing, +} + +impl FromStr for PipelineStatus { + type Err = serde_plain::Error; + + fn from_str(s: &str) -> Result { + serde_plain::from_str::(s) + } +} + +impl Display for PipelineStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = serde_plain::to_string(&self).expect("cannot serialize value"); + write!(f, "{}", value) + } +} + +#[derive(ToSchema, Serialize, Deserialize)] +pub(crate) struct BnaPipeline { + /// Cost of an analysis in USD + #[schema(examples("6.8941"))] + cost: Option, + /// End time + end_time: Option>, + /// Fargate price identifier used to compute the cost + fargate_price_id: Option, + /// ARN of the Fargate task that performed the analysis + #[schema(examples( + "arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0" + ))] + fargate_task_arn: Option, + /// Path of the S3 bucket where the results were stored + #[schema(examples("united states/new mexico/santa rosa/24.05.4"))] + s3_bucket: Option, + /// Copy of the JSON message that was sent for processing + #[schema(examples(json!({"country":"United States","city":"santa rosa","region":"new mexico","fips_code":"3570670"})))] + sqs_message: Option, + /// Start time + start_time: DateTime, + /// Pipeline identifier + /// This is the ID of the AWS state machine that was used to run the pipeline + state_machine_id: Uuid, + /// Pipeline status + status: PipelineStatus, + /// Last pipeline step that was completed + step: BnaPipelineStep, +} + +impl From for BnaPipeline { + fn from(value: entity::bna_pipeline::Model) -> Self { + Self { + cost: value.cost, + end_time: value.end_time, + fargate_price_id: value.fargate_price_id, + fargate_task_arn: value.fargate_task_arn, + s3_bucket: value.s3_bucket, + sqs_message: value + .sqs_message + .and_then(|v| serde_json::to_string(&v).ok()), + start_time: value.start_time, + state_machine_id: value.state_machine_id, + status: PipelineStatus::from_str(&value.status).expect("a valid status"), + step: BnaPipelineStep::from_str(&value.step).expect("a valid step"), + } + } +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct BnaPipelinePost { + /// Cost of an analysis in USD + #[schema(examples("6.8941"))] + cost: Option, + /// End time + end_time: Option>, + /// Fargate price identifier used to compute the cost + fargate_price_id: Option, + /// ARN of the Fargate task that performed the analysis + #[schema(examples( + "arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0" + ))] + fargate_task_arn: Option, + /// Path of the S3 bucket where the results were stored + #[schema(examples("united states/new mexico/santa rosa/24.05.4"))] + s3_bucket: Option, + /// Copy of the JSON message that was sent for processing + #[schema(examples(json!({"country":"United States","city":"santa rosa","region":"new mexico","fips_code":"3570670"})))] + sqs_message: Option, + /// Last pipeline step that was completed + step: BnaPipelineStep, +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct BnaPipelinePatch { + /// Cost of an analysis in USD + #[schema(examples("6.8941"))] + cost: Option, + /// End time + end_time: Option>, + /// Fargate price identifier used to compute the cost + fargate_price_id: Option, + /// ARN of the Fargate task that performed the analysis + #[schema(examples( + "arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0" + ))] + fargate_task_arn: Option, + /// Path of the S3 bucket where the results were stored + #[schema(examples("united states/new mexico/santa rosa/24.05.4"))] + s3_bucket: Option, + /// Copy of the JSON message that was sent for processing + #[schema(examples(json!({"country":"United States","city":"santa rosa","region":"new mexico","fips_code":"3570670"})))] + sqs_message: Option, + /// Start time + start_time: DateTime, + /// Pipeline status + status: PipelineStatus, + /// Last pipeline step that was completed + step: BnaPipelineStep, +} + +#[derive(ToSchema, Serialize, Deserialize)] +pub(crate) enum BnaPipelineStep { + SqsMessage, + Setup, + Analysis, + Cleanup, +} + +impl FromStr for BnaPipelineStep { + type Err = serde_plain::Error; + + fn from_str(s: &str) -> Result { + serde_plain::from_str::(s) + } +} + +impl Display for BnaPipelineStep { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = serde_plain::to_string(&self).expect("cannot serialize value"); + write!(f, "{}", value) + } +} + +#[allow(dead_code)] +#[derive(ToSchema)] +pub(crate) struct BnaPipelines(Vec); diff --git a/lambdas/src/core/resource/price/adaptor.rs b/lambdas/src/core/resource/price/adaptor.rs index f76c222..f41589b 100644 --- a/lambdas/src/core/resource/price/adaptor.rs +++ b/lambdas/src/core/resource/price/adaptor.rs @@ -3,6 +3,7 @@ use crate::{ core::resource::price::db::{fetch_fargate_price, fetch_fargate_prices}, database_connect, Context, ExecutionError, PageFlow, Paginatron, }; +use entity::fargate_price; use serde_json::{json, Value}; pub async fn get_price_fargate_adaptor(id: i32, ctx: Context) -> Result { @@ -21,11 +22,30 @@ pub async fn get_price_fargate_adaptor(id: i32, ctx: Context) -> Result Result { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Fetch the city model. + let model = fetch_fargate_price(&db, id).await?; + match model { + Some(model) => Ok(model), + None => Err(ExecutionError::NotFound( + ctx.request_id(), + ctx.source(), + format!("cannot find a fargate price with ID {id}"), + )), + } +} + pub async fn get_prices_fargate_adaptor( params: PriceParameters, page: u64, page_size: u64, -) -> Result { +) -> Result>, ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; @@ -42,6 +62,27 @@ pub async fn get_prices_fargate_adaptor( // Return the paginated response. Ok(PageFlow::new( Paginatron::new(None, total_items, page, page_size), - json!(models), + models, )) } + +pub async fn get_prices_fargate_adaptor_model_( + params: PriceParameters, + page: u64, + page_size: u64, +) -> Result<(u64, Vec), ExecutionError> { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Fetch a page of cities. + let (total_items, models) = fetch_fargate_prices( + &db, + params.sort.unwrap_or_default(), + params.latest, + page, + page_size, + ) + .await?; + + Ok((total_items, models)) +} diff --git a/lambdas/src/core/resource/price/endpoint.rs b/lambdas/src/core/resource/price/endpoint.rs index beebc8d..74abee2 100644 --- a/lambdas/src/core/resource/price/endpoint.rs +++ b/lambdas/src/core/resource/price/endpoint.rs @@ -1,36 +1,80 @@ +use super::{ + adaptor::{get_price_fargate_adaptor_model_, get_prices_fargate_adaptor_model_}, + PriceParameters, +}; +use crate::{ + core::resource::{ + price::schema::{FargatePrice, FargatePrices}, + schema::ErrorResponses, + }, + PageFlow, Paginatron, +}; +use crate::{Context, ExecutionError}; use axum::{ extract::{Path, Query}, - response::IntoResponse, - routing::get, - Json, Router, + Json, }; use effortless::api::PaginationParameters; -use serde_json::Value; +use utoipa_axum::{router::OpenApiRouter, routes}; -use crate::{Context, ExecutionError}; +const TAG: &str = "price"; -use super::{ - adaptor::{get_price_fargate_adaptor, get_prices_fargate_adaptor}, - PriceParameters, -}; - -pub fn routes() -> Router { - Router::new() - .route("/prices/fargate", get(get_prices_fargate)) - .route("/prices/fargate/:price_id", get(get_price_fargate)) +pub fn routes() -> OpenApiRouter { + OpenApiRouter::new() + .routes(routes!(get_prices_fargate)) + .routes(routes!(get_price_fargate)) } -pub async fn get_prices_fargate( +#[utoipa::path( + get, + path = "/prices/fargate", + description = "Get all the AWS Fargate prices used to compute analysis costs.", + tag = TAG, + params( + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches a collection of Fargate prices", body = FargatePrices), + ))] +pub(crate) async fn get_prices_fargate( pagination: Option>, price_parameters: PriceParameters, -) -> impl IntoResponse { +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_prices_fargate_adaptor(price_parameters, pagination.page, pagination.page_size()).await + let (total_items, models) = get_prices_fargate_adaptor_model_( + price_parameters, + pagination.page, + pagination.page_size(), + ) + .await?; + let payload: FargatePrices = models.into(); + Ok(PageFlow::new( + Paginatron::new(None, total_items, pagination.page, pagination.page_size()), + payload, + )) } -pub async fn get_price_fargate( +#[utoipa::path( + get, + path = "/prices/fargate/{price_id}", + description = "Get a specific AWS Fargate price used to compute the cost of analysis cost.", + tag = TAG, + params( + ("price_id" = i32, Path, description = "Identifier of a Fargate price")), + responses( + (status = OK, description = "Fetches a Fargate price used to estimate the cost of an analysis", body = FargatePrice), + ErrorResponses, + ))] +pub(crate) async fn get_price_fargate( Path(price_id): Path, ctx: Context, -) -> Result, ExecutionError> { - get_price_fargate_adaptor(price_id, ctx).await.map(Json) +) -> Result, ExecutionError> { + get_price_fargate_adaptor_model_(price_id, ctx) + .await + .map(FargatePrice::from) + .map(Json) } + +// (status = BAD_REQUEST, description = "The request was formatted incorrectly or missing required parameters.", body = UserResponses::BadRequest), +// (status = NOT_FOUND, description = "The particular resource you are requesting was not found. This occurs, for example, if you request a resource by an id that does not exist.", body = APIErrorNotFound ), diff --git a/lambdas/src/core/resource/price/mod.rs b/lambdas/src/core/resource/price/mod.rs index cb0d94b..8737a1f 100644 --- a/lambdas/src/core/resource/price/mod.rs +++ b/lambdas/src/core/resource/price/mod.rs @@ -9,6 +9,7 @@ use query_map::QueryMap; pub mod adaptor; mod db; pub mod endpoint; +mod schema; pub struct PriceParameters { sort: Option, diff --git a/lambdas/src/core/resource/price/schema.rs b/lambdas/src/core/resource/price/schema.rs new file mode 100644 index 0000000..0b18e7c --- /dev/null +++ b/lambdas/src/core/resource/price/schema.rs @@ -0,0 +1,42 @@ +//! Describes the Price schemas. +use chrono::DateTime; +use sea_orm::prelude::Decimal; +use serde::Serialize; +use utoipa::ToSchema; + +#[derive(ToSchema, Serialize)] +#[schema(description = "A Fargate price used to estimate the cost of an analysis")] +pub(crate) struct FargatePrice { + /// Identifier of the Fargate Price rate used to compute the cost of the pipeline run + #[schema(examples("1"))] + id: i32, + /// Cost to run Fargate for 1 second + #[schema(examples("0.0023"))] + per_second: Decimal, + /// Creation date + created_at: DateTime, +} + +impl From for FargatePrice { + fn from(value: entity::fargate_price::Model) -> Self { + Self { + id: value.id, + per_second: value.per_second, + created_at: value.created_at, + } + } +} + +#[derive(ToSchema, Serialize)] +#[schema(description = "A collection of Fargate prices.")] +pub(crate) struct FargatePrices(Vec); + +impl From> for FargatePrices { + fn from(value: Vec) -> Self { + let prices = value + .into_iter() + .map(FargatePrice::from) + .collect::>(); + Self(prices) + } +} diff --git a/lambdas/src/core/resource/ratings/adaptor.rs b/lambdas/src/core/resource/ratings/adaptor.rs index a92b5df..b5d89ee 100644 --- a/lambdas/src/core/resource/ratings/adaptor.rs +++ b/lambdas/src/core/resource/ratings/adaptor.rs @@ -1,72 +1,35 @@ -use super::{ - db::{ - fetch_ratings_analyses, fetch_ratings_analysis, fetch_ratings_city, - fetch_ratings_summaries, fetch_ratings_summary_with_parts, - }, - BNAComponent, -}; -use crate::{database_connect, Context, ExecutionError, PageFlow, Paginatron}; +use super::db::{fetch_rating, fetch_ratings, fetch_ratings_city, fetch_ratings_summaries, Bna}; +use crate::{database_connect, Context, ExecutionError}; use entity::{ core_services, infrastructure, opportunity, people, recreation, retail, summary, transit, - wrappers::{ - bna::{BNAPost, RatingFlat}, - bna_pipeline::{BNAPipelinePatch, BNAPipelinePost}, - }, + wrappers::bna::BNAPost, }; -use sea_orm::{ActiveModelTrait, ActiveValue, DbErr, IntoActiveModel}; -use serde_json::{json, Value}; +use sea_orm::{ActiveModelTrait, ActiveValue}; use tracing::info; use uuid::Uuid; pub async fn get_ratings_summaries_adaptor( page: u64, page_size: u64, -) -> Result { +) -> Result<(u64, Vec), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch a page of summary. - let (total_items, models) = fetch_ratings_summaries(&db, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) + Ok(fetch_ratings_summaries(&db, page, page_size).await?) } -pub async fn get_rating_adaptor( +pub(crate) async fn get_rating_adaptor( rating_id: Uuid, - component: Option, ctx: Context, -) -> Result { +) -> Result { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch the model. - let model = fetch_ratings_summary_with_parts(&db, rating_id, component).await?; + let model: Option = fetch_rating(&db, rating_id).await?; match model { - Some(model) => match model { - super::db::BNAComponentValue::All(bna) => Ok(json!(bna)), - super::db::BNAComponentValue::Summary(summary) => Ok(json!(summary)), - super::db::BNAComponentValue::Infrastructure(summary, infrastructure) => { - Ok(json!((summary, infrastructure))) - } - super::db::BNAComponentValue::Recreation(summary, recreation) => { - Ok(json!((summary, recreation))) - } - super::db::BNAComponentValue::Opportunity(summary, opportunity) => { - Ok(json!((summary, opportunity))) - } - super::db::BNAComponentValue::CoreServices(summary, core_services) => { - Ok(json!((summary, core_services))) - } - super::db::BNAComponentValue::People(summary, people) => Ok(json!((summary, people))), - super::db::BNAComponentValue::Retail(summary, retail) => Ok(json!((summary, retail))), - super::db::BNAComponentValue::Transit(summary, transit) => { - Ok(json!((summary, transit))) - } - }, + Some(model) => Ok(model), None => Err(ExecutionError::NotFound( ctx.request_id(), ctx.source(), @@ -75,66 +38,27 @@ pub async fn get_rating_adaptor( } } -pub async fn get_ratings_adaptor(page: u64, page_size: u64) -> Result { - // Set the database connection. - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // Fetch a page of summary. - let (total_items, models) = fetch_ratings_summaries(&db, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) -} - -pub async fn get_ratings_analyses_adaptor( +pub(crate) async fn get_ratings_adaptor( page: u64, page_size: u64, -) -> Result { +) -> Result<(u64, Vec), ExecutionError> { // Set the database connection. let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch a page of summary. - let (total_items, models) = fetch_ratings_analyses(&db, page, page_size).await?; - - // Return the paginated response. - Ok(PageFlow::new( - Paginatron::new(None, total_items, page, page_size), - json!(models), - )) -} - -pub async fn get_ratings_analysis_adaptor( - analysis_id: Uuid, - ctx: Context, -) -> Result { - // Set the database connection. - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // Fetch the model. - let model = fetch_ratings_analysis(&db, analysis_id).await?; - match model { - Some(model) => Ok(json!(model)), - None => Err(ExecutionError::NotFound( - ctx.request_id(), - ctx.source(), - format!("cannot find a rating with the ID {analysis_id}"), - )), - } + Ok(fetch_ratings(&db, page, page_size).await?) } -pub async fn get_ratings_city_adaptor( +pub(crate) async fn get_ratings_city_adaptor( rating_id: Uuid, ctx: Context, -) -> Result { +) -> Result<(Bna, entity::city::Model), ExecutionError> { let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; // Fetch the model. let model = fetch_ratings_city(&db, rating_id).await?; match model { - Some(model) => Ok(json!(model)), + Some((bna, city)) => Ok((bna, city)), None => Err(ExecutionError::NotFound( ctx.request_id(), ctx.source(), @@ -143,63 +67,13 @@ pub async fn get_ratings_city_adaptor( } } -pub async fn post_ratings_analysis_adaptor( - bna_pipeline: BNAPipelinePost, -) -> Result { - // Set the database connection. - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // Turn the post model into an active model. - let active_model = bna_pipeline.into_active_model(); - - // And insert a new entry. - info!( - "inserting Brokenspoke pipeline into database: {:?}", - active_model - ); - let model = active_model.insert(&db).await?; - Ok(json!(model)) -} - -pub async fn patch_ratings_analysis_adaptor( - bna_pipeline: BNAPipelinePatch, - analysis_id: Uuid, - ctx: Context, -) -> Result { - // Set the database connection. - let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; - - // Turn the patch model into an active model. - let mut active_model = bna_pipeline.into_active_model(); - active_model.state_machine_id = ActiveValue::Unchanged(analysis_id); - - // Update the entry. - info!("Tartiflette!"); - let model = match active_model.update(&db).await { - Ok(m) => m, - Err(db_err) => { - dbg!(&db_err); - match db_err { - DbErr::RecordNotUpdated => { - match get_ratings_analysis_adaptor(analysis_id, ctx).await { - Ok(_) => return Err(ExecutionError::DatabaseError(db_err)), - Err(exec_err) => return Err(exec_err), - } - } - _ => return Err(ExecutionError::DatabaseError(db_err)), - } - } - }; - Ok(json!(model)) -} - -pub async fn post_ratings_adaptor(bna: BNAPost) -> Result { +pub(crate) async fn post_ratings_adaptor(bna: BNAPost) -> Result { // Turn the model wrapper into active models. let summary = summary::ActiveModel { - id: ActiveValue::Set(bna.summary.rating_id), + id: ActiveValue::NotSet, city_id: ActiveValue::Set(bna.summary.city_id), created_at: ActiveValue::NotSet, - score: ActiveValue::Set(bna.summary.score), + score: ActiveValue::NotSet, version: ActiveValue::Set(bna.summary.version), }; info!("{:?}", summary); @@ -268,16 +142,33 @@ pub async fn post_ratings_adaptor(bna: BNAPost) -> Result let recreation_model = recreation.insert(&db).await?; let retail_model = retail.insert(&db).await?; let transit_model = transit.insert(&db).await?; - let rating = RatingFlat { - core_services: core_services_model, - infrastructure: infrastructure_model, - opportunity: opportunity_model, - people: people_model, - recreation: recreation_model, - retail: retail_model, - summary: summary_model, - transit: transit_model, + let bna = Bna { + id: summary_model.id, + city_id: summary_model.city_id, + score: summary_model.score, + version: summary_model.version, + low_stress_miles: infrastructure_model.low_stress_miles, + high_stress_miles: infrastructure_model.high_stress_miles, + community_centers: recreation_model.community_centers, + parks: recreation_model.parks, + recreation_trails: recreation_model.recreation_trails, + recreation_score: recreation_model.score, + employment: opportunity_model.employment, + higher_education: opportunity_model.higher_education, + k12_education: opportunity_model.k12_education, + opportunity_score: opportunity_model.score, + technical_vocational_college: opportunity_model.technical_vocational_college, + dentists: core_services_model.dentists, + doctors: core_services_model.doctors, + grocery: core_services_model.grocery, + hospitals: core_services_model.hospitals, + pharmacies: core_services_model.pharmacies, + coreservices_score: core_services_model.score, + social_services: core_services_model.social_services, + people: people_model.score, + retail: retail_model.score, + transit: transit_model.score, }; - info!("{:?}", rating); - Ok(json!(rating)) + info!("{:?}", bna); + Ok(bna) } diff --git a/lambdas/src/core/resource/ratings/db.rs b/lambdas/src/core/resource/ratings/db.rs index d026640..481bbe7 100644 --- a/lambdas/src/core/resource/ratings/db.rs +++ b/lambdas/src/core/resource/ratings/db.rs @@ -1,7 +1,4 @@ -use entity::{ - bna_pipeline, city, core_services, infrastructure, opportunity, people, recreation, retail, - summary, transit, -}; +use entity::{city, summary}; use sea_orm::{ DatabaseConnection, EntityTrait, FromQueryResult, JoinType, PaginatorTrait, QuerySelect, RelationTrait, @@ -9,50 +6,48 @@ use sea_orm::{ use serde::{Deserialize, Serialize}; use uuid::Uuid; -use super::BNAComponent; - #[derive(Debug, FromQueryResult, Clone, PartialEq, Serialize, Deserialize)] -pub struct Bna { +pub(crate) struct Bna { // BNA Summary - id: Uuid, - city_id: Uuid, - score: f64, - version: String, + pub(crate) id: Uuid, + pub(crate) city_id: Uuid, + pub(crate) score: f64, + pub(crate) version: String, // BNAInfrastructure - low_stress_miles: Option, - high_stress_miles: Option, + pub(crate) low_stress_miles: Option, + pub(crate) high_stress_miles: Option, // BNA Recreation - community_centers: Option, - parks: Option, - recreation_trails: Option, - recreation_score: Option, + pub(crate) community_centers: Option, + pub(crate) parks: Option, + pub(crate) recreation_trails: Option, + pub(crate) recreation_score: Option, // BNA Opportunity - employment: Option, - higher_education: Option, - k12_education: Option, - opportunity_score: Option, - technical_vocational_college: Option, + pub(crate) employment: Option, + pub(crate) higher_education: Option, + pub(crate) k12_education: Option, + pub(crate) opportunity_score: Option, + pub(crate) technical_vocational_college: Option, // BNA Core Services - dentists: Option, - doctors: Option, - grocery: Option, - hospitals: Option, - pharmacies: Option, - coreservices_score: Option, - social_services: Option, + pub(crate) dentists: Option, + pub(crate) doctors: Option, + pub(crate) grocery: Option, + pub(crate) hospitals: Option, + pub(crate) pharmacies: Option, + pub(crate) coreservices_score: Option, + pub(crate) social_services: Option, // BNA People - people: Option, + pub(crate) people: Option, // BNA Retail - retail: Option, + pub(crate) retail: Option, // BNA Transit - transit: Option, + pub(crate) transit: Option, } #[derive(Debug, FromQueryResult, Deserialize, Serialize)] @@ -112,18 +107,18 @@ pub struct Transit { transit: Option, } -#[derive(Debug)] -pub enum BNAComponentValue { - All(Bna), - Summary(Summary), - Infrastructure(Summary, Option), - Recreation(Summary, Option), - Opportunity(Summary, Option), - CoreServices(Summary, Option), - People(Summary, Option), - Retail(Summary, Option), - Transit(Summary, Option), -} +// #[derive(Debug)] +// pub enum BNAComponentValue { +// All(Bna), +// Summary(Summary), +// Infrastructure(Summary, Option), +// Recreation(Summary, Option), +// Opportunity(Summary, Option), +// CoreServices(Summary, Option), +// People(Summary, Option), +// Retail(Summary, Option), +// Transit(Summary, Option), +// } pub async fn fetch_ratings_summaries( db: &DatabaseConnection, @@ -140,165 +135,330 @@ pub async fn fetch_ratings_summaries( Ok((count, models)) } -pub async fn fetch_ratings_summary_with_parts( +// pub async fn fetch_ratings_summary_with_parts( +// db: &DatabaseConnection, +// rating_id: Uuid, +// component: Option, +// ) -> Result, sea_orm::DbErr> { +// let select = summary::Entity::find_by_id(rating_id); +// let component = component.unwrap_or(BNAComponent::All); +// dbg!(&component); +// let res = match component { +// BNAComponent::All => select +// .clone() +// .columns([ +// entity::core_services::Column::Dentists, +// entity::core_services::Column::Doctors, +// entity::core_services::Column::Grocery, +// entity::core_services::Column::Hospitals, +// entity::core_services::Column::Pharmacies, +// entity::core_services::Column::SocialServices, +// ]) +// .column_as(entity::core_services::Column::Score, "coreservices_score") +// .columns([ +// entity::infrastructure::Column::HighStressMiles, +// entity::infrastructure::Column::LowStressMiles, +// ]) +// .columns([ +// entity::recreation::Column::CommunityCenters, +// entity::recreation::Column::Parks, +// entity::recreation::Column::RecreationTrails, +// ]) +// .column_as(entity::recreation::Column::Score, "recreation_score") +// .columns([ +// entity::opportunity::Column::Employment, +// entity::opportunity::Column::HigherEducation, +// entity::opportunity::Column::K12Education, +// entity::opportunity::Column::TechnicalVocationalCollege, +// ]) +// .column_as(entity::opportunity::Column::Score, "opportunity_score") +// .column_as(entity::people::Column::Score, "people_score") +// .column_as(entity::retail::Column::Score, "retail_score") +// .column_as(entity::transit::Column::Score, "transit_score") +// .join( +// JoinType::InnerJoin, +// entity::summary::Relation::CoreServices.def(), +// ) +// .join( +// JoinType::InnerJoin, +// entity::summary::Relation::Infrastructure.def(), +// ) +// .join( +// JoinType::InnerJoin, +// entity::summary::Relation::Recreation.def(), +// ) +// .join( +// JoinType::InnerJoin, +// entity::summary::Relation::Opportunity.def(), +// ) +// .join( +// sea_orm::JoinType::InnerJoin, +// entity::summary::Relation::People.def(), +// ) +// .join( +// sea_orm::JoinType::InnerJoin, +// entity::summary::Relation::Retail.def(), +// ) +// .join( +// sea_orm::JoinType::InnerJoin, +// entity::summary::Relation::Transit.def(), +// ) +// .into_model::() +// .one(db) +// .await? +// .map(BNAComponentValue::All), +// BNAComponent::Summary => select +// .clone() +// .into_model::() +// .one(db) +// .await? +// .map(BNAComponentValue::Summary), +// BNAComponent::Infratructure => select +// .clone() +// .find_also_related(infrastructure::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::Infrastructure(m.0, m.1)), +// BNAComponent::Recreation => select +// .clone() +// .find_also_related(recreation::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::Recreation(m.0, m.1)), +// BNAComponent::Opportunity => select +// .clone() +// .find_also_related(opportunity::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::Opportunity(m.0, m.1)), +// BNAComponent::CoreServices => select +// .clone() +// .find_also_related(core_services::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::CoreServices(m.0, m.1)), +// BNAComponent::People => select +// .clone() +// .find_also_related(people::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::People(m.0, m.1)), +// BNAComponent::Retail => select +// .clone() +// .find_also_related(retail::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::Retail(m.0, m.1)), +// BNAComponent::Transit => select +// .clone() +// .find_also_related(transit::Entity) +// .into_model::() +// .one(db) +// .await? +// .map(|m| BNAComponentValue::Transit(m.0, m.1)), +// }; +// Ok(res) +// } + +// pub async fn fetch_ratings_analyses( +// db: &DatabaseConnection, +// page: u64, +// page_size: u64, +// ) -> Result<(u64, Vec), sea_orm::DbErr> { +// let select = bna_pipeline::Entity::find(); +// let models = select +// .clone() +// .paginate(db, page_size) +// .fetch_page(page) +// .await?; +// let count = select.count(db).await?; +// Ok((count, models)) +// } + +// pub async fn fetch_ratings_analysis( +// db: &DatabaseConnection, +// analysis_id: Uuid, +// ) -> Result, sea_orm::DbErr> { +// bna_pipeline::Entity::find_by_id(analysis_id).one(db).await +// } + +pub async fn fetch_ratings_city( + db: &DatabaseConnection, + rating_id: Uuid, +) -> Result, sea_orm::DbErr> { + match summary::Entity::find_by_id(rating_id) + .find_also_related(city::Entity) + .one(db) + .await? + { + Some((_, city)) => { + let bna = fetch_rating(db, rating_id).await?; + Ok(Some(( + bna.expect("we already found this bna so it must exist"), + city.expect("a city must be attached to a rating"), + ))) + } + None => Ok(None), + } + // let bna = fetch_rating(db, rating_id).await?; + // match bna { + // Some(bna) => { + // let a = summary::Entity::find_by_id(rating_id) + // .find_also_related(city::Entity) + // .one(db) + // .await?; + // Ok((bna, city: city.expect("a city must be attached to a rating"))) + // } + // None => Err(ExecutionError::NotFound( + // ctx.request_id(), + // ctx.source(), + // format!("cannot find a rating with id {rating_id}"), + // )), +} + +pub async fn fetch_rating( db: &DatabaseConnection, rating_id: Uuid, - component: Option, -) -> Result, sea_orm::DbErr> { - let select = summary::Entity::find_by_id(rating_id); - let component = component.unwrap_or(BNAComponent::All); - dbg!(&component); - let res = match component { - BNAComponent::All => select - .clone() - .columns([ - entity::core_services::Column::Dentists, - entity::core_services::Column::Doctors, - entity::core_services::Column::Grocery, - entity::core_services::Column::Hospitals, - entity::core_services::Column::Pharmacies, - entity::core_services::Column::SocialServices, - ]) - .column_as(entity::core_services::Column::Score, "coreservices_score") - .columns([ - entity::infrastructure::Column::HighStressMiles, - entity::infrastructure::Column::LowStressMiles, - ]) - .columns([ - entity::recreation::Column::CommunityCenters, - entity::recreation::Column::Parks, - entity::recreation::Column::RecreationTrails, - ]) - .column_as(entity::recreation::Column::Score, "recreation_score") - .columns([ - entity::opportunity::Column::Employment, - entity::opportunity::Column::HigherEducation, - entity::opportunity::Column::K12Education, - entity::opportunity::Column::TechnicalVocationalCollege, - ]) - .column_as(entity::opportunity::Column::Score, "opportunity_score") - .column_as(entity::people::Column::Score, "people_score") - .column_as(entity::retail::Column::Score, "retail_score") - .column_as(entity::transit::Column::Score, "transit_score") - .join( - JoinType::InnerJoin, - entity::summary::Relation::CoreServices.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Infrastructure.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Recreation.def(), - ) - .join( - JoinType::InnerJoin, - entity::summary::Relation::Opportunity.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::People.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::Retail.def(), - ) - .join( - sea_orm::JoinType::InnerJoin, - entity::summary::Relation::Transit.def(), - ) - .into_model::() - .one(db) - .await? - .map(BNAComponentValue::All), - BNAComponent::Summary => select - .clone() - .into_model::() - .one(db) - .await? - .map(BNAComponentValue::Summary), - BNAComponent::Infratructure => select - .clone() - .find_also_related(infrastructure::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::Infrastructure(m.0, m.1)), - BNAComponent::Recreation => select - .clone() - .find_also_related(recreation::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::Recreation(m.0, m.1)), - BNAComponent::Opportunity => select - .clone() - .find_also_related(opportunity::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::Opportunity(m.0, m.1)), - BNAComponent::CoreServices => select - .clone() - .find_also_related(core_services::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::CoreServices(m.0, m.1)), - BNAComponent::People => select - .clone() - .find_also_related(people::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::People(m.0, m.1)), - BNAComponent::Retail => select - .clone() - .find_also_related(retail::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::Retail(m.0, m.1)), - BNAComponent::Transit => select - .clone() - .find_also_related(transit::Entity) - .into_model::() - .one(db) - .await? - .map(|m| BNAComponentValue::Transit(m.0, m.1)), - }; +) -> Result, sea_orm::DbErr> { + let res = summary::Entity::find_by_id(rating_id) + .columns([ + entity::core_services::Column::Dentists, + entity::core_services::Column::Doctors, + entity::core_services::Column::Grocery, + entity::core_services::Column::Hospitals, + entity::core_services::Column::Pharmacies, + entity::core_services::Column::SocialServices, + ]) + .column_as(entity::core_services::Column::Score, "coreservices_score") + .columns([ + entity::infrastructure::Column::HighStressMiles, + entity::infrastructure::Column::LowStressMiles, + ]) + .columns([ + entity::recreation::Column::CommunityCenters, + entity::recreation::Column::Parks, + entity::recreation::Column::RecreationTrails, + ]) + .column_as(entity::recreation::Column::Score, "recreation_score") + .columns([ + entity::opportunity::Column::Employment, + entity::opportunity::Column::HigherEducation, + entity::opportunity::Column::K12Education, + entity::opportunity::Column::TechnicalVocationalCollege, + ]) + .column_as(entity::opportunity::Column::Score, "opportunity_score") + .column_as(entity::people::Column::Score, "people_score") + .column_as(entity::retail::Column::Score, "retail_score") + .column_as(entity::transit::Column::Score, "transit_score") + .join( + JoinType::InnerJoin, + entity::summary::Relation::CoreServices.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Infrastructure.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Recreation.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Opportunity.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::People.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::Retail.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::Transit.def(), + ) + .into_model::() + .one(db) + .await?; Ok(res) } -pub async fn fetch_ratings_analyses( +pub async fn fetch_ratings( db: &DatabaseConnection, page: u64, page_size: u64, -) -> Result<(u64, Vec), sea_orm::DbErr> { - let select = bna_pipeline::Entity::find(); +) -> Result<(u64, Vec), sea_orm::DbErr> { + let select = summary::Entity::find() + .columns([ + entity::core_services::Column::Dentists, + entity::core_services::Column::Doctors, + entity::core_services::Column::Grocery, + entity::core_services::Column::Hospitals, + entity::core_services::Column::Pharmacies, + entity::core_services::Column::SocialServices, + ]) + .column_as(entity::core_services::Column::Score, "coreservices_score") + .columns([ + entity::infrastructure::Column::HighStressMiles, + entity::infrastructure::Column::LowStressMiles, + ]) + .columns([ + entity::recreation::Column::CommunityCenters, + entity::recreation::Column::Parks, + entity::recreation::Column::RecreationTrails, + ]) + .column_as(entity::recreation::Column::Score, "recreation_score") + .columns([ + entity::opportunity::Column::Employment, + entity::opportunity::Column::HigherEducation, + entity::opportunity::Column::K12Education, + entity::opportunity::Column::TechnicalVocationalCollege, + ]) + .column_as(entity::opportunity::Column::Score, "opportunity_score") + .column_as(entity::people::Column::Score, "people_score") + .column_as(entity::retail::Column::Score, "retail_score") + .column_as(entity::transit::Column::Score, "transit_score") + .join( + JoinType::InnerJoin, + entity::summary::Relation::CoreServices.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Infrastructure.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Recreation.def(), + ) + .join( + JoinType::InnerJoin, + entity::summary::Relation::Opportunity.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::People.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::Retail.def(), + ) + .join( + sea_orm::JoinType::InnerJoin, + entity::summary::Relation::Transit.def(), + ); let models = select .clone() + .into_model::() .paginate(db, page_size) .fetch_page(page) .await?; let count = select.count(db).await?; Ok((count, models)) } - -pub async fn fetch_ratings_analysis( - db: &DatabaseConnection, - analysis_id: Uuid, -) -> Result, sea_orm::DbErr> { - bna_pipeline::Entity::find_by_id(analysis_id).one(db).await -} - -pub async fn fetch_ratings_city( - db: &DatabaseConnection, - rating_id: Uuid, -) -> Result)>, sea_orm::DbErr> { - summary::Entity::find_by_id(rating_id) - .find_also_related(city::Entity) - .one(db) - .await -} diff --git a/lambdas/src/core/resource/ratings/endpoint.rs b/lambdas/src/core/resource/ratings/endpoint.rs index 61763ec..a64a5fc 100644 --- a/lambdas/src/core/resource/ratings/endpoint.rs +++ b/lambdas/src/core/resource/ratings/endpoint.rs @@ -1,137 +1,129 @@ use super::{ adaptor::{ - get_rating_adaptor, get_ratings_analyses_adaptor, get_ratings_analysis_adaptor, - get_ratings_city_adaptor, get_ratings_summaries_adaptor, patch_ratings_analysis_adaptor, - post_ratings_adaptor, post_ratings_analysis_adaptor, + get_rating_adaptor, get_ratings_adaptor, get_ratings_city_adaptor, post_ratings_adaptor, }, - BNAComponent, + schema::{Rating, RatingPost, RatingWithCity, Ratings}, +}; +use crate::{ + core::resource::schema::ErrorResponses, Context, ExecutionError, PageFlow, Paginatron, }; -use crate::{Context, ExecutionError}; use axum::{ - debug_handler, extract::{Path, Query}, http::StatusCode, - response::IntoResponse, - routing::get, - Json, Router, + Json, }; use effortless::api::PaginationParameters; -use entity::wrappers::{ - bna::BNAPost, - bna_pipeline::{BNAPipelinePatch, BNAPipelinePost}, -}; -use serde_json::{json, Value}; +use entity::wrappers::bna::BNAPost; use tracing::debug; +use utoipa_axum::{router::OpenApiRouter, routes}; use uuid::Uuid; -pub fn routes() -> Router { - Router::new() - .route("/ratings", get(get_ratings).post(post_ratings)) - .route("/ratings/:rating_id", get(get_rating)) - .route("/ratings/:rating_id/city", get(get_ratings_city)) - .route( - "/ratings/analyses", - get(get_ratings_analyses).post(post_ratings_analysis), - ) - .route( - "/ratings/analyses/:analysis_id", - get(get_ratings_analysis).patch(patch_ratings_analysis), - ) -} +const TAG: &str = "rating"; -async fn get_ratings(pagination: Option>) -> impl IntoResponse { - let Query(pagination) = pagination.unwrap_or_default(); - get_ratings_summaries_adaptor(pagination.page, pagination.page_size()).await +pub fn routes() -> OpenApiRouter { + OpenApiRouter::new() + .routes(routes!(get_rating)) + .routes(routes!(get_ratings)) + .routes(routes!(post_rating)) + .routes(routes!(get_ratings_city)) } +#[utoipa::path( + get, + path = "/ratings/{rating_id}", + description = "Get the details of a specific city rating", + tag = TAG, + params( + ("rating_id" = Uuid, Path, description = "Rating identifier") + ), + responses( + (status = OK, description = "Fetches the details of a city rating", body = Rating ), + ErrorResponses, + ))] async fn get_rating( Path(rating_id): Path, - component: Option>, ctx: Context, -) -> Result, ExecutionError> { - let component = match component { - Some(c) => { - let Query(c) = c; - Some(c) - } - None => None, - }; - - get_rating_adaptor(rating_id, component, ctx) +) -> Result, ExecutionError> { + get_rating_adaptor(rating_id, ctx) .await .map_err(|e| { debug!("{e}"); e }) - .map(|v| Json(json!(v))) -} - -async fn get_ratings_city( - Path(rating_id): Path, - ctx: Context, -) -> Result, ExecutionError> { - get_ratings_city_adaptor(rating_id, ctx).await.map(Json) + .map(Rating::from) + .map(Json) } -async fn get_ratings_analyses( +#[utoipa::path( + get, + path = "/ratings", + description = "Get city ratings", + tag = TAG, + params( + ("page_size" = Option, Query, description = "The number of items per page", example = "25"), + ("page" = Option, Query, description = "The result page being returned", example = "1"), + ), + responses( + (status = OK, description = "Fetches the city ratings", body = Ratings), + ))] +async fn get_ratings( pagination: Option>, -) -> Result, ExecutionError> { +) -> Result, ExecutionError> { let Query(pagination) = pagination.unwrap_or_default(); - get_ratings_analyses_adaptor(pagination.page, pagination.page_size()) - .await - .map(|v| Json(json!(v.payload()))) -} + let (total_items, models) = + get_ratings_adaptor(pagination.page, pagination.page_size()).await?; -async fn get_ratings_analysis( - Path(analysis_id): Path, - ctx: Context, -) -> Result, ExecutionError> { - get_ratings_analysis_adaptor(analysis_id, ctx) - .await - .map(Json) + let payload: Ratings = models.into(); + Ok(PageFlow::new( + Paginatron::new(None, total_items, pagination.page, pagination.page_size()), + payload, + )) } -async fn post_ratings_analysis( - Json(bna_pipeline): Json, -) -> Result<(StatusCode, Json), ExecutionError> { - post_ratings_analysis_adaptor(bna_pipeline) +#[utoipa::path( + post, + path = "/ratings", + description = "Create a new city rating", + tag = TAG, + request_body = RatingPost, + responses( + (status = CREATED, description = "Creates a new city rating", body = Rating ), + ErrorResponses, + ))] +async fn post_rating( + Json(bna): Json, +) -> Result<(StatusCode, Json), ExecutionError> { + post_ratings_adaptor(bna) .await .map_err(|e| { debug!("{e}"); e }) + .map(Rating::from) .map(|v| (StatusCode::CREATED, Json(v))) } -#[debug_handler] -async fn patch_ratings_analysis( - Path(analysis_id): Path, - Json(bna_pipeline): Json, -) -> Result, ExecutionError> { - patch_ratings_analysis_adaptor( - bna_pipeline, - analysis_id, - Context { - request_id: None, - source: format!("/ratings/analyses/{analysis_id}"), - }, - ) - .await - .map_err(|e| { - debug!("{e}"); - e - }) - .map(Json) -} - -async fn post_ratings( - Json(bna): Json, -) -> Result<(StatusCode, Json), ExecutionError> { - post_ratings_adaptor(bna) +#[utoipa::path( + get, + path = "/ratings/{rating_id}/city", + description = "Get a city rating and its associated city details", + tag = TAG, + params( + ("rating_id" = Uuid, Path, description = "Rating identifier") + ), + responses( + (status = OK, description = "Fetches a city rating and its associated city details" , body = RatingWithCity ), + ErrorResponses, + ))] +async fn get_ratings_city( + Path(rating_id): Path, + ctx: Context, +) -> Result, ExecutionError> { + get_ratings_city_adaptor(rating_id, ctx) .await - .map_err(|e| { - debug!("{e}"); - e + .map(|(rating, model)| RatingWithCity { + rating: rating.into(), + city: model.into(), }) - .map(|v| (StatusCode::CREATED, Json(v))) + .map(Json) } diff --git a/lambdas/src/core/resource/ratings/mod.rs b/lambdas/src/core/resource/ratings/mod.rs index 5790d4c..fb009f2 100644 --- a/lambdas/src/core/resource/ratings/mod.rs +++ b/lambdas/src/core/resource/ratings/mod.rs @@ -10,6 +10,7 @@ use uuid::Uuid; pub mod adaptor; mod db; pub mod endpoint; +mod schema; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BNAComponent { diff --git a/lambdas/src/core/resource/ratings/schema.rs b/lambdas/src/core/resource/ratings/schema.rs new file mode 100644 index 0000000..11ddcf5 --- /dev/null +++ b/lambdas/src/core/resource/ratings/schema.rs @@ -0,0 +1,227 @@ +//! Describes the Ratings schemas. +use super::db::Bna; +use crate::core::resource::schema::City; +use serde::Serialize; +use utoipa::ToSchema; +use uuid::Uuid; + +#[derive(ToSchema, Serialize)] +pub(crate) struct Rating { + // BNA Summary + /// Rating identifier + id: Uuid, + /// City identifier + city_id: Uuid, + /// Total rating score + #[schema(minimum = 0, maximum = 100)] + score: f64, + /// Rating version + /// The format follows the [calver](https://calver.org) specification with + /// the YY.0M[.Minor] scheme. + version: String, + + /// BNAInfrastructure + infrastructure: Infrastructure, + + /// BNA Recreation + recreation: Recreation, + + /// BNA Opportunity + opportunity: Opportunity, + + /// BNA Core Services + core_services: CoreServices, + + /// BNA People + people: People, + + /// BNA Retail + retail: Retail, + + /// BNA Transit + transit: Transit, +} + +impl From for Rating { + fn from(value: Bna) -> Self { + Self { + id: value.id, + city_id: value.city_id, + score: value.score, + version: value.version, + infrastructure: Infrastructure { + low_stress_miles: value.low_stress_miles, + high_stress_miles: value.high_stress_miles, + }, + recreation: Recreation { + community_centers: value.community_centers, + parks: value.parks, + trails: value.recreation_trails, + score: Some(value.score), + }, + opportunity: Opportunity { + employment: value.employment, + higher_education: value.higher_education, + k12_education: value.k12_education, + score: Some(value.score), + technical_vocational_college: value.technical_vocational_college, + }, + core_services: CoreServices { + dentists: value.dentists, + doctors: value.doctors, + grocery: value.grocery, + hospitals: value.hospitals, + pharmacies: value.pharmacies, + score: Some(value.score), + social_services: value.social_services, + }, + people: People { + people: value.people, + }, + retail: Retail { + retail: value.retail, + }, + transit: Transit { + transit: value.transit, + }, + } + } +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Infrastructure { + /// Total miles of low-stress streets and paths in the measured area. + #[schema(examples(127))] + low_stress_miles: Option, + /// Total miles of high-stress streets in the measured area. + #[schema(examples(253))] + high_stress_miles: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Recreation { + /// BNA category subscore for access to community centers. + #[schema(minimum = 0, maximum = 100)] + community_centers: Option, + /// BNA category subscore for access to parks. + #[schema(minimum = 0, maximum = 100)] + parks: Option, + /// BNA category subscore for access to bikeable trails. + #[schema(minimum = 0, maximum = 100)] + trails: Option, + /// BNA category score for access to recreational facilities. + #[schema(minimum = 0, maximum = 100)] + score: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Opportunity { + /// BNA category subscore for access to job location areas. + #[schema(minimum = 0, maximum = 100)] + employment: Option, + /// BNA category subscore for access to universities and colleges. + #[schema(minimum = 0, maximum = 100)] + higher_education: Option, + /// BNA category subscore for access to k12 schools + #[schema(minimum = 0, maximum = 100)] + k12_education: Option, + /// BNA category score for access to education and jobs. + #[schema(minimum = 0, maximum = 100)] + score: Option, + /// BNA category subscore for access to technical and vocational colleges. + #[schema(minimum = 0, maximum = 100)] + technical_vocational_college: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct CoreServices { + /// BNA category subscore for access to dentists. + #[schema(minimum = 0, maximum = 100)] + dentists: Option, + /// BNA category subscore for access to doctors. + #[schema(minimum = 0, maximum = 100)] + doctors: Option, + /// BNA category subscore for access to grocery stores. + #[schema(minimum = 0, maximum = 100)] + grocery: Option, + /// BNA category subscore for access to hospitals. + #[schema(minimum = 0, maximum = 100)] + hospitals: Option, + /// BNA category subscore for access to pharmacies. + #[schema(minimum = 0, maximum = 100)] + pharmacies: Option, + /// BNA category score for access to core services. + #[schema(minimum = 0, maximum = 100)] + score: Option, + /// BNA category subscore for access to social services. + #[schema(minimum = 0, maximum = 100)] + social_services: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct People { + /// BNA category score for access to residential areas. + #[schema(minimum = 0, maximum = 100)] + people: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Retail { + /// BNA category score for access to major retail centers. + #[schema(minimum = 0, maximum = 100)] + retail: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Transit { + /// BNA category score for access to major transit stops. + #[schema(minimum = 0, maximum = 100)] + transit: Option, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct Ratings(Vec); + +impl From> for Ratings { + fn from(value: Vec) -> Self { + let ratings = value.into_iter().map(Rating::from).collect::>(); + Self(ratings) + } +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct RatingWithCity { + pub(crate) rating: Rating, + pub(crate) city: City, +} + +#[derive(ToSchema, Serialize)] +pub(crate) struct RatingPost { + /// City identifier + city_id: Uuid, + /// Rating version + /// The format follows the [calver](https://calver.org) specification with + /// the YY.0M[.Minor] scheme. + version: String, + + /// BNAInfrastructure + infrastructure: Infrastructure, + + /// BNA Recreation + recreation: Recreation, + + /// BNA Opportunity + opportunity: Opportunity, + + /// BNA Core Services + core_services: CoreServices, + + /// BNA People + people: People, + + /// BNA Retail + retail: Retail, + + /// BNA Transit + transit: Transit, +} diff --git a/lambdas/src/core/resource/schema.rs b/lambdas/src/core/resource/schema.rs new file mode 100644 index 0000000..e45b9a2 --- /dev/null +++ b/lambdas/src/core/resource/schema.rs @@ -0,0 +1,234 @@ +//! Describes the schemas shared accross resources. +use chrono::DateTime; +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; +use std::{fmt::Display, str::FromStr}; +use utoipa::{IntoResponses, ToSchema}; +use uuid::Uuid; + +#[derive(ToSchema, Serialize, Deserialize)] +pub(crate) enum Country { + Australia, + Belgium, + Brazil, + Canada, + Chile, + Colombia, + Croatia, + Cuba, + England, + France, + Germany, + Greece, + Guatemala, + Iran, + Iraq, + Ireland, + Italy, + Mexico, + Netherlands, + #[schema(rename = "New Zealand")] + NewZealand, + #[schema(rename = "Northern Ireland")] + NorthernIreland, + Portugal, + Scotland, + Spain, + #[schema(rename = "United States")] + UnitedStates, + Vietnam, + Wales, +} + +impl FromStr for Country { + type Err = serde_plain::Error; + + fn from_str(s: &str) -> Result { + serde_plain::from_str::(s) + } +} + +impl From for Country { + fn from(value: String) -> Self { + Country::from_str(value.as_str()).expect("cannot serialize value") + } +} + +impl Display for Country { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = serde_plain::to_string(&self).expect("cannot serialize value"); + write!(f, "{}", value) + } +} + +#[derive(ToSchema, Serialize)] +#[schema(description = "Detailed information of a city")] +pub(crate) struct City { + /// City identifier + id: Uuid, + /// Country name + #[schema(examples("Belgium"))] + country: Country, + /// State name + #[schema(examples("Antwerp"))] + state: String, + /// City name + #[schema(examples("Antwerp"))] + name: String, + /// Geographic coordinate that specifies the north-south position of a point + /// on the surface of the Earth. + #[schema(examples("51.260197"))] + latitude: Option, + /// Geographic coordinate that specifies the east–west position of a point + /// on the surface of the Earth. + #[schema(examples("4.402771"))] + longitude: Option, + /// Region name. A region can be a state, a province, a community, or + /// something similar depending on the country. If a country does not have + /// this concept, then the country name is used. + #[schema(examples("Antwerp"))] + region: Option, + /// A short version of the state name, usually 2 or 3 character long + #[schema(examples("VAN"))] + state_abbrev: Option, + /// Speed limit in kilometer per hour (km/h). + #[schema(examples("50"))] + speed_limit: Option, + /// Creation date + created_at: DateTime, + /// Update date + updated_at: Option>, +} + +impl From for City { + fn from(value: entity::city::Model) -> Self { + Self { + id: value.id, + country: value.country.into(), + state: value.state, + name: value.name, + latitude: value.latitude, + longitude: value.latitude, + region: value.region, + state_abbrev: value.state_abbrev, + speed_limit: value.speed_limit, + created_at: value.created_at, + updated_at: value.updated_at, + } + } +} + +/// An object containing references to the primary source of the error. +/// +/// It SHOULD include one of the following members or be omitted: +/// +/// - pointer: a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901) to the +/// value in the request document that caused the error [e.g. "/data" for a primary +/// data object, or "/data/attributes/title" for a specific attribute]. +/// This MUST point to a value in the request document that exists; if it doesn’t, +/// the client SHOULD simply ignore the pointer. +/// - parameter: a string indicating which URI query parameter caused the error. +/// - header: a string indicating the name of a single request header which caused the +/// error. +#[derive(Deserialize, Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum APIErrorSource { + /// A JSON Pointer [RFC6901] to the value in the request document that caused the error. + #[schema(examples(json!({"pointer": "/data/attributes/title"})))] + Pointer(String), + /// A string indicating which URI query parameter caused the error. + #[schema(examples(json!({ "parameter": "include" })))] + Parameter(String), + /// A string indicating the name of a single request header which caused the error. + #[schema(examples(json!({ "header": "Content-Type" })))] + Header(String), +} + +/// Single API Error object as described in . +#[skip_serializing_none] +#[derive(Deserialize, Serialize, ToSchema)] +pub struct APIError { + /// A unique identifier for this particular occurrence of the problem. + #[schema(examples("blfwkg8nvHcEJnQ="))] + id: Option, + /// The HTTP status code applicable to this problem, expressed as a string value. + #[schema(examples("404"))] + status: String, + /// A short, human-readable summary of the problem + #[schema(examples("Item Not Found"))] + title: String, + /// A human-readable explanation specific to this occurrence of the problem + #[schema(examples("the entry was not found"))] + details: String, + /// An object containing references to the primary source of the error. + /// + /// This field may be omitted in some situation. For instance, if the server cannot + /// parse the request as valid JSON, including source doesn’t make sense + /// (because there’s no JSON document for source to refer to). + #[schema(examples(json!("pointer": "/bnas/analysis/e6aade5a-b343-120b-dbaa-bd916cd99221")))] + source: Option, +} + +/// Error objects MUST be returned as an array keyed by errors in the top level of a +/// JSON:API document. +#[derive(Deserialize, Serialize, ToSchema)] +pub(crate) struct APIErrors { + pub errors: Vec, +} + +#[allow(dead_code)] +#[derive(Serialize, IntoResponses, ToSchema)] +pub(crate) enum ErrorResponses { + /// Bad Request + #[response( + status = 400, + description = "The request was formatted incorrectly or missing required parameters.", + example = json!([{ + "details": "the request was formatted incorrectly or missing required parameters", + "id": "blfwkg8nvHcEJnQ=", + "source": {"parameter": "status"}, + "status": "400", + "title": "Bad Request" + }]) + )] + BadRequest(#[to_schema] Vec), + /// Unauthorized + #[response( + status = 401, + description = "The request has not been fulfilled because it lacks valid authentication credentials for the target resource.", + example = json!([{ + "details": "invalid authentication credentials to access the specified resource", + "id": "blfwkg8nvHcEJnQ=", + "source": {"pointer": "/bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221"}, + "status": "401", + "title": "Unauthorized" + }]) + )] + Unauthorized(#[to_schema] APIErrors), + /// Forbidden + #[response( + status = 403, + description = "Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions.", + example = json!([{ + "details": "access to the requested resource is forbidden", + "id": "blfwkg8nvHcEJnQ=", + "source": {"pointer": "/bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221"}, + "status": "403", + "title": "Forbidden" + }]) + )] + Forbidden(#[to_schema] APIErrors), + /// Item Not Found + #[response( + status = 404, + description = "The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist.", + example = json!([{ + "details": "the resource was not found", + "id": "blfwkg8nvHcEJnQ=", + "source": {"pointer": "/bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221"}, + "status": "404", + "title": "Item Not Found" + }]) + )] + NotFound(#[to_schema] APIErrors), +} diff --git a/lambdas/src/lib.rs b/lambdas/src/lib.rs index 17138f2..56ab473 100644 --- a/lambdas/src/lib.rs +++ b/lambdas/src/lib.rs @@ -217,26 +217,35 @@ impl Paginatron { } #[derive(Serialize)] -pub struct PageFlow { +pub struct PageFlow +where + T: Serialize, +{ paginatron: Paginatron, - payload: Value, + payload: T, } -impl PageFlow { - pub fn new(paginatron: Paginatron, payload: Value) -> Self { +impl PageFlow +where + T: Serialize, +{ + pub fn new(paginatron: Paginatron, payload: T) -> Self { Self { paginatron, payload, } } - pub fn payload(&self) -> Value { - self.payload.clone() + pub fn payload(&self) -> &T { + &self.payload } } -impl From for Response { - fn from(value: PageFlow) -> Self { +impl From> for Response +where + T: Serialize, +{ + fn from(value: PageFlow) -> Self { let nav = value.paginatron.navigation(); Response::builder() .header( @@ -250,12 +259,17 @@ impl From for Response { .header("x-total", value.paginatron.total_items) .header("x-total-pages", nav.last()) .header(header::CONTENT_TYPE, "application/json") - .body(Body::from(value.payload.to_string())) + .body(Body::from( + serde_json::to_string(&value.payload).expect("payload must serialize"), + )) .expect("failed to build response") } } -impl IntoResponse for PageFlow { +impl IntoResponse for PageFlow +where + T: Serialize, +{ fn into_response(self) -> axum::response::Response { let nav = self.paginatron.navigation(); let r: Response = axum::response::Response::builder() @@ -267,7 +281,9 @@ impl IntoResponse for PageFlow { .header("x-total", self.paginatron.total_items) .header("x-total-pages", nav.last()) .header(header::CONTENT_TYPE, "application/json") - .body(axum::body::Body::from(self.payload.to_string())) + .body(axum::body::Body::from( + serde_json::to_string(&self.payload).expect("payload must serialize"), + )) .expect("failed to build response"); r } diff --git a/lambdas/src/main.rs b/lambdas/src/main.rs index 199a185..70c3c99 100644 --- a/lambdas/src/main.rs +++ b/lambdas/src/main.rs @@ -1,9 +1,20 @@ -use ::tracing::debug; -use axum::Router; +use ::tracing::{debug, info}; use lambda_http::{run, tracing, Error}; -use lambdas::core::resource::{cities, price, ratings}; -use std::env::{self, set_var}; +use lambdas::core::resource::{ + cities, pipelines, price, ratings, + schema::{APIError, APIErrorSource}, +}; +use std::{ + env::{self, set_var}, + fs, +}; use tower_http::trace::TraceLayer; +use utoipa::{ + openapi::{Components, ContactBuilder, Info, OpenApiBuilder, Server, Tag}, + schema, +}; +use utoipa_axum::router::OpenApiRouter; +use utoipa_swagger_ui::SwaggerUi; #[tokio::main] async fn main() -> Result<(), Error> { @@ -34,12 +45,92 @@ async fn main() -> Result<(), Error> { .init(); debug!(loglevel= ?log_level); + // Define the OpenApi Specification. + let api = OpenApiBuilder::new() + .info( + Info::builder() + .title("BNA REST API") + .version("1.0.0") + .description(Some( + "Provides a way to retrieve the BNA results programmatically.", + )) + .contact(Some( + ContactBuilder::new() + .name(Some("The BNA Mechanics team")) + .url(Some("https://peopleforbikes.github.io/")) + .build(), + )) + .build(), + ) + .servers(Some(vec![ + Server::builder() + .description(Some("Local development API")) + .url("https://localhost:3000") + .build(), + Server::builder() + .description(Some("Staging API")) + .url("https://api.peopleforbikes.xyz") + .build(), + ])) + .tags(Some(vec![ + Tag::builder() + .name("city") + .description(Some("City API endpoints")) + .build(), + Tag::builder() + .name("pipeline") + .description(Some("Pipeline API endpoints")) + .build(), + Tag::builder() + .name("price") + .description(Some("Price API endpoints")) + .build(), + Tag::builder() + .name("rating") + .description(Some("Rating API endpoints")) + .build(), + ])) + .components(Some( + Components::builder() + .schema( + "APIError", + schema!( + #[inline] + APIError + ), + ) + .schema( + "APIErrorSource", + schema!( + #[inline] + APIErrorSource + ), + ) + .build(), + )) + .build(); + // Create the app router. - let app = Router::new() + let (app, api) = OpenApiRouter::with_openapi(api) .merge(cities::endpoint::routes()) + .merge(pipelines::endpoint::routes()) .merge(price::endpoint::routes()) .merge(ratings::endpoint::routes()) - .layer(TraceLayer::new_for_http()); + .layer(TraceLayer::new_for_http()) + .split_for_parts(); + + // Write the specification file to disk. + if env::var("BNA_API_GENERATE_ONLY") + .ok() + .map_or(false, |v| v == *"1") + { + info!("Regenerating the OpenAPI specification file."); + let _ = fs::write("./openapi-3.1.yaml", api.to_yaml().unwrap()); + return Ok(()); + } + + // Add the Swagger UI. + let app = app.merge(SwaggerUi::new("/swagger-ui").url("/apidoc/openapi.json", api)); // Lookup for the standalone flag. let standalone = env::var("BNA_API_STANDALONE") diff --git a/migration/src/m20240202_004130_brokenspoke_analyzer_pipeline.rs b/migration/src/m20240202_004130_brokenspoke_analyzer_pipeline.rs index 85d7572..2ce5cf7 100644 --- a/migration/src/m20240202_004130_brokenspoke_analyzer_pipeline.rs +++ b/migration/src/m20240202_004130_brokenspoke_analyzer_pipeline.rs @@ -1,7 +1,7 @@ use sea_orm_migration::{ prelude::*, schema::{ - boolean_null, decimal, decimal_null, integer_null, json_null, pk_auto, string, string_null, + decimal, decimal_null, integer_null, json_null, pk_auto, string, string_null, timestamp_with_time_zone, timestamp_with_time_zone_null, uuid, }, }; @@ -80,7 +80,7 @@ impl MigrationTrait for Migration { .table(BNAPipeline::Table) .if_not_exists() .col(uuid(BNAPipeline::StateMachineId).primary_key()) - .col(string_null(BNAPipeline::Step)) + .col(string(BNAPipeline::Step)) .col(json_null(BNAPipeline::SqsMessage)) .col(integer_null(BNAPipeline::FargatePriceId)) .col(string_null(BNAPipeline::FargateTaskARN)) @@ -88,8 +88,6 @@ impl MigrationTrait for Migration { .col(string(BNAPipeline::Status).default("Pending".to_string())) .col(timestamp_with_time_zone(BNAPipeline::StartTime)) .col(timestamp_with_time_zone_null(BNAPipeline::EndTime)) - .col(boolean_null(BNAPipeline::TornDown)) - .col(boolean_null(BNAPipeline::ResultsPosted)) .col(decimal_null(BNAPipeline::Cost)) .foreign_key( ForeignKey::create() @@ -137,14 +135,12 @@ enum BNAPipeline { EndTime, FargatePriceId, FargateTaskARN, - ResultsPosted, S3Bucket, SqsMessage, StartTime, StateMachineId, Status, Step, - TornDown, } /// Lookup table for the brokenspoke statuses. diff --git a/openapi-3.0.yaml b/openapi-3.0.yaml new file mode 100644 index 0000000..0c2f3f8 --- /dev/null +++ b/openapi-3.0.yaml @@ -0,0 +1,4010 @@ +openapi: 3.0.3 +info: + title: BNA REST API + description: Provides a way to retrieve the BNA results programmatically. + contact: + name: The BNA Mechanics team + url: https://peopleforbikes.github.io/ + version: 1.0.0 +servers: + - url: https://localhost:3000 + description: Local development API + - url: https://api.peopleforbikes.xyz + description: Staging API +paths: + /cities: + get: + tags: + - city + description: Get the details of all cities where an BNA analysis was performed. + operationId: get_cities + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches cities + content: + application/json: + schema: + $ref: '#/components/schemas/Cities' + post: + tags: + - city + description: Create a new city. + operationId: post_city + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CityPost' + required: true + responses: + '201': + description: Creates a new city + content: + application/json: + schema: + $ref: '#/components/schemas/City' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/submissions: + get: + tags: + - city + description: Get the submissions details. + operationId: get_cities_submissions + parameters: + - name: status + in: query + description: Filter for the submission status + required: false + schema: + type: string + example: Pending + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches submissions + content: + application/json: + schema: + $ref: '#/components/schemas/Submissions' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - city + description: Create a new city submission. + operationId: post_cities_submission + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionPost' + required: true + responses: + '201': + description: Creates a new city submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/submissions/{submission_id}: + get: + tags: + - city + description: Get the details of a specific sumission. + operationId: get_cities_submission + parameters: + - name: submission_id + in: path + description: Submission identifier + required: true + schema: + type: integer + format: int32 + example: '1' + - name: status + in: query + description: Filter for the submission status + required: false + schema: + type: string + example: Pending + responses: + '200': + description: Fetches a submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + patch: + tags: + - city + description: Update a city submission. + operationId: patch_cities_submission + parameters: + - name: submission_id + in: path + description: Submission identifier + required: true + schema: + type: integer + format: int32 + example: '1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionPatch' + required: true + responses: + '200': + description: Updates a city submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}: + get: + tags: + - city + description: Get the details of a specific city where an BNA analysis was computed. + operationId: get_city + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: >- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not + have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + responses: + '200': + description: Fetches a city + content: + application/json: + schema: + $ref: '#/components/schemas/City' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}/census: + get: + tags: + - city + description: >- + Get the details of a specific city with its associated census + information. + operationId: get_city_censuses + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: >- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not + have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches city censuses + content: + application/json: + schema: + $ref: '#/components/schemas/CityCensuses' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - city + description: Create census information for a specific city. + operationId: post_city_census + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: >- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not + have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CensusPost' + required: true + responses: + '201': + description: Creates a new census entry for a city + content: + application/json: + schema: + $ref: '#/components/schemas/Census' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}/ratings: + get: + tags: + - city + description: >- + Get the details of a specific city with all the analysis that were + performed against it. + operationId: get_city_ratings + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: >- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not + have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches city ratings + content: + application/json: + schema: + $ref: '#/components/schemas/CityRatings' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /pipelines/bna: + get: + tags: + - pipeline + description: Get the details of all BNA pipelines + operationId: get_pipelines_bnas + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches the details of all BNA pipelines + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelines' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - pipeline + description: Create a new BNA pipeline + operationId: post_pipelines_bna + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelinePost' + required: true + responses: + '201': + description: Creates a new city submission + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /pipelines/bna/{pipeline_id}: + get: + tags: + - pipeline + description: Get the details of a specific BNA pipeline + operationId: get_pipelines_bna + parameters: + - name: pipeline_id + in: path + description: Pipeline identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches the details of a BNA pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + patch: + tags: + - pipeline + description: Update the details of a specific BNA pipeline + operationId: patch_pipelines_bna + parameters: + - name: pipeline_id + in: path + description: Pipeline identifier + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelinePatch' + required: true + responses: + '200': + description: Updates the details of a BNA pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /prices/fargate: + get: + tags: + - price + description: Get all the AWS Fargate prices used to compute analysis costs. + operationId: get_prices_fargate + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches a collection of Fargate prices + content: + application/json: + schema: + $ref: '#/components/schemas/FargatePrices' + /prices/fargate/{price_id}: + get: + tags: + - price + description: >- + Get a specific AWS Fargate price used to compute the cost of analysis + cost. + operationId: get_price_fargate + parameters: + - name: price_id + in: path + description: Identifier of a Fargate price + required: true + schema: + type: integer + format: int32 + responses: + '200': + description: Fetches a Fargate price used to estimate the cost of an analysis + content: + application/json: + schema: + $ref: '#/components/schemas/FargatePrice' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings: + get: + tags: + - rating + description: Get city ratings + operationId: get_ratings + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches the city ratings + content: + application/json: + schema: + $ref: '#/components/schemas/Ratings' + post: + tags: + - rating + description: Create a new city rating + operationId: post_rating + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RatingPost' + required: true + responses: + '201': + description: Creates a new city rating + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings/{rating_id}: + get: + tags: + - rating + description: Get the details of a specific city rating + operationId: get_rating + parameters: + - name: rating_id + in: path + description: Rating identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches the details of a city rating + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings/{rating_id}/city: + get: + tags: + - rating + description: Get a city rating and its associated city details + operationId: get_ratings_city + parameters: + - name: rating_id + in: path + description: Rating identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches a city rating and its associated city details + content: + application/json: + schema: + $ref: '#/components/schemas/RatingWithCity' + '400': + description: >- + The request was formatted incorrectly or missing required + parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence + of the problem + example: the entry was not found + id: + type: string + description: >- + A unique identifier for this particular occurrence of + the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, + expressed as a string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + example: + - details: >- + the request was formatted incorrectly or missing required + parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: >- + The request has not been fulfilled because it lacks valid + authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: >- + invalid authentication credentials to access the specified + resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: >- + Forbidden to make the request. Most likely this indicates an issue + with the credentials or permissions. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: >- + The particular resource requested was not found. This occurs, for + example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: >- + Error objects MUST be returned as an array keyed by errors in + the top level of a + + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found +components: + schemas: + APIError: + type: object + description: >- + Single API Error object as described in + . + required: + - status + - title + - details + properties: + details: + type: string + description: >- + A human-readable explanation specific to this occurrence of the + problem + example: the entry was not found + id: + type: string + description: A unique identifier for this particular occurrence of the problem. + example: blfwkg8nvHcEJnQ= + nullable: true + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + status: + type: string + description: >- + The HTTP status code applicable to this problem, expressed as a + string value. + example: '404' + title: + type: string + description: A short, human-readable summary of the problem + example: Item Not Found + APIErrorSource: + oneOf: + - type: object + description: >- + A JSON Pointer [RFC6901] to the value in the request document that + caused the error. + required: + - pointer + properties: + pointer: + type: string + description: >- + A JSON Pointer [RFC6901] to the value in the request document + that caused the error. + example: + pointer: /data/attributes/title + - type: object + description: A string indicating which URI query parameter caused the error. + required: + - parameter + properties: + parameter: + type: string + description: A string indicating which URI query parameter caused the error. + example: + parameter: include + - type: object + description: >- + A string indicating the name of a single request header which caused + the error. + required: + - header + properties: + header: + type: string + description: >- + A string indicating the name of a single request header which + caused the error. + example: + header: Content-Type + description: |- + An object containing references to the primary source of the error. + + It SHOULD include one of the following members or be omitted: + + - pointer: a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901) to the + value in the request document that caused the error [e.g. "/data" for a primary + data object, or "/data/attributes/title" for a specific attribute]. + This MUST point to a value in the request document that exists; if it doesn’t, + the client SHOULD simply ignore the pointer. + - parameter: a string indicating which URI query parameter caused the error. + - header: a string indicating the name of a single request header which caused the + error. + BnaPipeline: + type: object + required: + - start_time + - state_machine_id + - status + - step + properties: + cost: + type: string + description: Cost of an analysis in USD + example: '6.8941' + nullable: true + end_time: + type: string + format: date-time + description: End time + nullable: true + fargate_price_id: + type: integer + format: int32 + description: Fargate price identifier used to compute the cost + nullable: true + fargate_task_arn: + type: string + description: ARN of the Fargate task that performed the analysis + example: >- + arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + nullable: true + s3_bucket: + type: string + description: Path of the S3 bucket where the results were stored + example: united states/new mexico/santa rosa/24.05.4 + nullable: true + sqs_message: + type: string + description: Copy of the JSON message that was sent for processing + example: + city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + nullable: true + start_time: + type: string + format: date-time + description: Start time + state_machine_id: + type: string + format: uuid + description: >- + Pipeline identifier + + This is the ID of the AWS state machine that was used to run the + pipeline + status: + $ref: '#/components/schemas/PipelineStatus' + step: + $ref: '#/components/schemas/BnaPipelineStep' + BnaPipelinePatch: + type: object + required: + - start_time + - status + - step + properties: + cost: + type: string + description: Cost of an analysis in USD + example: '6.8941' + nullable: true + end_time: + type: string + format: date-time + description: End time + nullable: true + fargate_price_id: + type: integer + format: int32 + description: Fargate price identifier used to compute the cost + nullable: true + fargate_task_arn: + type: string + description: ARN of the Fargate task that performed the analysis + example: >- + arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + nullable: true + s3_bucket: + type: string + description: Path of the S3 bucket where the results were stored + example: united states/new mexico/santa rosa/24.05.4 + nullable: true + sqs_message: + type: string + description: Copy of the JSON message that was sent for processing + example: + city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + nullable: true + start_time: + type: string + format: date-time + description: Start time + status: + $ref: '#/components/schemas/PipelineStatus' + step: + $ref: '#/components/schemas/BnaPipelineStep' + BnaPipelinePost: + type: object + required: + - step + properties: + cost: + type: string + description: Cost of an analysis in USD + example: '6.8941' + nullable: true + end_time: + type: string + format: date-time + description: End time + nullable: true + fargate_price_id: + type: integer + format: int32 + description: Fargate price identifier used to compute the cost + nullable: true + fargate_task_arn: + type: string + description: ARN of the Fargate task that performed the analysis + example: >- + arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + nullable: true + s3_bucket: + type: string + description: Path of the S3 bucket where the results were stored + example: united states/new mexico/santa rosa/24.05.4 + nullable: true + sqs_message: + type: string + description: Copy of the JSON message that was sent for processing + example: + city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + nullable: true + step: + $ref: '#/components/schemas/BnaPipelineStep' + BnaPipelineStep: + type: string + enum: + - SqsMessage + - Setup + - Analysis + - Cleanup + BnaPipelines: + type: array + items: + $ref: '#/components/schemas/BnaPipeline' + Census: + type: object + description: Census information of a city + required: + - id + - city_id + - created_at + - fips_code + - pop_size + - population + properties: + city_id: + type: string + format: uuid + description: City identifier + created_at: + type: string + format: date-time + description: Creation date + fips_code: + type: string + description: >- + Numerical city identifier given by the U.S. census, or 0 for non-US + cities + example: '4805000' + id: + type: integer + format: int32 + description: Census identifier + pop_size: + type: integer + format: int32 + description: City population size category (small (0), medium (1), large (2)) + example: '1' + population: + type: integer + format: int32 + description: City population + example: '907779' + CensusPost: + type: object + required: + - fips_code + - pop_size + - population + properties: + fips_code: + type: string + description: >- + Numerical city identifier given by the U.S. census, or 0 for non-US + cities + example: '4805000' + pop_size: + type: integer + format: int32 + description: City population size category (small (0), medium (1), large (2)) + example: '1' + population: + type: integer + format: int32 + description: City population + example: '907779' + Cities: + type: array + items: + $ref: '#/components/schemas/City' + City: + type: object + description: Detailed information of a city + required: + - id + - country + - state + - name + - created_at + properties: + country: + $ref: '#/components/schemas/Country' + created_at: + type: string + format: date-time + description: Creation date + id: + type: string + format: uuid + description: City identifier + latitude: + type: number + format: double + description: >- + Geographic coordinate that specifies the north-south position of a + point + + on the surface of the Earth. + example: '51.260197' + nullable: true + longitude: + type: number + format: double + description: >- + Geographic coordinate that specifies the east–west position of a + point + + on the surface of the Earth. + example: '4.402771' + nullable: true + name: + type: string + description: City name + example: Antwerp + region: + type: string + description: >- + Region name. A region can be a state, a province, a community, or + + something similar depending on the country. If a country does not + have + + this concept, then the country name is used. + example: Antwerp + nullable: true + speed_limit: + type: integer + format: int32 + description: Speed limit in kilometer per hour (km/h). + example: '50' + nullable: true + state: + type: string + description: State name + example: Antwerp + state_abbrev: + type: string + description: A short version of the state name, usually 2 or 3 character long + example: VAN + nullable: true + updated_at: + type: string + format: date-time + description: Update date + nullable: true + CityCensuses: + type: object + required: + - city + - censuses + properties: + censuses: + type: array + items: + $ref: '#/components/schemas/Census' + city: + $ref: '#/components/schemas/City' + CityPost: + type: object + required: + - country + - name + - state + properties: + country: + $ref: '#/components/schemas/Country' + latitude: + type: number + format: double + description: >- + Geographic coordinate that specifies the north-south position of a + point + + on the surface of the Earth. + example: '51.260197' + nullable: true + longitude: + type: number + format: double + description: >- + Geographic coordinate that specifies the east–west position of a + point + + on the surface of the Earth. + example: '4.402771' + nullable: true + name: + type: string + description: City name + example: Antwerp + region: + type: string + description: >- + Region name. A region can be a state, a province, a community, or + + something similar depending on the country. If a country does not + have + + this concept, then the country name is used. + example: Antwerp + nullable: true + speed_limit: + type: integer + format: int32 + description: Speed limit in kilometer per hour (km/h). + example: '50' + nullable: true + state: + type: string + description: A short version of the state name, usually 2 or 3 character long + example: VAN + state_abbrev: + type: string + description: A short version of the state name, usually 2 or 3 character long + example: VAN + nullable: true + CityRatings: + type: object + required: + - city + - ratings + properties: + city: + $ref: '#/components/schemas/City' + ratings: + type: array + items: + $ref: '#/components/schemas/RatingSummary' + CoreServices: + type: object + properties: + dentists: + type: number + format: double + description: BNA category subscore for access to dentists. + maximum: 100 + minimum: 0 + nullable: true + doctors: + type: number + format: double + description: BNA category subscore for access to doctors. + maximum: 100 + minimum: 0 + nullable: true + grocery: + type: number + format: double + description: BNA category subscore for access to grocery stores. + maximum: 100 + minimum: 0 + nullable: true + hospitals: + type: number + format: double + description: BNA category subscore for access to hospitals. + maximum: 100 + minimum: 0 + nullable: true + pharmacies: + type: number + format: double + description: BNA category subscore for access to pharmacies. + maximum: 100 + minimum: 0 + nullable: true + score: + type: number + format: double + description: BNA category score for access to core services. + maximum: 100 + minimum: 0 + nullable: true + social_services: + type: number + format: double + description: BNA category subscore for access to social services. + maximum: 100 + minimum: 0 + nullable: true + Country: + type: string + enum: + - Australia + - Belgium + - Brazil + - Canada + - Chile + - Colombia + - Croatia + - Cuba + - England + - France + - Germany + - Greece + - Guatemala + - Iran + - Iraq + - Ireland + - Italy + - Mexico + - Netherlands + - New Zealand + - Northern Ireland + - Portugal + - Scotland + - Spain + - United States + - Vietnam + - Wales + FargatePrice: + type: object + description: A Fargate price used to estimate the cost of an analysis + required: + - id + - per_second + - created_at + properties: + created_at: + type: string + format: date-time + description: Creation date + id: + type: integer + format: int32 + description: >- + Identifier of the Fargate Price rate used to compute the cost of the + pipeline run + example: '1' + per_second: + type: string + description: Cost to run Fargate for 1 second + example: '0.0023' + FargatePrices: + type: array + items: + $ref: '#/components/schemas/FargatePrice' + description: A collection of Fargate prices. + Infrastructure: + type: object + properties: + high_stress_miles: + type: number + format: double + description: Total miles of high-stress streets in the measured area. + example: 253 + nullable: true + low_stress_miles: + type: number + format: double + description: Total miles of low-stress streets and paths in the measured area. + example: 127 + nullable: true + Opportunity: + type: object + properties: + employment: + type: number + format: double + description: BNA category subscore for access to job location areas. + maximum: 100 + minimum: 0 + nullable: true + higher_education: + type: number + format: double + description: BNA category subscore for access to universities and colleges. + maximum: 100 + minimum: 0 + nullable: true + k12_education: + type: number + format: double + description: BNA category subscore for access to k12 schools + maximum: 100 + minimum: 0 + nullable: true + score: + type: number + format: double + description: BNA category score for access to education and jobs. + maximum: 100 + minimum: 0 + nullable: true + technical_vocational_college: + type: number + format: double + description: >- + BNA category subscore for access to technical and vocational + colleges. + maximum: 100 + minimum: 0 + nullable: true + People: + type: object + properties: + people: + type: number + format: double + description: BNA category score for access to residential areas. + maximum: 100 + minimum: 0 + nullable: true + PipelineStatus: + type: string + enum: + - Completed + - Pending + - Processing + Rating: + type: object + required: + - id + - city_id + - score + - version + - infrastructure + - recreation + - opportunity + - core_services + - people + - retail + - transit + properties: + city_id: + type: string + format: uuid + description: City identifier + core_services: + $ref: '#/components/schemas/CoreServices' + id: + type: string + format: uuid + description: Rating identifier + infrastructure: + $ref: '#/components/schemas/Infrastructure' + opportunity: + $ref: '#/components/schemas/Opportunity' + people: + $ref: '#/components/schemas/People' + recreation: + $ref: '#/components/schemas/Recreation' + retail: + $ref: '#/components/schemas/Retail' + score: + type: number + format: double + description: Total rating score + maximum: 100 + minimum: 0 + transit: + $ref: '#/components/schemas/Transit' + version: + type: string + description: >- + Rating version + + The format follows the [calver](https://calver.org) specification + with + + the YY.0M[.Minor] scheme. + RatingPost: + type: object + required: + - city_id + - version + - infrastructure + - recreation + - opportunity + - core_services + - people + - retail + - transit + properties: + city_id: + type: string + format: uuid + description: City identifier + core_services: + $ref: '#/components/schemas/CoreServices' + infrastructure: + $ref: '#/components/schemas/Infrastructure' + opportunity: + $ref: '#/components/schemas/Opportunity' + people: + $ref: '#/components/schemas/People' + recreation: + $ref: '#/components/schemas/Recreation' + retail: + $ref: '#/components/schemas/Retail' + transit: + $ref: '#/components/schemas/Transit' + version: + type: string + description: >- + Rating version + + The format follows the [calver](https://calver.org) specification + with + + the YY.0M[.Minor] scheme. + RatingSummary: + type: object + required: + - id + - city_id + - created_at + - score + - version + properties: + city_id: + type: string + format: uuid + description: City identifier + created_at: + type: string + format: date-time + description: Creation date + id: + type: string + format: uuid + description: Analysis identifier + score: + type: number + format: double + description: BNA score + example: '77.0' + version: + type: string + description: >- + Analysis version. The format follows the + [calver](https://calver.org) + + specification with the YY.0M[.Minor] scheme. + example: '23.12' + RatingWithCity: + type: object + required: + - rating + - city + properties: + city: + $ref: '#/components/schemas/City' + rating: + $ref: '#/components/schemas/Rating' + Ratings: + type: array + items: + $ref: '#/components/schemas/Rating' + Recreation: + type: object + properties: + community_centers: + type: number + format: double + description: BNA category subscore for access to community centers. + maximum: 100 + minimum: 0 + nullable: true + parks: + type: number + format: double + description: BNA category subscore for access to parks. + maximum: 100 + minimum: 0 + nullable: true + score: + type: number + format: double + description: BNA category score for access to recreational facilities. + maximum: 100 + minimum: 0 + nullable: true + trails: + type: number + format: double + description: BNA category subscore for access to bikeable trails. + maximum: 100 + minimum: 0 + nullable: true + Retail: + type: object + properties: + retail: + type: number + format: double + description: BNA category score for access to major retail centers. + maximum: 100 + minimum: 0 + nullable: true + Submission: + type: object + required: + - id + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + - created_at + properties: + city: + type: string + description: City name + example: Antwerp + consent: + type: boolean + description: Consent status + example: 'true' + country: + $ref: '#/components/schemas/Country' + created_at: + type: string + format: date-time + description: Creation date + email: + type: string + description: email address + example: jane.doe@orgllc.com + fips_code: + type: string + description: >- + Numerical city identifier given by the U.S. census, or 0 for non-US + cities + example: '4805000' + first_name: + type: string + description: First name + example: Jane + id: + type: integer + format: int32 + description: Submission identifier + last_name: + type: string + description: Last name + occupation: + type: string + description: Job title or position + example: CTO + nullable: true + organization: + type: string + description: Organization or company + example: Organization LLC + nullable: true + region: + type: string + description: >- + Region name. A region can be a state, a province, a community, or + + something similar depending on the country. If a country does not + have + + this concept, then the country name is used. + example: Antwerp + nullable: true + status: + type: string + description: Submission status, e.g. "Pending" + example: Pending + SubmissionPatch: + type: object + required: + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + properties: + city: + type: string + description: City name + example: Antwerp + consent: + type: boolean + description: Consent status + example: 'true' + country: + $ref: '#/components/schemas/Country' + email: + type: string + description: email address + example: jane.doe@orgllc.com + fips_code: + type: string + description: >- + Numerical city identifier given by the U.S. census, or 0 for non-US + cities + example: '4805000' + first_name: + type: string + description: First name + example: Jane + last_name: + type: string + description: Last name + occupation: + type: string + description: Job title or position + example: CTO + nullable: true + organization: + type: string + description: Organization or company + example: Organization LLC + nullable: true + region: + type: string + description: >- + Region name. A region can be a state, a province, a community, or + + something similar depending on the country. If a country does not + have + + this concept, then the country name is used. + example: Antwerp + nullable: true + status: + type: string + description: Submission status, e.g. "Pending" + example: Pending + SubmissionPost: + type: object + required: + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + properties: + city: + type: string + description: City name + example: Antwerp + consent: + type: boolean + description: Consent status + example: 'true' + country: + $ref: '#/components/schemas/Country' + email: + type: string + description: email address + example: jane.doe@orgllc.com + fips_code: + type: string + description: >- + Numerical city identifier given by the U.S. census, or 0 for non-US + cities + example: '4805000' + first_name: + type: string + description: First name + example: Jane + last_name: + type: string + description: Last name + occupation: + type: string + description: Job title or position + example: CTO + nullable: true + organization: + type: string + description: Organization or company + example: Organization LLC + nullable: true + region: + type: string + description: >- + Region name. A region can be a state, a province, a community, or + + something similar depending on the country. If a country does not + have + + this concept, then the country name is used. + example: Antwerp + nullable: true + status: + type: string + description: Submission status, e.g. "Pending" + example: Pending + Submissions: + type: array + items: + $ref: '#/components/schemas/Submission' + Transit: + type: object + properties: + transit: + type: number + format: double + description: BNA category score for access to major transit stops. + maximum: 100 + minimum: 0 + nullable: true +tags: + - name: city + description: City API endpoints + - name: pipeline + description: Pipeline API endpoints + - name: price + description: Price API endpoints + - name: rating + description: Rating API endpoints diff --git a/openapi-3.1.yaml b/openapi-3.1.yaml new file mode 100644 index 0000000..5766587 --- /dev/null +++ b/openapi-3.1.yaml @@ -0,0 +1,3829 @@ +openapi: 3.1.0 +info: + title: BNA REST API + description: Provides a way to retrieve the BNA results programmatically. + contact: + name: The BNA Mechanics team + url: https://peopleforbikes.github.io/ + version: 1.0.0 +servers: +- url: https://localhost:3000 + description: Local development API +- url: https://api.peopleforbikes.xyz + description: Staging API +paths: + /cities: + get: + tags: + - city + description: Get the details of all cities where an BNA analysis was performed. + operationId: get_cities + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches cities + content: + application/json: + schema: + $ref: '#/components/schemas/Cities' + post: + tags: + - city + description: Create a new city. + operationId: post_city + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CityPost' + required: true + responses: + '201': + description: Creates a new city + content: + application/json: + schema: + $ref: '#/components/schemas/City' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/submissions: + get: + tags: + - city + description: Get the submissions details. + operationId: get_cities_submissions + parameters: + - name: status + in: query + description: Filter for the submission status + required: false + schema: + type: string + example: Pending + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches submissions + content: + application/json: + schema: + $ref: '#/components/schemas/Submissions' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - city + description: Create a new city submission. + operationId: post_cities_submission + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionPost' + required: true + responses: + '201': + description: Creates a new city submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/submissions/{submission_id}: + get: + tags: + - city + description: Get the details of a specific sumission. + operationId: get_cities_submission + parameters: + - name: submission_id + in: path + description: Submission identifier + required: true + schema: + type: integer + format: int32 + example: '1' + - name: status + in: query + description: Filter for the submission status + required: false + schema: + type: string + example: Pending + responses: + '200': + description: Fetches a submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + patch: + tags: + - city + description: Update a city submission. + operationId: patch_cities_submission + parameters: + - name: submission_id + in: path + description: Submission identifier + required: true + schema: + type: integer + format: int32 + example: '1' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionPatch' + required: true + responses: + '200': + description: Updates a city submission + content: + application/json: + schema: + $ref: '#/components/schemas/Submission' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}: + get: + tags: + - city + description: Get the details of a specific city where an BNA analysis was computed. + operationId: get_city + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + responses: + '200': + description: Fetches a city + content: + application/json: + schema: + $ref: '#/components/schemas/City' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}/census: + get: + tags: + - city + description: Get the details of a specific city with its associated census information. + operationId: get_city_censuses + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches city censuses + content: + application/json: + schema: + $ref: '#/components/schemas/CityCensuses' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - city + description: Create census information for a specific city. + operationId: post_city_census + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CensusPost' + required: true + responses: + '201': + description: Creates a new census entry for a city + content: + application/json: + schema: + $ref: '#/components/schemas/Census' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /cities/{country}/{region}/{name}/ratings: + get: + tags: + - city + description: Get the details of a specific city with all the analysis that were performed against it. + operationId: get_city_ratings + parameters: + - name: country + in: path + description: Country name + required: true + schema: + $ref: '#/components/schemas/Country' + example: Belgium + - name: region + in: path + description: Region name. A region can be a state, a province, a community, or something similar depending on the country. If a country does not have this concept, then the country name is used. + required: true + schema: + type: string + example: Antwerp + - name: name + in: path + description: City name + required: true + schema: + type: string + example: Antwerp + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches city ratings + content: + application/json: + schema: + $ref: '#/components/schemas/CityRatings' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /pipelines/bna: + get: + tags: + - pipeline + description: Get the details of all BNA pipelines + operationId: get_pipelines_bnas + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches the details of all BNA pipelines + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelines' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + post: + tags: + - pipeline + description: Create a new BNA pipeline + operationId: post_pipelines_bna + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelinePost' + required: true + responses: + '201': + description: Creates a new city submission + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /pipelines/bna/{pipeline_id}: + get: + tags: + - pipeline + description: Get the details of a specific BNA pipeline + operationId: get_pipelines_bna + parameters: + - name: pipeline_id + in: path + description: Pipeline identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches the details of a BNA pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + patch: + tags: + - pipeline + description: Update the details of a specific BNA pipeline + operationId: patch_pipelines_bna + parameters: + - name: pipeline_id + in: path + description: Pipeline identifier + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipelinePatch' + required: true + responses: + '200': + description: Updates the details of a BNA pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/BnaPipeline' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /prices/fargate: + get: + tags: + - price + description: Get all the AWS Fargate prices used to compute analysis costs. + operationId: get_prices_fargate + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches a collection of Fargate prices + content: + application/json: + schema: + $ref: '#/components/schemas/FargatePrices' + /prices/fargate/{price_id}: + get: + tags: + - price + description: Get a specific AWS Fargate price used to compute the cost of analysis cost. + operationId: get_price_fargate + parameters: + - name: price_id + in: path + description: Identifier of a Fargate price + required: true + schema: + type: integer + format: int32 + responses: + '200': + description: Fetches a Fargate price used to estimate the cost of an analysis + content: + application/json: + schema: + $ref: '#/components/schemas/FargatePrice' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings: + get: + tags: + - rating + description: Get city ratings + operationId: get_ratings + parameters: + - name: page_size + in: query + description: The number of items per page + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '25' + - name: page + in: query + description: The result page being returned + required: false + schema: + type: integer + format: int64 + minimum: 0 + example: '1' + responses: + '200': + description: Fetches the city ratings + content: + application/json: + schema: + $ref: '#/components/schemas/Ratings' + post: + tags: + - rating + description: Create a new city rating + operationId: post_rating + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RatingPost' + required: true + responses: + '201': + description: Creates a new city rating + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings/{rating_id}: + get: + tags: + - rating + description: Get the details of a specific city rating + operationId: get_rating + parameters: + - name: rating_id + in: path + description: Rating identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches the details of a city rating + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found + /ratings/{rating_id}/city: + get: + tags: + - rating + description: Get a city rating and its associated city details + operationId: get_ratings_city + parameters: + - name: rating_id + in: path + description: Rating identifier + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Fetches a city rating and its associated city details + content: + application/json: + schema: + $ref: '#/components/schemas/RatingWithCity' + '400': + description: The request was formatted incorrectly or missing required parameters. + content: + application/json: + schema: + type: array + items: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + example: + - details: the request was formatted incorrectly or missing required parameters + id: blfwkg8nvHcEJnQ= + source: + parameter: status + status: '400' + title: Bad Request + '401': + description: The request has not been fulfilled because it lacks valid authentication credentials for the target resource. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: invalid authentication credentials to access the specified resource + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '401' + title: Unauthorized + '403': + description: Forbidden to make the request. Most likely this indicates an issue with the credentials or permissions. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: access to the requested resource is forbidden + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '403' + title: Forbidden + '404': + description: The particular resource requested was not found. This occurs, for example, when the id of the requested resource does not exist. + content: + application/json: + schema: + type: object + description: |- + Error objects MUST be returned as an array keyed by errors in the top level of a + JSON:API document. + required: + - errors + properties: + errors: + type: array + items: + $ref: '#/components/schemas/APIError' + example: + - details: the resource was not found + id: blfwkg8nvHcEJnQ= + source: + pointer: /bnas/ratings/e6aade5a-b343-120b-dbaa-bd916cd99221 + status: '404' + title: Item Not Found +components: + schemas: + APIError: + type: object + description: Single API Error object as described in . + required: + - status + - title + - details + properties: + details: + type: string + description: A human-readable explanation specific to this occurrence of the problem + examples: + - the entry was not found + id: + type: + - string + - 'null' + description: A unique identifier for this particular occurrence of the problem. + examples: + - blfwkg8nvHcEJnQ= + source: + oneOf: + - type: 'null' + - $ref: '#/components/schemas/APIErrorSource' + description: |- + An object containing references to the primary source of the error. + + This field may be omitted in some situation. For instance, if the server cannot + parse the request as valid JSON, including source doesn’t make sense + (because there’s no JSON document for source to refer to). + status: + type: string + description: The HTTP status code applicable to this problem, expressed as a string value. + examples: + - '404' + title: + type: string + description: A short, human-readable summary of the problem + examples: + - Item Not Found + APIErrorSource: + oneOf: + - type: object + description: A JSON Pointer [RFC6901] to the value in the request document that caused the error. + required: + - pointer + properties: + pointer: + type: string + description: A JSON Pointer [RFC6901] to the value in the request document that caused the error. + examples: + - pointer: /data/attributes/title + - type: object + description: A string indicating which URI query parameter caused the error. + required: + - parameter + properties: + parameter: + type: string + description: A string indicating which URI query parameter caused the error. + examples: + - parameter: include + - type: object + description: A string indicating the name of a single request header which caused the error. + required: + - header + properties: + header: + type: string + description: A string indicating the name of a single request header which caused the error. + examples: + - header: Content-Type + description: |- + An object containing references to the primary source of the error. + + It SHOULD include one of the following members or be omitted: + + - pointer: a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901) to the + value in the request document that caused the error [e.g. "/data" for a primary + data object, or "/data/attributes/title" for a specific attribute]. + This MUST point to a value in the request document that exists; if it doesn’t, + the client SHOULD simply ignore the pointer. + - parameter: a string indicating which URI query parameter caused the error. + - header: a string indicating the name of a single request header which caused the + error. + BnaPipeline: + type: object + required: + - start_time + - state_machine_id + - status + - step + properties: + cost: + type: + - string + - 'null' + description: Cost of an analysis in USD + examples: + - '6.8941' + end_time: + type: + - string + - 'null' + format: date-time + description: End time + fargate_price_id: + type: + - integer + - 'null' + format: int32 + description: Fargate price identifier used to compute the cost + fargate_task_arn: + type: + - string + - 'null' + description: ARN of the Fargate task that performed the analysis + examples: + - arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + s3_bucket: + type: + - string + - 'null' + description: Path of the S3 bucket where the results were stored + examples: + - united states/new mexico/santa rosa/24.05.4 + sqs_message: + type: + - string + - 'null' + description: Copy of the JSON message that was sent for processing + examples: + - city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + start_time: + type: string + format: date-time + description: Start time + state_machine_id: + type: string + format: uuid + description: |- + Pipeline identifier + This is the ID of the AWS state machine that was used to run the pipeline + status: + $ref: '#/components/schemas/PipelineStatus' + description: Pipeline status + step: + $ref: '#/components/schemas/BnaPipelineStep' + description: Last pipeline step that was completed + BnaPipelinePatch: + type: object + required: + - start_time + - status + - step + properties: + cost: + type: + - string + - 'null' + description: Cost of an analysis in USD + examples: + - '6.8941' + end_time: + type: + - string + - 'null' + format: date-time + description: End time + fargate_price_id: + type: + - integer + - 'null' + format: int32 + description: Fargate price identifier used to compute the cost + fargate_task_arn: + type: + - string + - 'null' + description: ARN of the Fargate task that performed the analysis + examples: + - arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + s3_bucket: + type: + - string + - 'null' + description: Path of the S3 bucket where the results were stored + examples: + - united states/new mexico/santa rosa/24.05.4 + sqs_message: + type: + - string + - 'null' + description: Copy of the JSON message that was sent for processing + examples: + - city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + start_time: + type: string + format: date-time + description: Start time + status: + $ref: '#/components/schemas/PipelineStatus' + description: Pipeline status + step: + $ref: '#/components/schemas/BnaPipelineStep' + description: Last pipeline step that was completed + BnaPipelinePost: + type: object + required: + - step + properties: + cost: + type: + - string + - 'null' + description: Cost of an analysis in USD + examples: + - '6.8941' + end_time: + type: + - string + - 'null' + format: date-time + description: End time + fargate_price_id: + type: + - integer + - 'null' + format: int32 + description: Fargate price identifier used to compute the cost + fargate_task_arn: + type: + - string + - 'null' + description: ARN of the Fargate task that performed the analysis + examples: + - arn:aws:ecs:us-west-2:123456789012:task/bna/29f979fc9fca402d94b014aa23d2f6e0 + s3_bucket: + type: + - string + - 'null' + description: Path of the S3 bucket where the results were stored + examples: + - united states/new mexico/santa rosa/24.05.4 + sqs_message: + type: + - string + - 'null' + description: Copy of the JSON message that was sent for processing + examples: + - city: santa rosa + country: United States + fips_code: '3570670' + region: new mexico + step: + $ref: '#/components/schemas/BnaPipelineStep' + description: Last pipeline step that was completed + BnaPipelineStep: + type: string + enum: + - SqsMessage + - Setup + - Analysis + - Cleanup + BnaPipelines: + type: array + items: + $ref: '#/components/schemas/BnaPipeline' + Census: + type: object + description: Census information of a city + required: + - id + - city_id + - created_at + - fips_code + - pop_size + - population + properties: + city_id: + type: string + format: uuid + description: City identifier + created_at: + type: string + format: date-time + description: Creation date + fips_code: + type: string + description: Numerical city identifier given by the U.S. census, or 0 for non-US cities + examples: + - '4805000' + id: + type: integer + format: int32 + description: Census identifier + pop_size: + type: integer + format: int32 + description: City population size category (small (0), medium (1), large (2)) + examples: + - '1' + population: + type: integer + format: int32 + description: City population + examples: + - '907779' + CensusPost: + type: object + required: + - fips_code + - pop_size + - population + properties: + fips_code: + type: string + description: Numerical city identifier given by the U.S. census, or 0 for non-US cities + examples: + - '4805000' + pop_size: + type: integer + format: int32 + description: City population size category (small (0), medium (1), large (2)) + examples: + - '1' + population: + type: integer + format: int32 + description: City population + examples: + - '907779' + Cities: + type: array + items: + $ref: '#/components/schemas/City' + City: + type: object + description: Detailed information of a city + required: + - id + - country + - state + - name + - created_at + properties: + country: + $ref: '#/components/schemas/Country' + description: Country name + created_at: + type: string + format: date-time + description: Creation date + id: + type: string + format: uuid + description: City identifier + latitude: + type: + - number + - 'null' + format: double + description: |- + Geographic coordinate that specifies the north-south position of a point + on the surface of the Earth. + examples: + - '51.260197' + longitude: + type: + - number + - 'null' + format: double + description: |- + Geographic coordinate that specifies the east–west position of a point + on the surface of the Earth. + examples: + - '4.402771' + name: + type: string + description: City name + examples: + - Antwerp + region: + type: + - string + - 'null' + description: |- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not have + this concept, then the country name is used. + examples: + - Antwerp + speed_limit: + type: + - integer + - 'null' + format: int32 + description: Speed limit in kilometer per hour (km/h). + examples: + - '50' + state: + type: string + description: State name + examples: + - Antwerp + state_abbrev: + type: + - string + - 'null' + description: A short version of the state name, usually 2 or 3 character long + examples: + - VAN + updated_at: + type: + - string + - 'null' + format: date-time + description: Update date + CityCensuses: + type: object + required: + - city + - censuses + properties: + censuses: + type: array + items: + $ref: '#/components/schemas/Census' + city: + $ref: '#/components/schemas/City' + CityPost: + type: object + required: + - country + - name + - state + properties: + country: + $ref: '#/components/schemas/Country' + description: Country name + latitude: + type: + - number + - 'null' + format: double + description: |- + Geographic coordinate that specifies the north-south position of a point + on the surface of the Earth. + examples: + - '51.260197' + longitude: + type: + - number + - 'null' + format: double + description: |- + Geographic coordinate that specifies the east–west position of a point + on the surface of the Earth. + examples: + - '4.402771' + name: + type: string + description: City name + examples: + - Antwerp + region: + type: + - string + - 'null' + description: |- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not have + this concept, then the country name is used. + examples: + - Antwerp + speed_limit: + type: + - integer + - 'null' + format: int32 + description: Speed limit in kilometer per hour (km/h). + examples: + - '50' + state: + type: string + description: A short version of the state name, usually 2 or 3 character long + examples: + - VAN + state_abbrev: + type: + - string + - 'null' + description: A short version of the state name, usually 2 or 3 character long + examples: + - VAN + CityRatings: + type: object + required: + - city + - ratings + properties: + city: + $ref: '#/components/schemas/City' + ratings: + type: array + items: + $ref: '#/components/schemas/RatingSummary' + CoreServices: + type: object + properties: + dentists: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to dentists. + maximum: 100 + minimum: 0 + doctors: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to doctors. + maximum: 100 + minimum: 0 + grocery: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to grocery stores. + maximum: 100 + minimum: 0 + hospitals: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to hospitals. + maximum: 100 + minimum: 0 + pharmacies: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to pharmacies. + maximum: 100 + minimum: 0 + score: + type: + - number + - 'null' + format: double + description: BNA category score for access to core services. + maximum: 100 + minimum: 0 + social_services: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to social services. + maximum: 100 + minimum: 0 + Country: + type: string + enum: + - Australia + - Belgium + - Brazil + - Canada + - Chile + - Colombia + - Croatia + - Cuba + - England + - France + - Germany + - Greece + - Guatemala + - Iran + - Iraq + - Ireland + - Italy + - Mexico + - Netherlands + - New Zealand + - Northern Ireland + - Portugal + - Scotland + - Spain + - United States + - Vietnam + - Wales + FargatePrice: + type: object + description: A Fargate price used to estimate the cost of an analysis + required: + - id + - per_second + - created_at + properties: + created_at: + type: string + format: date-time + description: Creation date + id: + type: integer + format: int32 + description: Identifier of the Fargate Price rate used to compute the cost of the pipeline run + examples: + - '1' + per_second: + type: string + description: Cost to run Fargate for 1 second + examples: + - '0.0023' + FargatePrices: + type: array + items: + $ref: '#/components/schemas/FargatePrice' + description: A collection of Fargate prices. + Infrastructure: + type: object + properties: + high_stress_miles: + type: + - number + - 'null' + format: double + description: Total miles of high-stress streets in the measured area. + examples: + - 253 + low_stress_miles: + type: + - number + - 'null' + format: double + description: Total miles of low-stress streets and paths in the measured area. + examples: + - 127 + Opportunity: + type: object + properties: + employment: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to job location areas. + maximum: 100 + minimum: 0 + higher_education: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to universities and colleges. + maximum: 100 + minimum: 0 + k12_education: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to k12 schools + maximum: 100 + minimum: 0 + score: + type: + - number + - 'null' + format: double + description: BNA category score for access to education and jobs. + maximum: 100 + minimum: 0 + technical_vocational_college: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to technical and vocational colleges. + maximum: 100 + minimum: 0 + People: + type: object + properties: + people: + type: + - number + - 'null' + format: double + description: BNA category score for access to residential areas. + maximum: 100 + minimum: 0 + PipelineStatus: + type: string + enum: + - Completed + - Pending + - Processing + Rating: + type: object + required: + - id + - city_id + - score + - version + - infrastructure + - recreation + - opportunity + - core_services + - people + - retail + - transit + properties: + city_id: + type: string + format: uuid + description: City identifier + core_services: + $ref: '#/components/schemas/CoreServices' + description: BNA Core Services + id: + type: string + format: uuid + description: Rating identifier + infrastructure: + $ref: '#/components/schemas/Infrastructure' + description: BNAInfrastructure + opportunity: + $ref: '#/components/schemas/Opportunity' + description: BNA Opportunity + people: + $ref: '#/components/schemas/People' + description: BNA People + recreation: + $ref: '#/components/schemas/Recreation' + description: BNA Recreation + retail: + $ref: '#/components/schemas/Retail' + description: BNA Retail + score: + type: number + format: double + description: Total rating score + maximum: 100 + minimum: 0 + transit: + $ref: '#/components/schemas/Transit' + description: BNA Transit + version: + type: string + description: |- + Rating version + The format follows the [calver](https://calver.org) specification with + the YY.0M[.Minor] scheme. + RatingPost: + type: object + required: + - city_id + - version + - infrastructure + - recreation + - opportunity + - core_services + - people + - retail + - transit + properties: + city_id: + type: string + format: uuid + description: City identifier + core_services: + $ref: '#/components/schemas/CoreServices' + description: BNA Core Services + infrastructure: + $ref: '#/components/schemas/Infrastructure' + description: BNAInfrastructure + opportunity: + $ref: '#/components/schemas/Opportunity' + description: BNA Opportunity + people: + $ref: '#/components/schemas/People' + description: BNA People + recreation: + $ref: '#/components/schemas/Recreation' + description: BNA Recreation + retail: + $ref: '#/components/schemas/Retail' + description: BNA Retail + transit: + $ref: '#/components/schemas/Transit' + description: BNA Transit + version: + type: string + description: |- + Rating version + The format follows the [calver](https://calver.org) specification with + the YY.0M[.Minor] scheme. + RatingSummary: + type: object + required: + - id + - city_id + - created_at + - score + - version + properties: + city_id: + type: string + format: uuid + description: City identifier + created_at: + type: string + format: date-time + description: Creation date + id: + type: string + format: uuid + description: Analysis identifier + score: + type: number + format: double + description: BNA score + examples: + - '77.0' + version: + type: string + description: |- + Analysis version. The format follows the [calver](https://calver.org) + specification with the YY.0M[.Minor] scheme. + examples: + - '23.12' + RatingWithCity: + type: object + required: + - rating + - city + properties: + city: + $ref: '#/components/schemas/City' + rating: + $ref: '#/components/schemas/Rating' + Ratings: + type: array + items: + $ref: '#/components/schemas/Rating' + Recreation: + type: object + properties: + community_centers: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to community centers. + maximum: 100 + minimum: 0 + parks: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to parks. + maximum: 100 + minimum: 0 + score: + type: + - number + - 'null' + format: double + description: BNA category score for access to recreational facilities. + maximum: 100 + minimum: 0 + trails: + type: + - number + - 'null' + format: double + description: BNA category subscore for access to bikeable trails. + maximum: 100 + minimum: 0 + Retail: + type: object + properties: + retail: + type: + - number + - 'null' + format: double + description: BNA category score for access to major retail centers. + maximum: 100 + minimum: 0 + Submission: + type: object + required: + - id + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + - created_at + properties: + city: + type: string + description: City name + examples: + - Antwerp + consent: + type: boolean + description: Consent status + examples: + - 'true' + country: + $ref: '#/components/schemas/Country' + description: Country + created_at: + type: string + format: date-time + description: Creation date + email: + type: string + description: email address + examples: + - jane.doe@orgllc.com + fips_code: + type: string + description: Numerical city identifier given by the U.S. census, or 0 for non-US cities + examples: + - '4805000' + first_name: + type: string + description: First name + examples: + - Jane + id: + type: integer + format: int32 + description: Submission identifier + last_name: + type: string + description: Last name + occupation: + type: + - string + - 'null' + description: Job title or position + examples: + - CTO + organization: + type: + - string + - 'null' + description: Organization or company + examples: + - Organization LLC + region: + type: + - string + - 'null' + description: |- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not have + this concept, then the country name is used. + examples: + - Antwerp + status: + type: string + description: Submission status, e.g. "Pending" + examples: + - Pending + SubmissionPatch: + type: object + required: + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + properties: + city: + type: string + description: City name + examples: + - Antwerp + consent: + type: boolean + description: Consent status + examples: + - 'true' + country: + $ref: '#/components/schemas/Country' + description: Country + email: + type: string + description: email address + examples: + - jane.doe@orgllc.com + fips_code: + type: string + description: Numerical city identifier given by the U.S. census, or 0 for non-US cities + examples: + - '4805000' + first_name: + type: string + description: First name + examples: + - Jane + last_name: + type: string + description: Last name + occupation: + type: + - string + - 'null' + description: Job title or position + examples: + - CTO + organization: + type: + - string + - 'null' + description: Organization or company + examples: + - Organization LLC + region: + type: + - string + - 'null' + description: |- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not have + this concept, then the country name is used. + examples: + - Antwerp + status: + type: string + description: Submission status, e.g. "Pending" + examples: + - Pending + SubmissionPost: + type: object + required: + - first_name + - last_name + - email + - country + - city + - fips_code + - consent + - status + properties: + city: + type: string + description: City name + examples: + - Antwerp + consent: + type: boolean + description: Consent status + examples: + - 'true' + country: + $ref: '#/components/schemas/Country' + description: Country + email: + type: string + description: email address + examples: + - jane.doe@orgllc.com + fips_code: + type: string + description: Numerical city identifier given by the U.S. census, or 0 for non-US cities + examples: + - '4805000' + first_name: + type: string + description: First name + examples: + - Jane + last_name: + type: string + description: Last name + occupation: + type: + - string + - 'null' + description: Job title or position + examples: + - CTO + organization: + type: + - string + - 'null' + description: Organization or company + examples: + - Organization LLC + region: + type: + - string + - 'null' + description: |- + Region name. A region can be a state, a province, a community, or + something similar depending on the country. If a country does not have + this concept, then the country name is used. + examples: + - Antwerp + status: + type: string + description: Submission status, e.g. "Pending" + examples: + - Pending + Submissions: + type: array + items: + $ref: '#/components/schemas/Submission' + Transit: + type: object + properties: + transit: + type: + - number + - 'null' + format: double + description: BNA category score for access to major transit stops. + maximum: 100 + minimum: 0 +tags: +- name: city + description: City API endpoints +- name: pipeline + description: Pipeline API endpoints +- name: price + description: Price API endpoints +- name: rating + description: Rating API endpoints