use crate::{api::Response, Value};
use serde::Serialize;
use std::path::PathBuf;
use std::{convert::Infallible, io};
use surrealdb_core::dbs::capabilities::{ParseFuncTargetError, ParseNetTargetError};
use thiserror::Error;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("{0}")]
Query(String),
#[error("There was an error processing a remote HTTP request: {0}")]
Http(String),
#[error("There was an error processing a remote WS request: {0}")]
Ws(String),
#[error("Unsupported protocol or storage engine, `{0}`")]
Scheme(String),
#[error("Connection uninitialised")]
ConnectionUninitialised,
#[error("Already connected")]
AlreadyConnected,
#[error("Invalid bindings: {0}")]
InvalidBindings(Value),
#[error("Tried to add a range to an record-id resource")]
RangeOnRecordId,
#[error("Tried to add a range to an object resource")]
RangeOnObject,
#[error("Tried to add a range to an array resource")]
RangeOnArray,
#[error("Tried to add a range to an edge resource")]
RangeOnEdges,
#[error("Tried to add a range to a resource which was already a range")]
RangeOnRange,
#[error("Tried to add a range to an unspecified resource")]
RangeOnUnspecified,
#[error("Table name `{table}` contained a colon (:), this is dissallowed to avoid confusion with record-id's try `Table(\"{table}\")` instead.")]
TableColonId {
table: String,
},
#[error("Duplicate request ID: {0}")]
DuplicateRequestId(i64),
#[error("Invalid request: {0}")]
InvalidRequest(String),
#[error("Invalid params: {0}")]
InvalidParams(String),
#[error("Internal error: {0}")]
InternalError(String),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Invalid semantic version: {0}")]
InvalidSemanticVersion(String),
#[error("Invalid URL: {0}")]
InvalidUrl(String),
#[error("Failed to convert `{value}` to `T`: {error}")]
FromValue {
value: Value,
error: String,
},
#[error("Failed to deserialize a binary response: {error}")]
ResponseFromBinary {
binary: Vec<u8>,
error: bincode::Error,
},
#[error("Failed to serialize `{value}` to JSON string: {error}")]
ToJsonString {
value: Value,
error: String,
},
#[error("Failed to deserialize `{string}` to sql::Value: {error}")]
FromJsonString {
string: String,
error: String,
},
#[error("Invalid namespace name: {0:?}")]
InvalidNsName(String),
#[error("Invalid database name: {0:?}")]
InvalidDbName(String),
#[error("Failed to open `{path}`: {error}")]
FileOpen {
path: PathBuf,
error: io::Error,
},
#[error("Failed to read `{path}`: {error}")]
FileRead {
path: PathBuf,
error: io::Error,
},
#[error("Tried to take only a single result from a query that contains multiple")]
LossyTake(Response),
#[error("The protocol or storage engine does not support backups on this architecture")]
BackupsNotSupported,
#[error("server version `{server_version}` does not match the range supported by the client `{supported_versions}`")]
VersionMismatch {
server_version: semver::Version,
supported_versions: String,
},
#[error("server build `{server_metadata}` is older than the minimum supported build `{supported_metadata}`")]
BuildMetadataMismatch {
server_metadata: semver::BuildMetadata,
supported_metadata: semver::BuildMetadata,
},
#[error("The protocol or storage engine does not support live queries on this architecture")]
LiveQueriesNotSupported,
#[error("Live queries on objects not supported")]
LiveOnObject,
#[error("Live queries on arrays not supported")]
LiveOnArray,
#[error("Live queries on edges not supported")]
LiveOnEdges,
#[error("Live queries on unspecified resource not supported")]
LiveOnUnspecified,
#[error("Query statement {0} is not a live query")]
NotLiveQuery(usize),
#[error("Query statement {0} is out of bounds")]
QueryIndexOutOfBounds(usize),
#[error("Tried to take a query response that has already been taken")]
ResponseAlreadyTaken,
#[error("Insert queries on objects are not supported")]
InsertOnObject,
#[error("Insert queries on arrays are not supported")]
InsertOnArray,
#[error("Insert queries on edges are not supported")]
InsertOnEdges,
#[error("Insert queries on ranges are not supported")]
InsertOnRange,
#[error("Insert queries on unspecified resource with no data are not supported")]
InsertOnUnspecified,
#[error("{0}")]
InvalidNetTarget(#[from] ParseNetTargetError),
#[error("{0}")]
InvalidFuncTarget(#[from] ParseFuncTargetError),
#[error("failed to serialize Value: {0}")]
SerializeValue(String),
#[error("failed to deserialize Value: {0}")]
DeSerializeValue(String),
#[error("failed to serialize to a Value: {0}")]
Serializer(String),
#[error("failed to deserialize from a Value: {0}")]
Deserializer(String),
#[error("tried to convert from a value which contained non-primitive values to a value which only allows primitive values.")]
RecievedInvalidValue,
}
impl serde::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
Error::SerializeValue(msg.to_string())
}
}
impl serde::de::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
Error::DeSerializeValue(msg.to_string())
}
}
impl From<Infallible> for crate::Error {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
impl From<ParseNetTargetError> for crate::Error {
fn from(e: ParseNetTargetError) -> Self {
Self::Api(Error::from(e))
}
}
impl From<ParseFuncTargetError> for crate::Error {
fn from(e: ParseFuncTargetError) -> Self {
Self::Api(Error::from(e))
}
}
#[cfg(feature = "protocol-http")]
impl From<reqwest::Error> for crate::Error {
fn from(e: reqwest::Error) -> Self {
Self::Api(Error::Http(e.to_string()))
}
}
#[cfg(all(feature = "protocol-ws", not(target_arch = "wasm32")))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "protocol-ws", not(target_arch = "wasm32")))))]
impl From<tokio_tungstenite::tungstenite::Error> for crate::Error {
fn from(error: tokio_tungstenite::tungstenite::Error) -> Self {
Self::Api(Error::Ws(error.to_string()))
}
}
impl<T> From<channel::SendError<T>> for crate::Error {
fn from(error: channel::SendError<T>) -> Self {
Self::Api(Error::InternalError(error.to_string()))
}
}
impl From<channel::RecvError> for crate::Error {
fn from(error: channel::RecvError) -> Self {
Self::Api(Error::InternalError(error.to_string()))
}
}
impl From<url::ParseError> for crate::Error {
fn from(error: url::ParseError) -> Self {
Self::Api(Error::InternalError(error.to_string()))
}
}
#[cfg(all(feature = "protocol-ws", target_arch = "wasm32"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "protocol-ws", target_arch = "wasm32"))))]
impl From<ws_stream_wasm::WsErr> for crate::Error {
fn from(error: ws_stream_wasm::WsErr) -> Self {
Self::Api(Error::Ws(error.to_string()))
}
}
#[cfg(all(feature = "protocol-ws", target_arch = "wasm32"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "protocol-ws", target_arch = "wasm32"))))]
impl From<pharos::PharErr> for crate::Error {
fn from(error: pharos::PharErr) -> Self {
Self::Api(Error::Ws(error.to_string()))
}
}
impl Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}