Skip to content

Commit

Permalink
Merge pull request #46 from serpent-os/feat/meta-db-filter
Browse files Browse the repository at this point in the history
Feat/meta db filter
  • Loading branch information
ikeycode authored Sep 27, 2023
2 parents 2ed6fab + 685a335 commit e46d179
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 65 deletions.
136 changes: 95 additions & 41 deletions moss/src/db/meta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,77 @@

use std::path::Path;

use sqlx::SqliteConnection;
use sqlx::{sqlite::SqliteConnectOptions, Acquire, Pool, Sqlite};
use sqlx::{QueryBuilder, SqliteConnection};
use thiserror::Error;

use crate::db::Encoding;
use crate::package::{self, Meta};
use crate::Provider;

#[derive(Debug, Clone, Copy)]
enum Table {
Meta,
Licenses,
Dependencies,
Providers,
}

#[derive(Debug)]
pub enum Filter {
Provider(Provider),
Name(package::Name),
}

impl Filter {
fn append(&self, table: Table, query: &mut QueryBuilder<Sqlite>) {
match self {
Filter::Provider(p) => {
if let Table::Providers = table {
query
.push(
"
where provider =
",
)
.push_bind(p.encode());
} else {
query
.push(
"
where package in
(select distinct package from meta_providers where provider =
",
)
.push_bind(p.encode())
.push(")");
}
}
Filter::Name(n) => {
if let Table::Meta = table {
query
.push(
"
where name =
",
)
.push_bind(n.encode().to_string());
} else {
query
.push(
"
where package in
(select distinct package from meta where name =
",
)
.push_bind(n.encode().to_string())
.push(")");
}
}
}
}
}

#[derive(Debug, Clone)]
pub struct Database {
pool: Pool<Sqlite>,
Expand Down Expand Up @@ -42,9 +105,8 @@ impl Database {
Ok(())
}

// TODO: Replace with specialized query interfaces
pub async fn all(&self) -> Result<Vec<(package::Id, Meta)>, Error> {
let entry_query = sqlx::query_as::<_, encoding::Entry>(
pub async fn query(&self, filter: Option<Filter>) -> Result<Vec<(package::Id, Meta)>, Error> {
let mut entry_query = sqlx::QueryBuilder::new(
"
SELECT package,
name,
Expand All @@ -59,36 +121,51 @@ impl Database {
uri,
hash,
download_size
FROM meta;
FROM meta
",
);

let licenses_query = sqlx::query_as::<_, encoding::License>(
let mut licenses_query = sqlx::QueryBuilder::new(
"
SELECT package, license
FROM meta_licenses;
FROM meta_licenses
",
);

let dependencies_query = sqlx::query_as::<_, encoding::Dependency>(
let mut dependencies_query = sqlx::QueryBuilder::new(
"
SELECT package, dependency
FROM meta_dependencies;
FROM meta_dependencies
",
);

let providers_query = sqlx::query_as::<_, encoding::Provider>(
let mut providers_query = sqlx::QueryBuilder::new(
"
SELECT package, provider
FROM meta_providers;
FROM meta_providers
",
);

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);
}

let (entries, licenses, dependencies, providers) = futures::try_join!(
entry_query.fetch_all(&self.pool),
licenses_query.fetch_all(&self.pool),
dependencies_query.fetch_all(&self.pool),
providers_query.fetch_all(&self.pool),
entry_query
.build_query_as::<encoding::Entry>()
.fetch_all(&self.pool),
licenses_query
.build_query_as::<encoding::License>()
.fetch_all(&self.pool),
dependencies_query
.build_query_as::<encoding::Dependency>()
.fetch_all(&self.pool),
providers_query
.build_query_as::<encoding::Provider>()
.fetch_all(&self.pool),
)?;

Ok(entries
Expand Down Expand Up @@ -130,29 +207,6 @@ impl Database {
.collect())
}

/// Firstly find all matching providers - then map them back via .get() to the full package
pub async fn get_providers(
&self,
provider: &Provider,
) -> Result<Vec<(package::Id, Meta)>, Error> {
let entry_query = sqlx::query_as::<_, encoding::Provider>(
"SELECT package, provider
FROM meta_providers
WHERE provider = ?;
",
)
.bind(provider.encode());

let entries = entry_query.fetch_all(&self.pool).await?;
let mut results = vec![];
for entry in entries {
let id = entry.id.0;
let lookup = self.get(&id).await?;
results.push((id, lookup));
}
Ok(results)
}

pub async fn get(&self, package: &package::Id) -> Result<Meta, Error> {
let entry_query = sqlx::query_as::<_, encoding::Entry>(
"
Expand Down Expand Up @@ -493,11 +547,11 @@ mod test {
assert_eq!(&meta.name, &"bash-completion".to_string().into());

// Now retrieve by provider.
let lookup = Provider {
let lookup = Filter::Provider(Provider {
kind: Kind::PackageName,
name: "bash-completion".to_string(),
};
let fetched = database.get_providers(&lookup).await.unwrap();
});
let fetched = database.query(Some(lookup)).await.unwrap();
assert_eq!(fetched.len(), 1);

batch_remove([&id], &mut database.pool.acquire().await.unwrap())
Expand Down
32 changes: 8 additions & 24 deletions moss/src/registry/plugin/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use log::warn;

use crate::{
db,
package::{self, Meta, Package},
package::{self, Package},
repository, Provider,
};

Expand Down Expand Up @@ -41,10 +41,10 @@ impl Repository {
}
}

async fn query(&self, flags: package::Flags, filter: impl Fn(&Meta) -> bool) -> Vec<Package> {
async fn query(&self, flags: package::Flags, filter: Option<db::meta::Filter>) -> Vec<Package> {
if flags.contains(package::Flags::AVAILABLE) {
// TODO: Error handling
let packages = match self.active.db.all().await {
let packages = match self.active.db.query(filter).await {
Ok(packages) => packages,
Err(error) => {
warn!("failed to query repository packages: {error}");
Expand All @@ -54,7 +54,6 @@ impl Repository {

packages
.into_iter()
.filter(|(_, meta)| filter(meta))
.map(|(id, meta)| Package {
id,
meta,
Expand All @@ -67,37 +66,22 @@ impl Repository {
}

pub async fn list(&self, flags: package::Flags) -> Vec<Package> {
self.query(flags, |_| true).await
self.query(flags, None).await
}

/// Query all packages that match the given provider identity
pub async fn query_provider(&self, provider: &Provider, flags: package::Flags) -> Vec<Package> {
if !flags.contains(package::Flags::AVAILABLE) {
return vec![];
}

let packages = self.active.db.get_providers(provider).await;
if packages.is_err() {
vec![]
} else {
packages
.unwrap()
.into_iter()
.map(|(id, meta)| Package {
id,
meta,
flags: package::Flags::AVAILABLE,
})
.collect()
}
self.query(flags, Some(db::meta::Filter::Provider(provider.clone())))
.await
}

pub async fn query_name(
&self,
package_name: &package::Name,
flags: package::Flags,
) -> Vec<Package> {
self.query(flags, |meta| meta.name == *package_name).await
self.query(flags, Some(db::meta::Filter::Name(package_name.clone())))
.await
}
}

Expand Down

0 comments on commit e46d179

Please sign in to comment.