1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::*;
use thiserror::Error;

/// When describing KeyClash, we need to know if the field was supposed be with
/// or without another field
#[derive(Debug, PartialEq)]
pub enum CibouletteClashDirection {
    With,
    Without,
}

impl std::fmt::Display for CibouletteClashDirection {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                CibouletteClashDirection::With => "with",
                CibouletteClashDirection::Without => "without",
            }
        )
    }
}

/// ## `JSON:API` Path type
#[derive(Debug, PartialEq)]
pub enum CiboulettePathType {
    Type,
    TypeId,
    TypeIdRelated,
    TypeIdRelationship,
}

impl std::fmt::Display for CiboulettePathType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            CiboulettePathType::Type => write!(f, "Type"),
            CiboulettePathType::TypeId => write!(f, "TypeId"),
            CiboulettePathType::TypeIdRelated => write!(f, "TypeIdRelated"),
            CiboulettePathType::TypeIdRelationship => write!(f, "TypeIdRelationship"),
        }
    }
}

impl From<&CiboulettePath<'_>> for CiboulettePathType {
    fn from(t: &CiboulettePath<'_>) -> Self {
        match t {
            CiboulettePath::Type(_) => CiboulettePathType::Type,
            CiboulettePath::TypeId(_, _) => CiboulettePathType::TypeId,
            CiboulettePath::TypeIdRelated(_, _, _) => CiboulettePathType::TypeIdRelated,
            CiboulettePath::TypeIdRelationship(_, _, _) => CiboulettePathType::TypeIdRelationship,
        }
    }
}

/// # An error throwable by [Ciboulette](crate)
#[derive(Error, Debug)]
pub enum CibouletteError {
    #[error("The main type in the path and in the body are not the same")]
    MainTypeClash,
    #[error("The json:api type `{0}` is unknown.")]
    UnknownType(String),
    #[error("No relationship `{1}` for type `{0}`.")]
    UnknownRelationship(String, String),
    #[error("No field {1} for type {0}.")]
    UnknownField(String, String),
    #[error("The resource object ({0}, {1}) should be unique by `type` and `id`")]
    UniqObj(String, String),
    #[error("The type `{0}` is already defined")]
    UniqType(String),
    #[error("The resource relationship ({0}, {1}) should be unique by `type` and `id`")]
    UniqRelationshipObject(String, String),
    #[error("The relationship between {0} and {1} already exists")]
    UniqRelationship(String, String),
    #[error("The linked object ({0}, {1}) is missing")]
    MissingLink(String, String),
    #[error("The linked object ({0}, {1}) is not completely linked")]
    NoCompleteLinkage(String, String),
    #[error("Type `{0}` is not in the graph")]
    TypeNotInGraph(String),
    #[error("Relation `{0}`-`{1}` is not in the graph")]
    RelNotInGraph(String, String),
    #[error("The key `{0}` must be present {1} `{2}`")]
    KeyClash(String, CibouletteClashDirection, String),
    #[error("The member name {0} doesn't respect the json:api specification")]
    InvalidMemberName(String),
    #[error("The `attributes` should be an object")]
    AttributesIsNotAnObject,
    #[error("The `data` object is missing")]
    NoData,
    #[error("Missing `id` field for a resource identifier")]
    MissingId,
    #[error("Bad `id` type: found `{0}`, expected `{1}`")]
    BadIdType(CibouletteIdType, CibouletteIdType),
    #[error("Unkown id type `{0}`")]
    UnknownIdType(String),
    #[error("Compound documents are forbidden for that kind of request")]
    NoCompound,
    #[error("No alias translation for `{1}` in type `{0}`")]
    MissingAliasTranslation(String, String),
    #[error("Couldn't parse the path, no type were specified")]
    MissingTypeInPath,
    #[error("Couldn't parse the path")]
    BadPath,
    #[error("Wrong request intention, got {0}, expected {1}")]
    WrongIntention(CibouletteIntention, CibouletteIntention),
    #[error("Wrong path type, got {0}, expected {1:?}")]
    WrongPathType(CiboulettePathType, Vec<CiboulettePathType>),
    #[error("Too many main data to build the response document for type `{0}`")]
    ResponseTooManyMainData(String),
    /// When there is a failure while deserializing the JSON
    #[error("An unkown error occured : {0}")]
    UnknownError(String),
    #[error(transparent)]
    SerdeJson(#[from] serde_json::Error),
    #[error(transparent)]
    UuidError(#[from] uuid::Error),
    #[error(transparent)]
    ParseIntError(#[from] std::num::ParseIntError),
    #[error(transparent)]
    SerdeUrlEncoded(#[from] serde_urlencoded::de::Error),
    #[error(transparent)]
    Url(#[from] url::ParseError),
}