pinto/storage/repository.rs
1//! Persistence traits shared by the file, Git, and SQLite backends.
2
3use crate::backlog::{BacklogItem, ItemId};
4use crate::error::Result;
5use crate::sprint::{Sprint, SprintId};
6use std::future::Future;
7use std::path::PathBuf;
8
9pub trait BacklogItemRepository {
10 /// Save a backlog item, replacing any existing item with the same ID.
11 fn save(&self, item: &BacklogItem) -> impl Future<Output = Result<()>>;
12
13 /// Load a backlog item by ID. Return [`crate::error::Error::NotFound`] when it does not exist.
14 fn load(&self, id: &ItemId) -> impl Future<Output = Result<BacklogItem>>;
15
16 /// Return all backlog items in lexicographic rank order, using the ID as a tie-breaker.
17 ///
18 /// Implementations may read files concurrently and parse them in parallel (see
19 /// `docs/DESIGN.md` ยง3.4).
20 fn list(&self) -> impl Future<Output = Result<Vec<BacklogItem>>>;
21
22 /// Return all archived backlog items in lexicographic rank order, using the ID as a tie-breaker.
23 fn list_archived(&self) -> impl Future<Output = Result<Vec<BacklogItem>>>;
24
25 /// Load an archived backlog item by ID. Return [`crate::error::Error::NotFound`] when it does
26 /// not exist in the archive.
27 fn load_archived(&self, id: &ItemId) -> impl Future<Output = Result<BacklogItem>>;
28
29 /// Delete a backlog item by ID. Return [`crate::error::Error::NotFound`] when it does not exist.
30 fn delete(&self, id: &ItemId) -> impl Future<Output = Result<()>>;
31
32 /// Move a backlog item by ID to `archive/` and return the destination path.
33 ///
34 /// This is the non-destructive alternative to [`Self::delete`]. Return
35 /// [`crate::error::Error::NotFound`] when the item does not exist.
36 fn archive(&self, id: &ItemId) -> impl Future<Output = Result<PathBuf>>;
37
38 /// Restore an archived backlog item to the active item store.
39 ///
40 /// Implementations must refuse an active item with the same ID without overwriting either
41 /// copy. Return [`crate::error::Error::NotFound`] when the archived item does not exist.
42 fn restore(&self, id: &ItemId) -> impl Future<Output = Result<()>>;
43
44 /// Return the next never-issued ID for `prefix`: one greater than the maximum issued or
45 /// existing number, or `1` when no such ID exists.
46 fn next_id(&self, prefix: &str) -> impl Future<Output = Result<ItemId>>;
47}
48
49/// Persistence operations for sprints.
50///
51/// Implementations store sprints separately from backlog items. The method names overlap with
52/// [`BacklogItemRepository`], so callers can disambiguate them with a fully qualified call such as
53/// `SprintRepository::save(&repo, &sprint)`.
54pub trait SprintRepository {
55 /// Save a sprint, replacing any existing sprint with the same ID.
56 fn save(&self, sprint: &Sprint) -> impl Future<Output = Result<()>>;
57
58 /// Load a sprint by ID. Return [`crate::error::Error::SprintNotFound`] when it does not exist.
59 fn load(&self, id: &SprintId) -> impl Future<Output = Result<Sprint>>;
60
61 /// Return all sprints in ascending creation-time order, using the ID as a tie-breaker.
62 fn list(&self) -> impl Future<Output = Result<Vec<Sprint>>>;
63
64 /// Delete a sprint by ID. Return [`crate::error::Error::SprintNotFound`] when it does not exist.
65 ///
66 /// Backend migration ([`crate::service::migrate_storage`]) uses this operation to remove
67 /// destination sprints that are absent from the source.
68 fn delete(&self, id: &SprintId) -> impl Future<Output = Result<()>>;
69}