things3_core/database/
validators.rs1#![allow(deprecated)]
3use crate::error::{Result as ThingsResult, ThingsError};
8use crate::models::ThingsId;
9use sqlx::SqlitePool;
10use tracing::instrument;
11
12#[instrument(skip(pool))]
18pub async fn validate_task_exists(pool: &SqlitePool, id: &ThingsId) -> ThingsResult<()> {
19 let exists = sqlx::query("SELECT 1 FROM TMTask WHERE uuid = ? AND trashed = 0")
20 .bind(id.as_str())
21 .fetch_optional(pool)
22 .await
23 .map_err(|e| ThingsError::unknown(format!("Failed to validate task: {e}")))?
24 .is_some();
25
26 if !exists {
27 return Err(ThingsError::unknown(format!("Task not found: {id}")));
28 }
29 Ok(())
30}
31
32#[instrument(skip(pool))]
38pub async fn validate_project_exists(pool: &SqlitePool, id: &ThingsId) -> ThingsResult<()> {
39 let exists = sqlx::query("SELECT 1 FROM TMTask WHERE uuid = ? AND type = 1 AND trashed = 0")
40 .bind(id.as_str())
41 .fetch_optional(pool)
42 .await
43 .map_err(|e| ThingsError::unknown(format!("Failed to validate project: {e}")))?
44 .is_some();
45
46 if !exists {
47 return Err(ThingsError::ProjectNotFound {
48 uuid: id.to_string(),
49 });
50 }
51 Ok(())
52}
53
54#[instrument(skip(pool))]
60pub async fn validate_area_exists(pool: &SqlitePool, id: &ThingsId) -> ThingsResult<()> {
61 let exists = sqlx::query("SELECT 1 FROM TMArea WHERE uuid = ?")
62 .bind(id.as_str())
63 .fetch_optional(pool)
64 .await
65 .map_err(|e| ThingsError::unknown(format!("Failed to validate area: {e}")))?
66 .is_some();
67
68 if !exists {
69 return Err(ThingsError::unknown(format!("Area not found: {id}")));
70 }
71 Ok(())
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[cfg(feature = "test-utils")]
79 #[tokio::test]
80 async fn test_validate_nonexistent_task() {
81 use crate::test_utils::create_test_database;
82 use tempfile::NamedTempFile;
83
84 let temp_file = NamedTempFile::new().unwrap();
85 let db_path = temp_file.path();
86 create_test_database(db_path).await.unwrap();
87
88 let pool = sqlx::SqlitePool::connect(&format!("sqlite://{}", db_path.display()))
89 .await
90 .unwrap();
91
92 let id = ThingsId::new_v4();
93 let result = validate_task_exists(&pool, &id).await;
94
95 assert!(result.is_err());
96 assert!(result.unwrap_err().to_string().contains("Task not found"));
97 }
98
99 #[cfg(feature = "test-utils")]
100 #[tokio::test]
101 async fn test_validate_nonexistent_project() {
102 use crate::test_utils::create_test_database;
103 use tempfile::NamedTempFile;
104
105 let temp_file = NamedTempFile::new().unwrap();
106 let db_path = temp_file.path();
107 create_test_database(db_path).await.unwrap();
108
109 let pool = sqlx::SqlitePool::connect(&format!("sqlite://{}", db_path.display()))
110 .await
111 .unwrap();
112
113 let id = ThingsId::new_v4();
114 let result = validate_project_exists(&pool, &id).await;
115
116 assert!(result.is_err());
117 assert!(result
118 .unwrap_err()
119 .to_string()
120 .contains("Project not found"));
121 }
122
123 #[cfg(feature = "test-utils")]
124 #[tokio::test]
125 async fn test_validate_nonexistent_area() {
126 use crate::test_utils::create_test_database;
127 use tempfile::NamedTempFile;
128
129 let temp_file = NamedTempFile::new().unwrap();
130 let db_path = temp_file.path();
131 create_test_database(db_path).await.unwrap();
132
133 let pool = sqlx::SqlitePool::connect(&format!("sqlite://{}", db_path.display()))
134 .await
135 .unwrap();
136
137 let id = ThingsId::new_v4();
138 let result = validate_area_exists(&pool, &id).await;
139
140 assert!(result.is_err());
141 assert!(result.unwrap_err().to_string().contains("Area not found"));
142 }
143}