From f72a27b3a5f7e4d0b54549b57d6111308ca557b9 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 19 Sep 2021 20:15:31 +0100 Subject: [PATCH] Only keep the latest crate metadata (readme, homepage, etc) around --- chartered-db/src/crates.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- chartered-db/src/schema.rs | 10 +++++----- chartered-git/src/main.rs | 2 +- migrations/2021-08-31-214501_create_crates_table/up.sql | 12 ++++++------ chartered-frontend/src/pages/crate/CrateView.tsx | 30 ++++++++++++++---------------- chartered-web/src/endpoints/web_api/crates/info.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 131 insertions(+), 122 deletions(-) diff --git a/chartered-db/src/crates.rs b/chartered-db/src/crates.rs index 8a19349..c7c172a 100644 --- a/chartered-db/src/crates.rs +++ a/chartered-db/src/crates.rs @@ -13,69 +13,12 @@ pub struct Crate { pub id: i32, pub name: String, -} - -#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] -#[belongs_to(Crate)] -pub struct CrateVersion<'a> { - pub id: i32, - pub crate_id: i32, - pub version: String, - pub filesystem_object: String, - pub yanked: bool, - // TODO: readme should be versioned in the db so we can just pass a reference rather - // than this massive blob for each version - or just update the readme for the whole - // crate and don't version it at all? we also need tags, etc too in a pivot table pub readme: Option, pub description: Option, pub repository: Option, pub homepage: Option, pub documentation: Option, - pub checksum: String, - pub dependencies: CrateDependencies<'a>, - pub features: CrateFeatures, - pub links: Option, -} - -impl<'a> CrateVersion<'a> { - #[must_use] - pub fn into_cargo_format( - self, - crate_: &'a Crate, - ) -> ( - chartered_types::cargo::CrateVersion<'a>, - chartered_types::cargo::CrateVersionMetadata, - ) { - ( - chartered_types::cargo::CrateVersion { - name: crate_.name.as_str().into(), - vers: self.version.into(), - deps: self.dependencies.0, - features: self.features.0, - links: self.links.map(Into::into), - }, - chartered_types::cargo::CrateVersionMetadata { - description: self.description, - readme: self.readme, - repository: self.repository, - homepage: self.homepage, - documentation: self.documentation, - }, - ) - } } - -#[derive(Serialize, Deserialize, FromSqlRow, AsExpression, Debug, Clone, PartialEq, Eq)] -#[sql_type = "diesel::sql_types::Blob"] -pub struct CrateDependencies<'a>(pub Vec>); - -derive_diesel_json!(CrateDependencies<'a>); - -#[derive(Serialize, Deserialize, FromSqlRow, AsExpression, Debug, Clone, PartialEq, Eq)] -#[sql_type = "diesel::sql_types::Blob"] -pub struct CrateFeatures(pub chartered_types::cargo::CrateFeatures); - -derive_diesel_json!(CrateFeatures); impl Crate { pub async fn all_with_versions( @@ -279,29 +222,41 @@ metadata: chartered_types::cargo::CrateVersionMetadata, ) -> Result<()> { use crate::schema::crate_versions::dsl::{ - checksum, crate_id, crate_versions, dependencies, description, documentation, features, - filesystem_object, homepage, links, readme, repository, version, + checksum, crate_id, crate_versions, dependencies, features, filesystem_object, links, + version, }; + use crate::schema::crates::dsl::{ + crates, description, documentation, homepage, id, readme, repository, + }; tokio::task::spawn_blocking(move || { let conn = conn.get()?; - insert_into(crate_versions) - .values(( - crate_id.eq(self.id), - filesystem_object.eq(file_identifier.to_string()), - checksum.eq(file_checksum), - version.eq(given.vers), - dependencies.eq(CrateDependencies(given.deps)), - features.eq(CrateFeatures(given.features)), - links.eq(given.links), - description.eq(metadata.description), - readme.eq(metadata.readme), - repository.eq(metadata.repository), - homepage.eq(metadata.homepage), - documentation.eq(metadata.documentation), - )) - .execute(&conn)?; + conn.transaction::<_, crate::Error, _>(|| { + diesel::update(crates.filter(id.eq(self.id))) + .set(( + description.eq(metadata.description), + readme.eq(metadata.readme), + repository.eq(metadata.repository), + homepage.eq(metadata.homepage), + documentation.eq(metadata.documentation), + )) + .execute(&conn)?; + + insert_into(crate_versions) + .values(( + crate_id.eq(self.id), + filesystem_object.eq(file_identifier.to_string()), + checksum.eq(file_checksum), + version.eq(given.vers), + dependencies.eq(CrateDependencies(given.deps)), + features.eq(CrateFeatures(given.features)), + links.eq(given.links), + )) + .execute(&conn)?; + + Ok(()) + })?; Ok(()) }) @@ -330,14 +285,53 @@ Ok(()) }) .await? + } +} + +#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] +#[belongs_to(Crate)] +pub struct CrateVersion<'a> { + pub id: i32, + pub crate_id: i32, + pub version: String, + pub filesystem_object: String, + pub yanked: bool, + pub checksum: String, + pub dependencies: CrateDependencies<'a>, + pub features: CrateFeatures, + pub links: Option, +} + +impl<'a> CrateVersion<'a> { + #[must_use] + pub fn into_cargo_format(self, crate_: &'a Crate) -> chartered_types::cargo::CrateVersion<'a> { + chartered_types::cargo::CrateVersion { + name: crate_.name.as_str().into(), + vers: self.version.into(), + deps: self.dependencies.0, + features: self.features.0, + links: self.links.map(Into::into), + } } } + +#[derive(Serialize, Deserialize, FromSqlRow, AsExpression, Debug, Clone, PartialEq, Eq)] +#[sql_type = "diesel::sql_types::Blob"] +pub struct CrateDependencies<'a>(pub Vec>); + +derive_diesel_json!(CrateDependencies<'a>); impl<'a> From>> for CrateDependencies<'a> { fn from(o: Vec>) -> Self { Self(o) } } + +#[derive(Serialize, Deserialize, FromSqlRow, AsExpression, Debug, Clone, PartialEq, Eq)] +#[sql_type = "diesel::sql_types::Blob"] +pub struct CrateFeatures(pub chartered_types::cargo::CrateFeatures); + +derive_diesel_json!(CrateFeatures); impl<'a> From for CrateFeatures { fn from(o: chartered_types::cargo::CrateFeatures) -> Self { diff --git a/chartered-db/src/schema.rs b/chartered-db/src/schema.rs index af75a13..384d4e2 100644 --- a/chartered-db/src/schema.rs +++ a/chartered-db/src/schema.rs @@ -5,11 +5,6 @@ version -> Text, filesystem_object -> Text, yanked -> Bool, - readme -> Nullable, - description -> Nullable, - repository -> Nullable, - homepage -> Nullable, - documentation -> Nullable, checksum -> Text, dependencies -> Binary, features -> Binary, @@ -21,6 +16,11 @@ crates (id) { id -> Integer, name -> Text, + readme -> Nullable, + description -> Nullable, + repository -> Nullable, + homepage -> Nullable, + documentation -> Nullable, } } diff --git a/chartered-git/src/main.rs b/chartered-git/src/main.rs index 7e44478..35aaab9 100644 --- a/chartered-git/src/main.rs +++ a/chartered-git/src/main.rs @@ -374,7 +374,7 @@ for version in versions { let cksum = version.checksum.clone(); let yanked = version.yanked; - let (version, _) = version.into_cargo_format(&crate_def); + let version = version.into_cargo_format(&crate_def); let entry = CrateFileEntry { inner: &version, diff --git a/migrations/2021-08-31-214501_create_crates_table/up.sql b/migrations/2021-08-31-214501_create_crates_table/up.sql index 67c5cdb..21d1db1 100644 --- a/migrations/2021-08-31-214501_create_crates_table/up.sql +++ a/migrations/2021-08-31-214501_create_crates_table/up.sql @@ -1,6 +1,11 @@ CREATE TABLE crates ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - name VARCHAR(255) NOT NULL UNIQUE + name VARCHAR(255) NOT NULL UNIQUE, + readme TEXT, + description VARCHAR(255), + repository VARCHAR(255), + homepage VARCHAR(255), + documentation VARCHAR(255) ); CREATE TABLE crate_versions ( @@ -9,11 +14,6 @@ version VARCHAR(255) NOT NULL, filesystem_object VARCHAR(255) NOT NULL, yanked BOOLEAN NOT NULL DEFAULT FALSE, - readme TEXT, - description VARCHAR(255), - repository VARCHAR(255), - homepage VARCHAR(255), - documentation VARCHAR(255), checksum VARCHAR(255) NOT NULL, dependencies BLOB NOT NULL, features BLOB NOT NULL, diff --git a/chartered-frontend/src/pages/crate/CrateView.tsx b/chartered-frontend/src/pages/crate/CrateView.tsx index 95b4e6b..3c7deb2 100644 --- a/chartered-frontend/src/pages/crate/CrateView.tsx +++ a/chartered-frontend/src/pages/crate/CrateView.tsx @@ -18,15 +18,17 @@ type Tab = "readme" | "versions" | "members"; export interface CrateInfo { + name: string; + readme?: string; + description?: string; + repository?: string; + homepage?: string; + documentation?: string; versions: CrateInfoVersion[]; } export interface CrateInfoVersion { vers: string; - homepage: string | null; - description: string | null; - documentation: string | null; - repository: string | null; deps: CrateInfoVersionDependency[]; } @@ -74,7 +76,7 @@

{crateVersion.vers}

-

{crateVersion.description}

+

{crateInfo.description}

@@ -83,15 +85,13 @@ @@ -148,11 +148,7 @@
- {currentTab == "readme" ? ( - - ) : ( - <> - )} + {currentTab == "readme" ? : <>} {currentTab == "versions" ? <>Versions : <>} {currentTab == "members" ? : <>}
@@ -195,10 +191,10 @@ ); } -function ReadMe(props: { crateInfo: any }) { +function ReadMe(props: { crate: CrateInfo }) { return ( , extract::Extension(db): extract::Extension, extract::Extension(user): extract::Extension>, -) -> Result, Error> { +) -> Result>, Error> { let crate_ = get_crate_with_permissions(db.clone(), user, name, &[Permission::VISIBLE]).await?; - let versions = crate_.clone().versions(db).await?; + // returning a Response instead of Json here so we don't have to close + // every Crate/CrateVersion etc, would be easier if we just had an owned + // version of each but we're using `spawn_blocking` in chartered-db for + // diesel which requires `'static' which basically forces us to use Arc + // if we want to keep a reference to anything ourselves. Ok(Json(Response { + info: crate_.as_ref().into(), versions: versions .into_iter() - .map(|v| { - let (inner, meta) = v.into_cargo_format(&crate_); - ResponseVersion { - inner: inner.into_owned(), - meta, - } - }) + .map(|v| v.into_cargo_format(&crate_)) .collect(), - })) + }) + .into_response()) } #[derive(Serialize)] -pub struct ResponseVersion { +pub struct Response<'a> { #[serde(flatten)] - meta: CrateVersionMetadata, - #[serde(flatten)] - inner: CrateVersion<'static>, + info: ResponseInfo<'a>, + versions: Vec>, } #[derive(Serialize)] -pub struct Response { - versions: Vec, +pub struct ResponseInfo<'a> { + name: &'a str, + readme: Option<&'a str>, + description: Option<&'a str>, + repository: Option<&'a str>, + homepage: Option<&'a str>, + documentation: Option<&'a str>, +} + +impl<'a> From<&'a Crate> for ResponseInfo<'a> { + fn from(crate_: &'a Crate) -> Self { + Self { + name: &crate_.name, + readme: crate_.readme.as_deref(), + description: crate_.description.as_deref(), + repository: crate_.repository.as_deref(), + homepage: crate_.homepage.as_deref(), + documentation: crate_.documentation.as_deref(), + } + } } -- rgit 0.1.3