Skip to main content

things3_core/database/mutations/
areas.rs

1#![allow(deprecated)]
2
3use crate::{
4    database::{validators, ThingsDatabase},
5    error::{Result as ThingsResult, ThingsError},
6    models::ThingsId,
7};
8use chrono::Utc;
9use tracing::{info, instrument};
10
11impl ThingsDatabase {
12    /// Create a new area
13    ///
14    /// # Errors
15    ///
16    /// Returns an error if the database insert fails
17    #[instrument(skip(self))]
18    pub async fn create_area(
19        &self,
20        request: crate::models::CreateAreaRequest,
21    ) -> ThingsResult<ThingsId> {
22        // Generate ID for new area
23        let id = ThingsId::new_things_native();
24
25        // Get current timestamp for creation/modification dates
26        let now = Utc::now().timestamp() as f64;
27
28        // Calculate next index (max + 1)
29        let max_index: Option<i64> = sqlx::query_scalar("SELECT MAX(`index`) FROM TMArea")
30            .fetch_one(&self.pool)
31            .await
32            .map_err(|e| ThingsError::unknown(format!("Failed to get max area index: {e}")))?;
33
34        let next_index = max_index.unwrap_or(-1) + 1;
35
36        // Insert into TMArea table
37        sqlx::query(
38            r"
39            INSERT INTO TMArea (
40                uuid, title, visible, `index`,
41                creationDate, userModificationDate
42            ) VALUES (?, ?, 1, ?, ?, ?)
43            ",
44        )
45        .bind(id.as_str())
46        .bind(&request.title)
47        .bind(next_index)
48        .bind(now)
49        .bind(now)
50        .execute(&self.pool)
51        .await
52        .map_err(|e| ThingsError::unknown(format!("Failed to create area: {e}")))?;
53
54        info!("Created area with UUID: {}", id);
55        Ok(id)
56    }
57
58    /// Update an existing area
59    ///
60    /// # Errors
61    ///
62    /// Returns an error if the area doesn't exist or if the database update fails
63    #[instrument(skip(self))]
64    pub async fn update_area(&self, request: crate::models::UpdateAreaRequest) -> ThingsResult<()> {
65        // Verify area exists
66        validators::validate_area_exists(&self.pool, &request.uuid).await?;
67
68        let now = Utc::now().timestamp() as f64;
69
70        sqlx::query("UPDATE TMArea SET title = ?, userModificationDate = ? WHERE uuid = ?")
71            .bind(&request.title)
72            .bind(now)
73            .bind(request.uuid.as_str())
74            .execute(&self.pool)
75            .await
76            .map_err(|e| ThingsError::unknown(format!("Failed to update area: {e}")))?;
77
78        info!("Updated area with UUID: {}", request.uuid);
79        Ok(())
80    }
81
82    /// Delete an area
83    ///
84    /// Hard delete (areas don't have a trashed field)
85    /// Orphans all projects in the area by setting their area to NULL
86    ///
87    /// # Errors
88    ///
89    /// Returns an error if the area doesn't exist or if the database delete fails
90    #[instrument(skip(self))]
91    pub async fn delete_area(&self, id: &ThingsId) -> ThingsResult<()> {
92        // Verify area exists
93        validators::validate_area_exists(&self.pool, id).await?;
94
95        let now = Utc::now().timestamp() as f64;
96
97        // Orphan all projects in this area (set area to NULL)
98        sqlx::query(
99            "UPDATE TMTask SET area = NULL, userModificationDate = ? WHERE area = ? AND type = 1 AND trashed = 0",
100        )
101        .bind(now)
102        .bind(id.as_str())
103        .execute(&self.pool)
104        .await
105        .map_err(|e| ThingsError::unknown(format!("Failed to orphan projects in area: {e}")))?;
106
107        // Delete the area (hard delete)
108        sqlx::query("DELETE FROM TMArea WHERE uuid = ?")
109            .bind(id.as_str())
110            .execute(&self.pool)
111            .await
112            .map_err(|e| ThingsError::unknown(format!("Failed to delete area: {e}")))?;
113
114        info!("Deleted area with UUID: {}", id);
115        Ok(())
116    }
117}