millipede_core/storage/
dataset.rs1use super::{StorageError, StorageResult};
4use futures_util::{StreamExt, stream::BoxStream};
5use serde::{Serialize, de::DeserializeOwned};
6
7#[derive(Debug, Clone, Default)]
9#[non_exhaustive]
10#[must_use = "list options do nothing unless passed to Dataset::list"]
11pub struct ListOptions {
12 pub offset: u64,
14 pub limit: Option<u64>,
16 pub desc: bool,
18}
19
20#[derive(Debug, Clone)]
22pub struct Page<T> {
23 pub items: Vec<T>,
25 pub total: u64,
27 pub offset: u64,
29 pub limit: Option<u64>,
31}
32
33#[derive(Debug, Clone)]
35#[non_exhaustive]
36pub struct DatasetInfo {
37 pub name: String,
39 pub item_count: u64,
41 pub created_at: time::OffsetDateTime,
43 pub modified_at: time::OffsetDateTime,
45}
46
47impl DatasetInfo {
48 pub fn new(
50 name: String,
51 item_count: u64,
52 created_at: time::OffsetDateTime,
53 modified_at: time::OffsetDateTime,
54 ) -> Self {
55 Self {
56 name,
57 item_count,
58 created_at,
59 modified_at,
60 }
61 }
62}
63
64#[async_trait::async_trait]
66pub trait Dataset: Send + Sync {
67 async fn push_json(&self, item: serde_json::Value) -> StorageResult<()>;
69 async fn push_json_batch(&self, items: Vec<serde_json::Value>) -> StorageResult<()>;
71 async fn list_raw(&self, opts: ListOptions) -> StorageResult<Page<serde_json::Value>>;
73 fn stream_raw(&self, opts: ListOptions) -> BoxStream<'_, StorageResult<serde_json::Value>>;
75 async fn export_json(&self, path: &std::path::Path) -> StorageResult<()>;
77 async fn export_csv(&self, path: &std::path::Path) -> StorageResult<()>;
79 async fn info(&self) -> StorageResult<DatasetInfo>;
81}
82
83#[async_trait::async_trait]
85pub trait DatasetExt: Dataset {
86 async fn push<T: Serialize + Send + Sync>(&self, item: &T) -> StorageResult<()> {
88 self.push_json(serde_json::to_value(item)?).await
89 }
90
91 async fn push_batch<T: Serialize + Send + Sync>(&self, items: &[T]) -> StorageResult<()> {
93 let items = items
94 .iter()
95 .map(serde_json::to_value)
96 .collect::<Result<Vec<_>, _>>()?;
97 self.push_json_batch(items).await
98 }
99
100 async fn list<T: DeserializeOwned>(&self, opts: ListOptions) -> StorageResult<Page<T>> {
102 let page = self.list_raw(opts).await?;
103 Ok(Page {
104 items: page
105 .items
106 .into_iter()
107 .map(serde_json::from_value)
108 .collect::<Result<Vec<_>, _>>()?,
109 total: page.total,
110 offset: page.offset,
111 limit: page.limit,
112 })
113 }
114
115 fn stream<T: DeserializeOwned + Send + 'static>(
117 &self,
118 opts: ListOptions,
119 ) -> BoxStream<'_, StorageResult<T>> {
120 Box::pin(self.stream_raw(opts).map(|result| {
121 result.and_then(|value| serde_json::from_value(value).map_err(StorageError::from))
122 }))
123 }
124}
125
126impl<D: Dataset + ?Sized> DatasetExt for D {}