codebase-graph 1.2.2

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

pub fn write_database(request: LadybugWriteRequest) -> Result<(), NativeError> {
    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 Path::new(&request.db_path).exists() {
        return Err(NativeError::InvalidInput(format!(
            "candidate database path already exists: {}",
            request.db_path
        )));
    }
    if let Some(parent) = Path::new(&request.db_path).parent() {
        fs::create_dir_all(parent)?;
    }
    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.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()))
            }
        }
    }
}