things3_core/database/queries/
projects.rs1#![allow(deprecated)]
2
3use crate::{
4 database::{conversions::safe_timestamp_convert, mappers::map_project_row, ThingsDatabase},
5 error::{Result as ThingsResult, ThingsError},
6 models::{Project, TaskStatus, ThingsId},
7};
8use chrono::{DateTime, Utc};
9use sqlx::Row;
10use tracing::{debug, instrument};
11
12impl ThingsDatabase {
13 #[instrument]
19 pub async fn get_all_projects(&self) -> ThingsResult<Vec<Project>> {
20 let rows = sqlx::query(
21 r"
22 SELECT
23 uuid, title, status,
24 area, notes,
25 creationDate, userModificationDate,
26 startDate, deadline
27 FROM TMTask
28 WHERE type = 1 AND trashed = 0
29 ORDER BY creationDate DESC
30 ",
31 )
32 .fetch_all(&self.pool)
33 .await
34 .map_err(|e| ThingsError::unknown(format!("Failed to fetch projects: {e}")))?;
35
36 let mut projects = Vec::new();
37 for row in rows {
38 let project = Project {
39 uuid: ThingsId::from_trusted(row.get::<String, _>("uuid")),
40 title: row.get("title"),
41 status: TaskStatus::from_i32(row.get("status")).unwrap_or(TaskStatus::Incomplete),
42 area_uuid: row
43 .get::<Option<String>, _>("area")
44 .map(ThingsId::from_trusted),
45 notes: row.get("notes"),
46 deadline: row
47 .get::<Option<i64>, _>("deadline")
48 .and_then(|ts| DateTime::from_timestamp(ts, 0))
49 .map(|dt| dt.date_naive()),
50 start_date: row
51 .get::<Option<i64>, _>("startDate")
52 .and_then(|ts| DateTime::from_timestamp(ts, 0))
53 .map(|dt| dt.date_naive()),
54 tags: Vec::new(), tasks: Vec::new(), created: {
57 let ts_f64 = row.get::<f64, _>("creationDate");
58 let ts = safe_timestamp_convert(ts_f64);
59 DateTime::from_timestamp(ts, 0).unwrap_or_else(Utc::now)
60 },
61 modified: {
62 let ts_f64 = row.get::<f64, _>("userModificationDate");
63 let ts = safe_timestamp_convert(ts_f64);
64 DateTime::from_timestamp(ts, 0).unwrap_or_else(Utc::now)
65 },
66 };
67 projects.push(project);
68 }
69
70 debug!("Fetched {} projects", projects.len());
71 Ok(projects)
72 }
73
74 #[instrument(skip(self))]
80 pub async fn get_projects(&self, limit: Option<usize>) -> ThingsResult<Vec<Project>> {
81 let _ = limit; self.get_all_projects().await
83 }
84
85 #[instrument(skip(self))]
93 pub async fn get_project_by_uuid(&self, id: &ThingsId) -> ThingsResult<Option<Project>> {
94 let row = sqlx::query(
95 r"
96 SELECT
97 uuid, title, status,
98 area, notes,
99 creationDate, userModificationDate,
100 startDate, deadline,
101 trashed, type
102 FROM TMTask
103 WHERE uuid = ? AND type = 1
104 ",
105 )
106 .bind(id.as_str())
107 .fetch_optional(&self.pool)
108 .await
109 .map_err(|e| ThingsError::unknown(format!("Failed to fetch project: {e}")))?;
110
111 if let Some(row) = row {
112 let trashed: i64 = row.get("trashed");
113 if trashed == 1 {
114 return Ok(None);
115 }
116 Ok(Some(map_project_row(&row)))
117 } else {
118 Ok(None)
119 }
120 }
121}