Skip to main content

ecat_data/
search.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2use async_trait::async_trait;
3use ecat_errors::{Error, ErrorCode};
4
5#[async_trait]
6pub trait SearchClient: Send + Sync {
7    async fn index(&self, index: &str, id: &str, doc: &serde_json::Value) -> Result<(), Error>;
8    async fn search(
9        &self,
10        index: &str,
11        query: &serde_json::Value,
12    ) -> Result<serde_json::Value, Error>;
13    async fn delete(&self, index: &str, id: &str) -> Result<(), Error>;
14
15    /// Bulk index documents as `(id, doc)` pairs in one round trip.
16    /// Backends that cannot bulk-index return an error.
17    async fn bulk_index(
18        &self,
19        _index: &str,
20        _docs: &[(String, serde_json::Value)],
21    ) -> Result<(), Error> {
22        Err(Error::new(
23            ErrorCode::Internal,
24            "search",
25            "bulk_index not supported by this backend",
26        ))
27    }
28
29    /// Update an existing document, replacing it with `doc`.
30    async fn update(&self, _index: &str, _id: &str, _doc: &serde_json::Value) -> Result<(), Error> {
31        Err(Error::new(
32            ErrorCode::Internal,
33            "search",
34            "update not supported by this backend",
35        ))
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    /// 只实现核心三操作的后端:可选操作必须走默认实现的报错路径。
44    struct MinimalSearch;
45
46    #[async_trait]
47    impl SearchClient for MinimalSearch {
48        async fn index(
49            &self,
50            _index: &str,
51            _id: &str,
52            _doc: &serde_json::Value,
53        ) -> Result<(), Error> {
54            Ok(())
55        }
56        async fn search(
57            &self,
58            _index: &str,
59            _query: &serde_json::Value,
60        ) -> Result<serde_json::Value, Error> {
61            Ok(serde_json::Value::Null)
62        }
63        async fn delete(&self, _index: &str, _id: &str) -> Result<(), Error> {
64            Ok(())
65        }
66    }
67
68    #[tokio::test]
69    async fn optional_ops_default_to_not_supported_error() {
70        let client = MinimalSearch;
71        let err = client.bulk_index("idx", &[]).await.unwrap_err();
72        assert!(
73            err.to_string().contains("bulk_index not supported"),
74            "got: {err}"
75        );
76        let err = client
77            .update("idx", "1", &serde_json::Value::Null)
78            .await
79            .unwrap_err();
80        assert!(
81            err.to_string().contains("update not supported"),
82            "got: {err}"
83        );
84    }
85}