pub struct ThingsDatabase { /* private fields */ }Expand description
SQLx-based database implementation for Things 3 data This provides async, Send + Sync compatible database access
Implementations§
Source§impl ThingsDatabase
impl ThingsDatabase
Sourcepub async fn new(database_path: &Path) -> ThingsResult<Self>
pub async fn new(database_path: &Path) -> ThingsResult<Self>
Create a new database connection pool with default configuration
§Examples
use things3_core::{ThingsDatabase, ThingsError};
use std::path::Path;
// Connect to Things 3 database
let db = ThingsDatabase::new(Path::new("/path/to/things.db")).await?;
// Get inbox tasks
let tasks = db.get_inbox(None).await?;
println!("Found {} tasks in inbox", tasks.len());§Errors
Returns an error if the database connection fails or if SQLite configuration fails
Sourcepub async fn new_with_config(
database_path: &Path,
config: DatabasePoolConfig,
) -> ThingsResult<Self>
pub async fn new_with_config( database_path: &Path, config: DatabasePoolConfig, ) -> ThingsResult<Self>
Create a new database connection pool with custom configuration
§Examples
use things3_core::{ThingsDatabase, DatabasePoolConfig, ThingsError};
use std::path::Path;
use std::time::Duration;
// Create custom pool configuration
let config = DatabasePoolConfig {
max_connections: 10,
min_connections: 2,
connect_timeout: Duration::from_secs(5),
idle_timeout: Duration::from_secs(300),
max_lifetime: Duration::from_secs(3600),
test_before_acquire: true,
sqlite_optimizations: Default::default(),
};
// Connect with custom configuration
let db = ThingsDatabase::new_with_config(
Path::new("/path/to/things.db"),
config,
).await?;§Errors
Returns an error if the database connection fails or if SQLite configuration fails
Sourcepub async fn from_connection_string(database_url: &str) -> ThingsResult<Self>
pub async fn from_connection_string(database_url: &str) -> ThingsResult<Self>
Create a new database connection pool from a connection string with default configuration
§Errors
Returns an error if the database connection fails or if SQLite configuration fails
Sourcepub async fn from_connection_string_with_config(
database_url: &str,
config: DatabasePoolConfig,
) -> ThingsResult<Self>
pub async fn from_connection_string_with_config( database_url: &str, config: DatabasePoolConfig, ) -> ThingsResult<Self>
Create a new database connection pool from a connection string with custom configuration
§Errors
Returns an error if the database connection fails or if SQLite configuration fails
Sourcepub fn pool(&self) -> &SqlitePool
pub fn pool(&self) -> &SqlitePool
Get the underlying connection pool
Sourcepub async fn is_connected(&self) -> bool
pub async fn is_connected(&self) -> bool
Check if the database is connected
Sourcepub async fn get_pool_health(&self) -> ThingsResult<PoolHealthStatus>
pub async fn get_pool_health(&self) -> ThingsResult<PoolHealthStatus>
Sourcepub async fn get_pool_metrics(&self) -> ThingsResult<PoolMetrics>
pub async fn get_pool_metrics(&self) -> ThingsResult<PoolMetrics>
Sourcepub async fn comprehensive_health_check(
&self,
) -> ThingsResult<ComprehensiveHealthStatus>
pub async fn comprehensive_health_check( &self, ) -> ThingsResult<ComprehensiveHealthStatus>
Perform a comprehensive health check including pool and database
§Errors
Returns an error if the health check fails
Sourcepub async fn get_stats(&self) -> ThingsResult<DatabaseStats>
pub async fn get_stats(&self) -> ThingsResult<DatabaseStats>
Sourcepub async fn get_all_tasks(&self) -> ThingsResult<Vec<Task>>
pub async fn get_all_tasks(&self) -> ThingsResult<Vec<Task>>
Get all tasks from the database
§Examples
use things3_core::{ThingsDatabase, ThingsError};
use std::path::Path;
let db = ThingsDatabase::new(Path::new("/path/to/things.db")).await?;
// Get all tasks
let tasks = db.get_all_tasks().await?;
println!("Found {} total tasks", tasks.len());
// Filter tasks by status
let incomplete: Vec<_> = tasks.iter()
.filter(|t| t.status == things3_core::TaskStatus::Incomplete)
.collect();
println!("Found {} incomplete tasks", incomplete.len());§Errors
Returns an error if the database query fails or if task data is invalid
Sourcepub async fn get_all_projects(&self) -> ThingsResult<Vec<Project>>
pub async fn get_all_projects(&self) -> ThingsResult<Vec<Project>>
Get all projects (from TMTask table where type = 1)
§Errors
Returns an error if the database query fails or if project data is invalid
Sourcepub async fn get_all_areas(&self) -> ThingsResult<Vec<Area>>
pub async fn get_all_areas(&self) -> ThingsResult<Vec<Area>>
Sourcepub async fn get_tasks_by_status(
&self,
status: TaskStatus,
) -> ThingsResult<Vec<Task>>
pub async fn get_tasks_by_status( &self, status: TaskStatus, ) -> ThingsResult<Vec<Task>>
Sourcepub async fn search_tasks(&self, query: &str) -> ThingsResult<Vec<Task>>
pub async fn search_tasks(&self, query: &str) -> ThingsResult<Vec<Task>>
Search tasks by title or notes
§Errors
Returns an error if the database query fails or if task data is invalid
Sourcepub async fn search_logbook(
&self,
search_text: Option<String>,
from_date: Option<NaiveDate>,
to_date: Option<NaiveDate>,
project_uuid: Option<Uuid>,
area_uuid: Option<Uuid>,
tags: Option<Vec<String>>,
limit: Option<u32>,
) -> ThingsResult<Vec<Task>>
pub async fn search_logbook( &self, search_text: Option<String>, from_date: Option<NaiveDate>, to_date: Option<NaiveDate>, project_uuid: Option<Uuid>, area_uuid: Option<Uuid>, tags: Option<Vec<String>>, limit: Option<u32>, ) -> ThingsResult<Vec<Task>>
Search completed tasks in the logbook
Returns completed tasks matching the provided filters. All filters are optional and can be combined.
§Parameters
search_text: Search in task titles and notes (case-insensitive)from_date: Start date for completion date rangeto_date: End date for completion date rangeproject_uuid: Filter by project UUIDarea_uuid: Filter by area UUIDtags: Filter by tags (all tags must match)limit: Maximum number of results (default: 50)
§Errors
Returns an error if the database query fails or if task data is invalid
Sourcepub async fn get_inbox(&self, limit: Option<usize>) -> ThingsResult<Vec<Task>>
pub async fn get_inbox(&self, limit: Option<usize>) -> ThingsResult<Vec<Task>>
Get inbox tasks (incomplete tasks without project)
§Errors
Returns an error if the database query fails or if task data is invalid
Sourcepub async fn get_projects(
&self,
limit: Option<usize>,
) -> ThingsResult<Vec<Project>>
pub async fn get_projects( &self, limit: Option<usize>, ) -> ThingsResult<Vec<Project>>
Get all projects (alias for get_all_projects for compatibility)
§Errors
Returns an error if the database query fails or if project data is invalid
Sourcepub async fn get_areas(&self) -> ThingsResult<Vec<Area>>
pub async fn get_areas(&self) -> ThingsResult<Vec<Area>>
Get all areas (alias for get_all_areas for compatibility)
§Errors
Returns an error if the database query fails or if area data is invalid
Sourcepub async fn create_task(
&self,
request: CreateTaskRequest,
) -> ThingsResult<Uuid>
pub async fn create_task( &self, request: CreateTaskRequest, ) -> ThingsResult<Uuid>
Create a new task in the database
Validates:
- Project UUID exists if provided
- Area UUID exists if provided
- Parent task UUID exists if provided
- Date range (deadline >= start_date)
Returns the UUID of the created task
§Examples
use things3_core::{ThingsDatabase, CreateTaskRequest, ThingsError};
use std::path::Path;
use chrono::NaiveDate;
let db = ThingsDatabase::new(Path::new("/path/to/things.db")).await?;
// Create a simple task
let request = CreateTaskRequest {
title: "Buy groceries".to_string(),
notes: Some("Milk, eggs, bread".to_string()),
deadline: Some(NaiveDate::from_ymd_opt(2024, 12, 31).unwrap()),
start_date: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
task_type: None,
status: None,
};
let task_uuid = db.create_task(request).await?;
println!("Created task with UUID: {}", task_uuid);§Errors
Returns an error if validation fails or if the database insert fails
Sourcepub async fn create_project(
&self,
request: CreateProjectRequest,
) -> ThingsResult<Uuid>
pub async fn create_project( &self, request: CreateProjectRequest, ) -> ThingsResult<Uuid>
Create a new project
Projects are tasks with type = 1 in the TMTask table
§Errors
Returns an error if validation fails or the database insert fails
Sourcepub async fn update_task(&self, request: UpdateTaskRequest) -> ThingsResult<()>
pub async fn update_task(&self, request: UpdateTaskRequest) -> ThingsResult<()>
Update an existing task
Only updates fields that are provided (Some(_)) Validates existence of referenced entities
§Errors
Returns an error if the task doesn’t exist, validation fails, or the database update fails
Sourcepub async fn get_project_by_uuid(
&self,
uuid: &Uuid,
) -> ThingsResult<Option<Project>>
pub async fn get_project_by_uuid( &self, uuid: &Uuid, ) -> ThingsResult<Option<Project>>
Get a single project by UUID
Returns None if the project doesn’t exist or is trashed
§Errors
Returns an error if the database query fails
Sourcepub async fn update_project(
&self,
request: UpdateProjectRequest,
) -> ThingsResult<()>
pub async fn update_project( &self, request: UpdateProjectRequest, ) -> ThingsResult<()>
Update an existing project
Only updates fields that are provided (Some(_)) Validates existence and that the entity is a project (type = 1)
§Errors
Returns an error if the project doesn’t exist, validation fails, or the database update fails
Sourcepub async fn get_task_by_uuid(&self, uuid: &Uuid) -> ThingsResult<Option<Task>>
pub async fn get_task_by_uuid(&self, uuid: &Uuid) -> ThingsResult<Option<Task>>
Get a task by its UUID
§Errors
Returns an error if the task does not exist or if the database query fails
Sourcepub async fn complete_task(&self, uuid: &Uuid) -> ThingsResult<()>
pub async fn complete_task(&self, uuid: &Uuid) -> ThingsResult<()>
Mark a task as completed
§Errors
Returns an error if the task does not exist or if the database update fails
Sourcepub async fn uncomplete_task(&self, uuid: &Uuid) -> ThingsResult<()>
pub async fn uncomplete_task(&self, uuid: &Uuid) -> ThingsResult<()>
Mark a completed task as incomplete
§Errors
Returns an error if the task does not exist or if the database update fails
Sourcepub async fn complete_project(
&self,
uuid: &Uuid,
child_handling: ProjectChildHandling,
) -> ThingsResult<()>
pub async fn complete_project( &self, uuid: &Uuid, child_handling: ProjectChildHandling, ) -> ThingsResult<()>
Complete a project and optionally handle its child tasks
§Errors
Returns an error if the project doesn’t exist or if the database update fails
Sourcepub async fn delete_task(
&self,
uuid: &Uuid,
child_handling: DeleteChildHandling,
) -> ThingsResult<()>
pub async fn delete_task( &self, uuid: &Uuid, child_handling: DeleteChildHandling, ) -> ThingsResult<()>
Soft delete a task (set trashed flag)
§Errors
Returns an error if the task does not exist, if child handling fails, or if the database update fails
Sourcepub async fn delete_project(
&self,
uuid: &Uuid,
child_handling: ProjectChildHandling,
) -> ThingsResult<()>
pub async fn delete_project( &self, uuid: &Uuid, child_handling: ProjectChildHandling, ) -> ThingsResult<()>
Soft delete a project and handle its child tasks
§Errors
Returns an error if the project doesn’t exist, if child handling fails, or if the database update fails
Sourcepub async fn create_area(
&self,
request: CreateAreaRequest,
) -> ThingsResult<Uuid>
pub async fn create_area( &self, request: CreateAreaRequest, ) -> ThingsResult<Uuid>
Sourcepub async fn update_area(&self, request: UpdateAreaRequest) -> ThingsResult<()>
pub async fn update_area(&self, request: UpdateAreaRequest) -> ThingsResult<()>
Update an existing area
§Errors
Returns an error if the area doesn’t exist or if the database update fails
Sourcepub async fn delete_area(&self, uuid: &Uuid) -> ThingsResult<()>
pub async fn delete_area(&self, uuid: &Uuid) -> ThingsResult<()>
Delete an area
Hard delete (areas don’t have a trashed field) Orphans all projects in the area by setting their area to NULL
§Errors
Returns an error if the area doesn’t exist or if the database delete fails
Sourcepub async fn find_tag_by_normalized_title(
&self,
normalized: &str,
) -> ThingsResult<Option<Tag>>
pub async fn find_tag_by_normalized_title( &self, normalized: &str, ) -> ThingsResult<Option<Tag>>
Find a tag by normalized title (exact match, case-insensitive)
§Errors
Returns an error if the database query fails
Find tags similar to the given title using fuzzy matching
Returns tags sorted by similarity score (highest first)
§Errors
Returns an error if the database query fails
Sourcepub async fn create_tag_smart(
&self,
request: CreateTagRequest,
) -> ThingsResult<TagCreationResult>
pub async fn create_tag_smart( &self, request: CreateTagRequest, ) -> ThingsResult<TagCreationResult>
Create a tag with smart duplicate detection
Returns:
Created: New tag was createdExisting: Exact match found (case-insensitive)SimilarFound: Similar tags found (user decision needed)
§Errors
Returns an error if the database operation fails
Sourcepub async fn create_tag_force(
&self,
request: CreateTagRequest,
) -> ThingsResult<Uuid>
pub async fn create_tag_force( &self, request: CreateTagRequest, ) -> ThingsResult<Uuid>
Create tag forcefully (skip duplicate check)
§Errors
Returns an error if the database operation fails
Sourcepub async fn update_tag(&self, request: UpdateTagRequest) -> ThingsResult<()>
pub async fn update_tag(&self, request: UpdateTagRequest) -> ThingsResult<()>
Sourcepub async fn delete_tag(
&self,
uuid: &Uuid,
remove_from_tasks: bool,
) -> ThingsResult<()>
pub async fn delete_tag( &self, uuid: &Uuid, remove_from_tasks: bool, ) -> ThingsResult<()>
Sourcepub async fn add_tag_to_task(
&self,
task_uuid: &Uuid,
tag_title: &str,
) -> ThingsResult<TagAssignmentResult>
pub async fn add_tag_to_task( &self, task_uuid: &Uuid, tag_title: &str, ) -> ThingsResult<TagAssignmentResult>
Add a tag to a task (with duplicate prevention)
Returns:
Assigned: Tag was successfully assignedSuggestions: Similar tags found (user decision needed)
§Errors
Returns an error if the task doesn’t exist or database operation fails
Sourcepub async fn remove_tag_from_task(
&self,
task_uuid: &Uuid,
tag_title: &str,
) -> ThingsResult<()>
pub async fn remove_tag_from_task( &self, task_uuid: &Uuid, tag_title: &str, ) -> ThingsResult<()>
Remove a tag from a task
§Errors
Returns an error if the task doesn’t exist or database operation fails
Replace all tags on a task (with duplicate prevention)
Returns any tag titles that had similar matches for user confirmation
§Errors
Returns an error if the task doesn’t exist or database operation fails
Sourcepub async fn get_tag_completions(
&self,
partial_input: &str,
limit: usize,
) -> ThingsResult<Vec<TagCompletion>>
pub async fn get_tag_completions( &self, partial_input: &str, limit: usize, ) -> ThingsResult<Vec<TagCompletion>>
Get tag completions for partial input
Returns tags sorted by:
- Exact prefix matches (prioritized)
- Contains matches
- Fuzzy matches Within each category, sorted by usage frequency
§Errors
Returns an error if the database query fails
Sourcepub async fn get_tag_statistics(
&self,
uuid: &Uuid,
) -> ThingsResult<TagStatistics>
pub async fn get_tag_statistics( &self, uuid: &Uuid, ) -> ThingsResult<TagStatistics>
Get detailed statistics for a tag
§Errors
Returns an error if the tag doesn’t exist or database query fails
Find duplicate or highly similar tags
Returns pairs of tags that are similar above the threshold
§Errors
Returns an error if the database query fails
Sourcepub async fn bulk_move(
&self,
request: BulkMoveRequest,
) -> ThingsResult<BulkOperationResult>
pub async fn bulk_move( &self, request: BulkMoveRequest, ) -> ThingsResult<BulkOperationResult>
Move multiple tasks to a project or area (transactional)
All tasks must exist and be valid, or the entire operation will be rolled back.
§Errors
Returns an error if:
- Task UUIDs array is empty
- Neither project_uuid nor area_uuid is specified
- Target project or area doesn’t exist
- Any task UUID is invalid or doesn’t exist
- Database operation fails
Sourcepub async fn bulk_update_dates(
&self,
request: BulkUpdateDatesRequest,
) -> ThingsResult<BulkOperationResult>
pub async fn bulk_update_dates( &self, request: BulkUpdateDatesRequest, ) -> ThingsResult<BulkOperationResult>
Update dates for multiple tasks with validation (transactional)
All tasks must exist and dates must be valid, or the entire operation will be rolled back. Validates that deadline >= start_date for each task after merging with existing dates.
§Errors
Returns an error if:
- Task UUIDs array is empty
- Any task UUID is invalid or doesn’t exist
- Date range validation fails (deadline before start_date)
- Database operation fails
Sourcepub async fn bulk_complete(
&self,
request: BulkCompleteRequest,
) -> ThingsResult<BulkOperationResult>
pub async fn bulk_complete( &self, request: BulkCompleteRequest, ) -> ThingsResult<BulkOperationResult>
Complete multiple tasks (transactional)
All tasks must exist, or the entire operation will be rolled back.
§Errors
Returns an error if:
- Task UUIDs array is empty
- Any task UUID is invalid or doesn’t exist
- Database operation fails
Sourcepub async fn bulk_delete(
&self,
request: BulkDeleteRequest,
) -> ThingsResult<BulkOperationResult>
pub async fn bulk_delete( &self, request: BulkDeleteRequest, ) -> ThingsResult<BulkOperationResult>
Delete multiple tasks (soft delete, transactional)
All tasks must exist, or the entire operation will be rolled back.
§Errors
Returns an error if:
- Task UUIDs array is empty
- Any task UUID is invalid or doesn’t exist
- Database operation fails
Trait Implementations§
Source§impl Clone for ThingsDatabase
impl Clone for ThingsDatabase
Source§fn clone(&self) -> ThingsDatabase
fn clone(&self) -> ThingsDatabase
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ThingsDatabase
impl !RefUnwindSafe for ThingsDatabase
impl Send for ThingsDatabase
impl Sync for ThingsDatabase
impl Unpin for ThingsDatabase
impl !UnwindSafe for ThingsDatabase
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more