use super::{
schema::{crate_versions, crates},
ConnectionPool, Result,
};
use diesel::{
insert_into, insert_or_ignore_into, prelude::*, Associations, Identifiable, Queryable,
};
use itertools::Itertools;
use std::{collections::HashMap, sync::Arc};
#[derive(Identifiable, Queryable, PartialEq, Eq, Hash, Debug)]
pub struct Crate {
pub id: i32,
pub name: String,
}
impl Crate {
pub async fn all_with_versions(
conn: ConnectionPool,
) -> Result<HashMap<Crate, Vec<CrateVersion>>> {
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
let crate_versions = crates::table
.inner_join(crate_versions::table)
.load(&conn)?;
Ok(crate_versions.into_iter().into_grouping_map().collect())
})
.await?
}
pub async fn find_by_name(conn: ConnectionPool, crate_name: String) -> Result<Option<Self>> {
use crate::schema::crates::dsl::{crates, name};
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
Ok(crates
.filter(name.eq(crate_name))
.first::<Crate>(&conn)
.optional()?)
})
.await?
}
pub async fn versions(self: Arc<Self>, conn: ConnectionPool) -> Result<Vec<CrateVersion>> {
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
Ok(CrateVersion::belonging_to(&*self).load::<CrateVersion>(&conn)?)
})
.await?
}
pub async fn version(
self: Arc<Self>,
conn: ConnectionPool,
crate_version: String,
) -> Result<Option<CrateVersion>> {
use crate::schema::crate_versions::version;
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
Ok(CrateVersion::belonging_to(&*self)
.filter(version.eq(crate_version))
.get_result::<CrateVersion>(&conn)
.optional()?)
})
.await?
}
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Crate)]
pub struct CrateVersion {
pub id: i32,
pub crate_id: i32,
pub version: String,
pub filesystem_object: String,
pub yanked: bool,
pub checksum: String,
}
pub async fn publish_crate(
conn: ConnectionPool,
crate_name: String,
version_string: String,
file_identifier: chartered_fs::FileReference,
file_checksum: String,
) -> Result<()> {
use crate::schema::{
crate_versions::dsl::{checksum, crate_id, crate_versions, filesystem_object, version},
crates::dsl::{crates, name},
};
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
insert_or_ignore_into(crates)
.values(name.eq(&crate_name))
.execute(&conn)?;
let selected_crate = crates.filter(name.eq(crate_name)).first::<Crate>(&conn)?;
insert_into(crate_versions)
.values((
crate_id.eq(selected_crate.id),
version.eq(version_string),
filesystem_object.eq(file_identifier.to_string()),
checksum.eq(file_checksum),
))
.execute(&conn)?;
Ok(())
})
.await?
}