use crate::{
ArcGISGeometry, GeometryType, ObjectId, RelationshipCardinality, RelationshipRole, SpatialRel,
};
use derive_setters::Setters;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
mod serde_helpers {
use crate::ArcGISGeometry;
use serde::Serializer;
pub fn serialize_string_vec<S>(
vec: &Option<Vec<String>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match vec {
Some(v) => serializer.serialize_str(&v.join(",")),
None => serializer.serialize_none(),
}
}
pub fn serialize_object_ids<S>(
vec: &Option<Vec<crate::ObjectId>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match vec {
Some(v) => {
let ids: Vec<String> = v.iter().map(|id| id.to_string()).collect();
serializer.serialize_str(&ids.join(","))
}
None => serializer.serialize_none(),
}
}
pub fn serialize_geometry<S>(
geom: &Option<ArcGISGeometry>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match geom {
Some(g) => {
let json = serde_json::to_string(g).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&json)
}
None => serializer.serialize_none(),
}
}
pub fn serialize_statistics<S>(
stats: &Option<Vec<super::StatisticDefinition>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match stats {
Some(s) => {
let json = serde_json::to_string(s).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&json)
}
None => serializer.serialize_none(),
}
}
pub fn serialize_top_filter<S>(
filter: &Option<super::TopFilter>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match filter {
Some(f) => {
let json = serde_json::to_string(f).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&json)
}
None => serializer.serialize_none(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ResponseFormat {
#[default]
Json,
#[serde(rename = "geojson")]
GeoJson,
Pbf,
}
#[derive(
Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters, derive_new::new,
)]
pub struct Feature {
attributes: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
geometry: Option<ArcGISGeometry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters, Default)]
pub struct FeatureSet {
#[serde(rename = "geometryType", skip_serializing_if = "Option::is_none")]
geometry_type: Option<GeometryType>,
#[serde(default)]
features: Vec<Feature>,
#[serde(skip_serializing_if = "Option::is_none")]
count: Option<u32>,
#[serde(rename = "exceededTransferLimit", default)]
exceeded_transfer_limit: bool,
}
impl FeatureSet {
pub(crate) fn new(
geometry_type: Option<GeometryType>,
features: Vec<Feature>,
count: Option<u32>,
exceeded_transfer_limit: bool,
) -> Self {
Self {
geometry_type,
features,
count,
exceeded_transfer_limit,
}
}
pub fn into_features(self) -> Vec<Feature> {
self.features
}
pub(crate) fn features_mut(&mut self) -> &mut Vec<Feature> {
&mut self.features
}
}
#[derive(Debug, Clone, Serialize, derive_builder::Builder, derive_getters::Getters, Setters)]
#[builder(setter(into, strip_option), default)]
#[setters(prefix = "set_", borrow_self)]
pub struct FeatureQueryParams {
#[serde(rename = "where")]
#[builder(default = "String::from(\"1=1\")")]
where_clause: String,
#[serde(
rename = "outFields",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
out_fields: Option<Vec<String>>,
#[serde(rename = "returnGeometry")]
#[builder(default = "true")]
return_geometry: bool,
#[serde(rename = "f")]
#[builder(default)]
format: ResponseFormat,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_geometry"
)]
geometry: Option<ArcGISGeometry>,
#[serde(rename = "geometryType", skip_serializing_if = "Option::is_none")]
geometry_type: Option<GeometryType>,
#[serde(rename = "spatialRel", skip_serializing_if = "Option::is_none")]
spatial_rel: Option<SpatialRel>,
#[serde(rename = "resultRecordCount", skip_serializing_if = "Option::is_none")]
result_record_count: Option<u32>,
#[serde(rename = "resultOffset", skip_serializing_if = "Option::is_none")]
result_offset: Option<u32>,
#[serde(
rename = "objectIds",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_object_ids"
)]
object_ids: Option<Vec<ObjectId>>,
#[serde(
rename = "returnDistinctValues",
skip_serializing_if = "Option::is_none"
)]
return_distinct_values: Option<bool>,
#[serde(rename = "returnIdsOnly", skip_serializing_if = "Option::is_none")]
return_ids_only: Option<bool>,
#[serde(rename = "returnCountOnly", skip_serializing_if = "Option::is_none")]
return_count_only: Option<bool>,
#[serde(
rename = "orderByFields",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
order_by_fields: Option<Vec<String>>,
#[serde(
rename = "groupByFieldsForStatistics",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
group_by_fields: Option<Vec<String>>,
#[serde(
rename = "outStatistics",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_statistics"
)]
out_statistics: Option<Vec<StatisticDefinition>>,
#[serde(rename = "having", skip_serializing_if = "Option::is_none")]
having: Option<String>,
#[serde(rename = "outSR", skip_serializing_if = "Option::is_none")]
out_sr: Option<i32>,
}
impl Default for FeatureQueryParams {
fn default() -> Self {
Self {
where_clause: "1=1".to_string(),
out_fields: None,
return_geometry: true,
format: ResponseFormat::default(),
geometry: None,
geometry_type: None,
spatial_rel: None,
result_record_count: None,
result_offset: None,
object_ids: None,
return_distinct_values: None,
return_ids_only: None,
return_count_only: None,
order_by_fields: None,
group_by_fields: None,
out_statistics: None,
having: None,
out_sr: None,
}
}
}
impl FeatureQueryParams {
pub fn builder() -> FeatureQueryParamsBuilder {
FeatureQueryParamsBuilder::default()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum StatisticType {
Count,
Sum,
Min,
Max,
Avg,
Stddev,
Var,
#[serde(rename = "PERCENTILE_CONT")]
PercentileCont,
#[serde(rename = "PERCENTILE_DISC")]
PercentileDisc,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
derive_getters::Getters,
derive_new::new,
)]
#[serde(rename_all = "camelCase")]
pub struct StatisticDefinition {
statistic_type: StatisticType,
on_statistic_field: String,
out_statistic_field_name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct FeatureStatisticsResponse {
features: Vec<Feature>,
#[serde(default)]
field_aliases: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, derive_builder::Builder, derive_getters::Getters)]
#[builder(setter(into, strip_option), default)]
pub struct RelatedRecordsParams {
#[serde(
rename = "objectIds",
serialize_with = "serde_helpers::serialize_object_ids"
)]
object_ids: Option<Vec<ObjectId>>,
#[serde(rename = "relationshipId")]
relationship_id: Option<u32>,
#[serde(
rename = "outFields",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
out_fields: Option<Vec<String>>,
#[serde(
rename = "definitionExpression",
skip_serializing_if = "Option::is_none"
)]
definition_expression: Option<String>,
#[serde(rename = "returnGeometry", skip_serializing_if = "Option::is_none")]
return_geometry: Option<bool>,
#[serde(rename = "outSR", skip_serializing_if = "Option::is_none")]
out_sr: Option<i32>,
#[serde(rename = "maxAllowableOffset", skip_serializing_if = "Option::is_none")]
max_allowable_offset: Option<f64>,
#[serde(rename = "geometryPrecision", skip_serializing_if = "Option::is_none")]
geometry_precision: Option<i32>,
#[serde(rename = "returnZ", skip_serializing_if = "Option::is_none")]
return_z: Option<bool>,
#[serde(rename = "returnM", skip_serializing_if = "Option::is_none")]
return_m: Option<bool>,
#[serde(rename = "gdbVersion", skip_serializing_if = "Option::is_none")]
gdb_version: Option<String>,
#[serde(rename = "historicMoment", skip_serializing_if = "Option::is_none")]
historic_moment: Option<i64>,
#[serde(rename = "returnCountOnly", skip_serializing_if = "Option::is_none")]
return_count_only: Option<bool>,
#[serde(
rename = "orderByFields",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
order_by_fields: Option<Vec<String>>,
#[serde(rename = "resultOffset", skip_serializing_if = "Option::is_none")]
result_offset: Option<u32>,
#[serde(rename = "resultRecordCount", skip_serializing_if = "Option::is_none")]
result_record_count: Option<u32>,
#[serde(rename = "f")]
#[builder(default = "ResponseFormat::Json")]
format: ResponseFormat,
}
impl Default for RelatedRecordsParams {
fn default() -> Self {
Self {
object_ids: None,
relationship_id: None,
out_fields: None,
definition_expression: None,
return_geometry: Some(true),
out_sr: None,
max_allowable_offset: None,
geometry_precision: None,
return_z: None,
return_m: None,
gdb_version: None,
historic_moment: None,
return_count_only: None,
order_by_fields: None,
result_offset: None,
result_record_count: None,
format: ResponseFormat::Json,
}
}
}
impl RelatedRecordsParams {
pub fn builder() -> RelatedRecordsParamsBuilder {
RelatedRecordsParamsBuilder::default()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct RelatedRecordGroup {
object_id: ObjectId,
#[serde(default)]
related_records: Vec<Feature>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct RelatedRecordsResponse {
#[serde(default)]
related_record_groups: Vec<RelatedRecordGroup>,
#[serde(skip_serializing_if = "Option::is_none")]
geometry_type: Option<GeometryType>,
#[serde(skip_serializing_if = "Option::is_none")]
spatial_reference: Option<serde_json::Value>,
#[serde(default)]
fields: Vec<serde_json::Value>,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
derive_getters::Getters,
derive_new::new,
)]
#[serde(rename_all = "camelCase")]
pub struct TopFilter {
group_by_fields: Vec<String>,
top_count: u32,
order_by_fields: Vec<String>,
}
#[derive(Debug, Clone, Serialize, derive_builder::Builder, derive_getters::Getters)]
#[builder(setter(into, strip_option), default)]
pub struct TopFeaturesParams {
#[serde(
rename = "topFilter",
serialize_with = "serde_helpers::serialize_top_filter"
)]
top_filter: Option<TopFilter>,
#[serde(skip_serializing_if = "Option::is_none")]
where_: Option<String>,
#[serde(
rename = "objectIds",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_object_ids"
)]
object_ids: Option<Vec<ObjectId>>,
#[serde(skip_serializing_if = "Option::is_none")]
time: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_geometry"
)]
geometry: Option<ArcGISGeometry>,
#[serde(rename = "geometryType", skip_serializing_if = "Option::is_none")]
geometry_type: Option<GeometryType>,
#[serde(rename = "inSR", skip_serializing_if = "Option::is_none")]
in_sr: Option<i32>,
#[serde(rename = "spatialRel", skip_serializing_if = "Option::is_none")]
spatial_rel: Option<SpatialRel>,
#[serde(skip_serializing_if = "Option::is_none")]
distance: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
units: Option<String>,
#[serde(
rename = "outFields",
skip_serializing_if = "Option::is_none",
serialize_with = "serde_helpers::serialize_string_vec"
)]
out_fields: Option<Vec<String>>,
#[serde(rename = "returnGeometry", skip_serializing_if = "Option::is_none")]
return_geometry: Option<bool>,
#[serde(rename = "maxAllowableOffset", skip_serializing_if = "Option::is_none")]
max_allowable_offset: Option<f64>,
#[serde(rename = "geometryPrecision", skip_serializing_if = "Option::is_none")]
geometry_precision: Option<i32>,
#[serde(rename = "outSR", skip_serializing_if = "Option::is_none")]
out_sr: Option<i32>,
#[serde(rename = "returnIdsOnly", skip_serializing_if = "Option::is_none")]
return_ids_only: Option<bool>,
#[serde(rename = "returnCountOnly", skip_serializing_if = "Option::is_none")]
return_count_only: Option<bool>,
#[serde(rename = "returnExtentOnly", skip_serializing_if = "Option::is_none")]
return_extent_only: Option<bool>,
#[serde(rename = "returnZ", skip_serializing_if = "Option::is_none")]
return_z: Option<bool>,
#[serde(rename = "returnM", skip_serializing_if = "Option::is_none")]
return_m: Option<bool>,
#[serde(rename = "resultType", skip_serializing_if = "Option::is_none")]
result_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
f: Option<String>,
}
impl Default for TopFeaturesParams {
fn default() -> Self {
Self {
top_filter: None,
where_: None,
object_ids: None,
time: None,
geometry: None,
geometry_type: None,
in_sr: None,
spatial_rel: None,
distance: None,
units: None,
out_fields: None,
return_geometry: Some(true),
max_allowable_offset: None,
geometry_precision: None,
out_sr: None,
return_ids_only: None,
return_count_only: None,
return_extent_only: None,
return_z: None,
return_m: None,
result_type: None,
f: Some("json".to_string()),
}
}
}
impl TopFeaturesParams {
pub fn builder() -> TopFeaturesParamsBuilder {
TopFeaturesParamsBuilder::default()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, derive_getters::Getters)]
pub struct TruncateResult {
success: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
pub struct QueryDomainsResponse {
layers: Vec<LayerDomainInfo>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct LayerDomainInfo {
id: i32,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default)]
domains: HashMap<String, Domain>,
#[serde(skip_serializing_if = "Option::is_none")]
subtypes: Option<Vec<Subtype>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct Domain {
#[serde(rename = "type")]
domain_type: String,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
coded_values: Option<Vec<CodedValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
range: Option<Vec<serde_json::Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
pub struct CodedValue {
code: serde_json::Value,
name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct Subtype {
code: i32,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
default_values: Option<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
domains: Option<HashMap<String, Domain>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FieldCalculation {
field: String,
#[serde(skip_serializing_if = "Option::is_none")]
value: Option<serde_json::Value>,
#[serde(rename = "sqlExpression", skip_serializing_if = "Option::is_none")]
sql_expression: Option<String>,
}
impl FieldCalculation {
pub fn with_value(field: impl Into<String>, value: serde_json::Value) -> Self {
Self {
field: field.into(),
value: Some(value),
sql_expression: None,
}
}
pub fn with_sql_expression(
field: impl Into<String>,
sql_expression: impl Into<String>,
) -> Self {
Self {
field: field.into(),
value: None,
sql_expression: Some(sql_expression.into()),
}
}
pub fn field(&self) -> &str {
&self.field
}
pub fn value(&self) -> Option<&serde_json::Value> {
self.value.as_ref()
}
pub fn sql_expression(&self) -> Option<&str> {
self.sql_expression.as_deref()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct RelationshipRule {
#[serde(rename = "ruleID")]
rule_id: i32,
origin_subtype_code: i32,
origin_minimum_cardinality: i32,
origin_maximum_cardinality: i32,
destination_subtype_code: i32,
destination_minimum_cardinality: i32,
destination_maximum_cardinality: i32,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
#[serde(rename_all = "camelCase")]
pub struct RelationshipClass {
id: i32,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
cardinality: RelationshipCardinality,
origin_layer_id: i32,
origin_primary_key: String,
#[serde(skip_serializing_if = "Option::is_none")]
origin_foreign_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
destination_layer_id: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
destination_primary_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
destination_foreign_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
backward_path_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
forward_path_label: Option<String>,
role: RelationshipRole,
attributed: bool,
#[serde(skip_serializing_if = "Option::is_none")]
relationship_table_id: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
key_field_in_relationship_table: Option<String>,
#[serde(rename = "catalogID", skip_serializing_if = "Option::is_none")]
catalog_id: Option<String>,
#[serde(default)]
rules: Vec<RelationshipRule>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, derive_getters::Getters)]
pub struct RelationshipsResponse {
relationships: Vec<RelationshipClass>,
}