Skip to main content

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}