use super::*;
use element::CibouletteResponseElementAlias;
use itertools::Itertools;
use serde::ser::SerializeStruct;
use std::cmp::{Ord, Ordering};
#[derive(Deserialize, Serialize, Debug, Getters, MutGetters, Clone)]
#[getset(get = "pub", get_mut = "pub")]
pub struct CibouletteResourceResponseIdentifierBuilder<'request> {
#[serde(rename = "type")]
pub type_: Cow<'request, str>,
pub id: Option<Cow<'request, str>>,
}
#[derive(Debug, Getters, MutGetters, Clone, Hash)]
#[getset(get = "pub", get_mut = "pub")]
pub struct CibouletteResourceResponseIdentifier<'request> {
pub type_: ArcStr,
pub id: CibouletteIdSelector<'request>,
}
impl<'request> Ord for CibouletteResourceResponseIdentifier<'request> {
fn cmp(&self, other: &Self) -> Ordering {
let type_cmp = self.type_.cmp(other.type_());
match type_cmp {
Ordering::Equal => self.id.cmp(other.id()),
_ => type_cmp,
}
}
}
impl<'request> PartialOrd for CibouletteResourceResponseIdentifier<'request> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let type_cmp = self.type_.cmp(other.type_());
match type_cmp {
Ordering::Equal => Some(self.id.cmp(other.id())),
_ => Some(type_cmp),
}
}
}
impl<'request> PartialEq for CibouletteResourceResponseIdentifier<'request> {
fn eq(&self, other: &Self) -> bool {
self.type_ == other.type_ && self.id == other.id
}
}
impl<'request> Eq for CibouletteResourceResponseIdentifier<'request> {}
impl<'request> From<CibouletteResourceIdentifierBuilder<'request>>
for CibouletteResourceResponseIdentifierBuilder<'request>
{
fn from(other: CibouletteResourceIdentifierBuilder<'request>) -> Self {
CibouletteResourceResponseIdentifierBuilder::new(other.id, other.type_)
}
}
impl<'request> CibouletteResourceResponseIdentifierBuilder<'request> {
pub fn build(
self,
store: &CibouletteStore,
) -> Result<CibouletteResourceResponseIdentifier<'request>, CibouletteError> {
let type_ = store.get_type(&self.type_)?;
Ok(CibouletteResourceResponseIdentifier {
id: match self.id {
Some(id) => CibouletteId::build_id(type_.ids(), id)?,
None => return Err(CibouletteError::MissingId),
},
type_: type_.name().clone(),
})
}
fn build_rel_chain(
store: &CibouletteStore,
base_type: Arc<CibouletteResourceType>,
rel_chain: Cow<'request, str>,
) -> Result<
(
Vec<CibouletteResourceRelationshipDetails>,
CibouletteIdTypeSelector,
),
CibouletteError,
> {
let mut wtype: Arc<CibouletteResourceType> = base_type.clone();
let mut res: Vec<CibouletteResourceRelationshipDetails> = Vec::new();
let mut last_id_type = base_type.ids();
for rel_name in rel_chain.split('.') {
let rel_details = wtype.get_relationship_details(store, rel_name)?;
wtype = rel_details.related_type().clone();
last_id_type = wtype.ids();
res.push(rel_details);
}
Ok((res, last_id_type.clone()))
}
pub fn build_relationships(
self,
store: &CibouletteStore,
base_type: Arc<CibouletteResourceType>,
) -> Result<CibouletteResponseElementAlias<'request>, CibouletteError> {
let (rel_chain, id_type) = Self::build_rel_chain(store, base_type.clone(), self.type_)?;
let last_type = rel_chain
.last()
.map(|x| x.related_type().clone())
.unwrap_or_else(|| base_type.clone());
Ok(CibouletteResponseElementAlias::new(
rel_chain,
CibouletteResourceResponseIdentifier {
type_: last_type.name().clone(),
id: CibouletteId::build_id(&id_type, self.id.ok_or(CibouletteError::MissingId)?)?,
},
))
}
}
impl<'request> CibouletteResourceResponseIdentifierBuilder<'request> {
pub fn new(id: Option<Cow<'request, str>>, type_: Cow<'request, str>) -> Self {
CibouletteResourceResponseIdentifierBuilder { id, type_ }
}
}
#[derive(Deserialize, Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum CibouletteResourceResponseIdentifierSelectorBuilder<'request> {
One(CibouletteResourceResponseIdentifierBuilder<'request>),
Many(Vec<CibouletteResourceResponseIdentifierBuilder<'request>>),
}
impl<'request> CibouletteResourceResponseIdentifierSelectorBuilder<'request> {
pub fn build(
self,
store: &CibouletteStore,
) -> Result<CibouletteResourceResponseIdentifierSelector<'request>, CibouletteError> {
match self {
CibouletteResourceResponseIdentifierSelectorBuilder::One(x) => Ok(
CibouletteResourceResponseIdentifierSelector::One(x.build(store)?),
),
CibouletteResourceResponseIdentifierSelectorBuilder::Many(ids) => {
let mut res: Vec<CibouletteResourceResponseIdentifier<'request>> =
Vec::with_capacity(ids.len());
for id in ids.into_iter() {
res.push(id.build(store)?);
}
Ok(CibouletteResourceResponseIdentifierSelector::Many(res))
}
}
}
}
#[derive(Debug, Serialize, Clone)]
#[serde(untagged)]
pub enum CibouletteResourceResponseIdentifierSelector<'request> {
One(CibouletteResourceResponseIdentifier<'request>),
Many(Vec<CibouletteResourceResponseIdentifier<'request>>),
}
impl<'request, B>
From<CibouletteResource<'request, B, CibouletteResourceResponseIdentifier<'request>>>
for CibouletteResourceResponseIdentifierSelector<'request>
{
fn from(
obj: CibouletteResource<'request, B, CibouletteResourceResponseIdentifier<'request>>,
) -> Self {
CibouletteResourceResponseIdentifierSelector::One(obj.identifier)
}
}
impl<'request, B>
From<CibouletteResourceSelector<'request, B, CibouletteResourceResponseIdentifier<'request>>>
for CibouletteResourceResponseIdentifierSelector<'request>
{
fn from(
obj: CibouletteResourceSelector<
'request,
B,
CibouletteResourceResponseIdentifier<'request>,
>,
) -> Self {
match obj {
CibouletteResourceSelector::One(x) => {
CibouletteResourceResponseIdentifierSelector::One(x.identifier)
}
CibouletteResourceSelector::Many(x) => {
CibouletteResourceResponseIdentifierSelector::Many(
x.into_iter().map(|x| x.identifier).collect(),
)
}
}
}
}
impl<'request> CibouletteResourceResponseIdentifier<'request> {
pub fn id_to_string(&self) -> String {
match self.id() {
CibouletteIdSelector::Single(x) => x.to_string(),
CibouletteIdSelector::Multi(x) => x.iter().join(","),
}
}
}
impl<'request> Serialize for CibouletteResourceResponseIdentifier<'request> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("CibouletteResourceIdentifier", 3)?;
state.serialize_field("type", &self.type_)?;
match self.id().len() {
0 => state.skip_field("id")?,
1 => state.serialize_field(
"id",
self.id().get(0).map_err(|_| {
serde::ser::Error::custom(
"Wrong number of id when deserializing resource identifier",
)
})?,
)?,
_ => state.serialize_field("id", &self.id_to_string())?,
};
state.end()
}
}