OXYGENHUB
# 07b1a5bbf481 oxygenhub / crates / hub / src / db / repos.rs
5.8 KiB · Rust · last changed Forks 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
    #[sqlx(default)]
18
    pub git_mirror: bool,
19
    #[sqlx(default)]
20
    pub git_mirror_state: String,
21
    /// The repository this one was forked from (migration 0009).
22
    #[sqlx(default)]
23
    pub forked_from: Option<i64>,
24
}
25
26
impl RepoRow {
27
    pub fn visibility(&self) -> Visibility {
28
        Visibility::parse(&self.visibility).unwrap_or(Visibility::Private)
29
    }
30
31
    pub fn slug(&self) -> String {
32
        format!("{}/{}", self.owner, self.name)
33
    }
34
}
35
36
#[derive(Clone, Debug, FromRow)]
37
pub struct PushRow {
38
    pub id: i64,
39
    pub at_ms: i64,
40
    pub reference: String,
41
    pub ok: bool,
42
    pub reason: String,
43
    pub old_state: String,
44
    pub new_state: String,
45
    pub heads: i64,
46
    pub changes: i64,
47
    pub pusher: String,
48
}
49
50
/// One reference's outcome in a push, as the protocol backend reports it.
51
#[derive(Clone, Debug)]
52
pub struct PushOutcome {
53
    pub reference: String,
54
    pub ok: bool,
55
    pub reason: String,
56
    pub old_state: String,
57
    pub new_state: String,
58
    pub heads: i64,
59
    pub changes: i64,
60
}
61
62
pub async fn list(pool: &Pool) -> sqlx::Result<Vec<RepoRow>> {
63
    sqlx::query_as("SELECT * FROM repositories ORDER BY updated_ms DESC, owner, name").fetch_all(pool).await
64
}
65
66
pub async fn get_by_id(pool: &Pool, id: i64) -> sqlx::Result<Option<RepoRow>> {
67
    sqlx::query_as("SELECT * FROM repositories WHERE id = ?").bind(id).fetch_optional(pool).await
68
}
69
70
pub async fn list_by_owner(pool: &Pool, owner: &str) -> sqlx::Result<Vec<RepoRow>> {
71
    sqlx::query_as("SELECT * FROM repositories WHERE owner = ? ORDER BY updated_ms DESC, name").bind(owner).fetch_all(pool).await
72
}
73
74
pub async fn get(pool: &Pool, owner: &str, name: &str) -> sqlx::Result<Option<RepoRow>> {
75
    sqlx::query_as("SELECT * FROM repositories WHERE owner = ? AND name = ?").bind(owner).bind(name).fetch_optional(pool).await
76
}
77
78
pub async fn create(pool: &Pool, owner: &str, name: &str, description: &str, visibility: Visibility) -> sqlx::Result<RepoRow> {
79
    let now = now_ms();
80
    sqlx::query_as(
81
        "INSERT INTO repositories (owner, name, description, visibility, created_ms, updated_ms) VALUES (?, ?, ?, ?, ?, ?) RETURNING *",
82
    )
83
    .bind(owner)
84
    .bind(name)
85
    .bind(description)
86
    .bind(visibility.as_str())
87
    .bind(now)
88
    .bind(now)
89
    .fetch_one(pool)
90
    .await
91
}
92
93
pub async fn delete(pool: &Pool, id: i64) -> sqlx::Result<()> {
94
    sqlx::query("DELETE FROM repositories WHERE id = ?").bind(id).execute(pool).await?;
95
    Ok(())
96
}
97
98
pub async fn set_description(pool: &Pool, id: i64, description: &str) -> sqlx::Result<()> {
99
    sqlx::query("UPDATE repositories SET description = ? WHERE id = ?").bind(description).bind(id).execute(pool).await?;
100
    Ok(())
101
}
102
103
pub async fn set_default_bookmark(pool: &Pool, id: i64, bookmark: &str) -> sqlx::Result<()> {
104
    sqlx::query("UPDATE repositories SET default_bookmark = ? WHERE id = ?").bind(bookmark).bind(id).execute(pool).await?;
105
    Ok(())
106
}
107
108
pub async fn set_visibility(pool: &Pool, id: i64, visibility: Visibility) -> sqlx::Result<()> {
109
    sqlx::query("UPDATE repositories SET visibility = ? WHERE id = ?").bind(visibility.as_str()).bind(id).execute(pool).await?;
110
    Ok(())
111
}
112
113
/// Record a push's per-reference results and bump the repository's activity.
114
pub async fn record_push(pool: &Pool, id: i64, pusher: Option<(i64, &str)>, results: &[PushOutcome]) -> sqlx::Result<()> {
115
    let now = now_ms();
116
    let mut tx = pool.begin().await?;
117
    for r in results {
118
        sqlx::query("INSERT INTO pushes (repo_id, at_ms, reference, ok, reason, old_state, new_state, heads, changes, account_id, pusher) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
119
            .bind(id)
120
            .bind(now)
121
            .bind(&r.reference)
122
            .bind(r.ok)
123
            .bind(&r.reason)
124
            .bind(&r.old_state)
125
            .bind(&r.new_state)
126
            .bind(r.heads)
127
            .bind(r.changes)
128
            .bind(pusher.map(|p| p.0).filter(|id| *id > 0))
129
            .bind(pusher.map(|p| p.1).unwrap_or(""))
130
            .execute(&mut *tx)
131
            .await?;
132
    }
133
    if results.iter().any(|r| r.ok) {
134
        sqlx::query("UPDATE repositories SET updated_ms = ? WHERE id = ?").bind(now).bind(id).execute(&mut *tx).await?;
135
    }
136
    tx.commit().await
137
}
138
139
pub async fn pushes(pool: &Pool, id: i64, limit: i64) -> sqlx::Result<Vec<PushRow>> {
140
    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 ?")
141
        .bind(id)
142
        .bind(limit)
143
        .fetch_all(pool)
144
        .await
145
}
146
147
/// Record that `id` is a fork of `from`.
148
pub async fn set_forked_from(pool: &Pool, id: i64, from: i64) -> sqlx::Result<()> {
149
    sqlx::query("UPDATE repositories SET forked_from = ? WHERE id = ?").bind(from).bind(id).execute(pool).await?;
150
    Ok(())
151
}
152
153
/// The forks of `id`, newest activity first.
154
pub async fn forks_of(pool: &Pool, id: i64) -> sqlx::Result<Vec<RepoRow>> {
155
    sqlx::query_as("SELECT * FROM repositories WHERE forked_from = ? ORDER BY updated_ms DESC").bind(id).fetch_all(pool).await
156
}
157
158
pub async fn set_git_mirror(pool: &Pool, id: i64, on: bool) -> sqlx::Result<()> {
159
    sqlx::query("UPDATE repositories SET git_mirror = ? WHERE id = ?").bind(on).bind(id).execute(pool).await?;
160
    Ok(())
161
}
162
163
pub async fn set_git_mirror_state(pool: &Pool, id: i64, state: &str) -> sqlx::Result<()> {
164
    sqlx::query("UPDATE repositories SET git_mirror_state = ? WHERE id = ?").bind(state).bind(id).execute(pool).await?;
165
    Ok(())
166
}