#![allow(clippy::ref_option, reason = "for the getset crate")]
use crate::places_new::FieldMask;
use crate::places_new::nearby_search::Response;
use crate::places_new::types::request::{LocationRestriction, PlaceTypeSet, RankPreference};
use icu_locale::Locale;
use reqwest::header::HeaderMap;
use rust_iso3166::CountryCode;
#[derive(
//std
Clone,
Debug,
// serde
serde::Serialize,
// getset
getset::Getters,
getset::CopyGetters,
getset::MutGetters,
getset::Setters,
// other
bon::Builder
)]
#[serde(rename_all = "camelCase")]
pub struct RequestWithClient<'c> {
#[serde(skip_deserializing, skip_serializing)]
pub(crate) client: &'c crate::Client,
#[serde(skip)]
#[builder(into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub field_mask: FieldMask,
#[builder(into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub location_restriction: LocationRestriction,
#[serde(default, skip_serializing_if = "PlaceTypeSet::is_empty")]
#[builder(default, into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub included_types: PlaceTypeSet,
#[serde(default, skip_serializing_if = "PlaceTypeSet::is_empty")]
#[builder(default, into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub excluded_types: PlaceTypeSet,
#[serde(default, skip_serializing_if = "PlaceTypeSet::is_empty")]
#[builder(default, into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub included_primary_types: PlaceTypeSet,
#[serde(default, skip_serializing_if = "PlaceTypeSet::is_empty")]
#[builder(default, into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub excluded_primary_types: PlaceTypeSet,
#[serde(
rename = "languageCode",
default,
skip_serializing_if = "Option::is_none",
serialize_with = "crate::places_new::serde::serialize_optional_locale",
deserialize_with = "crate::places_new::serde::deserialize_optional_locale"
)]
#[builder(into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub language: Option<Locale>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub max_result_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(into)]
#[getset(get = "pub", set = "pub", get_mut = "pub")]
pub rank_preference: Option<RankPreference>,
#[serde(
rename = "regionCode",
default,
skip_serializing_if = "Option::is_none",
serialize_with = "crate::places_new::serde::serialize_optional_country_code",
deserialize_with = "crate::places_new::serde::deserialize_optional_country_code"
)]
pub region: Option<CountryCode>,
}
impl RequestWithClient<'_> {
#[must_use]
pub fn into_request(self) -> crate::places_new::nearby_search::Request {
self.into()
}
pub async fn execute(self) -> Result<Response, crate::Error> {
let response = self.client.post_request(&self).await?;
Ok(response)
}
}
impl<S: request_with_client_builder::State> RequestWithClientBuilder<'_, S> {
pub async fn execute(self) -> Result<Response, crate::Error>
where
S: request_with_client_builder::IsComplete,
{
let request = self.build(); let response = request.client.post_request(&request).await?;
Ok(response)
}
}
impl crate::client::Client {
pub fn nearby_search<L>(
&self,
location_restriction: L,
) -> Result<
RequestWithClientBuilder<
'_,
crate::places_new::nearby_search::request_with_client::request_with_client_builder::SetLocationRestriction<
crate::places_new::nearby_search::request_with_client::request_with_client_builder::SetClient
>
>,
crate::Error,
>
where
L: TryInto<LocationRestriction>,
L::Error: Into<crate::Error>,
{
let location_restriction = location_restriction
.try_into()
.map_err(Into::into)?;
Ok(RequestWithClient::builder()
.client(self)
.location_restriction(location_restriction))
}
}
#[cfg(feature = "reqwest")]
use crate::request_rate::api::Api;
impl crate::traits::EndPoint for &RequestWithClient<'_> {
fn service_url() -> &'static str {
"https://places.googleapis.com/v1/places:searchNearby"
}
fn output_format() -> std::option::Option<&'static str> {
None }
#[cfg(feature = "reqwest")]
fn title() -> &'static str {
"Places API (New) Nearby Search"
}
#[cfg(feature = "reqwest")]
fn apis() -> &'static [Api] {
&[Api::All, Api::PlacesNew, Api::NearbySearch]
}
}
#[cfg(feature = "reqwest")]
impl crate::traits::RequestBody for &RequestWithClient<'_> {
fn request_body(&self) -> Result<String, crate::Error> {
Ok(serde_json::to_string(self)?)
}
}
#[cfg(feature = "reqwest")]
impl crate::traits::QueryString for &RequestWithClient<'_> {
fn query_string(&self) -> String {
String::new()
}
}
#[cfg(feature = "reqwest")]
impl crate::traits::RequestHeaders for &RequestWithClient<'_> {
fn request_headers(&self) -> HeaderMap {
let field_mask = self.field_mask().to_string();
let mut headers = HeaderMap::new();
match reqwest::header::HeaderValue::from_str(field_mask.as_str()) {
Ok(header_value) => { headers.insert("X-Goog-FieldMask", header_value); },
Err(error) => tracing::error!("error building request headers: {error}"),
}
headers
}
fn send_x_goog_api_key() -> bool {
true
}
}
#[cfg(feature = "reqwest")]
impl crate::traits::Validatable for &RequestWithClient<'_> {
fn validate(&self) -> Result<(), crate::Error> {
if let crate::places_new::FieldMask::Specific(fields) = &self.field_mask {
if fields.is_empty() {
let debug = "field_mask: FieldMask::Specific(vec![])".to_string();
let span = (0, debug.len());
return Err(crate::places_new::nearby_search::Error::EmptyFieldMask {
debug,
span: span.into(),
}
.into());
}
}
let validate_table_a = |types: &PlaceTypeSet, field_name: &str| {
for place_type in types {
if place_type.is_table_b() {
let debug = format!("{field_name}: vec![..., PlaceType::{place_type}, ...]");
let span = (0, debug.len());
return Err::<(), crate::Error>(crate::places_new::nearby_search::Error::InvalidPlaceTypeForFilter {
place_type: place_type.to_string(),
debug,
span: span.into(),
}
.into());
}
}
Ok(())
};
if let LocationRestriction::Rectangle(viewport) = &self.location_restriction {
let debug = format!(
"location_restriction: Rectangle(Viewport {{ low: {}, high: {} }})",
viewport.low, viewport.high
);
let span = (0, debug.len());
return Err(crate::places_new::nearby_search::Error::UnsupportedLocationRestriction {
restriction_type: "Rectangle".to_string(),
debug,
span: span.into(),
}.into());
}
validate_table_a(&self.included_types, "included_types")?;
validate_table_a(&self.excluded_types, "excluded_types")?;
validate_table_a(&self.included_primary_types, "included_primary_types")?;
validate_table_a(&self.excluded_primary_types, "excluded_primary_types")?;
for place_type in &self.included_types {
if self.excluded_types.contains(place_type) {
let debug = format!(
"included_types: vec![..., PlaceType::{place_type}, ...], \
excluded_types: vec![..., PlaceType::{place_type}, ...]"
);
let span = (0, debug.len());
return Err(
crate::places_new::nearby_search::Error::ConflictingPlaceTypes {
place_type: place_type.to_string(),
debug,
span: span.into(),
}
.into(),
);
}
}
for place_type in &self.included_primary_types {
if self.excluded_primary_types.contains(place_type) {
let debug = format!(
"included_primary_types: vec![..., PlaceType::{place_type}, ...], \
excluded_primary_types: vec![..., PlaceType::{place_type}, ...]"
);
let span = (0, debug.len());
return Err(
crate::places_new::nearby_search::Error::ConflictingPrimaryPlaceTypes {
place_type: place_type.to_string(),
debug,
span: span.into(),
}
.into(),
);
}
}
Ok(())
}
}