aimcal_core/store.rs
1// SPDX-FileCopyrightText: 2025-2026 Zexin Yuan <aim@yzx9.xyz>
2//
3// SPDX-License-Identifier: Apache-2.0
4
5pub mod caldav;
6pub mod local;
7
8pub use caldav::CaldavStore;
9pub use local::LocalStore;
10
11use std::error::Error;
12
13use aimcal_ical::{VEvent, VTodo};
14use async_trait::async_trait;
15
16use crate::{EventPatch, TodoPatch};
17
18/// Error type for store operations that is Send + Sync.
19pub type StoreError = Box<dyn Error + Send + Sync>;
20
21/// Result of a backend synchronization operation.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct SyncResult {
24 /// Number of items created during synchronization.
25 pub created: usize,
26 /// Number of items updated during synchronization.
27 pub updated: usize,
28 /// Number of items deleted during synchronization.
29 pub deleted: usize,
30}
31
32/// Store trait for storing and synchronizing events and todos.
33///
34/// This trait abstracts different storage backends (local ICS files, `CalDAV` servers, etc.)
35/// providing a unified interface for CRUD operations on calendar items.
36#[async_trait]
37pub trait Store: Send + Sync {
38 /// Creates a new event in the store.
39 ///
40 /// # Arguments
41 ///
42 /// * `uid` - The unique identifier for the event
43 /// * `event` - The event to create
44 ///
45 /// # Errors
46 ///
47 /// Returns an error if the event cannot be created in the store.
48 async fn create_event(&self, uid: &str, event: &VEvent<String>) -> Result<String, StoreError>;
49
50 /// Retrieves an event from the store by UID.
51 ///
52 /// # Arguments
53 ///
54 /// * `uid` - The unique identifier of the event to retrieve
55 ///
56 /// # Errors
57 ///
58 /// Returns an error if the event is not found or cannot be retrieved.
59 async fn get_event(&self, uid: &str) -> Result<VEvent<String>, StoreError>;
60
61 /// Updates an existing event in the store.
62 ///
63 /// # Arguments
64 ///
65 /// * `uid` - The unique identifier of the event to update
66 /// * `patch` - The patch to apply to the event
67 ///
68 /// # Errors
69 ///
70 /// Returns an error if the event is not found or cannot be updated.
71 async fn update_event(
72 &self,
73 uid: &str,
74 patch: &EventPatch,
75 ) -> Result<VEvent<String>, StoreError>;
76
77 /// Deletes an event from the store.
78 ///
79 /// # Arguments
80 ///
81 /// * `uid` - The unique identifier of the event to delete
82 ///
83 /// # Errors
84 ///
85 /// Returns an error if the event is not found or cannot be deleted.
86 async fn delete_event(&self, uid: &str) -> Result<(), StoreError>;
87
88 /// Creates a new todo in the store.
89 ///
90 /// # Arguments
91 ///
92 /// * `uid` - The unique identifier for the todo
93 /// * `todo` - The todo to create
94 ///
95 /// # Errors
96 ///
97 /// Returns an error if the todo cannot be created in the store.
98 async fn create_todo(&self, uid: &str, todo: &VTodo<String>) -> Result<String, StoreError>;
99
100 /// Retrieves a todo from the store by UID.
101 ///
102 /// # Arguments
103 ///
104 /// * `uid` - The unique identifier of the todo to retrieve
105 ///
106 /// # Errors
107 ///
108 /// Returns an error if the todo is not found or cannot be retrieved.
109 async fn get_todo(&self, uid: &str) -> Result<VTodo<String>, StoreError>;
110
111 /// Updates an existing todo in the store.
112 ///
113 /// # Arguments
114 ///
115 /// * `uid` - The unique identifier of the todo to update
116 /// * `patch` - The patch to apply to the todo
117 ///
118 /// # Errors
119 ///
120 /// Returns an error if the todo is not found or cannot be updated.
121 async fn update_todo(&self, uid: &str, patch: &TodoPatch) -> Result<VTodo<String>, StoreError>;
122
123 /// Deletes a todo from the store.
124 ///
125 /// # Arguments
126 ///
127 /// * `uid` - The unique identifier of the todo to delete
128 ///
129 /// # Errors
130 ///
131 /// Returns an error if the todo is not found or cannot be deleted.
132 async fn delete_todo(&self, uid: &str) -> Result<(), StoreError>;
133
134 /// Lists all events in the store.
135 ///
136 /// # Errors
137 ///
138 /// Returns an error if the events cannot be listed.
139 async fn list_events(&self) -> Result<Vec<(String, VEvent<String>)>, StoreError>;
140
141 /// Lists all todos in the store.
142 ///
143 /// # Errors
144 ///
145 /// Returns an error if the todos cannot be listed.
146 async fn list_todos(&self) -> Result<Vec<(String, VTodo<String>)>, StoreError>;
147
148 /// Checks if a UID exists in the store.
149 ///
150 /// # Arguments
151 ///
152 /// * `uid` - The unique identifier to check
153 ///
154 /// # Returns
155 ///
156 /// `true` if the UID exists, `false` otherwise.
157 ///
158 /// # Errors
159 ///
160 /// Returns an error if the check cannot be performed.
161 async fn uid_exists(&self, uid: &str) -> Result<bool, StoreError>;
162
163 /// Returns the calendar identifier for this store.
164 ///
165 /// This identifies which calendar in the database items from this store belong to.
166 fn calendar_id(&self) -> &str;
167
168 /// Synchronizes the store with the local cache (database).
169 ///
170 /// This operation scans the store for changes and updates the local
171 /// database accordingly.
172 ///
173 /// # Returns
174 ///
175 /// A `SyncResult` containing counts of created, updated, and deleted items.
176 ///
177 /// # Errors
178 ///
179 /// Returns an error if synchronization fails.
180 async fn sync_cache(&self) -> Result<SyncResult, StoreError>;
181}