use chrono::NaiveDate;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
pub type BrokerEvent = crate::sse::Event;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct GetEventsRequest {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub since: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub until: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub since_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub until_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub group_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub include_preprocessing: Option<bool>,
}
impl GetEventsRequest {
#[must_use]
pub fn since(since: NaiveDate) -> Self {
Self {
since: Some(since),
..Self::default()
}
}
#[must_use]
pub fn after_id(id: impl Into<String>) -> Self {
Self {
id: Some(id.into()),
..Self::default()
}
}
#[must_use]
pub fn from_id(since_id: impl Into<String>) -> Self {
Self {
since_id: Some(since_id.into()),
..Self::default()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum EventVersion {
V1,
V2,
V2Beta1,
}
impl EventVersion {
pub(crate) fn segment(self) -> &'static str {
match self {
Self::V1 => "v1",
Self::V2 => "v2",
Self::V2Beta1 => "v2beta1",
}
}
fn cursor_params(self) -> (&'static str, &'static str) {
match self {
Self::V1 => ("since_ulid", "until_ulid"),
Self::V2 | Self::V2Beta1 => ("since_id", "until_id"),
}
}
pub(crate) fn query(self, filter: &GetEventsRequest) -> Vec<(&'static str, String)> {
let mut query = Vec::new();
if let Some(id) = &filter.id {
query.push(("id", id.clone()));
}
if let Some(since) = filter.since {
query.push(("since", since.to_string()));
}
if let Some(until) = filter.until {
query.push(("until", until.to_string()));
}
let (since_key, until_key) = self.cursor_params();
if let Some(since_id) = &filter.since_id {
query.push((since_key, since_id.clone()));
}
if let Some(until_id) = &filter.until_id {
query.push((until_key, until_id.clone()));
}
if let Some(group_id) = filter.group_id {
query.push(("group_id", group_id.to_string()));
}
if let Some(include_preprocessing) = filter.include_preprocessing {
query.push(("include_preprocessing", include_preprocessing.to_string()));
}
query
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_cursor_is_named_for_the_version_it_is_sent_to() {
let filter = GetEventsRequest {
since_id: Some("01ARZ3NDEKTSV4RRFFQ69G5FAV".to_owned()),
until_id: Some("01ARZ3NDEKTSV4RRFFQ69G5FBW".to_owned()),
..GetEventsRequest::default()
};
assert_eq!(
EventVersion::V1.query(&filter),
vec![
("since_ulid", "01ARZ3NDEKTSV4RRFFQ69G5FAV".to_owned()),
("until_ulid", "01ARZ3NDEKTSV4RRFFQ69G5FBW".to_owned()),
]
);
assert_eq!(
EventVersion::V2.query(&filter),
vec![
("since_id", "01ARZ3NDEKTSV4RRFFQ69G5FAV".to_owned()),
("until_id", "01ARZ3NDEKTSV4RRFFQ69G5FBW".to_owned()),
]
);
}
#[test]
fn an_empty_filter_sends_nothing() {
let filter = GetEventsRequest::default();
assert!(EventVersion::V1.query(&filter).is_empty());
assert!(EventVersion::V2.query(&filter).is_empty());
}
#[test]
fn dates_render_as_the_wire_format() {
let filter = GetEventsRequest {
since: Some("2022-02-01".parse().unwrap()),
until: Some("2022-02-28".parse().unwrap()),
..GetEventsRequest::default()
};
assert_eq!(
EventVersion::V2.query(&filter),
vec![
("since", "2022-02-01".to_owned()),
("until", "2022-02-28".to_owned()),
]
);
}
}