mod entries;
mod index;
mod query;
pub use self::query::Query;
use self::{entries::Entries, index::Index};
use crate::{
advisory::{self, Advisory},
error::Error,
package,
repository::{Commit, Repository},
};
pub type Iter<'a> = std::slice::Iter<'a, Advisory>;
#[derive(Debug)]
pub struct Database {
advisories: Entries,
rust_index: Index,
crate_index: Index,
latest_commit: Commit,
}
impl Database {
pub fn fetch() -> Result<Self, Error> {
let repo = Repository::fetch_default_repo()?;
Self::load(&repo)
}
pub fn load(repo: &Repository) -> Result<Self, Error> {
let advisory_paths = repo.advisories()?;
let latest_commit = repo.latest_commit()?;
let mut advisories = Entries::new();
let mut rust_index = Index::new();
let mut crate_index = Index::new();
for path in &advisory_paths {
if let Some(slot) = advisories.load_file(path)? {
let advisory = advisories.get(slot).unwrap();
match advisory.metadata.collection.unwrap() {
package::Collection::Crates => {
crate_index.insert(&advisory.metadata.package, slot);
}
package::Collection::Rust => {
rust_index.insert(&advisory.metadata.package, slot);
}
}
}
}
Ok(Self {
advisories,
crate_index,
rust_index,
latest_commit,
})
}
pub fn get(&self, id: &advisory::Id) -> Option<&Advisory> {
self.advisories.find_by_id(id)
}
pub fn query(&self, query: &Query) -> Vec<&Advisory> {
if let Some(name) = &query.package {
if let Some(collection) = query.collection {
return match collection {
package::Collection::Crates => self.crate_index.get(name),
package::Collection::Rust => self.rust_index.get(name),
}
.map(|slots| {
slots
.map(|slot| self.advisories.get(*slot).unwrap())
.filter(|advisory| query.matches(advisory))
.collect()
})
.unwrap_or_else(Vec::new);
}
}
self.iter()
.filter(|advisory| query.matches(advisory))
.collect()
}
pub fn iter(&self) -> Iter<'_> {
self.advisories.iter()
}
pub fn latest_commit(&self) -> &Commit {
&self.latest_commit
}
}