use std::backtrace;
use std::fmt::Debug;
use async_graphql::{InputType, InputValueError};
use surrealdb_types::ToSql;
use thiserror::Error;
use crate::expr::Kind;
#[derive(Error, Debug)]
pub enum GraphqlError {
#[error("Database error: {0}")]
DbError(#[from] anyhow::Error),
#[error("Error generating schema: {0}")]
SchemaError(String),
#[error("Error resolving request: {0}")]
ResolverError(String),
#[error("No Namespace specified")]
UnspecifiedNamespace,
#[error("No Database specified")]
UnspecifiedDatabase,
#[error("GraphQL has not been configured for this database")]
NotConfigured,
#[error("Internal Error: {0}")]
InternalError(String),
#[error("Authentication error: {0}")]
AuthError(String),
#[error("Error converting value: {val} to type: {}", target.to_sql())]
TypeError {
target: Kind,
val: async_graphql::Value,
},
}
pub fn schema_error(msg: impl Into<String>) -> GraphqlError {
GraphqlError::SchemaError(msg.into())
}
pub fn resolver_error(msg: impl Into<String>) -> GraphqlError {
GraphqlError::ResolverError(msg.into())
}
pub fn auth_error(msg: impl Into<String>) -> GraphqlError {
GraphqlError::AuthError(msg.into())
}
pub fn internal_error(msg: impl Into<String>) -> GraphqlError {
let msg = msg.into();
let bt = backtrace::Backtrace::capture();
error!("{}\n{bt}", msg);
GraphqlError::InternalError(msg)
}
pub fn type_error(kind: Kind, val: &async_graphql::Value) -> GraphqlError {
GraphqlError::TypeError {
target: kind,
val: val.to_owned(),
}
}
impl<T> From<InputValueError<T>> for GraphqlError
where
T: InputType + Debug,
{
fn from(value: InputValueError<T>) -> Self {
GraphqlError::ResolverError(format!("{value:?}"))
}
}
impl From<GraphqlError> for async_graphql::Error {
fn from(value: GraphqlError) -> Self {
async_graphql::Error::new(value.to_string())
}
}