use std::collections::HashMap;
use std::fmt::Debug;
use serde::Deserialize;
use serde_json::Value;
use crate::errors::PrimaBridgeError;
pub type ParsedGraphqlResponse<T> = Result<T, PossiblyParsedData<T>>;
pub trait ParsedGraphqlResponseExt<T>
where
for<'de> T: Deserialize<'de>,
{
fn from_str(body_as_str: &str) -> Result<Self, PrimaBridgeError>
where
Self: Sized;
fn get_errors(&self) -> Vec<Error>;
fn has_parsed_data(&self) -> bool;
}
impl<T> ParsedGraphqlResponseExt<T> for ParsedGraphqlResponse<T>
where
for<'de> T: Deserialize<'de>,
{
fn from_str(body_as_str: &str) -> Result<Self, PrimaBridgeError> {
let result: serde_json::Result<GraphqlResponse<T>> = serde_json::from_str(body_as_str);
match result {
Ok(t) => Ok(t.into()),
Err(_e) => {
let value: Value = serde_json::from_str(body_as_str)?;
Ok(Err(PossiblyParsedData::UnparsedData(value, vec![])))
}
}
}
fn get_errors(&self) -> Vec<Error> {
match self {
Ok(_) => vec![],
Err(possibly_parsed_data) => match possibly_parsed_data {
PossiblyParsedData::ParsedData(_, errors) => errors.to_vec(),
PossiblyParsedData::UnparsedData(_, errors) => errors.to_vec(),
PossiblyParsedData::EmptyData(errors) => errors.to_vec(),
},
}
}
fn has_parsed_data(&self) -> bool {
matches!(
self,
ParsedGraphqlResponse::Ok(_) | ParsedGraphqlResponse::Err(PossiblyParsedData::ParsedData(..))
)
}
}
#[derive(Deserialize, Debug)]
struct GraphqlResponse<T> {
pub data: Option<T>,
pub errors: Option<Vec<Error>>,
}
impl<T> From<GraphqlResponse<T>> for ParsedGraphqlResponse<T> {
fn from(gql_response: GraphqlResponse<T>) -> Self {
match (gql_response.data, gql_response.errors) {
(Some(t), None) => Ok(t),
(Some(t), Some(errors)) => Err(PossiblyParsedData::ParsedData(t, errors)),
(None, Some(errors)) => Err(PossiblyParsedData::EmptyData(errors)),
_ => Err(PossiblyParsedData::EmptyData(vec![])),
}
}
}
#[derive(Deserialize, Debug, Clone)]
pub struct Error {
pub message: String,
pub locations: Option<Vec<Location>>,
pub path: Option<Vec<PathSegment>>,
pub extensions: Option<HashMap<String, String>>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct Location {
pub line: u32,
pub column: u32,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum PathSegment {
String(String),
Num(u32),
}
#[derive(Debug)]
pub enum PossiblyParsedData<T> {
ParsedData(T, Vec<Error>),
UnparsedData(Value, Vec<Error>),
EmptyData(Vec<Error>),
}