use crate::{ArcGISPoint, SpatialReference};
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters)]
pub struct AddressCandidate {
address: String,
location: ArcGISPoint,
score: f64,
#[serde(default)]
attributes: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
extent: Option<Extent>,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Getters)]
pub struct Extent {
xmin: f64,
ymin: f64,
xmax: f64,
ymax: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters)]
#[serde(rename_all = "camelCase")]
pub struct GeocodeResponse {
candidates: Vec<AddressCandidate>,
#[serde(skip_serializing_if = "Option::is_none")]
spatial_reference: Option<SpatialReference>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters)]
pub struct ReverseGeocodeResponse {
address: GeocodeAddress,
location: ArcGISPoint,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Getters)]
#[serde(rename_all = "PascalCase")]
pub struct GeocodeAddress {
#[serde(skip_serializing_if = "Option::is_none")]
match_addr: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
long_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
short_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
addr_type: Option<String>,
#[serde(rename = "Type", skip_serializing_if = "Option::is_none")]
feature_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
place_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
add_num: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
st_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
st_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
region: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
region_abbr: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
postal: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
postal_ext: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
country_code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
cntry_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Getters)]
#[serde(rename_all = "camelCase")]
pub struct Suggestion {
text: String,
magic_key: String,
is_collection: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Getters)]
pub struct SuggestResponse {
suggestions: Vec<Suggestion>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum LocationType {
#[default]
Rooftop,
Street,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Category {
Poi,
Education,
Food,
Shops,
Custom(String),
}
impl Category {
pub fn as_str(&self) -> &str {
match self {
Self::Poi => "POI",
Self::Education => "Education",
Self::Food => "Food",
Self::Shops => "Shops and Service",
Self::Custom(s) => s.as_str(),
}
}
}
impl From<&str> for Category {
fn from(s: &str) -> Self {
match s {
"POI" => Self::Poi,
"Education" => Self::Education,
"Food" => Self::Food,
"Shops and Service" => Self::Shops,
_ => Self::Custom(s.to_string()),
}
}
}
impl GeocodeAddress {
pub fn new(address: impl Into<String>) -> Self {
Self {
match_addr: Some(address.into()),
long_label: None,
short_label: None,
addr_type: None,
feature_type: None,
place_name: None,
add_num: None,
st_name: None,
st_type: None,
city: None,
region: None,
region_abbr: None,
postal: None,
postal_ext: None,
country_code: None,
cntry_name: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, derive_new::new)]
pub struct BatchGeocodeRecord {
#[serde(rename = "OBJECTID")]
object_id: i32,
#[serde(rename = "SingleLine", skip_serializing_if = "Option::is_none")]
#[new(default)]
single_line: Option<String>,
#[serde(rename = "Address", skip_serializing_if = "Option::is_none")]
#[new(default)]
address: Option<String>,
#[serde(rename = "City", skip_serializing_if = "Option::is_none")]
#[new(default)]
city: Option<String>,
#[serde(rename = "Region", skip_serializing_if = "Option::is_none")]
#[new(default)]
region: Option<String>,
#[serde(rename = "Postal", skip_serializing_if = "Option::is_none")]
#[new(default)]
postal: Option<String>,
#[serde(rename = "CountryCode", skip_serializing_if = "Option::is_none")]
#[new(default)]
country_code: Option<String>,
}
impl BatchGeocodeRecord {
pub fn with_single_line(object_id: i32, address: impl Into<String>) -> Self {
Self {
object_id,
single_line: Some(address.into()),
address: None,
city: None,
region: None,
postal: None,
country_code: None,
}
}
pub fn with_components(
object_id: i32,
address: impl Into<String>,
city: Option<impl Into<String>>,
region: Option<impl Into<String>>,
postal: Option<impl Into<String>>,
country_code: Option<impl Into<String>>,
) -> Self {
Self {
object_id,
single_line: None,
address: Some(address.into()),
city: city.map(Into::into),
region: region.map(Into::into),
postal: postal.map(Into::into),
country_code: country_code.map(Into::into),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters)]
pub struct BatchGeocodeResponse {
locations: Vec<BatchLocation>,
#[serde(skip_serializing_if = "Option::is_none")]
spatial_reference: Option<SpatialReference>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters)]
pub struct BatchLocation {
address: String,
location: ArcGISPoint,
score: f64,
#[serde(default)]
attributes: HashMap<String, serde_json::Value>,
}