Skip to main content

FactsDb

Struct FactsDb 

pub struct FactsDb { /* private fields */ }

Implementations§

§

impl FactsDb

pub fn ingest<R: Repo>(&self, repo: &R, opts: &Options) -> Result<IngestStats>

§Panics

Panics if the producer thread panics (internal logic error, not expected in normal use).

§

impl FactsDb

pub fn new_in_memory() -> Result<Self>

Open a fresh in-memory fact store, spilling to the default temp directory (see [default_spill_dir]) once memory_limit is exceeded. Equivalent to new_in_memory_with_temp_dir(None).

pub fn new_in_memory_with_temp_dir(temp_dir: Option<&Path>) -> Result<Self>

Like [new_in_memory] but honors an explicit spill-directory override (falls back to [default_spill_dir] when None). Used by callers that resolved Options::temp_dir / --temp-dir — the plain --no-cache in-memory path bypasses the persistent cache entirely (so there is no cache root to derive a default from) but must still spill instead of OOM-ing on a very large repo.

pub fn open(path: impl AsRef<Path>) -> Result<Self>

pub fn open_file(path: &Path, temp_dir: &Path) -> Result<Self>

Open (or create) a read-write DuckDB file at path, spilling to temp_dir once memory_limit is exceeded. Unlike open(), this does NOT call create_schema — the caller is responsible for schema initialisation (used internally by open_or_ingest).

pub fn open_read_only(path: &Path) -> Result<Self>

Open an existing DuckDB file in read-only mode.

Validates the stored schema_version against the binary’s expected version (schema::CURRENT_SCHEMA_VERSION) so an operator who hands a stale .duckdb to --cache-dir directly gets a typed parse-time error instead of cryptic Catalog Error: Table … does not exist at analysis time. The cache-hit path (open_or_ingest) is already guarded by the cache key — this check defends the direct-open path.

§Errors

Returns CodeLoreError::Analysis if the file isn’t a DuckDB fact store, lacks a provenance table, or has a different schema_version than this binary produces.

pub fn open_read_only_with_temp_dir( path: &Path, temp_dir: Option<&Path>, ) -> Result<Self>

Like [open_read_only] but honors an explicit spill-directory override (falls back to [default_spill_dir] when None). A read-only-mode connection can still build TEMP tables and materialize large intermediate query state (coupling, code-health, and friends all do), so it needs the same memory ceiling + spill target as the read-write constructors — memory_limit and temp_directory are session/engine settings, not writes to the (read-only) database file, so setting them here is safe.

pub fn explain_sql<P: Params>(&self, sql: &str, params: P) -> Result<String>

Run EXPLAIN <sql> against the underlying DuckDB connection and return the optimizer plan as a single string (newline-separated rows). Used by --explain to emit per-analysis query plans without coupling the CLI to duckdb::params! macros.

§Errors

Returns CodeLoreError::Analysis if the underlying EXPLAIN query fails to prepare or iterate.

pub fn flush(&self) -> Result<()>

Flush any pending writes to disk. Called before an atomic rename to ensure durability (APFS gotcha).

pub fn open_or_ingest<R: Repo>(opts: &Options, repo: &R) -> Result<Self>

Content-addressed persistent cache constructor.

Cache key: (canonical_repo_path, head_sha, pkg_version, opts_thresholds, schema_v1).

Hit path: open existing .duckdb file in read-only mode. Miss path: ingest to .duckdb.tmp, CHECKPOINT, sync_all, atomic rename, prune stale entries, open result in read-only mode.

Use --no-cache in the CLI to bypass this constructor.

pub fn open_or_ingest_with_cache_root<R: Repo>( opts: &Options, repo: &R, cache_root: &Path, ) -> Result<Self>

Same as [open_or_ingest] but with an explicit cache root for testing and for the --cache-dir CLI flag.

pub fn list_tables(&self) -> Result<Vec<String>>

pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>>

Prepare a SQL statement against the underlying connection. Returns a duckdb::Statement<'_> whose lifetime is tied to &self. Use for the prepare → query_map / query_row → collect pattern when the caller needs multi-row iteration. Errors are wrapped in CodeLoreError::Analysis so they share the analysis-error exit code (4) the rest of the lib uses for SQL failures.

§Errors

Returns CodeLoreError::Analysis if statement preparation fails.

pub fn execute_batch(&self, sql: &str) -> Result<()>

Run multiple SQL statements separated by ;. Useful for test fixtures and one-shot DDL/DML. Single-statement SQL also works — DuckDB’s execute_batch just feeds the whole string through the parser.

§Errors

Returns CodeLoreError::Analysis on any SQL error.

pub fn query_row<T, P, F>(&self, sql: &str, params: P, mapper: F) -> Result<T>
where P: Params, F: FnOnce(&Row<'_>) -> Result<T>,

Run a single SQL statement that returns exactly one row, mapping it via the caller-supplied closure. Mirrors rusqlite’s shape so migration from db.conn().query_row(...) is mechanical.

§Errors

Returns CodeLoreError::Analysis on prepare / execute / no-rows error.

pub fn commit_count(&self) -> Result<i64>

Number of commits in the fact store — the persisted, cache-safe form of ingest::IngestStats::commits_ingested (one row per ingested commit). Unlike that in-memory counter it is readable after a cache HIT as well as a fresh ingest; and unlike complexity_metrics / changes it is the raw output of the commit walk — it does not derive from the changes ⋈ commits join, so a blind walk that empties that join still leaves this readable (and zero). That independence is what makes it a witness.

§Errors

CodeLoreError::Analysis on query failure.

pub fn complexity_row_count(&self) -> Result<i64>

Rows the HEAD-state scan produced, for use as a witness where Self::commit_count cannot be one.

A head-only ingest deliberately leaves the history tables empty — it scans complexity and imports at HEAD and walks no commits — so commit_count is zero for a perfectly healthy run. Anything gating on that count therefore fires unconditionally on this path. This counts the table the head-only scan actually fills, so “did the ingest see anything?” stays answerable in both modes.

§Errors

CodeLoreError::Analysis on query failure.

pub fn ensure_ingest_witnessed(&self, head_sha: &str) -> Result<()>

Fail loudly when the walk ingested no commits while HEAD names a real commit — the signature of a truncated checkout. A shallow fetch-depth clone whose tip is a merge commit ingests zero commits under the default merge filter, leaving an empty fact store on which every quality gate finds nothing to violate and codelore check reports a green pass over no data. Gating on the ingest count turns that silent pass into a hard, distinct error.

An empty head_sha (an unborn HEAD — git init with nothing committed) is deliberately not this case and passes through: that is a genuinely empty repository, the province of the empty-repository preflight, not a truncated one.

§Errors

CodeLoreError::Repo (spec §6.6 exit 3 — the shallow/corrupted-repo bucket that CodeLoreError::BlobNotFound also occupies) when HEAD is real but no commits were ingested.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more