use base64::prelude::*;
use juniper::{ParseScalarResult, ParseScalarValue, ScalarToken, ScalarValue};
use crate::CursorError;
pub const CURSOR_SEGMENT_DELIMITER: &str = "||";
pub trait Cursor {
type CursorType;
fn to_raw_string(&self) -> String;
fn new(raw: &str, parts: Vec<&str>) -> Result<Self::CursorType, CursorError>;
fn from_encoded_string(input: &str) -> Result<Self::CursorType, CursorError> {
let decoded = BASE64_URL_SAFE.decode(input)?;
let decoded_string = String::from_utf8(decoded)?;
Self::new(
decoded_string.as_str(),
decoded_string.split(CURSOR_SEGMENT_DELIMITER).collect(),
)
}
fn to_encoded_string(&self) -> String {
BASE64_URL_SAFE.encode(self.to_raw_string().as_bytes())
}
fn to_output(&self) -> String {
self.to_encoded_string()
}
fn from_input(input: &str) -> Result<Self::CursorType, Box<str>> {
let res = Self::from_encoded_string(input);
match res {
Ok(cursor) => Ok(cursor),
Err(err) => Err(err.to_string().into_boxed_str()),
}
}
fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
<String as ParseScalarValue<S>>::from_str(value)
}
}
pub fn cursor_from_encoded_string<T>(input: &str) -> Result<T, CursorError>
where
T: Cursor<CursorType = T>,
{
let cursor = T::from_encoded_string(input)?;
Ok(cursor)
}