versa 1.9.0-rc2

Versa types and utilities for developing Versa client applications in Rust
Documentation
use serde::{Deserialize, Serialize};

// Feature flagged imports

use std::fmt;
#[cfg(feature = "diesel")]
use std::io::Write;

#[cfg(feature = "diesel")]
use diesel::deserialize::{self, FromSql, FromSqlRow};
#[cfg(feature = "diesel")]
use diesel::prelude::*;
#[cfg(feature = "diesel")]
use diesel::serialize::{self, IsNull, Output, ToSql};
#[cfg(feature = "diesel")]
use diesel::{expression::AsExpression, sql_types::Text};

#[cfg(feature = "diesel")]
use diesel::mysql::{Mysql, MysqlValue};

use crate::protocol::webhook::WebhookEventType;

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
#[cfg_attr(
  feature = "diesel",
  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
)]
#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
#[cfg_attr(test, derive(strum::EnumIter))]
pub enum EventType {
  #[serde(rename = "booking")]
  Booking,
  #[serde(rename = "invoice")]
  Invoice,
  #[serde(rename = "itinerary")]
  Itinerary,
  #[serde(rename = "receipt")]
  Receipt,
  #[serde(rename = "transit_route.status.updated")]
  TransitRouteStatusUpdated,
  #[serde(rename = "transit_route.location.updated")]
  TransitRouteLocationUpdated,
}

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
#[cfg_attr(
  feature = "diesel",
  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
)]
#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
#[cfg_attr(test, derive(strum::EnumIter))]
pub enum InitialEventType {
  #[serde(rename = "booking")]
  Booking,
  #[serde(rename = "invoice")]
  Invoice,
  #[serde(rename = "itinerary")]
  Itinerary,
  #[serde(rename = "receipt")]
  Receipt,
}

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
#[cfg_attr(
  feature = "diesel",
  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
)]
#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
#[cfg_attr(test, derive(strum::EnumIter))]
pub enum UpdateEventType {
  #[serde(rename = "transit_route.status.updated")]
  TransitRouteStatusUpdated,
  #[serde(rename = "transit_route.location.updated")]
  TransitRouteLocationUpdated,
}

impl From<InitialEventType> for EventType {
  fn from(event: InitialEventType) -> Self {
    match event {
      InitialEventType::Booking => EventType::Booking,
      InitialEventType::Invoice => EventType::Invoice,
      InitialEventType::Itinerary => EventType::Itinerary,
      InitialEventType::Receipt => EventType::Receipt,
    }
  }
}

impl From<UpdateEventType> for EventType {
  fn from(event: UpdateEventType) -> Self {
    match event {
      UpdateEventType::TransitRouteStatusUpdated => EventType::TransitRouteStatusUpdated,
      UpdateEventType::TransitRouteLocationUpdated => EventType::TransitRouteLocationUpdated,
    }
  }
}

impl fmt::Display for EventType {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let serialized = serde_json::to_string(self).unwrap().replace("\"", "");
    write!(f, "{}", serialized)
  }
}

impl fmt::Display for InitialEventType {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let serialized = serde_json::to_string(self).unwrap().replace("\"", "");
    write!(f, "{}", serialized)
  }
}

impl fmt::Display for UpdateEventType {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let serialized = serde_json::to_string(self).unwrap().replace("\"", "");
    write!(f, "{}", serialized)
  }
}

impl EventType {
  pub fn is_update_event(&self) -> bool {
    matches!(
      self,
      EventType::TransitRouteStatusUpdated | EventType::TransitRouteLocationUpdated
    )
  }
  pub fn is_initial_event(&self) -> bool {
    matches!(self, EventType::Itinerary | EventType::Receipt)
  }

  pub fn update_event_type(&self) -> Option<UpdateEventType> {
    match self {
      EventType::TransitRouteStatusUpdated => Some(UpdateEventType::TransitRouteStatusUpdated),
      EventType::TransitRouteLocationUpdated => Some(UpdateEventType::TransitRouteLocationUpdated),
      _ => None,
    }
  }

  pub fn initial_event_type(&self) -> Option<InitialEventType> {
    match self {
      EventType::Itinerary => Some(InitialEventType::Itinerary),
      EventType::Receipt => Some(InitialEventType::Receipt),
      _ => None,
    }
  }
}

impl From<EventType> for WebhookEventType {
  fn from(event: EventType) -> Self {
    match event {
      EventType::Booking => WebhookEventType::Booking,
      EventType::Invoice => WebhookEventType::Invoice,
      EventType::Itinerary => WebhookEventType::Itinerary,
      EventType::Receipt => WebhookEventType::Receipt,
      EventType::TransitRouteStatusUpdated => WebhookEventType::TransitRouteStatusUpdated,
      EventType::TransitRouteLocationUpdated => WebhookEventType::TransitRouteLocationUpdated,
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use strum::IntoEnumIterator;

  #[test]
  fn test_all_event_types_serialize_to_webhook_event_type() {
    // Test all EventType variants can serialize/deserialize to WebhookEventType
    for event_type in EventType::iter() {
      let serialized = serde_json::to_string(&event_type).unwrap();
      let deserialized_result: Result<WebhookEventType, _> = serde_json::from_str(&serialized);
      assert!(
        deserialized_result.is_ok(),
        "EventType::{:?} failed to deserialize into WebhookEventType",
        event_type
      );
    }
  }
}