spam-db 0.2.3

Parser and query library for SPAM databases
Documentation
//! Parser and query library for [spam](https://github.com/feel-co/spam) databases.
//!
//! spam indexes Nix package closures and `nixosOptionsDoc` output into compact
//! compressed databases. Use this crate to open those databases and run
//! substring queries against them.
//!
//! ## Database kinds
//!
//! - [`OptionsDb`]: NixOS module options, keyed by option name.
//! - [`PackagesDb`]: Nix store file paths, keyed by path. Opens both
//!   `packages` databases from `spam db build` and `index` databases from
//!   `spam index`.
//!
//! ## File format
//!
//! ```text
//! # spam-db-v3\t{options|packages}\n
//! [256 x 16-byte index entries: (offset: u64le, length: u64le)]
//! [concatenated zstd-compressed bucket blobs]
//!
//! # spam-db-v3\tindex\n
//! [one zstd-compressed package stream]
//! ```
//!
//! `options` and `packages` are bucket-indexed. `index` is a package-grouped
//! stream with prefix-delta encoded paths.
//!
//! ## Usage
//!
//! ```rust,no_run
//! use spam_db::SpamDb;
//!
//! match SpamDb::open("files.db").unwrap() {
//!     SpamDb::Options(db) => {
//!         for rec in db.query("services.nginx").unwrap() {
//!             println!("{}: {:?}", rec.name, rec.summary);
//!         }
//!     }
//!     SpamDb::Packages(db) => {
//!         for rec in db.query("/bin/").unwrap() {
//!             println!("{} -> {}", rec.path, rec.packages.join(", "));
//!         }
//!     }
//!     SpamDb::Index(db) => {
//!         for rec in db.query("/bin/").unwrap() {
//!             println!("{} -> {}", rec.path, rec.packages.join(", "));
//!         }
//!     }
//! }
//! ```
//!
//! ```rust,no_run
//! use spam_db::OptionsDb;
//!
//! let db = OptionsDb::open("options.db").unwrap();
//! let results = db.query("networking.firewall").unwrap();
//! ```

mod format;

pub mod error;
pub mod options;
pub mod packages;

pub use error::Error;
pub use format::DbKind;
pub use options::{OptionRecord, OptionsDb};
pub use packages::{FileKind, FileRecord, PackagesDb};

/// Convenience alias for `Result<T, spam_db::Error>`.
pub type Result<T> = std::result::Result<T, Error>;

/// A spam database returned by [`SpamDb::open`] when the kind is not known at
/// compile time.
#[derive(Debug)]
pub enum SpamDb {
    /// An options database (NixOS module options).
    Options(OptionsDb),
    /// A package-manifest database from `spam db build`.
    Packages(PackagesDb),
    /// An autonomous package index from `spam index`.
    Index(PackagesDb),
}

impl SpamDb {
    /// Open a spam database, detecting the kind from the file header.
    pub fn open(path: impl AsRef<std::path::Path>) -> Result<Self> {
        let db = format::DbFile::open(path)?;
        match db.kind {
            DbKind::Options => Ok(SpamDb::Options(OptionsDb::from_file(db))),
            DbKind::Packages => Ok(SpamDb::Packages(PackagesDb::from_file(db))),
            DbKind::Index => Ok(SpamDb::Index(PackagesDb::from_file(db))),
        }
    }

    /// The kind of this database.
    pub fn kind(&self) -> DbKind {
        match self {
            SpamDb::Options(_) => DbKind::Options,
            SpamDb::Packages(_) => DbKind::Packages,
            SpamDb::Index(_) => DbKind::Index,
        }
    }
}