1use async_trait::async_trait;
2use serde_json::Value;
3use std::sync::OnceLock;
4
5#[async_trait]
6pub trait SearchEngine: Send + Sync {
7 async fn update(&self, table: &str, id: i32, payload: Value) -> Result<(), crate::Error>;
8 async fn delete(&self, table: &str, id: i32) -> Result<(), crate::Error>;
9 async fn search(&self, table: &str, query: &str) -> Result<Vec<i32>, crate::Error>;
10}
11
12static SEARCH_ENGINE: OnceLock<Box<dyn SearchEngine>> = OnceLock::new();
13
14pub fn set_search_engine(engine: Box<dyn SearchEngine>) {
15 let _ = SEARCH_ENGINE.set(engine);
16}
17
18pub fn get_search_engine() -> Option<&'static dyn SearchEngine> {
19 SEARCH_ENGINE.get().map(|e| &**e)
20}
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25
26 #[test]
27 fn test_get_search_engine_none_before_set() {
28 let _ = get_search_engine(); }
35
36 #[test]
37 fn test_set_search_engine_is_idempotent() {
38 struct Noop;
41 #[async_trait::async_trait]
42 impl SearchEngine for Noop {
43 async fn update(
44 &self,
45 _: &str,
46 _: i32,
47 _: serde_json::Value,
48 ) -> Result<(), crate::Error> {
49 Ok(())
50 }
51 async fn delete(&self, _: &str, _: i32) -> Result<(), crate::Error> {
52 Ok(())
53 }
54 async fn search(&self, _: &str, _: &str) -> Result<Vec<i32>, crate::Error> {
55 Ok(vec![])
56 }
57 }
58 set_search_engine(Box::new(Noop));
59 set_search_engine(Box::new(Noop)); }
61}