Skip to main content

Pauses

Struct Pauses 

Source
pub struct Pauses {
    pub conn: Arc<Mutex<Connection>>,
    pub min_duration: Option<String>,
    pub max_duration: Option<String>,
}
Expand description

Database manager for pause/break tracking operations.

The Pauses struct provides a high-level interface for managing work break records in the database. It uses thread-safe connection handling to support concurrent access from the activity monitor and user commands.

§Thread Safety

The connection is wrapped in an Arc<Mutex<>> to allow safe concurrent access from multiple threads, particularly important when the activity monitor is running in the background while users interact with the CLI.

§Connection Management

Each Pauses instance maintains its own database connection and ensures the pauses table schema is properly initialized on creation.

Fields§

§conn: Arc<Mutex<Connection>>

Thread-safe database connection wrapper.

The connection is protected by a mutex to prevent race conditions when multiple threads attempt to record or query pause data simultaneously.

§min_duration: Option<String>§max_duration: Option<String>

Implementations§

Source§

impl Pauses

Source

pub fn new() -> Result<Pauses>

Creates a new Pauses instance and initializes the database schema.

This constructor establishes a database connection, ensures the pauses table exists with the proper schema, and wraps the connection for thread-safe access. The schema creation is idempotent and safe to call multiple times.

§Returns

Returns a new Pauses instance ready for pause tracking operations, or an error if database initialization fails.

§Example
use kasl::db::pauses::Pauses;

let pauses = Pauses::new()?;
// Ready to track pauses
§Errors

Returns an error if:

  • Database connection cannot be established
  • Schema creation fails due to permissions or corruption
  • Table initialization encounters SQL errors
Source

pub fn set_min_duration(&self, min_duration: u64) -> Self

Source

pub fn set_max_duration(&self, max_duration: u64) -> Self

Source

pub fn insert_start(&self) -> Result<()>

Records the start of a new pause with the current timestamp.

This method creates a new pause record using the current system time as the start timestamp. The pause remains “open” (end IS NULL) until it’s completed with insert_end(). Multiple open pauses are allowed to handle edge cases in activity detection.

§Returns

Returns Ok(()) if the pause start is recorded successfully, or an error if the database operation fails.

§Example
let pauses = Pauses::new()?;
pauses.insert_start()?; // Pause started at current time
§Thread Safety

This method is thread-safe and can be called concurrently from multiple threads, such as the activity monitor daemon.

Source

pub fn insert_start_with_time(&self, start_time: NaiveDateTime) -> Result<()>

Records the start of a new pause with a specific timestamp.

This method allows manual insertion of pause records with exact timestamps, useful for importing historical data or correcting activity tracking records. The specified time should be in the local timezone for consistency with other records.

§Arguments
  • start_time - The exact timestamp when the pause began
§Returns

Returns Ok(()) if the pause is recorded successfully, or an error if the database operation fails.

§Example
use chrono::NaiveDateTime;

let pauses = Pauses::new()?;
let start_time = NaiveDateTime::parse_from_str(
    "2025-01-15 14:30:00",
    "%Y-%m-%d %H:%M:%S"
)?;
pauses.insert_start_with_time(start_time)?;
§Data Integrity

The caller is responsible for ensuring the timestamp is reasonable and doesn’t conflict with existing work session boundaries.

Source

pub fn insert_end(&self) -> Result<()>

Completes the most recent open pause with duration calculation.

This method finds the last pause record that has a start time but no end time, then updates it with the current timestamp and the provided duration. The duration is typically calculated by the activity monitor based on the actual inactive period.

§Duration Calculation

While the end timestamp is set to the current time, the duration parameter contains the actual pause length in seconds. This allows for accurate tracking even when there’s a delay between activity resumption and pause recording.

§Returns

Returns Ok(()) if the pause is completed successfully, or an error if no open pause exists or the database operation fails.

§Example
let pauses = Pauses::new()?;
pauses.insert_start()?;
// ... user is inactive for 5 minutes ...
pauses.insert_end()?;
§Behavior Notes
  • Only affects the most recent open pause record
  • If no open pause exists, the operation may fail silently
  • Duration should be a positive number of seconds
Source

pub fn insert_manual( &self, start: NaiveDateTime, duration: TimeDelta, protected: bool, reason: Option<&str>, ) -> Result<i64>

Records a complete pause stated by the user, with explicit bounds.

Unlike monitor-detected pauses, which are opened by insert_start and closed later by insert_end, a manual pause is written in one shot: the user knows when they left and how long they were gone. No placement is inferred and no time is invented.

§Arguments
  • start - When the absence began
  • duration - How long it lasted
  • protected - Exempt the record from threshold filtering and merging
  • reason - Optional note describing the absence
§Returns

Returns the id of the inserted pause record.

Source

pub fn find_overlapping( &self, start: NaiveDateTime, end: NaiveDateTime, ) -> Result<Option<Pause>>

Returns the pause overlapping the given time range, if any exists.

Used to reject a manual pause that would collide with an already recorded one, so the day never contains contradictory absences.

Source

pub fn get_daily_pauses(&self, date: NaiveDate) -> Result<Vec<Pause>>

Retrieves all pause records for a specific date with duration filtering.

This method fetches all completed pause records for the given date that meet or exceed the specified minimum duration threshold. It’s commonly used for daily reporting and work time calculations where very short pauses (e.g., under 5 minutes) may be ignored.

§Filtering Logic
  • Only includes pauses that started on the specified date
  • Filters out pauses shorter than the minimum duration
  • Includes ongoing pauses (duration IS NULL) regardless of threshold
  • Results are ordered by start time for chronological display
§Arguments
  • date - The target date to query (uses local timezone)
  • min_duration - Minimum pause length to include (in minutes)
§Returns

Returns a vector of Pause objects representing the filtered pause records, or an error if the database query fails.

§Example
use chrono::Local;

// Get pauses of 10 minutes or longer
let pauses = Pauses::new()?.set_min_duration(10);
let today = Local::now().date_naive();

let significant_pauses = pauses.get_daily_pauses(today)?;
for pause in significant_pauses {
    println!("Pause: {:?} - {:?}", pause.start, pause.end);
}
§Performance Notes

This query uses date functions and may be slower on large datasets. Consider adding indices on the start column for better performance.

Source

pub fn get_workday_pauses(&self, workday: &Workday) -> Result<Vec<Pause>>

Fetches daily pauses and keeps only the portions inside the workday bounds.

Drops pauses entirely before workday.start or after workday.end, and clips straddling pauses to [workday.start, workday.end].

Source

pub fn delete(&self, id: i32) -> Result<()>

Deletes a single pause record by its unique identifier.

This method removes a specific pause record from the database, typically used for correcting erroneous pause recordings or user-requested deletions. The operation is permanent and cannot be undone without database backups.

§Arguments
  • id - The unique identifier of the pause record to delete
§Returns

Returns Ok(()) if the deletion succeeds, or an error if the database operation fails. Note that deleting a non-existent record is not considered an error.

§Example
let pauses = Pauses::new()?;
pauses.delete(123)?; // Delete pause with ID 123
§Safety Considerations
  • Deletion is immediate and permanent
  • No confirmation prompts are provided at this level
  • Callers should implement appropriate confirmation flows
Source

pub fn delete_many(&self, ids: &[i32]) -> Result<usize>

Deletes multiple pause records efficiently in a batch operation.

This method removes multiple pause records in a single transaction, providing better performance than individual deletions and ensuring atomicity. If any deletion fails, all changes are rolled back.

§Transaction Handling

All deletions are performed within a single database transaction to ensure consistency. Either all specified records are deleted or none are deleted if any error occurs.

§Arguments
  • ids - Slice of pause record IDs to delete
§Returns

Returns the number of records actually deleted, or an error if the batch operation fails. The count may be less than the input length if some IDs don’t exist in the database.

§Example
let pauses = Pauses::new()?;
let ids_to_delete = vec![101, 102, 103];
let deleted_count = pauses.delete_many(&ids_to_delete)?;
println!("Deleted {} pause records", deleted_count);
§Performance Benefits
  • Single transaction reduces database overhead
  • More efficient than individual delete operations
  • Atomic operation ensures data consistency
§Edge Cases
  • Empty input slice returns 0 without database interaction
  • Non-existent IDs are silently ignored
  • Partial failures result in complete rollback

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more