Skip to main content

mini_apm/models/
deploy.rs

1use crate::DbPool;
2use chrono::Utc;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Deploy {
7    pub id: i64,
8    pub project_id: Option<i64>,
9    pub git_sha: String,
10    pub version: Option<String>,
11    pub env: Option<String>,
12    pub deployed_at: String,
13    pub description: Option<String>,
14    pub deployer: Option<String>,
15}
16
17impl Deploy {
18    pub fn short_sha(&self) -> &str {
19        if self.git_sha.len() >= 7 {
20            &self.git_sha[..7]
21        } else {
22            &self.git_sha
23        }
24    }
25}
26
27#[derive(Debug, Deserialize)]
28pub struct IncomingDeploy {
29    pub git_sha: String,
30    pub version: Option<String>,
31    pub env: Option<String>,
32    pub description: Option<String>,
33    pub deployer: Option<String>,
34    pub timestamp: Option<String>,
35}
36
37pub fn insert(
38    pool: &DbPool,
39    deploy: &IncomingDeploy,
40    project_id: Option<i64>,
41) -> anyhow::Result<i64> {
42    let conn = pool.get()?;
43    let now = Utc::now().to_rfc3339();
44    let timestamp = deploy.timestamp.as_ref().unwrap_or(&now);
45
46    conn.execute(
47        r#"
48        INSERT INTO deploys (project_id, git_sha, version, env, deployed_at, description, deployer)
49        VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
50        "#,
51        (
52            project_id,
53            &deploy.git_sha,
54            &deploy.version,
55            &deploy.env,
56            timestamp,
57            &deploy.description,
58            &deploy.deployer,
59        ),
60    )?;
61
62    Ok(conn.last_insert_rowid())
63}
64
65pub fn list(pool: &DbPool, project_id: Option<i64>, limit: i64) -> anyhow::Result<Vec<Deploy>> {
66    let conn = pool.get()?;
67    let mut stmt = conn.prepare(
68        r#"
69        SELECT id, project_id, git_sha, version, env,
70               strftime('%Y-%m-%d %H:%M', deployed_at) as deployed_at,
71               description, deployer
72        FROM deploys
73        WHERE (?1 IS NULL OR project_id = ?1)
74        ORDER BY deployed_at DESC
75        LIMIT ?2
76        "#,
77    )?;
78
79    let deploys = stmt
80        .query_map(rusqlite::params![project_id, limit], |row| {
81            Ok(Deploy {
82                id: row.get(0)?,
83                project_id: row.get(1)?,
84                git_sha: row.get(2)?,
85                version: row.get(3)?,
86                env: row.get(4)?,
87                deployed_at: row.get(5)?,
88                description: row.get(6)?,
89                deployer: row.get(7)?,
90            })
91        })?
92        .collect::<Result<Vec<_>, _>>()?;
93
94    Ok(deploys)
95}
96
97/// Get deploys within a time range for chart markers
98pub fn list_since(
99    pool: &DbPool,
100    project_id: Option<i64>,
101    since: &str,
102) -> anyhow::Result<Vec<Deploy>> {
103    let conn = pool.get()?;
104    let mut stmt = conn.prepare(
105        r#"
106        SELECT id, project_id, git_sha, version, env,
107               deployed_at,
108               description, deployer
109        FROM deploys
110        WHERE deployed_at >= ?1 AND (?2 IS NULL OR project_id = ?2)
111        ORDER BY deployed_at ASC
112        "#,
113    )?;
114
115    let deploys = stmt
116        .query_map(rusqlite::params![since, project_id], |row| {
117            Ok(Deploy {
118                id: row.get(0)?,
119                project_id: row.get(1)?,
120                git_sha: row.get(2)?,
121                version: row.get(3)?,
122                env: row.get(4)?,
123                deployed_at: row.get(5)?,
124                description: row.get(6)?,
125                deployer: row.get(7)?,
126            })
127        })?
128        .collect::<Result<Vec<_>, _>>()?;
129
130    Ok(deploys)
131}
132
133/// Get the most recent deploy
134pub fn latest(pool: &DbPool, project_id: Option<i64>) -> anyhow::Result<Option<Deploy>> {
135    let conn = pool.get()?;
136    let deploy = conn
137        .query_row(
138            r#"
139            SELECT id, project_id, git_sha, version, env,
140                   strftime('%Y-%m-%d %H:%M', deployed_at) as deployed_at,
141                   description, deployer
142            FROM deploys
143            WHERE (?1 IS NULL OR project_id = ?1)
144            ORDER BY deployed_at DESC
145            LIMIT 1
146            "#,
147            rusqlite::params![project_id],
148            |row| {
149                Ok(Deploy {
150                    id: row.get(0)?,
151                    project_id: row.get(1)?,
152                    git_sha: row.get(2)?,
153                    version: row.get(3)?,
154                    env: row.get(4)?,
155                    deployed_at: row.get(5)?,
156                    description: row.get(6)?,
157                    deployer: row.get(7)?,
158                })
159            },
160        )
161        .ok();
162
163    Ok(deploy)
164}
165
166pub fn delete_before(pool: &DbPool, before: &str) -> anyhow::Result<usize> {
167    let conn = pool.get()?;
168    let deleted = conn.execute("DELETE FROM deploys WHERE deployed_at < ?1", [before])?;
169    Ok(deleted)
170}