rusty-beads 0.1.0

Git-backed graph issue tracker for AI coding agents - a Rust implementation with context store, dependency tracking, and semantic compaction
Documentation
//! Storage layer for Beads.
//!
//! Provides an abstraction over different storage backends (SQLite, in-memory)
//! with support for transactions, dependency tracking, and dirty issue management.

mod schema;
mod sqlite;
mod error;
pub mod jsonl;

pub use sqlite::SqliteStorage;
pub use error::StorageError;
pub use jsonl::{export_to_jsonl, import_from_jsonl, sync_jsonl, ExportStats, ImportStats};

use crate::types::{
    BlockedIssue, Comment, Dependency, DependencyType, Event, Issue,
    IssueFilter, Statistics,
};

/// Result type for storage operations.
pub type Result<T> = std::result::Result<T, StorageError>;

/// The main storage trait for Beads.
///
/// Provides methods for managing issues, dependencies, labels, and configuration.
/// All implementations must be thread-safe (Send + Sync).
pub trait Storage: Send + Sync {
    // === Issue Operations ===

    /// Create a new issue.
    fn create_issue(&self, issue: &Issue) -> Result<()>;

    /// Create multiple issues in a batch.
    fn create_issues(&self, issues: &[Issue]) -> Result<()>;

    /// Get an issue by ID.
    fn get_issue(&self, id: &str) -> Result<Option<Issue>>;

    /// Get an issue by external reference.
    fn get_issue_by_external_ref(&self, external_ref: &str) -> Result<Option<Issue>>;

    /// Update an existing issue.
    fn update_issue(&self, issue: &Issue) -> Result<()>;

    /// Close an issue.
    fn close_issue(&self, id: &str, actor: &str, reason: Option<&str>) -> Result<()>;

    /// Soft-delete an issue (tombstone).
    fn delete_issue(&self, id: &str, actor: &str, reason: Option<&str>) -> Result<()>;

    /// Search issues with filters.
    fn search_issues(&self, filter: &IssueFilter) -> Result<Vec<Issue>>;

    // === Dependency Operations ===

    /// Add a dependency between issues.
    fn add_dependency(&self, dep: &Dependency) -> Result<()>;

    /// Remove a dependency between issues.
    fn remove_dependency(&self, issue_id: &str, depends_on_id: &str) -> Result<()>;

    /// Get all dependencies for an issue (issues this one depends on).
    fn get_dependencies(&self, issue_id: &str) -> Result<Vec<Dependency>>;

    /// Get all dependents of an issue (issues that depend on this one).
    fn get_dependents(&self, issue_id: &str) -> Result<Vec<Dependency>>;

    /// Check if adding a dependency would create a cycle.
    fn would_create_cycle(&self, from_id: &str, to_id: &str, dep_type: DependencyType) -> Result<bool>;

    // === Ready Work ===

    /// Get all issues that are ready for work (open, no blocking dependencies).
    fn get_ready_work(&self) -> Result<Vec<Issue>>;

    /// Get all blocked issues with their blocking counts.
    fn get_blocked_issues(&self) -> Result<Vec<BlockedIssue>>;

    /// Check if an issue is blocked.
    fn is_blocked(&self, issue_id: &str) -> Result<bool>;

    // === Label Operations ===

    /// Add a label to an issue.
    fn add_label(&self, issue_id: &str, label: &str) -> Result<()>;

    /// Remove a label from an issue.
    fn remove_label(&self, issue_id: &str, label: &str) -> Result<()>;

    /// Get all labels for an issue.
    fn get_labels(&self, issue_id: &str) -> Result<Vec<String>>;

    /// Get all issues with a specific label.
    fn get_issues_by_label(&self, label: &str) -> Result<Vec<Issue>>;

    // === Comment Operations ===

    /// Add a comment to an issue.
    fn add_comment(&self, issue_id: &str, author: &str, text: &str) -> Result<i64>;

    /// Get all comments for an issue.
    fn get_comments(&self, issue_id: &str) -> Result<Vec<Comment>>;

    // === Event Operations ===

    /// Get all events for an issue.
    fn get_events(&self, issue_id: &str) -> Result<Vec<Event>>;

    // === Config Operations ===

    /// Set a configuration value.
    fn set_config(&self, key: &str, value: &str) -> Result<()>;

    /// Get a configuration value.
    fn get_config(&self, key: &str) -> Result<Option<String>>;

    /// Delete a configuration value.
    fn delete_config(&self, key: &str) -> Result<()>;

    /// Get all configuration values.
    fn get_all_config(&self) -> Result<std::collections::HashMap<String, String>>;

    // === Dirty Tracking ===

    /// Mark an issue as dirty (needs export).
    fn mark_dirty(&self, issue_id: &str) -> Result<()>;

    /// Get all dirty issue IDs.
    fn get_dirty_issues(&self) -> Result<Vec<String>>;

    /// Clear dirty flags for specific issues.
    fn clear_dirty(&self, issue_ids: &[String]) -> Result<()>;

    // === Statistics ===

    /// Get database statistics.
    fn get_statistics(&self) -> Result<Statistics>;

    // === Child Counter ===

    /// Get the next child counter for a parent issue.
    fn next_child_counter(&self, parent_id: &str) -> Result<u32>;

    // === Transaction Support ===

    /// Run a function within a transaction.
    fn transaction<F, T>(&self, f: F) -> Result<T>
    where
        F: FnOnce() -> Result<T>;

    // === Lifecycle ===

    /// Close the storage connection.
    fn close(&self) -> Result<()>;
}