1use chrono::{DateTime, Utc};
2
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "json")]
6mod json;
7#[cfg(feature = "json")]
8pub use json::JsonDataProvide;
9
10#[cfg(feature = "sqlite")]
11mod sqlite;
12#[cfg(feature = "sqlite")]
13pub use sqlite::SqliteDataProvide;
14
15pub const TRANSFER_DATA_VERSION: u16 = 100;
16
17#[derive(Debug, thiserror::Error)]
18pub enum ModifyEntryError {
19 #[error("{0}")]
20 ValidationError(String),
21 #[error("{0}")]
22 DataError(#[from] anyhow::Error),
23}
24
25#[allow(async_fn_in_trait)]
27pub trait DataProvider {
28 async fn load_all_entries(&self) -> anyhow::Result<Vec<Entry>>;
29 async fn add_entry(&self, entry: EntryDraft) -> Result<Entry, ModifyEntryError>;
30 async fn remove_entry(&self, entry_id: u32) -> anyhow::Result<()>;
31 async fn update_entry(&self, entry: Entry) -> Result<Entry, ModifyEntryError>;
32 async fn get_export_object(&self, entries_ids: &[u32]) -> anyhow::Result<EntriesDTO>;
33 async fn import_entries(&self, entries_dto: EntriesDTO) -> anyhow::Result<()> {
34 debug_assert_eq!(
35 TRANSFER_DATA_VERSION, entries_dto.version,
36 "Version mismatches check if there is a need to do a converting to the data"
37 );
38
39 for entry_draft in entries_dto.entries {
40 self.add_entry(entry_draft).await?;
41 }
42
43 Ok(())
44 }
45 async fn assign_priority_to_entries(&self, priority: u32) -> anyhow::Result<()>;
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct Entry {
51 pub id: u32,
52 pub date: DateTime<Utc>,
53 pub title: String,
54 pub content: String,
55 #[serde(default)]
56 pub tags: Vec<String>,
57 #[serde(default)]
58 pub priority: Option<u32>,
59}
60
61impl Entry {
62 #[allow(dead_code)]
63 pub fn new(
64 id: u32,
65 date: DateTime<Utc>,
66 title: String,
67 content: String,
68 tags: Vec<String>,
69 priority: Option<u32>,
70 ) -> Self {
71 Self {
72 id,
73 date,
74 title,
75 content,
76 tags,
77 priority,
78 }
79 }
80
81 pub fn from_draft(id: u32, draft: EntryDraft) -> Self {
82 Self {
83 id,
84 date: draft.date,
85 title: draft.title,
86 content: draft.content,
87 tags: draft.tags,
88 priority: draft.priority,
89 }
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94pub struct EntryDraft {
95 pub date: DateTime<Utc>,
96 pub title: String,
97 pub content: String,
98 pub tags: Vec<String>,
99 pub priority: Option<u32>,
100}
101
102impl EntryDraft {
103 pub fn new(
104 date: DateTime<Utc>,
105 title: String,
106 tags: Vec<String>,
107 priority: Option<u32>,
108 ) -> Self {
109 let content = String::new();
110 Self {
111 date,
112 title,
113 content,
114 tags,
115 priority,
116 }
117 }
118
119 #[must_use]
120 pub fn with_content(mut self, content: String) -> Self {
121 self.content = content;
122 self
123 }
124
125 pub fn from_entry(entry: Entry) -> Self {
126 Self {
127 date: entry.date,
128 title: entry.title,
129 content: entry.content,
130 tags: entry.tags,
131 priority: entry.priority,
132 }
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct EntriesDTO {
139 pub version: u16,
140 pub entries: Vec<EntryDraft>,
141}
142
143impl EntriesDTO {
144 pub fn new(entries: Vec<EntryDraft>) -> Self {
145 Self {
146 version: TRANSFER_DATA_VERSION,
147 entries,
148 }
149 }
150}