Skip to main content

rullst_orm/
scout.rs

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        // In a fresh process (or when set_search_engine has not been called),
29        // get_search_engine returns None. Because OnceLock ignores subsequent
30        // writes, we can only reliably assert the Option shape here.
31        // If another test in this suite already called set_search_engine the
32        // result will be Some — both branches are valid at runtime.
33        let _ = get_search_engine(); // must not panic
34    }
35
36    #[test]
37    fn test_set_search_engine_is_idempotent() {
38        // A second set_search_engine call is silently ignored by OnceLock.
39        // This test verifies that calling it multiple times does not panic.
40        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)); // second call must not panic
60    }
61}