#[cfg(feature = "cosmos")]
use gremlin_client::GremlinError;
use std::fmt::{Display, Formatter};
use std::num::ParseIntError;
#[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 },
#[cfg(feature = "cosmos")]
CosmosActionFailed {
source: Box<gremlin_client::GremlinError>,
},
DatabaseNotFound,
DeserializationFailed { source: serde_yaml::Error },
EnvironmentVariableNotFound { name: String },
EnvironmentVariableNotParsed { source: ParseIntError },
ExtensionFailed {
source: Box<dyn std::error::Error + Sync + Send>,
},
InputItemNotFound { name: String },
LabelNotFound,
#[cfg(feature = "neo4j")]
Neo4jQueryFailed {
message: bolt_proto::message::Message,
},
#[cfg(feature = "neo4j")]
Neo4jPoolError {
source: bb8::RunError<bb8_bolt::Error>,
},
#[cfg(feature = "neo4j")]
Neo4jPoolNotBuilt { source: bb8_bolt::Error },
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,
ValidationFailed { message: String },
ValidatorNotFound { name: String },
}
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)
}
#[cfg(feature = "cosmos")]
Error::CosmosActionFailed { source } => {
write!(f, "Either building a database connection pool or query failed. Source error: {}", source)
}
Error::DatabaseNotFound => {
write!(f, "Use of resolvers required a database back-end. Please select either cosmos or neo4j.")
}
Error::DeserializationFailed { source } => {
write!(f, "Failed to deserialize configuration. Source error: {}", source)
}
Error::EnvironmentVariableNotFound { name } => {
write!(f, "Could not find environment variable: {}", name)
}
Error::EnvironmentVariableNotParsed { source } => {
write!(f, "Failed to parse environment variable to integer port number. Source error: {}", source)
}
Error::ExtensionFailed { source } => {
write!(f, "Extension returned an error: {}", source)
}
Error::InputItemNotFound { name } => {
write!(f, "Could not find an expected argument, {}, in the GraphQL query.", name)
}
Error::LabelNotFound => {
write!(f, "Could not find a label for a destination node.")
}
#[cfg(feature = "neo4j")]
Error::Neo4jPoolNotBuilt { source } => {
write!(f, "Could not build database connection pool for Neo4J. Source error: {}.", source)
}
#[cfg(feature = "neo4j")]
Error::Neo4jPoolError { source } => {
write!(f, "Failed to get connection from Neo4j Pool. Source error: {}", 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 => {
write!(f, "Warpgrapher encountered a type that was not expected, such as a non-string ID")
}
Error::ValidationFailed { message } => {
write!(f, "{}", message)
}
Error::ValidatorNotFound { name } => {
write!(f, "A validator function named {} could not be found", name)
}
}
}
}
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,
#[cfg(feature = "cosmos")]
Error::CosmosActionFailed { source } => Some(source),
Error::DatabaseNotFound => None,
Error::DeserializationFailed { source } => Some(source),
Error::EnvironmentVariableNotFound { name: _ } => None,
Error::EnvironmentVariableNotParsed { source } => Some(source),
Error::ExtensionFailed { source } => Some(source.as_ref()),
Error::InputItemNotFound { name: _ } => None,
Error::LabelNotFound => None,
#[cfg(feature = "neo4j")]
Error::Neo4jPoolNotBuilt { source } => Some(source),
#[cfg(feature = "neo4j")]
Error::Neo4jPoolError { 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 => None,
Error::ValidationFailed { message: _ } => None,
Error::ValidatorNotFound { name: _ } => None,
}
}
}
impl From<Box<dyn std::error::Error + Sync + Send>> for Error {
fn from(e: Box<dyn std::error::Error + Sync + Send>) -> Self {
Error::ExtensionFailed { source: e }
}
}
#[cfg(feature = "neo4j")]
impl From<bb8_bolt::Error> for Error {
fn from(e: bb8_bolt::Error) -> Self {
Error::Neo4jPoolNotBuilt { 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(feature = "cosmos")]
impl From<GremlinError> for Error {
fn from(e: GremlinError) -> Self {
Error::CosmosActionFailed {
source: Box::new(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::DeserializationFailed { source: e }
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::ConfigOpenFailed { source: e }
}
}
impl From<std::num::ParseIntError> for Error {
fn from(e: std::num::ParseIntError) -> Self {
Error::EnvironmentVariableNotParsed { 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 }
}
}
#[cfg(feature = "neo4j")]
impl From<bb8::RunError<bb8_bolt::Error>> for Error {
fn from(e: bb8::RunError<bb8_bolt::Error>) -> Self {
Error::Neo4jPoolError { 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>();
}
}