use std::future::{Future, IntoFuture};
use std::pin::Pin;
use chrono::{DateTime, FixedOffset};
use crate::memory::{KindSelector, Memory, Scope};
use crate::store::{DEFAULT_TIMELINE_LIMIT, MemoryStore, TimelineDirection, TimelineParams};
use super::{Client, ClientError};
#[must_use = "timeline(..) returns a builder that must be awaited"]
pub struct TimelineBuilder<'a> {
client: &'a Client,
scope: Scope,
episodic: bool,
semantic: bool,
created_after: Option<DateTime<FixedOffset>>,
created_before: Option<DateTime<FixedOffset>>,
event_at_after: Option<DateTime<FixedOffset>>,
event_at_before: Option<DateTime<FixedOffset>>,
include_superseded: bool,
limit: usize,
direction: TimelineDirection,
}
impl<'a> TimelineBuilder<'a> {
pub(super) fn new(client: &'a Client, scope: Scope) -> Self {
Self {
client,
scope,
episodic: false,
semantic: false,
created_after: None,
created_before: None,
event_at_after: None,
event_at_before: None,
include_superseded: true,
limit: DEFAULT_TIMELINE_LIMIT,
direction: TimelineDirection::Descending,
}
}
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
pub fn episodic(mut self) -> Self {
self.episodic = true;
self
}
pub fn semantic(mut self) -> Self {
self.semantic = true;
self
}
pub fn created_after(mut self, at: impl Into<DateTime<FixedOffset>>) -> Self {
self.created_after = Some(at.into());
self
}
pub fn created_before(mut self, at: impl Into<DateTime<FixedOffset>>) -> Self {
self.created_before = Some(at.into());
self
}
pub fn event_at_after(mut self, at: impl Into<DateTime<FixedOffset>>) -> Self {
self.event_at_after = Some(at.into());
self
}
pub fn event_at_before(mut self, at: impl Into<DateTime<FixedOffset>>) -> Self {
self.event_at_before = Some(at.into());
self
}
pub fn exclude_superseded(mut self) -> Self {
self.include_superseded = false;
self
}
pub fn ascending(mut self) -> Self {
self.direction = TimelineDirection::Ascending;
self
}
}
fn kind_selector(episodic: bool, semantic: bool) -> KindSelector {
match (episodic, semantic) {
(false, false) => KindSelector::default(),
(episodic, semantic) => KindSelector { episodic, semantic },
}
}
impl<'a> IntoFuture for TimelineBuilder<'a> {
type Output = Result<Vec<Memory>, ClientError>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(execute(self))
}
}
async fn execute(builder: TimelineBuilder<'_>) -> Result<Vec<Memory>, ClientError> {
let kinds = kind_selector(builder.episodic, builder.semantic);
let TimelineBuilder {
client,
scope,
created_after,
created_before,
event_at_after,
event_at_before,
include_superseded,
limit,
direction,
..
} = builder;
let params = TimelineParams {
kinds,
created_after,
created_before,
event_at_after,
event_at_before,
include_superseded,
limit,
direction,
};
let memories = client.inner.store.timeline(scope, params).await?;
Ok(memories)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_select_all_kinds_when_no_kind_toggled() {
let selector = kind_selector(false, false);
assert!(selector.episodic);
assert!(selector.semantic);
}
#[test]
fn should_select_only_episodic_when_only_episodic_toggled() {
let selector = kind_selector(true, false);
assert!(selector.episodic);
assert!(!selector.semantic);
}
}