cido 0.2.0

Core traits and implementations for indexing with cido
Documentation
use crate::sql::order_direction::Direction;

#[derive(Debug, Clone)]
pub enum GraphqlOrderDirection {
  Single(Direction),
  Multiple(Vec<Direction>),
}

impl Default for GraphqlOrderDirection {
  fn default() -> Self {
    Self::new()
  }
}

impl GraphqlOrderDirection {
  pub const fn new() -> Self {
    Self::asc()
  }

  pub const fn desc() -> Self {
    Self::Single(Direction::Desc)
  }

  pub const fn asc() -> Self {
    Self::Single(Direction::Asc)
  }

  pub fn first_direction(&self) -> Direction {
    match self {
      Self::Single(d) => *d,
      Self::Multiple(v) => v.first().copied().unwrap_or_else(Direction::default),
    }
  }
}

impl async_graphql::InputType for GraphqlOrderDirection {
  type RawValueType = Self;

  fn type_name() -> std::borrow::Cow<'static, str> {
    // we can do this as long as we never actually register the `Direction` type
    "OrderDirection".into()
  }

  fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
    registry.create_input_type::<Self, _>(async_graphql::registry::MetaTypeId::Enum, |_| {
      async_graphql::registry::MetaType::Enum {
        name: Self::type_name().to_string(),
        description: Some("Defines the order direction, either ascending or descending".into()),
        enum_values: {
          let mut map = async_graphql::indexmap::IndexMap::new();
          map.insert("asc".to_string(), async_graphql::registry::MetaEnumValue {
            name: "asc".into(),
            description: Some("asc for ascending".into()),
            deprecation: async_graphql::registry::Deprecation::NoDeprecated,
            visible: None,
            inaccessible: false,
            tags: vec![],
            directive_invocations: vec![],
          });
          map.insert("desc".to_string(), async_graphql::registry::MetaEnumValue {
            name: "desc".into(),
            description: Some("desc for descending".into()),
            deprecation: async_graphql::registry::Deprecation::NoDeprecated,
            visible: None,
            inaccessible: false,
            tags: vec![],
            directive_invocations: vec![],
          });
          map
        },
        visible: None,
        rust_typename: Some(std::any::type_name::<Self>()),
        inaccessible: false,
        tags: vec![],
        directive_invocations: vec![],
      }
    })
  }

  fn parse(value: Option<async_graphql::Value>) -> async_graphql::InputValueResult<Self> {
    match value {
      Some(val) => match val {
        async_graphql::Value::String(d) => d
          .parse::<Direction>()
          .map(Self::Single)
          .map_err(async_graphql::InputValueError::custom),
        async_graphql::Value::Enum(d) => d
          .parse::<Direction>()
          .map(Self::Single)
          .map_err(async_graphql::InputValueError::custom),
        async_graphql::Value::List(directions) => {
          let mut set = async_graphql::indexmap::IndexSet::with_capacity(directions.len());
          for d in directions {
            set.insert(
              Direction::parse(Some(d)).map_err(async_graphql::InputValueError::propagate)?,
            );
          }
          let mut v = set.into_iter().collect::<Vec<_>>();
          if v.len() == 1 {
            return Ok(Self::Single(v.pop().unwrap()));
          }
          Ok(Self::Multiple(v))
        }
        x => async_graphql::Result::Err(async_graphql::InputValueError::expected_type(x)),
      },
      None => async_graphql::Result::Err(async_graphql::InputValueError::expected_type(
        value.unwrap_or_default(),
      )),
    }
  }

  fn to_value(&self) -> async_graphql::Value {
    match self {
      GraphqlOrderDirection::Single(direction) => {
        async_graphql::Value::Enum(async_graphql::Name::new(direction))
      }
      GraphqlOrderDirection::Multiple(directions) => async_graphql::Value::List(
        directions
          .iter()
          .map(|d| async_graphql::Value::Enum(async_graphql::Name::new(d)))
          .collect(),
      ),
    }
  }

  fn as_raw_value(&self) -> Option<&Self::RawValueType> {
    Some(self)
  }
}

impl async_graphql::InputObjectType for GraphqlOrderDirection {}

#[test]
fn test_order_direction() {
  use async_graphql::{InputType, value};
  let asc = Direction::parse(Some(value!("asc"))).unwrap();
  assert_eq!(asc, Direction::Asc);
  let desc = Direction::parse(Some(value!("desc"))).unwrap();
  assert_eq!(desc, Direction::Desc);
}