use async_trait::async_trait;
use serde_json::Value;
use std::sync::OnceLock;
#[async_trait]
pub trait SearchEngine: Send + Sync {
async fn update(&self, table: &str, id: i32, payload: Value) -> Result<(), sqlx::Error>;
async fn delete(&self, table: &str, id: i32) -> Result<(), sqlx::Error>;
async fn search(&self, table: &str, query: &str) -> Result<Vec<i32>, sqlx::Error>;
}
static SEARCH_ENGINE: OnceLock<Box<dyn SearchEngine>> = OnceLock::new();
pub fn set_search_engine(engine: Box<dyn SearchEngine>) {
let _ = SEARCH_ENGINE.set(engine);
}
pub fn get_search_engine() -> Option<&'static dyn SearchEngine> {
SEARCH_ENGINE.get().map(|e| &**e)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_search_engine_none_before_set() {
let _ = get_search_engine(); }
#[test]
fn test_set_search_engine_is_idempotent() {
struct Noop;
#[async_trait::async_trait]
impl SearchEngine for Noop {
async fn update(
&self,
_: &str,
_: i32,
_: serde_json::Value,
) -> Result<(), sqlx::Error> {
Ok(())
}
async fn delete(&self, _: &str, _: i32) -> Result<(), sqlx::Error> {
Ok(())
}
async fn search(&self, _: &str, _: &str) -> Result<Vec<i32>, sqlx::Error> {
Ok(vec![])
}
}
set_search_engine(Box::new(Noop));
set_search_engine(Box::new(Noop)); }
}