1
Fork 0
mirror of https://github.com/RGBCube/dix synced 2025-07-28 12:17:45 +00:00

feat: Connection newtype

This commit is contained in:
RGBCube 2025-05-08 22:22:43 +03:00 committed by bloxx12
parent db09147da6
commit 574142c4a0
2 changed files with 125 additions and 116 deletions

View file

@ -1,4 +1,24 @@
use std::path::{
Path,
PathBuf,
};
use derive_more::Deref;
use ref_cast::RefCast;
pub mod error;
pub mod print;
pub mod store;
pub mod util;
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DerivationId(i64);
#[derive(RefCast, Deref, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct StorePath(Path);
#[derive(Deref, Debug, Clone, PartialEq, Eq)]
pub struct StorePathBuf(PathBuf);

View file

@ -1,23 +1,21 @@
use std::{
path::{
Path,
PathBuf,
},
result,
};
use std::result;
use anyhow::{
Context as _,
Result,
};
use derive_more::Deref;
use ref_cast::RefCast;
use rusqlite::Connection;
use rustc_hash::{
FxBuildHasher,
FxHashMap,
};
use crate::{
DerivationId,
StorePath,
StorePathBuf,
};
macro_rules! path_to_str {
($path:ident) => {
let $path = $path.canonicalize().with_context(|| {
@ -36,50 +34,43 @@ macro_rules! path_to_str {
};
}
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DerivationId(i64);
#[expect(clippy::module_name_repetitions)]
#[derive(RefCast, Deref, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct StorePath(Path);
#[expect(clippy::module_name_repetitions)]
#[derive(Deref, Debug, Clone, PartialEq, Eq)]
pub struct StorePathBuf(PathBuf);
#[derive(Deref)]
pub struct Connection(rusqlite::Connection);
/// Connects to the Nix database.
pub fn connect() -> Result<Connection> {
const DATABASE_PATH: &str = "/nix/var/nix/db/db.sqlite";
Connection::open(DATABASE_PATH).with_context(|| {
let inner = rusqlite::Connection::open(DATABASE_PATH).with_context(|| {
format!("failed to connect to Nix database at {DATABASE_PATH}")
})
})?;
Ok(Connection(inner))
}
/// Gathers all derivations that the given store path depends on.
pub fn query_depdendents(
connection: &mut Connection,
path: &StorePath,
) -> Result<Vec<(DerivationId, StorePathBuf)>> {
const QUERY: &str = "
WITH RECURSIVE
graph(p) AS (
SELECT id
FROM ValidPaths
WHERE path = ?
UNION
SELECT reference FROM Refs
JOIN graph ON referrer = p
)
SELECT id, path from graph
JOIN ValidPaths ON id = p;
";
impl Connection {
/// Gathers all derivations that the given store path depends on.
pub fn query_depdendents(
&mut self,
path: &StorePath,
) -> Result<Vec<(DerivationId, StorePathBuf)>> {
const QUERY: &str = "
WITH RECURSIVE
graph(p) AS (
SELECT id
FROM ValidPaths
WHERE path = ?
UNION
SELECT reference FROM Refs
JOIN graph ON referrer = p
)
SELECT id, path from graph
JOIN ValidPaths ON id = p;
";
path_to_str!(path);
path_to_str!(path);
let packages: result::Result<Vec<(DerivationId, StorePathBuf)>, _> =
connection
let packages: result::Result<Vec<(DerivationId, StorePathBuf)>, _> = self
.prepare_cached(QUERY)?
.query_map([path], |row| {
Ok((
@ -89,79 +80,77 @@ pub fn query_depdendents(
})?
.collect();
Ok(packages?)
}
/// Gets the total closure size of the given store path by summing up the nar
/// size of all depdendent derivations.
pub fn query_closure_size(
connection: &mut Connection,
path: &StorePath,
) -> Result<usize> {
const QUERY: &str = "
WITH RECURSIVE
graph(p) AS (
SELECT id
FROM ValidPaths
WHERE path = ?
UNION
SELECT reference FROM Refs
JOIN graph ON referrer = p
)
SELECT SUM(narSize) as sum from graph
JOIN ValidPaths ON p = id;
";
path_to_str!(path);
let closure_size = connection
.prepare_cached(QUERY)?
.query_row([path], |row| row.get(0))?;
Ok(closure_size)
}
/// Gathers the complete dependency graph of of the store path as an adjacency
/// list.
///
/// We might want to collect the paths in the graph directly as
/// well in the future, depending on how much we use them
/// in the operations on the graph.
pub fn query_dependency_graph(
connection: &mut Connection,
path: &StorePath,
) -> Result<FxHashMap<DerivationId, Vec<DerivationId>>> {
const QUERY: &str = "
WITH RECURSIVE
graph(p, c) AS (
SELECT id as par, reference as chd
FROM ValidPaths
JOIN Refs ON referrer = id
WHERE path = ?
UNION
SELECT referrer as par, reference as chd FROM Refs
JOIN graph ON referrer = c
)
SELECT p, c from graph;
";
path_to_str!(path);
let mut adj =
FxHashMap::<DerivationId, Vec<DerivationId>>::with_hasher(FxBuildHasher);
let mut statement = connection.prepare_cached(QUERY)?;
let edges = statement.query_map([path], |row| {
Ok((DerivationId(row.get(0)?), DerivationId(row.get(1)?)))
})?;
for row in edges {
let (from, to) = row?;
adj.entry(from).or_default().push(to);
adj.entry(to).or_default();
Ok(packages?)
}
Ok(adj)
/// Gets the total closure size of the given store path by summing up the nar
/// size of all depdendent derivations.
pub fn query_closure_size(&mut self, path: &StorePath) -> Result<usize> {
const QUERY: &str = "
WITH RECURSIVE
graph(p) AS (
SELECT id
FROM ValidPaths
WHERE path = ?
UNION
SELECT reference FROM Refs
JOIN graph ON referrer = p
)
SELECT SUM(narSize) as sum from graph
JOIN ValidPaths ON p = id;
";
path_to_str!(path);
let closure_size = self
.prepare_cached(QUERY)?
.query_row([path], |row| row.get(0))?;
Ok(closure_size)
}
/// Gathers the complete dependency graph of of the store path as an adjacency
/// list.
///
/// We might want to collect the paths in the graph directly as
/// well in the future, depending on how much we use them
/// in the operations on the graph.
pub fn query_dependency_graph(
&mut self,
path: &StorePath,
) -> Result<FxHashMap<DerivationId, Vec<DerivationId>>> {
const QUERY: &str = "
WITH RECURSIVE
graph(p, c) AS (
SELECT id as par, reference as chd
FROM ValidPaths
JOIN Refs ON referrer = id
WHERE path = ?
UNION
SELECT referrer as par, reference as chd FROM Refs
JOIN graph ON referrer = c
)
SELECT p, c from graph;
";
path_to_str!(path);
let mut adj =
FxHashMap::<DerivationId, Vec<DerivationId>>::with_hasher(FxBuildHasher);
let mut statement = self.prepare_cached(QUERY)?;
let edges = statement.query_map([path], |row| {
Ok((DerivationId(row.get(0)?), DerivationId(row.get(1)?)))
})?;
for row in edges {
let (from, to) = row?;
adj.entry(from).or_default().push(to);
adj.entry(to).or_default();
}
Ok(adj)
}
}