Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for conflicts #94

Closed
wants to merge 10 commits into from
Prev Previous commit
Next Next commit
moss: update db implementation to load and store conflicts
Signed-off-by: Gavin Zhao <git@gzgz.dev>
GZGavinZhao committed Jan 25, 2024
commit 1096fd48a4f50e10885e53e3522ba3a1aeb57cd5
6 changes: 6 additions & 0 deletions crates/moss/src/db/meta/migrations/20230912204438_init.sql
Original file line number Diff line number Diff line change
@@ -32,3 +32,9 @@ CREATE TABLE IF NOT EXISTS meta_providers (
provider TEXT NOT NULL,
FOREIGN KEY (package) REFERENCES meta(package) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS meta_conflicts (
package TEXT NOT NULL,
conflict TEXT NOT NULL,
FOREIGN KEY (package) REFERENCES meta(package) ON DELETE CASCADE
);
61 changes: 55 additions & 6 deletions crates/moss/src/db/meta/mod.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ enum Table {
Licenses,
Dependencies,
Providers,
Conflicts,
}

#[derive(Debug)]
@@ -169,14 +170,22 @@ impl Database {
",
);

let mut conflicts_query = sqlx::QueryBuilder::new(
"
SELECT package, conflict
FROM meta_conflicts
",
);

if let Some(filter) = filter {
filter.append(Table::Meta, &mut entry_query);
filter.append(Table::Licenses, &mut licenses_query);
filter.append(Table::Dependencies, &mut dependencies_query);
filter.append(Table::Providers, &mut providers_query);
filter.append(Table::Conflicts, &mut conflicts_query)
}

let (entries, licenses, dependencies, providers) = futures::try_join!(
let (entries, licenses, dependencies, providers, conflicts) = futures::try_join!(
entry_query
.build_query_as::<encoding::Entry>()
.fetch_all(&self.pool),
@@ -189,6 +198,9 @@ impl Database {
providers_query
.build_query_as::<encoding::Provider>()
.fetch_all(&self.pool),
conflicts_query
.build_query_as::<encoding::Conflict>()
.fetch_all(&self.pool)
)?;

Ok(entries
@@ -221,7 +233,11 @@ impl Database {
.filter(|l| l.id.0 == entry.id.0)
.map(|p| p.provider.0.clone())
.collect(),
conflicts: Default::default(),
conflicts: conflicts
.iter()
.filter(|l| l.id.0 == entry.id.0)
.map(|p| p.conflict.0.clone())
.collect(),
uri: entry.uri,
hash: entry.hash,
download_size: entry.download_size.map(|i| i as u64),
@@ -280,11 +296,21 @@ impl Database {
)
.bind(package.encode());

let (entry, licenses, dependencies, providers) = futures::try_join!(
let conflicts_query = sqlx::query_as::<_, encoding::Conflict>(
"
SELECT package, conflict
FROM meta_conflicts
WHERE package = ?;
",
)
.bind(package.encode());

let (entry, licenses, dependencies, providers, conflicts) = futures::try_join!(
entry_query.fetch_one(&self.pool),
licenses_query.fetch_all(&self.pool),
dependencies_query.fetch_all(&self.pool),
providers_query.fetch_all(&self.pool),
conflicts_query.fetch_all(&self.pool),
)?;

Ok(Meta {
@@ -300,7 +326,7 @@ impl Database {
licenses: licenses.into_iter().map(|l| l.license).collect(),
dependencies: dependencies.into_iter().map(|d| d.dependency.0).collect(),
providers: providers.into_iter().map(|p| p.provider.0).collect(),
conflicts: Default::default(),
conflicts: conflicts.into_iter().map(|p| p.conflict.0).collect(),
uri: entry.uri,
hash: entry.hash,
download_size: entry.download_size.map(|i| i as u64),
@@ -451,6 +477,26 @@ impl Database {
.await?;
}

// Conflicts
let conflicts = packages
.iter()
.flat_map(|(id, meta)| meta.conflicts.iter().map(move |conflict| (id, conflict)))
.collect::<Vec<_>>();
println!("conflicts: {conflicts:?}");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder to remove this println

if !conflicts.is_empty() {
sqlx::QueryBuilder::new(
"
INSERT INTO meta_conflicts (package, conflict)
",
)
.push_values(conflicts, |mut b, (id, conflict)| {
b.push_bind(id.encode()).push_bind(conflict.encode());
})
.build()
.execute(transaction.acquire().await?)
.await?;
}

transaction.commit().await?;

Ok(())
@@ -555,8 +601,10 @@ mod encoding {
}

#[derive(FromRow)]
pub struct ProviderPackage {
pub package: Decoder<package::Id>,
pub struct Conflict {
#[sqlx(rename = "package")]
pub id: Decoder<package::Id>,
pub conflict: Decoder<crate::Conflict>,
}
}

@@ -595,6 +643,7 @@ mod test {
database.add(id.clone(), meta.clone()).await.unwrap();

assert_eq!(&meta.name, &"bash-completion".to_string().into());
assert_eq!(meta.conflicts, HashSet::default());

// Now retrieve by provider.
let lookup = Filter::Provider(Provider {
16 changes: 15 additions & 1 deletion crates/moss/src/db/mod.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ mod encoding {
use sqlx::{Sqlite, Type};
use thiserror::Error;

use crate::{dependency, package, state, Dependency, Provider};
use crate::{dependency, package, state, Conflict, Dependency, Provider};

/// Decode from a database type using [`Encoding::decode`]
#[derive(Debug, Clone, Copy)]
@@ -115,6 +115,20 @@ mod encoding {
}
}

/// Encoding of Conflict type
impl<'a> Encoding<'a> for Conflict {
type Encoded = String;
type Error = dependency::ParseError;

fn decode(encoded: String) -> Result<Self, Self::Error> {
encoded.parse()
}

fn encode(&self) -> String {
self.to_string()
}
}

impl<'a> Encoding<'a> for state::Id {
type Encoded = i64;
type Error = Infallible;
15 changes: 8 additions & 7 deletions crates/moss/src/package/meta.rs
Original file line number Diff line number Diff line change
@@ -259,13 +259,14 @@ fn meta_provider(meta: &payload::Meta) -> Option<Provider> {
}

fn meta_conflict(meta: &payload::Meta) -> Option<Conflict> {
if let payload::meta::Kind::Provider(kind, name) = meta.kind.clone() {
Some(Conflict {
kind: dependency::Kind::from(kind),
name: name,
})
} else {
None
match (meta.tag, &meta.kind) {
(payload::meta::Tag::Conflicts, payload::meta::Kind::Provider(kind, name)) => {
Some(Conflict {
kind: dependency::Kind::from(*kind),
name: name.clone(),
})
}
_ => None,
}
}