nullnet_libdatastore/
client.rs

1use crate::datastore::store_service_client::StoreServiceClient;
2use crate::utils::{authorize_request, validate_response_and_convert_to_reponse_data};
3use crate::{datastore::*, DatastoreConfig, ResponseData};
4use nullnet_liberror::{location, Error, ErrorHandler, Location};
5use tonic::transport::{Channel, ClientTlsConfig};
6
7/// A client for interacting with the datastore service.
8#[derive(Debug, Clone)]
9pub struct DatastoreClient {
10    /// Configuration for connecting to the datastore.
11    config: DatastoreConfig,
12}
13
14impl DatastoreClient {
15    /// Creates a new instance of `DatastoreClient`.
16    ///
17    /// # Arguments
18    /// * `config` - The configuration settings for connecting to the datastore.
19    #[must_use]
20    pub fn new(config: DatastoreConfig) -> Self {
21        Self { config }
22    }
23
24    /// Establishes a connection to the datastore service.
25    ///
26    /// # Returns
27    /// * `Ok(StoreServiceClient<Channel>)` - The client for interacting with the datastore service.
28    /// * `Err(Error)` - If the connection fails.
29    async fn connect(&self) -> Result<StoreServiceClient<Channel>, Error> {
30        let protocol = if self.config.tls { "https" } else { "http" };
31        let host = self.config.host.as_str();
32        let port = self.config.port;
33
34        let mut endpoint = Channel::from_shared(format!("{protocol}://{host}:{port}"))
35            .handle_err(location!())?
36            .connect_timeout(std::time::Duration::from_secs(10));
37
38        if self.config.tls {
39            endpoint = endpoint
40                .tls_config(ClientTlsConfig::new().with_native_roots())
41                .handle_err(location!())?;
42        }
43
44        let channel: Channel = endpoint.connect().await.handle_err(location!())?;
45
46        Ok(StoreServiceClient::new(channel))
47    }
48
49    /// Logs in to the datastore service with the provided request.
50    ///
51    /// # Arguments
52    /// * `request` - The login request containing the necessary credentials.
53    ///
54    /// # Returns
55    /// * `Ok(LoginResponse)` - The response received after a successful login.
56    /// * `Err(Error)` - If the login fails or if an error occurs during the process.
57    #[allow(clippy::missing_errors_doc)]
58    pub async fn login(&self, request: LoginRequest) -> Result<LoginResponse, Error> {
59        let mut client_inner = self.connect().await?;
60
61        let response = client_inner.login(request).await.handle_err(location!())?;
62
63        Ok(response.into_inner())
64    }
65
66    /// Creates multiple records in the datastore with the provided request.
67    ///
68    /// # Arguments
69    /// * `request` - The batch create request containing the records to be created.
70    /// * `token` - The authorization token to authorize the request.
71    ///
72    /// # Returns
73    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
74    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
75    #[allow(clippy::missing_errors_doc)]
76    pub async fn batch_create(
77        &self,
78        request: BatchCreateRequest,
79        token: &str,
80    ) -> Result<ResponseData, Error> {
81        let mut client_inner = self.connect().await?;
82        let request = authorize_request(request, token)?;
83
84        let response = client_inner
85            .batch_create(request)
86            .await
87            .handle_err(location!())?;
88
89        validate_response_and_convert_to_reponse_data(response.into_inner())
90    }
91
92    /// Creates a single record in the datastore with the provided request.
93    ///
94    /// # Arguments
95    /// * `request` - The create request containing the record to be created.
96    /// * `token` - The authorization token to authorize the request.
97    ///
98    /// # Returns
99    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
100    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
101    #[allow(clippy::missing_errors_doc)]
102    pub async fn create(&self, request: CreateRequest, token: &str) -> Result<ResponseData, Error> {
103        let mut client_inner = self.connect().await?;
104        let request = authorize_request(request, token)?;
105
106        let response = client_inner.create(request).await.handle_err(location!())?;
107
108        validate_response_and_convert_to_reponse_data(response.into_inner())
109    }
110
111    /// Deletes a record from the datastore with the provided request.
112    ///
113    /// # Arguments
114    /// * `request` - The delete request containing the identifier of the record to be deleted.
115    /// * `token` - The authorization token to authorize the request.
116    ///
117    /// # Returns
118    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
119    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
120    #[allow(clippy::missing_errors_doc)]
121    pub async fn delete(&self, request: DeleteRequest, token: &str) -> Result<ResponseData, Error> {
122        let mut client_inner = self.connect().await?;
123        let request = authorize_request(request, token)?;
124
125        let response = client_inner.delete(request).await.handle_err(location!())?;
126
127        validate_response_and_convert_to_reponse_data(response.into_inner())
128    }
129
130    /// Deletes multiple records from the datastore with the provided request.
131    ///
132    /// # Arguments
133    /// * `request` - The batch delete request containing the identifiers of the records to be deleted.
134    /// * `token` - The authorization token to authorize the request.
135    ///
136    /// # Returns
137    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
138    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
139    #[allow(clippy::missing_errors_doc)]
140    pub async fn batch_delete(
141        &self,
142        request: BatchDeleteRequest,
143        token: &str,
144    ) -> Result<ResponseData, Error> {
145        let mut client_inner = self.connect().await?;
146        let request = authorize_request(request, token)?;
147
148        let response = client_inner
149            .batch_delete(request)
150            .await
151            .handle_err(location!())?;
152
153        validate_response_and_convert_to_reponse_data(response.into_inner())
154    }
155
156    /// Updates a record in the datastore with the provided request.
157    ///
158    /// # Arguments
159    /// * `request` - The update request containing the record's updated data.
160    /// * `token` - The authorization token to authorize the request.
161    ///
162    /// # Returns
163    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
164    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
165    #[allow(clippy::missing_errors_doc)]
166    pub async fn update(&self, request: UpdateRequest, token: &str) -> Result<ResponseData, Error> {
167        let mut client_inner = self.connect().await?;
168        let request = authorize_request(request, token)?;
169
170        let response = client_inner.update(request).await.handle_err(location!())?;
171
172        validate_response_and_convert_to_reponse_data(response.into_inner())
173    }
174
175    /// Updates multiple records in the datastore with the provided request.
176    ///
177    /// # Arguments
178    /// * `request` - The batch update request containing the updated data for multiple records.
179    /// * `token` - The authorization token to authorize the request.
180    ///
181    /// # Returns
182    /// * `Ok(ResponseData)` - The response data containing the result of the operation.
183    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
184    #[allow(clippy::missing_errors_doc)]
185    pub async fn batch_update(
186        &self,
187        request: BatchUpdateRequest,
188        token: &str,
189    ) -> Result<ResponseData, Error> {
190        let mut client_inner = self.connect().await?;
191        let request = authorize_request(request, token)?;
192
193        let response = client_inner
194            .batch_update(request)
195            .await
196            .handle_err(location!())?;
197
198        validate_response_and_convert_to_reponse_data(response.into_inner())
199    }
200
201    /// Retrieves records from the datastore based on the specified filter.
202    ///
203    /// # Arguments
204    /// * `request` - The request containing the filter criteria.
205    /// * `token` - The authorization token to authorize the request.
206    ///
207    /// # Returns
208    /// * `Ok(ResponseData)` - The response data containing the records that match the filter.
209    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
210    #[allow(clippy::missing_errors_doc)]
211    pub async fn get_by_filter(
212        &self,
213        request: GetByFilterRequest,
214        token: &str,
215    ) -> Result<ResponseData, Error> {
216        let mut client_inner = self.connect().await?;
217        let request = authorize_request(request, token)?;
218
219        let response = client_inner
220            .get_by_filter(request)
221            .await
222            .handle_err(location!())?;
223
224        validate_response_and_convert_to_reponse_data(response.into_inner())
225    }
226
227    /// Performs aggregation on records in the datastore based on the provided request.
228    ///
229    /// # Arguments
230    /// * `request` - The aggregation request specifying the criteria for aggregation.
231    /// * `token` - The authorization token to authorize the request.
232    ///
233    /// # Returns
234    /// * `Ok(ResponseData)` - The response data containing the result of the aggregation.
235    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
236    #[allow(clippy::missing_errors_doc)]
237    pub async fn aggregate(
238        &self,
239        request: AggregateRequest,
240        token: &str,
241    ) -> Result<ResponseData, Error> {
242        let mut client_inner = self.connect().await?;
243        let request = authorize_request(request, token)?;
244
245        let response = client_inner
246            .aggregate(request)
247            .await
248            .handle_err(location!())?;
249
250        validate_response_and_convert_to_reponse_data(response.into_inner())
251    }
252
253    /// Retrieves a record from the datastore by its identifier.
254    ///
255    /// # Arguments
256    /// * `request` - The request containing the identifier of the record to be retrieved.
257    /// * `token` - The authorization token to authorize the request.
258    ///
259    /// # Returns
260    /// * `Ok(ResponseData)` - The response data containing the requested record.
261    /// * `Err(Error)` - If the operation fails or if an error occurs during the process.
262    #[allow(clippy::missing_errors_doc)]
263    pub async fn get_by_id(
264        &self,
265        request: GetByIdRequest,
266        token: &str,
267    ) -> Result<ResponseData, Error> {
268        let mut client_inner = self.connect().await?;
269        let request = authorize_request(request, token)?;
270
271        let response = client_inner
272            .get_by_id(request)
273            .await
274            .handle_err(location!())?;
275
276        validate_response_and_convert_to_reponse_data(response.into_inner())
277    }
278}