use crate::graphql_scalar;
mod for_minimal_versions_check_only {
use tap as _;
}
#[graphql_scalar]
#[graphql(
name = "ObjectID",
with = object_id,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/object-id",
)]
type ObjectId = bson::oid::ObjectId;
mod object_id {
use super::ObjectId;
pub(super) fn to_output(v: &ObjectId) -> String {
v.to_hex()
}
pub(super) fn from_input(s: &str) -> Result<ObjectId, Box<str>> {
ObjectId::parse_str(s).map_err(|e| format!("Failed to parse `ObjectID`: {e}").into())
}
}
#[graphql_scalar]
#[graphql(
with = date_time,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/date-time",
)]
type DateTime = bson::DateTime;
mod date_time {
use super::DateTime;
pub(super) fn to_output(v: &DateTime) -> String {
(*v).try_to_rfc3339_string()
.unwrap_or_else(|e| panic!("failed to format `DateTime` as RFC 3339: {e}"))
}
pub(super) fn from_input(s: &str) -> Result<DateTime, Box<str>> {
DateTime::parse_rfc3339_str(s)
.map_err(|e| format!("Failed to parse `DateTime`: {e}").into())
}
}
#[cfg(test)]
mod test {
use bson::oid::ObjectId;
use crate::{FromInputValue, InputValue, graphql_input_value};
#[test]
fn objectid_from_input() {
let raw = "53e37d08776f724e42000000";
let input: InputValue = graphql_input_value!((raw));
let parsed: ObjectId = FromInputValue::from_input_value(&input).unwrap();
let id = ObjectId::parse_str(raw).unwrap();
assert_eq!(parsed, id);
}
}
#[cfg(test)]
mod date_time_test {
use crate::{FromInputValue as _, InputValue, ToInputValue as _, graphql_input_value};
use super::DateTime;
#[test]
fn parses_correct_input() {
for (raw, expected) in [
(
"2014-11-28T21:00:09+09:00",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(12)
.second(9)
.build()
.unwrap(),
),
(
"2014-11-28T21:00:09Z",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(21)
.second(9)
.build()
.unwrap(),
),
(
"2014-11-28 21:00:09z",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(21)
.second(9)
.build()
.unwrap(),
),
(
"2014-11-28T21:00:09+00:00",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(21)
.second(9)
.build()
.unwrap(),
),
(
"2014-11-28T21:00:09.05+09:00",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(12)
.second(9)
.millisecond(50)
.build()
.unwrap(),
),
(
"2014-11-28 21:00:09.05+09:00",
DateTime::builder()
.year(2014)
.month(11)
.day(28)
.hour(12)
.second(9)
.millisecond(50)
.build()
.unwrap(),
),
] {
let input: InputValue = graphql_input_value!((raw));
let parsed = DateTime::from_input_value(&input);
assert!(
parsed.is_ok(),
"failed to parse `{raw}`: {:?}",
parsed.unwrap_err(),
);
assert_eq!(parsed.unwrap(), expected, "input: {raw}");
}
}
#[test]
fn fails_on_invalid_input() {
for input in [
graphql_input_value!("12"),
graphql_input_value!("12:"),
graphql_input_value!("56:34:22"),
graphql_input_value!("56:34:22.000"),
graphql_input_value!("1996-12-1914:23:43"),
graphql_input_value!("1996-12-19T14:23:43"),
graphql_input_value!("1996-12-19T14:23:43ZZ"),
graphql_input_value!("1996-12-19T14:23:43.543"),
graphql_input_value!("1996-12-19T14:23"),
graphql_input_value!("1996-12-19T14:23:1"),
graphql_input_value!("1996-12-19T14:23:"),
graphql_input_value!("1996-12-19T23:78:43Z"),
graphql_input_value!("1996-12-19T23:18:99Z"),
graphql_input_value!("1996-12-19T24:00:00Z"),
graphql_input_value!("1996-12-19T99:02:13Z"),
graphql_input_value!("1996-12-19T99:02:13Z"),
graphql_input_value!("1996-12-19T12:02:13+4444444"),
graphql_input_value!("i'm not even a datetime"),
graphql_input_value!(2.32),
graphql_input_value!(1),
graphql_input_value!(null),
graphql_input_value!(false),
] {
let input: InputValue = input;
let parsed = DateTime::from_input_value(&input);
assert!(parsed.is_err(), "allows input: {input:?}");
}
}
#[test]
fn formats_correctly() {
for (val, expected) in [
(
DateTime::builder()
.year(1996)
.month(12)
.day(19)
.hour(12)
.build()
.unwrap(),
graphql_input_value!("1996-12-19T12:00:00Z"),
),
(
DateTime::builder()
.year(1564)
.month(1)
.day(30)
.hour(5)
.minute(3)
.second(3)
.millisecond(1)
.build()
.unwrap(),
graphql_input_value!("1564-01-30T05:03:03.001Z"),
),
] {
let actual: InputValue = val.to_input_value();
assert_eq!(actual, expected, "on value: {val}");
}
}
}