Skip to main content

stint_core/storage/
mod.rs

1//! Storage traits and implementations for Stint.
2
3pub mod error;
4pub mod sqlite;
5
6use std::path::Path;
7use time::OffsetDateTime;
8
9use crate::models::entry::{EntryFilter, TimeEntry};
10use crate::models::project::{Project, ProjectStatus};
11use crate::models::session::ShellSession;
12use crate::models::types::{EntryId, ProjectId, SessionId};
13
14use self::error::StorageError;
15
16pub use self::sqlite::SqliteStorage;
17
18/// Pluggable storage backend for Stint.
19pub trait Storage {
20    // --- Projects ---
21
22    /// Creates a new project. Returns error if name already exists.
23    fn create_project(&self, project: &Project) -> Result<(), StorageError>;
24
25    /// Retrieves a project by its ID.
26    fn get_project(&self, id: &ProjectId) -> Result<Option<Project>, StorageError>;
27
28    /// Retrieves a project by its name (case-insensitive).
29    fn get_project_by_name(&self, name: &str) -> Result<Option<Project>, StorageError>;
30
31    /// Finds the project whose registered path is the longest prefix of `path`.
32    fn get_project_by_path(&self, path: &Path) -> Result<Option<Project>, StorageError>;
33
34    /// Lists all projects, optionally filtered by status.
35    fn list_projects(&self, status: Option<ProjectStatus>) -> Result<Vec<Project>, StorageError>;
36
37    /// Updates an existing project.
38    fn update_project(&self, project: &Project) -> Result<(), StorageError>;
39
40    /// Deletes a project and all associated data.
41    fn delete_project(&self, id: &ProjectId) -> Result<(), StorageError>;
42
43    // --- Time Entries ---
44
45    /// Creates a new time entry.
46    fn create_entry(&self, entry: &TimeEntry) -> Result<(), StorageError>;
47
48    /// Retrieves a time entry by its ID.
49    fn get_entry(&self, id: &EntryId) -> Result<Option<TimeEntry>, StorageError>;
50
51    /// Finds the currently running entry for a specific project.
52    fn get_running_entry(&self, project_id: &ProjectId) -> Result<Option<TimeEntry>, StorageError>;
53
54    /// Finds the currently running hook-sourced entry for a specific project.
55    fn get_running_hook_entry(
56        &self,
57        project_id: &ProjectId,
58    ) -> Result<Option<TimeEntry>, StorageError>;
59
60    /// Finds any currently running entry across all projects.
61    fn get_any_running_entry(&self) -> Result<Option<TimeEntry>, StorageError>;
62
63    /// Lists entries matching the given filter.
64    fn list_entries(&self, filter: &EntryFilter) -> Result<Vec<TimeEntry>, StorageError>;
65
66    /// Returns the most recent time entry.
67    fn get_last_entry(&self) -> Result<Option<TimeEntry>, StorageError>;
68
69    /// Updates an existing time entry.
70    fn update_entry(&self, entry: &TimeEntry) -> Result<(), StorageError>;
71
72    /// Deletes a time entry.
73    fn delete_entry(&self, id: &EntryId) -> Result<(), StorageError>;
74
75    // --- Sessions ---
76
77    /// Creates or updates a shell session record.
78    fn upsert_session(&self, session: &ShellSession) -> Result<(), StorageError>;
79
80    /// Retrieves a session by its ID.
81    fn get_session(&self, id: &SessionId) -> Result<Option<ShellSession>, StorageError>;
82
83    /// Finds an active session by shell PID.
84    fn get_session_by_pid(&self, pid: u32) -> Result<Option<ShellSession>, StorageError>;
85
86    /// Marks a session as ended.
87    fn end_session(&self, id: &SessionId, ended_at: OffsetDateTime) -> Result<(), StorageError>;
88
89    /// Counts active sessions tracking a given project, excluding a specific session.
90    fn count_active_sessions_for_project(
91        &self,
92        project_id: &ProjectId,
93        exclude_session_id: &SessionId,
94    ) -> Result<usize, StorageError>;
95
96    /// Finds active sessions whose last heartbeat is older than the given time.
97    fn get_stale_sessions(
98        &self,
99        older_than: OffsetDateTime,
100    ) -> Result<Vec<ShellSession>, StorageError>;
101
102    // --- Ignored Paths ---
103
104    /// Adds a path to the ignore list for auto-discovery.
105    fn add_ignored_path(&self, path: &Path) -> Result<(), StorageError>;
106
107    /// Removes a path from the ignore list.
108    fn remove_ignored_path(&self, path: &Path) -> Result<bool, StorageError>;
109
110    /// Checks if a path (or any of its ancestors) is in the ignore list.
111    fn is_path_ignored(&self, path: &Path) -> Result<bool, StorageError>;
112
113    /// Lists all ignored paths.
114    fn list_ignored_paths(&self) -> Result<Vec<std::path::PathBuf>, StorageError>;
115}