use serde::{Deserialize, Serialize};
use super::{enums::object_type::IcingaObjectType, metadata::IcingaMetadata};
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct ResultsWrapper<T> {
pub results: Vec<T>,
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct QueryResultObjectWithJoins<Obj, ObjJoins> {
pub attrs: Obj,
pub joins: ObjJoins,
pub meta: IcingaMetadata,
pub name: String,
#[serde(rename = "type")]
pub object_type: IcingaObjectType,
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct QueryResultObject<Obj> {
pub attrs: Obj,
pub meta: IcingaMetadata,
pub name: String,
#[serde(rename = "type")]
pub object_type: IcingaObjectType,
}
pub trait QueryableObject {
type ListEndpoint;
fn default_query_endpoint() -> Result<Self::ListEndpoint, crate::error::Error>;
}
macro_rules! query_with_joins {
($name:ident, $builder_name:ident, $object_category:path, $path_component:path, $return_type:ty, $join_types:ty, $join_return_type:ty, $object_type:expr, $url_fragment:expr) => {
use std::collections::BTreeMap;
#[rustfmt::skip]
use crate::types::{
enums::object_type::IcingaObjectType,
filter::IcingaFilter,
join_types::{
add_joins_to_url,
$path_component::{$join_return_type, $join_types},
IcingaJoins,
},
metadata::{add_meta_to_url, IcingaMetadataType},
query::{QueryableObject, QueryResultObject, QueryResultObjectWithJoins, ResultsWrapper},
rest::{RestApiEndpoint, RestApiResponse},
$object_category::{
$path_component::{
$return_type,
}
}
};
#[allow(clippy::missing_errors_doc)]
#[derive(Debug, Clone, derive_builder::Builder)]
#[builder(
build_fn(error = "crate::error::Error", validate = "Self::validate"),
derive(Debug)
)]
pub struct $name<'a> {
#[builder(default, setter(strip_option, into))]
joins: Option<IcingaJoins<'a, $join_types>>,
#[builder(default, setter(strip_option, into))]
meta: Option<Vec<IcingaMetadataType>>,
#[builder(default, setter(strip_option, into))]
filter: Option<IcingaFilter>,
}
impl<'a> $name<'a> {
#[must_use]
pub fn builder() -> $builder_name<'a> {
$builder_name::default()
}
}
impl QueryableObject for $return_type {
type ListEndpoint = $name<'static>;
fn default_query_endpoint() -> Result<Self::ListEndpoint, crate::error::Error> {
$name::builder().build()
}
}
impl<'a> $builder_name<'a> {
pub fn validate(&self) -> Result<(), crate::error::Error> {
let expected = $object_type;
if let Some(Some(filter)) = &self.filter {
if filter.object_type != expected {
Err(crate::error::Error::FilterObjectTypeMismatch(
vec![expected],
filter.object_type.to_owned(),
))
} else {
Ok(())
}
} else {
Ok(())
}
}
}
impl<'a> RestApiEndpoint for $name<'a> {
type RequestBody = IcingaFilter;
fn method(&self) -> Result<reqwest::Method, crate::error::Error> {
Ok(reqwest::Method::GET)
}
fn url(&self, base_url: &url::Url) -> Result<url::Url, crate::error::Error> {
let mut url = base_url
.join($url_fragment)
.map_err(crate::error::Error::CouldNotParseUrlFragment)?;
if let Some(joins) = &self.joins {
add_joins_to_url(&mut url, &joins)?;
}
if let Some(meta) = &self.meta {
add_meta_to_url(&mut url, &meta)?;
}
Ok(url)
}
fn request_body(
&self,
) -> Result<Option<std::borrow::Cow<Self::RequestBody>>, crate::error::Error>
where
Self::RequestBody: Clone + serde::Serialize + std::fmt::Debug,
{
Ok(self.filter.as_ref().map(|f| std::borrow::Cow::Borrowed(f)))
}
}
impl<'a> RestApiResponse<$name<'a>> for ResultsWrapper<QueryResultObject<$return_type>> {}
impl<'a> RestApiResponse<$name<'a>>
for ResultsWrapper<QueryResultObject<BTreeMap<String, serde_json::Value>>>
{
}
impl<'a> RestApiResponse<$name<'a>>
for ResultsWrapper<QueryResultObjectWithJoins<$return_type, $join_return_type>>
{
}
impl<'a> RestApiResponse<$name<'a>>
for ResultsWrapper<
QueryResultObjectWithJoins<BTreeMap<String, serde_json::Value>, $join_return_type>,
>
{
}
impl<'a> RestApiResponse<$name<'a>>
for ResultsWrapper<
QueryResultObjectWithJoins<$return_type, BTreeMap<String, serde_json::Value>>,
>
{
}
impl<'a> RestApiResponse<$name<'a>>
for ResultsWrapper<
QueryResultObjectWithJoins<
BTreeMap<String, serde_json::Value>,
BTreeMap<String, serde_json::Value>,
>,
>
{
}
};
}
pub(crate) use query_with_joins;
macro_rules! query {
($name:ident, $builder_name:ident, $object_category:path, $path_component:path, $return_type:ty, $object_type:expr, $url_fragment:expr) => {
use std::collections::BTreeMap;
#[rustfmt::skip]
use crate::types::{
enums::object_type::IcingaObjectType,
filter::IcingaFilter,
metadata::{add_meta_to_url, IcingaMetadataType},
query::{QueryableObject, QueryResultObject, ResultsWrapper},
rest::{RestApiEndpoint, RestApiResponse},
$object_category::{
$path_component::{
$return_type,
},
},
};
#[allow(clippy::missing_errors_doc)]
#[derive(Debug, Clone, derive_builder::Builder)]
#[builder(
build_fn(error = "crate::error::Error", validate = "Self::validate"),
derive(Debug)
)]
pub struct $name {
#[builder(default, setter(strip_option, into))]
meta: Option<Vec<IcingaMetadataType>>,
#[builder(default, setter(strip_option, into))]
filter: Option<IcingaFilter>,
}
impl $name {
#[must_use]
pub fn builder() -> $builder_name {
$builder_name::default()
}
}
impl QueryableObject for $return_type {
type ListEndpoint = $name;
fn default_query_endpoint() -> Result<Self::ListEndpoint, crate::error::Error> {
$name::builder().build()
}
}
impl $builder_name {
pub fn validate(&self) -> Result<(), crate::error::Error> {
let expected = $object_type;
if let Some(Some(filter)) = &self.filter {
if filter.object_type != expected {
Err(crate::error::Error::FilterObjectTypeMismatch(
vec![expected],
filter.object_type.to_owned(),
))
} else {
Ok(())
}
} else {
Ok(())
}
}
}
impl RestApiEndpoint for $name {
type RequestBody = IcingaFilter;
fn method(&self) -> Result<reqwest::Method, crate::error::Error> {
Ok(reqwest::Method::GET)
}
fn url(&self, base_url: &url::Url) -> Result<url::Url, crate::error::Error> {
let mut url = base_url
.join($url_fragment)
.map_err(crate::error::Error::CouldNotParseUrlFragment)?;
if let Some(meta) = &self.meta {
add_meta_to_url(&mut url, &meta)?;
}
Ok(url)
}
fn request_body(
&self,
) -> Result<Option<std::borrow::Cow<Self::RequestBody>>, crate::error::Error>
where
Self::RequestBody: Clone + serde::Serialize + std::fmt::Debug,
{
Ok(self.filter.as_ref().map(|f| std::borrow::Cow::Borrowed(f)))
}
}
impl RestApiResponse<$name> for ResultsWrapper<QueryResultObject<$return_type>> {}
impl RestApiResponse<$name>
for ResultsWrapper<QueryResultObject<BTreeMap<String, serde_json::Value>>>
{
}
};
}
pub(crate) use query;