reinfer-client 0.37.3

API client for Re:infer, the conversational data intelligence platform
Documentation
use chrono::{DateTime, Utc};
use core::fmt;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str::FromStr;

use crate::{
    error::{Error, Result},
    resources::user::Username,
};

static FULL_NAME_REGEX: Lazy<Regex> =
    Lazy::new(|| Regex::new("^[A-Za-z0-9-_]{1,256}/[A-Za-z0-9-_]{1,256}$").unwrap());

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct Bucket {
    pub id: Id,
    pub name: Name,
    pub owner: Username,
    pub created_at: DateTime<Utc>,
}

impl Bucket {
    pub fn full_name(&self) -> FullName {
        FullName(format!("{}/{}", self.owner.0, self.name.0))
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Name(pub String);

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct FullName(pub String);

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Id(pub String);

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct ModelFamily(pub String);

// TODO(mcobzarenco)[3963]: Make `Identifier` into a trait (ensure it still implements
// `FromStr` so we can take T: Identifier as a clap command line argument).
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub enum Identifier {
    Id(Id),
    FullName(FullName),
}

impl From<FullName> for Identifier {
    fn from(full_name: FullName) -> Self {
        Identifier::FullName(full_name)
    }
}

impl From<Id> for Identifier {
    fn from(id: Id) -> Self {
        Identifier::Id(id)
    }
}

impl FromStr for Identifier {
    type Err = Error;

    fn from_str(string: &str) -> Result<Self> {
        if string.chars().all(|c| c.is_ascii_hexdigit()) {
            Ok(Identifier::Id(Id(string.into())))
        } else if FULL_NAME_REGEX.is_match(string) {
            Ok(Identifier::FullName(FullName(string.into())))
        } else {
            Err(Error::BadBucketIdentifier {
                identifier: string.into(),
            })
        }
    }
}

impl Display for FullName {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        write!(formatter, "{}", self.0)
    }
}

impl Display for Id {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        write!(formatter, "{}", self.0)
    }
}

impl Display for Identifier {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        match self {
            Identifier::Id(id) => Display::fmt(id, formatter),
            Identifier::FullName(full_name) => Display::fmt(full_name, formatter),
        }
    }
}

#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct NewBucket<'request> {
    pub bucket_type: BucketType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<&'request str>,
}

#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct CreateRequest<'request> {
    pub bucket: NewBucket<'request>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct CreateResponse {
    pub bucket: Bucket,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum FolderStatus {
    InProgress,
    UpToDate,
}

impl fmt::Display for FolderStatus {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match *self {
            Self::InProgress => write!(f, "In progress"),
            Self::UpToDate => write!(f, "Up to date"),
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct KeyedSyncState {
    pub mailbox_name: String,
    pub folder_id: String,
    pub folder_path: Vec<String>,
    pub status: FolderStatus,
    pub synced_until: Option<DateTime<Utc>>,
    pub last_synced_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct GetKeyedSyncStatesResponse {
    pub keyed_sync_states: Vec<KeyedSyncState>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct KeyedSyncStateId(pub String);

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct GetKeyedSyncStateIdsRequest {
    pub mailbox_name: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct DeleteKeyedSyncStateResponse {}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct GetKeyedSyncStateIdsResponse {
    pub keyed_sync_state_ids: Vec<KeyedSyncStateId>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct GetAvailableResponse {
    pub buckets: Vec<Bucket>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub(crate) struct GetResponse {
    pub bucket: Bucket,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub enum BucketType {
    #[serde(rename = "emails")]
    Emails,
}

impl FromStr for BucketType {
    type Err = Error;

    fn from_str(string: &str) -> Result<Self> {
        match string {
            "emails" => Ok(Self::Emails),
            _ => Err(Error::BadBucketType {
                bucket_type: string.into(),
            }),
        }
    }
}

impl Default for BucketType {
    fn default() -> Self {
        Self::Emails
    }
}

impl Display for BucketType {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        match *self {
            Self::Emails => write!(formatter, "emails"),
        }
    }
}

impl FromStr for FullName {
    type Err = Error;
    fn from_str(string: &str) -> Result<Self> {
        if FULL_NAME_REGEX.is_match(string) {
            Ok(FullName(string.into()))
        } else {
            Err(Error::BadBucketName {
                name: string.into(),
            })
        }
    }
}