use std::fmt;
use serde_json::Value;
use crate::error::Result;
pub trait CustomScalar: Send + Sync + fmt::Debug {
fn name(&self) -> &str;
fn serialize(&self, value: &Value) -> Result<Value>;
fn parse_value(&self, value: &Value) -> Result<Value>;
fn parse_literal(&self, ast: &Value) -> Result<Value>;
}
pub type CustomScalarResult = Result<Value>;
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use serde_json::{Value, json};
use super::CustomScalar;
use crate::error::{FraiseQLError, Result};
#[derive(Debug)]
struct EmailScalar;
#[allow(clippy::unnecessary_literal_bound)] impl CustomScalar for EmailScalar {
fn name(&self) -> &str {
"Email"
}
fn serialize(&self, value: &Value) -> Result<Value> {
Ok(value.clone())
}
fn parse_value(&self, value: &Value) -> Result<Value> {
let s = value
.as_str()
.ok_or_else(|| FraiseQLError::validation("Email must be a string"))?;
if !s.contains('@') {
return Err(FraiseQLError::validation(format!("invalid email: {s}")));
}
Ok(Value::String(s.to_string()))
}
fn parse_literal(&self, ast: &Value) -> Result<Value> {
self.parse_value(ast)
}
}
#[test]
fn test_name() {
let scalar = EmailScalar;
assert_eq!(scalar.name(), "Email");
}
#[test]
fn test_serialize_returns_value_unchanged() {
let scalar = EmailScalar;
let v = json!("user@example.com");
assert_eq!(scalar.serialize(&v).unwrap(), v);
}
#[test]
fn test_parse_value_valid_email() {
let scalar = EmailScalar;
let v = json!("user@example.com");
assert_eq!(scalar.parse_value(&v).unwrap(), v);
}
#[test]
fn test_parse_value_invalid_email_no_at() {
let scalar = EmailScalar;
let v = json!("notanemail");
assert!(
matches!(scalar.parse_value(&v), Err(crate::error::FraiseQLError::Validation { .. })),
"email without '@' should fail with Validation error, got: {:?}",
scalar.parse_value(&v)
);
}
#[test]
fn test_parse_value_non_string_input() {
let scalar = EmailScalar;
let v = json!(42);
let err = scalar.parse_value(&v).unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("string") || msg.contains("Email"), "unexpected: {msg}");
}
#[test]
fn test_parse_literal_delegates_to_parse_value() {
let scalar = EmailScalar;
let v = json!("lit@example.com");
assert_eq!(scalar.parse_literal(&v).unwrap(), v);
}
#[test]
fn test_custom_scalar_result_type_alias_is_result_value() {
let _result: super::CustomScalarResult = Ok(json!("ok"));
}
}