OXYGENHUB
# 19bb31ff1f5c oxygenhub / crates / hub / src / db / repos.rs
4.6 KiB · Rust · last changed Milestone 0.2: accounts and access 1 month ago source blame history raw
1
//! The `repositories` and `pushes` tables.
2
3
use super::{now_ms, Pool};
4
use hub_api::Visibility;
5
use sqlx::FromRow;
6
7
#[derive(Clone, Debug, FromRow)]
8
pub struct RepoRow {
9
    pub id: i64,
10
    pub owner: String,
11
    pub name: String,
12
    pub description: String,
13
    pub default_bookmark: String,
14
    pub visibility: String,
15
    pub created_ms: i64,
16
    pub updated_ms: i64,
17
}
18
19
impl RepoRow {
20
    pub fn visibility(&self) -> Visibility {
21
        Visibility::parse(&self.visibility).unwrap_or(Visibility::Private)
22
    }
23
24
    pub fn slug(&self) -> String {
25
        format!("{}/{}", self.owner, self.name)
26
    }
27
}
28
29
#[derive(Clone, Debug, FromRow)]
30
pub struct PushRow {
31
    pub id: i64,
32
    pub at_ms: i64,
33
    pub reference: String,
34
    pub ok: bool,
35
    pub reason: String,
36
    pub old_state: String,
37
    pub new_state: String,
38
    pub heads: i64,
39
    pub changes: i64,
40
    pub pusher: String,
41
}
42
43
/// One reference's outcome in a push, as the protocol backend reports it.
44
#[derive(Clone, Debug)]
45
pub struct PushOutcome {
46
    pub reference: String,
47
    pub ok: bool,
48
    pub reason: String,
49
    pub old_state: String,
50
    pub new_state: String,
51
    pub heads: i64,
52
    pub changes: i64,
53
}
54
55
pub async fn list(pool: &Pool) -> sqlx::Result<Vec<RepoRow>> {
56
    sqlx::query_as("SELECT * FROM repositories ORDER BY updated_ms DESC, owner, name").fetch_all(pool).await
57
}
58
59
pub async fn get_by_id(pool: &Pool, id: i64) -> sqlx::Result<Option<RepoRow>> {
60
    sqlx::query_as("SELECT * FROM repositories WHERE id = ?").bind(id).fetch_optional(pool).await
61
}
62
63
pub async fn list_by_owner(pool: &Pool, owner: &str) -> sqlx::Result<Vec<RepoRow>> {
64
    sqlx::query_as("SELECT * FROM repositories WHERE owner = ? ORDER BY updated_ms DESC, name").bind(owner).fetch_all(pool).await
65
}
66
67
pub async fn get(pool: &Pool, owner: &str, name: &str) -> sqlx::Result<Option<RepoRow>> {
68
    sqlx::query_as("SELECT * FROM repositories WHERE owner = ? AND name = ?").bind(owner).bind(name).fetch_optional(pool).await
69
}
70
71
pub async fn create(pool: &Pool, owner: &str, name: &str, description: &str, visibility: Visibility) -> sqlx::Result<RepoRow> {
72
    let now = now_ms();
73
    sqlx::query_as(
74
        "INSERT INTO repositories (owner, name, description, visibility, created_ms, updated_ms) VALUES (?, ?, ?, ?, ?, ?) RETURNING *",
75
    )
76
    .bind(owner)
77
    .bind(name)
78
    .bind(description)
79
    .bind(visibility.as_str())
80
    .bind(now)
81
    .bind(now)
82
    .fetch_one(pool)
83
    .await
84
}
85
86
pub async fn delete(pool: &Pool, id: i64) -> sqlx::Result<()> {
87
    sqlx::query("DELETE FROM repositories WHERE id = ?").bind(id).execute(pool).await?;
88
    Ok(())
89
}
90
91
pub async fn set_description(pool: &Pool, id: i64, description: &str) -> sqlx::Result<()> {
92
    sqlx::query("UPDATE repositories SET description = ? WHERE id = ?").bind(description).bind(id).execute(pool).await?;
93
    Ok(())
94
}
95
96
pub async fn set_default_bookmark(pool: &Pool, id: i64, bookmark: &str) -> sqlx::Result<()> {
97
    sqlx::query("UPDATE repositories SET default_bookmark = ? WHERE id = ?").bind(bookmark).bind(id).execute(pool).await?;
98
    Ok(())
99
}
100
101
pub async fn set_visibility(pool: &Pool, id: i64, visibility: Visibility) -> sqlx::Result<()> {
102
    sqlx::query("UPDATE repositories SET visibility = ? WHERE id = ?").bind(visibility.as_str()).bind(id).execute(pool).await?;
103
    Ok(())
104
}
105
106
/// Record a push's per-reference results and bump the repository's activity.
107
pub async fn record_push(pool: &Pool, id: i64, pusher: Option<(i64, &str)>, results: &[PushOutcome]) -> sqlx::Result<()> {
108
    let now = now_ms();
109
    let mut tx = pool.begin().await?;
110
    for r in results {
111
        sqlx::query("INSERT INTO pushes (repo_id, at_ms, reference, ok, reason, old_state, new_state, heads, changes, account_id, pusher) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
112
            .bind(id)
113
            .bind(now)
114
            .bind(&r.reference)
115
            .bind(r.ok)
116
            .bind(&r.reason)
117
            .bind(&r.old_state)
118
            .bind(&r.new_state)
119
            .bind(r.heads)
120
            .bind(r.changes)
121
            .bind(pusher.map(|p| p.0).filter(|id| *id > 0))
122
            .bind(pusher.map(|p| p.1).unwrap_or(""))
123
            .execute(&mut *tx)
124
            .await?;
125
    }
126
    if results.iter().any(|r| r.ok) {
127
        sqlx::query("UPDATE repositories SET updated_ms = ? WHERE id = ?").bind(now).bind(id).execute(&mut *tx).await?;
128
    }
129
    tx.commit().await
130
}
131
132
pub async fn pushes(pool: &Pool, id: i64, limit: i64) -> sqlx::Result<Vec<PushRow>> {
133
    sqlx::query_as("SELECT id, at_ms, reference, ok, reason, old_state, new_state, heads, changes, pusher FROM pushes WHERE repo_id = ? ORDER BY at_ms DESC, id DESC LIMIT ?")
134
        .bind(id)
135
        .bind(limit)
136
        .fetch_all(pool)
137
        .await
138
}