summaryrefslogtreecommitdiffstats
path: root/src/likes/models.rs
blob: 56001d9de55767a9cde24b5b0884d4abf33ae686 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use crate::{db::get_client, errors::AppError};
use chrono::{Local, NaiveDateTime};
use serde::{Deserialize, Serialize};
use sqlx::Row;

/// Likes model
#[derive(Serialize, Deserialize, sqlx::FromRow)]
pub struct Like {
    id: i32,
    user_id: i32,
    model_id: i32,
    created: NaiveDateTime,
}

impl Like {
    /// Create a new like
    pub fn new(user_id: i32, model_id: i32) -> Self {
        let now = Local::now().naive_utc();
        Self {
            id: 0,
            user_id,
            model_id,
            created: now,
        }
    }

    /// Returns `true` if an user has already assigned a like to a model
    pub async fn exists(&self) -> Result<bool, AppError> {
        let pool = unsafe { get_client() };
        let cursor = sqlx::query(
            r#"
                SELECT COUNT(id) as count FROM likes WHERE user_id = $1 AND model_id = $2
            "#,
        )
        .bind(self.user_id)
        .bind(self.model_id)
        .fetch_one(pool)
        .await?;

        let count: i64 = cursor.try_get(0).unwrap();

        Ok(count > 0)
    }

    /// Save new like into db
    pub async fn save(&self) -> Result<Like, AppError> {
        let pool = unsafe { get_client() };

        if self.exists().await? {
            return Err(AppError::BadRequest(
                "This user already likes this model".to_string(),
            ));
        }

        let rec: Like = sqlx::query_as(
            r#"
            INSERT INTO likes (user_id, model_id, created)
            VALUES ($1, $2, $3)
            RETURNING *
            "#,
        )
        .bind(self.user_id)
        .bind(self.model_id)
        .bind(self.created)
        .fetch_one(pool)
        .await?;

        Ok(rec)
    }

    /// Remove a like
    pub async fn remove(&self) -> Result<(), AppError> {
        let pool = unsafe { get_client() };

        if !self.exists().await? {
            return Err(AppError::NotFound("Like not found".to_string()));
        }

        sqlx::query(
            r#"
            DELETE FROM likes WHERE user_id = $1 AND model_id = $2
            "#,
        )
        .bind(self.user_id)
        .bind(self.model_id)
        .execute(pool)
        .await?;

        Ok(())
    }
}