codebase-graph 1.1.6

Native codebaseGraph CLI and MCP server for local code knowledge graphs.
use super::cleanup::remove_existing_database;
use super::extensions::preseed_ladybug_extensions;
use super::request::LadybugWriteRequest;
use super::schema::schema_statements;
use super::{
    acquire_write_intent, connect_ladybug_database, open_ladybug_database,
    retry_transient_database, WRITE_RETRY_POLICY,
};
use crate::error::NativeError;
use lbug::Connection;
use std::path::Path;

pub fn write_database(request: LadybugWriteRequest) -> Result<(), NativeError> {
    let _write_intent = acquire_write_intent(Path::new(&request.db_path))?;
    retry_transient_database(WRITE_RETRY_POLICY, || write_database_once(&request))
}

fn write_database_once(request: &LadybugWriteRequest) -> Result<(), NativeError> {
    preseed_ladybug_extensions(request.include_fts)?;
    if request.replace_database {
        remove_existing_database(&request.db_path)?;
    }
    let database = open_ladybug_database(Path::new(&request.db_path), false)?;
    let connection = connect_ladybug_database(&database)?;
    for statement in schema_statements(request.include_fts, request.schema_statements.clone()) {
        query_ignoring_existing(&connection, &statement)?;
    }
    for statement in &request.delete_statements {
        query_ignoring_missing(&connection, statement)?;
    }
    for statement in &request.copy_statements {
        connection
            .query(statement)
            .map_err(|error| NativeError::Database(error.to_string()))?;
    }
    Ok(())
}

fn query_ignoring_existing(
    connection: &Connection<'_>,
    statement: &str,
) -> Result<(), NativeError> {
    match connection.query(statement) {
        Ok(_) => Ok(()),
        Err(error) => {
            let message = error.to_string().to_lowercase();
            if message.contains("already exists")
                || message.contains("exists already")
                || message.contains("already installed")
            {
                Ok(())
            } else {
                Err(NativeError::Database(error.to_string()))
            }
        }
    }
}

fn query_ignoring_missing(connection: &Connection<'_>, statement: &str) -> Result<(), NativeError> {
    match connection.query(statement) {
        Ok(_) => Ok(()),
        Err(error) => {
            let message = error.to_string().to_lowercase();
            if message.contains("does not exist")
                || message.contains("not found")
                || message.contains("no such")
            {
                Ok(())
            } else {
                Err(NativeError::Database(error.to_string()))
            }
        }
    }
}