//! The `repositories` and `pushes` tables. use super::{now_ms, Pool}; use hub_api::Visibility; use sqlx::FromRow; #[derive(Clone, Debug, FromRow)] pub struct RepoRow { pub id: i64, pub owner: String, pub name: String, pub description: String, pub default_bookmark: String, pub visibility: String, pub created_ms: i64, pub updated_ms: i64, } impl RepoRow { pub fn visibility(&self) -> Visibility { Visibility::parse(&self.visibility).unwrap_or(Visibility::Private) } pub fn slug(&self) -> String { format!("{}/{}", self.owner, self.name) } } #[derive(Clone, Debug, FromRow)] pub struct PushRow { pub id: i64, pub at_ms: i64, pub reference: String, pub ok: bool, pub reason: String, pub old_state: String, pub new_state: String, pub heads: i64, pub changes: i64, pub pusher: String, } /// One reference's outcome in a push, as the protocol backend reports it. #[derive(Clone, Debug)] pub struct PushOutcome { pub reference: String, pub ok: bool, pub reason: String, pub old_state: String, pub new_state: String, pub heads: i64, pub changes: i64, } pub async fn list(pool: &Pool) -> sqlx::Result> { sqlx::query_as("SELECT * FROM repositories ORDER BY updated_ms DESC, owner, name").fetch_all(pool).await } pub async fn get_by_id(pool: &Pool, id: i64) -> sqlx::Result> { sqlx::query_as("SELECT * FROM repositories WHERE id = ?").bind(id).fetch_optional(pool).await } pub async fn list_by_owner(pool: &Pool, owner: &str) -> sqlx::Result> { sqlx::query_as("SELECT * FROM repositories WHERE owner = ? ORDER BY updated_ms DESC, name").bind(owner).fetch_all(pool).await } pub async fn get(pool: &Pool, owner: &str, name: &str) -> sqlx::Result> { sqlx::query_as("SELECT * FROM repositories WHERE owner = ? AND name = ?").bind(owner).bind(name).fetch_optional(pool).await } pub async fn create(pool: &Pool, owner: &str, name: &str, description: &str, visibility: Visibility) -> sqlx::Result { let now = now_ms(); sqlx::query_as( "INSERT INTO repositories (owner, name, description, visibility, created_ms, updated_ms) VALUES (?, ?, ?, ?, ?, ?) RETURNING *", ) .bind(owner) .bind(name) .bind(description) .bind(visibility.as_str()) .bind(now) .bind(now) .fetch_one(pool) .await } pub async fn delete(pool: &Pool, id: i64) -> sqlx::Result<()> { sqlx::query("DELETE FROM repositories WHERE id = ?").bind(id).execute(pool).await?; Ok(()) } pub async fn set_description(pool: &Pool, id: i64, description: &str) -> sqlx::Result<()> { sqlx::query("UPDATE repositories SET description = ? WHERE id = ?").bind(description).bind(id).execute(pool).await?; Ok(()) } pub async fn set_default_bookmark(pool: &Pool, id: i64, bookmark: &str) -> sqlx::Result<()> { sqlx::query("UPDATE repositories SET default_bookmark = ? WHERE id = ?").bind(bookmark).bind(id).execute(pool).await?; Ok(()) } pub async fn set_visibility(pool: &Pool, id: i64, visibility: Visibility) -> sqlx::Result<()> { sqlx::query("UPDATE repositories SET visibility = ? WHERE id = ?").bind(visibility.as_str()).bind(id).execute(pool).await?; Ok(()) } /// Record a push's per-reference results and bump the repository's activity. pub async fn record_push(pool: &Pool, id: i64, pusher: Option<(i64, &str)>, results: &[PushOutcome]) -> sqlx::Result<()> { let now = now_ms(); let mut tx = pool.begin().await?; for r in results { sqlx::query("INSERT INTO pushes (repo_id, at_ms, reference, ok, reason, old_state, new_state, heads, changes, account_id, pusher) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") .bind(id) .bind(now) .bind(&r.reference) .bind(r.ok) .bind(&r.reason) .bind(&r.old_state) .bind(&r.new_state) .bind(r.heads) .bind(r.changes) .bind(pusher.map(|p| p.0).filter(|id| *id > 0)) .bind(pusher.map(|p| p.1).unwrap_or("")) .execute(&mut *tx) .await?; } if results.iter().any(|r| r.ok) { sqlx::query("UPDATE repositories SET updated_ms = ? WHERE id = ?").bind(now).bind(id).execute(&mut *tx).await?; } tx.commit().await } pub async fn pushes(pool: &Pool, id: i64, limit: i64) -> sqlx::Result> { 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 ?") .bind(id) .bind(limit) .fetch_all(pool) .await }