Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend-errors #15

Merged
merged 4 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 4 additions & 219 deletions crates/sdk/src/connector.rs
Original file line number Diff line number Diff line change
@@ -1,225 +1,10 @@
use std::error::Error;
use std::fmt::Display;
use std::path::{Path, PathBuf};

use crate::json_response::JsonResponse;
use async_trait::async_trait;
use ndc_models as models;
use serde::Serialize;
use thiserror::Error;

use crate::json_response::JsonResponse;

use std::path::Path;
pub mod error;
pub mod example;

/// Errors which occur when trying to validate connector
/// configuration.
///
/// See [`Connector::parse_configuration`].
#[derive(Debug, Error)]
pub enum ParseError {
#[error("error parsing configuration: {0}")]
ParseError(LocatedError),
#[error("error validating configuration: {0}")]
ValidateError(InvalidNodes),
#[error("could not find configuration file: {0}")]
CouldNotFindConfiguration(PathBuf),
#[error("error processing configuration: {0}")]
IoError(#[from] std::io::Error),
#[error("error processing configuration: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// An error associated with the position of a single character in a text file.
#[derive(Debug, Clone)]
pub struct LocatedError {
pub file_path: PathBuf,
pub line: usize,
pub column: usize,
pub message: String,
}

impl Display for LocatedError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{0}:{1}:{2}: {3}",
self.file_path.display(),
self.line,
self.column,
self.message
)
}
}

/// An error associated with a node in a graph structure.
#[derive(Debug, Clone)]
pub struct InvalidNode {
pub file_path: PathBuf,
pub node_path: Vec<KeyOrIndex>,
pub message: String,
}

impl Display for InvalidNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}, at ", self.file_path.display())?;
for segment in &self.node_path {
write!(f, ".{segment}")?;
}
write!(f, ": {}", self.message)?;
Ok(())
}
}

/// A set of invalid nodes.
#[derive(Debug, Clone)]
pub struct InvalidNodes(pub Vec<InvalidNode>);

impl Display for InvalidNodes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iterator = self.0.iter();
if let Some(first) = iterator.next() {
first.fmt(f)?;
}
for next in iterator {
write!(f, ", {next}")?;
}
Ok(())
}
}

/// A segment in a node path, used with [InvalidNode].
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum KeyOrIndex {
Key(String),
Index(u32),
}

impl Display for KeyOrIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Key(key) => write!(f, "[{key:?}]"),
Self::Index(index) => write!(f, "[{index}]"),
}
}
}

/// Errors which occur when trying to initialize connector
/// state.
///
/// See [`Connector::try_init_state`].
#[derive(Debug, Error)]
pub enum InitializationError {
#[error("error initializing connector state: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when trying to update metrics.
///
/// See [`Connector::fetch_metrics`].
#[derive(Debug, Error)]
pub enum FetchMetricsError {
#[error("error fetching metrics: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when checking connector health.
///
/// See [`Connector::health_check`].
#[derive(Debug, Error)]
pub enum HealthError {
#[error("error checking health status: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when retrieving the connector schema.
///
/// See [`Connector::get_schema`].
#[derive(Debug, Error)]
pub enum SchemaError {
#[error("error retrieving the schema: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when executing a query.
///
/// See [`Connector::query`].
#[derive(Debug, Error)]
pub enum QueryError {
/// The request was invalid or did not match the
/// requirements of the specification. This indicates
/// an error with the client.
#[error("invalid request: {0}")]
InvalidRequest(String),
/// The request was well formed but was unable to be
/// followed due to semantic errors. This indicates
/// an error with the client.
#[error("unprocessable content: {0}")]
UnprocessableContent(String),
/// The request relies on an unsupported feature or
/// capability. This may indicate an error with the client,
/// or just an unimplemented feature.
#[error("unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("error executing query: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when explaining a query.
///
/// See [`Connector::query_explain`, `Connector::mutation_explain`].
#[derive(Debug, Error)]
pub enum ExplainError {
/// The request was invalid or did not match the
/// requirements of the specification. This indicates
/// an error with the client.
#[error("invalid request: {0}")]
InvalidRequest(String),
/// The request was well formed but was unable to be
/// followed due to semantic errors. This indicates
/// an error with the client.
#[error("unprocessable content: {0}")]
UnprocessableContent(String),
/// The request relies on an unsupported feature or
/// capability. This may indicate an error with the client,
/// or just an unimplemented feature.
#[error("unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("explain error: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}

/// Errors which occur when executing a mutation.
///
/// See [`Connector::mutation`].
#[derive(Debug, Error)]
pub enum MutationError {
/// The request was invalid or did not match the
/// requirements of the specification. This indicates
/// an error with the client.
#[error("invalid request: {0}")]
InvalidRequest(String),
/// The request was well formed but was unable to be
/// followed due to semantic errors. This indicates
/// an error with the client.
#[error("unprocessable content: {0}")]
UnprocessableContent(String),
/// The request relies on an unsupported feature or
/// capability. This may indicate an error with the client,
/// or just an unimplemented feature.
#[error("unsupported operation: {0}")]
UnsupportedOperation(String),
/// The request would result in a conflicting state
/// in the underlying data store.
#[error("mutation would result in a conflicting state: {0}")]
Conflict(String),
/// The request would violate a constraint in the
/// underlying data store.
#[error("mutation violates constraint: {0}")]
ConstraintNotMet(String),
#[error("error executing mutation: {0}")]
Other(#[from] Box<dyn Error + Send + Sync>),
}
pub use error::*;

/// Connectors using this library should implement this trait.
///
Expand Down
Loading
Loading