1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use reqwest::Url;
use std::error::Error;
use std::sync::Arc;

use crate::collections::meta::Metadata;

/// All meta related endpoints and functionality described in
/// [Weaviate meta API documentation](https://weaviate.io/developers/weaviate/api/rest/meta)
#[derive(Debug)]
pub struct Meta {
    /// The full URL to the Meta endpoint
    endpoint: Url,
    /// The sub-client which executes the requests - temporary
    client: Arc<reqwest::Client>,
}

impl Meta {
    /// Create a new instance of the Meta endpoint struct. Should only be done by the parent
    /// client.
    pub(super) fn new(url: &Url, client: Arc<reqwest::Client>) -> Result<Self, Box<dyn Error>> {
        let endpoint = url.join("/v1/meta/")?;
        Ok(Meta { endpoint, client })
    }

    /// Get the metadata associated to the clients Weaviate instance.
    ///
    /// # Return value
    ///
    /// * Full Response of get request, deserializable into: hostname, version, module
    ///
    /// # Errors
    ///
    /// If the client is unable to execute get, an Err result is returned.
    ///
    /// # Examples
    /// ```no_run
    /// use weaviate_community::WeaviateClient;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = WeaviateClient::builder("http://localhost:8080").build()?;
    ///     let res = client.meta.get_meta().await?;
    ///
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_meta(&self) -> Result<Metadata, Box<dyn Error>> {
        let res = self.client.get(self.endpoint.clone()).send().await?;
        let res: Metadata = res.json().await?;
        Ok(res)
    }
}

#[cfg(test)]
mod tests {
    use crate::{collections::meta::Metadata, WeaviateClient};

    fn get_test_harness() -> (mockito::ServerGuard, WeaviateClient) {
        let mock_server = mockito::Server::new();
        let mut host = "http://".to_string();
        host.push_str(&mock_server.host_with_port());
        let client = WeaviateClient::builder(&host).build().unwrap();
        (mock_server, client)
    }

    fn test_metadata() -> Metadata {
        let data: Metadata = serde_json::from_value(serde_json::json!({
            "hostname": "http://[::]:8080",
            "modules": {
                "text2vec-contextionary": {
                  "version": "en0.16.0-v0.4.21",
                  "wordCount": 818072
                }
            },
            "version": "1.0.0"
        }))
        .unwrap();
        data
    }

    fn mock_get(
        server: &mut mockito::ServerGuard,
        endpoint: &str,
        status_code: usize,
        body: &str,
    ) -> mockito::Mock {
        server
            .mock("GET", endpoint)
            .with_status(status_code)
            .with_header("content-type", "application/json")
            .with_body(body)
            .create()
    }

    #[tokio::test]
    async fn test_get_meta_ok() {
        let (mut mock_server, client) = get_test_harness();
        let metadata = test_metadata();
        let metadata_str = serde_json::to_string(&metadata).unwrap();
        let mock = mock_get(&mut mock_server, "/v1/meta/", 200, &metadata_str);
        let res = client.meta.get_meta().await;
        mock.assert();
        assert!(res.is_ok());
        assert_eq!(res.unwrap().hostname, metadata.hostname);
    }

    #[tokio::test]
    async fn test_get_meta_err() {
        let (mut mock_server, client) = get_test_harness();
        let mock = mock_get(&mut mock_server, "/v1/meta/", 404, "");
        let res = client.meta.get_meta().await;
        mock.assert();
        assert!(res.is_err());
    }
}