#[cfg(any(feature = "cosmos", feature = "gremlin"))]
use gremlin_client::GremlinError;
use http::header::{InvalidHeaderName, InvalidHeaderValue};
use std::fmt::{Display, Formatter};
use std::num::ParseIntError;
use std::str::ParseBoolError;
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "neo4j")]
BoltClientFailed {
source: bolt_client::error::Error,
},
ClientRequestFailed {
source: reqwest::Error,
},
ConfigItemDuplicated {
type_name: String,
},
ConfigItemReserved {
type_name: String,
},
ConfigOpenFailed {
source: std::io::Error,
},
ConfigVersionMismatched {
expected: i32,
found: i32,
},
DatabaseNotFound,
JsonDeserializationFailed {
source: serde_json::Error,
},
EnvironmentVariableNotFound {
name: String,
},
EnvironmentVariableBoolNotParsed {
source: ParseBoolError,
},
EnvironmentVariableIntNotParsed {
source: ParseIntError,
},
EventError {
source: Box<dyn std::error::Error + Sync + Send>,
},
#[cfg(any(feature = "cosmos", feature = "gremlin"))]
GremlinActionFailed {
source: Box<gremlin_client::GremlinError>,
},
InputItemNotFound {
name: String,
},
InvalidHeaderName {
source: InvalidHeaderName,
},
InvalidHeaderValue {
source: InvalidHeaderValue,
},
LabelNotFound,
#[cfg(feature = "neo4j")]
Neo4jPoolFailed {
source: mobc::Error<mobc_boltrs::Error>,
},
#[cfg(feature = "neo4j")]
Neo4jPoolNotBuilt {
source: mobc_boltrs::Error,
},
#[cfg(feature = "neo4j")]
Neo4jQueryFailed {
message: bolt_proto::message::Message,
},
PartitionKeyNotFound,
PayloadNotFound {
response: serde_json::Value,
},
RelDuplicated {
rel_name: String,
ids: String,
},
ResolverNotFound {
name: String,
},
ResponseSetNotFound,
ResponseItemNotFound {
name: String,
},
SerializationFailed {
source: serde_json::Error,
},
SchemaItemNotFound {
name: String,
},
ThreadCommunicationFailed {
source: std::sync::mpsc::RecvError,
},
TransactionFinished,
TypeConversionFailed {
src: String,
dst: String,
},
TypeNotExpected {
details: Option<String>,
},
UserDefinedError {
source: Box<dyn std::error::Error + Sync + Send>,
},
UuidNotParsed {
source: uuid::Error,
},
ValidationFailed {
message: String,
},
ValidatorNotFound {
name: String,
},
YamlDeserializationFailed {
source: serde_yaml::Error,
},
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
#[cfg(feature = "neo4j")]
Error::BoltClientFailed { source } => {
write!(f, "Neo4j client failed. Source error: {}.", source)
}
Error::ClientRequestFailed { source } => {
write!(f, "Client request failed. Source error: {}", source)
}
Error::ConfigItemDuplicated { type_name } => {
write!(f, "Config model contains duplicate item: {}", type_name)
}
Error::ConfigItemReserved { type_name } => {
write!(
f,
"Config item cannot use a reserved word as a name: {}",
type_name
)
}
Error::ConfigOpenFailed { source } => {
write!(
f,
"Config file could not be opened. Source error: {}",
source
)
}
Error::ConfigVersionMismatched { expected, found } => {
write!(
f,
"Configs must be the same version: expected {} but found {}",
expected, found
)
}
Error::DatabaseNotFound => {
write!(f, "Use of resolvers required a database back-end. Please select either cosmos or neo4j.")
}
Error::EnvironmentVariableNotFound { name } => {
write!(f, "Could not find environment variable: {}", name)
}
Error::EnvironmentVariableBoolNotParsed { source } => {
write!(
f,
"Failed to parse environment variable to boolean flag. Source error: {}",
source
)
}
Error::EnvironmentVariableIntNotParsed { source } => {
write!(
f,
"Failed to parse environment variable to integer port number. Source error: {}",
source
)
}
Error::EventError { source } => {
write!(f, "Event handler returned an error: {}", source)
}
#[cfg(any(feature = "cosmos", feature = "gremlin"))]
Error::GremlinActionFailed { source } => {
write!(
f,
"Either building a database connection pool or query failed. Source error: {}",
source
)
}
Error::InputItemNotFound { name } => {
write!(
f,
"Could not find an expected argument, {}, in the GraphQL query.",
name
)
}
Error::InvalidHeaderName { source } => {
write!(f, "Invalid HTTP header given to Client: {}", source)
}
Error::InvalidHeaderValue { source } => {
write!(f, "Invalid HTTP header given to Client: {}", source)
}
Error::LabelNotFound => {
write!(f, "Could not find a label for a destination node.")
}
Error::JsonDeserializationFailed { source } => {
write!(f, "Failed to deserialize JSON into struct: {}", source)
}
#[cfg(feature = "neo4j")]
Error::Neo4jPoolFailed { source } => {
write!(f, "Could not get Neo4J transaction from pool: {}", source)
}
#[cfg(feature = "neo4j")]
Error::Neo4jPoolNotBuilt { source } => {
write!(f, "Could not build Neo4j connection pool: {}", source)
}
#[cfg(feature = "neo4j")]
Error::Neo4jQueryFailed { message } => {
write!(
f,
"Neo4j query execution failed. Error message: {:#?}.",
message
)
}
Error::PartitionKeyNotFound => {
write!(f, "Partition keys are required when using Cosmos DB.")
}
Error::PayloadNotFound { response } => {
write!(
f,
"Required data and/or error fields are missing from the response: {}",
response
)
}
Error::RelDuplicated { rel_name, ids } => {
write!(f, "Tried to read the single-node (i.e. one-to-one) relationship named {}, but found multipled ids: {}", rel_name, ids)
}
Error::ResolverNotFound { name } => {
write!(f, "Could not find a custom resolver named {}", name)
}
Error::ResponseItemNotFound { name } => {
write!(
f,
"Could not find an expected response item, {}, in the database results.",
name
)
}
Error::ResponseSetNotFound => {
write!(f, "Could not find an expected database set of results.")
}
Error::SerializationFailed { source } => {
write!(
f,
"Serialization of the GraphQL response failed. Source error: {}",
source
)
}
Error::SchemaItemNotFound { name } => {
write!(
f,
"The following item could not be found in the schema: {}",
name
)
}
Error::ThreadCommunicationFailed { source } => {
write!(
f,
"Communication from the engine thread failed. Source error: {}",
source
)
}
Error::TransactionFinished => {
write!(
f,
"Cannot use a database transaction already committed or rolled back."
)
}
Error::TypeConversionFailed { src, dst } => {
write!(
f,
"The type or value {} could not be converted to type {}",
src, dst
)
}
Error::TypeNotExpected { details } => {
write!(
f,
"Warpgrapher encountered a type that was not expected {}",
if let Some(s) = details {
format!("({:#?}", s)
} else {
"".to_string()
}
)
}
Error::UserDefinedError { source } => {
write!(f, "User defined error. Source error: {:#?}", source)
}
Error::UuidNotParsed { source } => {
write!(
f,
"Failed to parse id attribute value. Source error: {}",
source
)
}
Error::ValidationFailed { message } => {
write!(f, "{}", message)
}
Error::ValidatorNotFound { name } => {
write!(f, "A validator function named {} could not be found", name)
}
Error::YamlDeserializationFailed { source } => {
write!(
f,
"Failed to deserialize yaml struct. Source error: {}",
source
)
}
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
#[cfg(feature = "neo4j")]
Error::BoltClientFailed { source } => Some(source),
Error::ClientRequestFailed { source } => Some(source),
Error::ConfigItemDuplicated { type_name: _ } => None,
Error::ConfigItemReserved { type_name: _ } => None,
Error::ConfigOpenFailed { source } => Some(source),
Error::ConfigVersionMismatched {
expected: _,
found: _,
} => None,
Error::DatabaseNotFound => None,
Error::EnvironmentVariableNotFound { name: _ } => None,
Error::EnvironmentVariableBoolNotParsed { source } => Some(source),
Error::EnvironmentVariableIntNotParsed { source } => Some(source),
Error::EventError { source } => Some(source.as_ref()),
#[cfg(any(feature = "cosmos", feature = "gremlin"))]
Error::GremlinActionFailed { source } => Some(source),
Error::InputItemNotFound { name: _ } => None,
Error::InvalidHeaderName { source } => Some(source),
Error::InvalidHeaderValue { source } => Some(source),
Error::JsonDeserializationFailed { source } => Some(source),
Error::LabelNotFound => None,
#[cfg(feature = "neo4j")]
Error::Neo4jPoolFailed { source } => Some(source),
#[cfg(feature = "neo4j")]
Error::Neo4jPoolNotBuilt { source } => Some(source),
#[cfg(feature = "neo4j")]
Error::Neo4jQueryFailed { message: _ } => None,
Error::PartitionKeyNotFound => None,
Error::PayloadNotFound { response: _ } => None,
Error::RelDuplicated {
rel_name: _,
ids: _,
} => None,
Error::ResolverNotFound { name: _ } => None,
Error::ResponseItemNotFound { name: _ } => None,
Error::ResponseSetNotFound => None,
Error::SerializationFailed { source } => Some(source),
Error::SchemaItemNotFound { name: _ } => None,
Error::ThreadCommunicationFailed { source } => Some(source),
Error::TransactionFinished => None,
Error::TypeConversionFailed { src: _, dst: _ } => None,
Error::TypeNotExpected { details: _ } => None,
Error::UserDefinedError { source: _ } => None,
Error::UuidNotParsed { source } => Some(source),
Error::ValidationFailed { message: _ } => None,
Error::ValidatorNotFound { name: _ } => None,
Error::YamlDeserializationFailed { source } => Some(source),
}
}
}
impl From<Box<dyn std::error::Error + Sync + Send>> for Error {
fn from(e: Box<dyn std::error::Error + Sync + Send>) -> Self {
Error::EventError { source: e }
}
}
#[cfg(feature = "neo4j")]
impl From<bolt_client::error::Error> for Error {
fn from(e: bolt_client::error::Error) -> Self {
Error::BoltClientFailed { source: e }
}
}
#[cfg(feature = "neo4j")]
impl From<bolt_proto::error::Error> for Error {
fn from(_e: bolt_proto::error::Error) -> Self {
Error::TypeConversionFailed {
src: "bolt_proto::value::Value".to_string(),
dst: "Value".to_string(),
}
}
}
#[cfg(any(feature = "cosmos", feature = "gremlin"))]
impl From<GremlinError> for Error {
fn from(e: GremlinError) -> Self {
Error::GremlinActionFailed {
source: Box::new(e),
}
}
}
#[cfg(feature = "neo4j")]
impl From<mobc::Error<mobc_boltrs::Error>> for Error {
fn from(e: mobc::Error<mobc_boltrs::Error>) -> Self {
Error::Neo4jPoolFailed { source: e }
}
}
#[cfg(feature = "neo4j")]
impl From<mobc_boltrs::Error> for Error {
fn from(e: mobc_boltrs::Error) -> Self {
Error::Neo4jPoolNotBuilt { source: e }
}
}
impl From<reqwest::Error> for Error {
fn from(e: reqwest::Error) -> Self {
Error::ClientRequestFailed { source: e }
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::SerializationFailed { source: e }
}
}
impl From<serde_yaml::Error> for Error {
fn from(e: serde_yaml::Error) -> Self {
Error::YamlDeserializationFailed { source: e }
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::ConfigOpenFailed { source: e }
}
}
impl From<std::str::ParseBoolError> for Error {
fn from(e: std::str::ParseBoolError) -> Self {
Error::EnvironmentVariableBoolNotParsed { source: e }
}
}
impl From<std::num::ParseIntError> for Error {
fn from(e: std::num::ParseIntError) -> Self {
Error::EnvironmentVariableIntNotParsed { source: e }
}
}
impl From<std::num::TryFromIntError> for Error {
fn from(_e: std::num::TryFromIntError) -> Self {
Error::TypeConversionFailed {
src: "i64 or uint64".to_string(),
dst: "i32".to_string(),
}
}
}
impl From<std::sync::mpsc::RecvError> for Error {
fn from(e: std::sync::mpsc::RecvError) -> Self {
Error::ThreadCommunicationFailed { source: e }
}
}
impl From<uuid::Error> for Error {
fn from(e: uuid::Error) -> Self {
Error::UuidNotParsed { source: e }
}
}
#[cfg(test)]
mod tests {
use super::Error;
#[test]
fn new_error() {
let e = Error::DatabaseNotFound;
assert!(std::error::Error::source(&e).is_none());
}
#[test]
fn display_fmt() {
let s = std::io::Error::new(std::io::ErrorKind::Other, "oh no!");
let e = Error::ConfigOpenFailed { source: s };
assert_eq!(
"Config file could not be opened. Source error: oh no!",
&format!("{}", e)
);
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Error>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Error>();
}
}