tmf_client/lib.rs
1//! # TMF Client Library
2//!
3//! ## Description
4//! Interact with TMF compliant APIs using an SDK
5//!
6//! ## Supported TMF APIs
7//!
8//! Currently supports:
9//!
10//! - TMF620
11//! - TMF622
12//! - TMF629
13//! - TMF632
14//! - TMF633
15//! - TMF648
16//! - TMF674
17//!
18//! ## Features
19//! All TMF APIs can be conditionally compiled. Deafult includes all APIs using V4 specifications.
20
21#![warn(missing_docs)]
22
23pub mod tmf;
24pub mod common;
25
26use common::tmf_error::TMFError;
27#[cfg(feature = "tmf620")]
28use tmf::tmf620::TMF620;
29#[cfg(feature = "tmf622")]
30use tmf::tmf622::TMF622;
31#[cfg(feature = "tmf629")]
32use tmf::tmf629::TMF629;
33#[cfg(feature = "tmf632")]
34use tmf::tmf632::TMF632;
35#[cfg(feature = "tmf633")]
36use tmf::tmf633::TMF633;
37#[cfg(feature = "tmf637")]
38use tmf::tmf637::TMF637;
39#[cfg(feature = "tmf638")]
40use tmf::tmf638::TMF638;
41#[cfg(feature = "tmf639")]
42use tmf::tmf639::TMF639;
43#[cfg(feature = "tmf645")]
44use tmf::tmf645::TMF645;
45#[cfg(feature = "tmf648")]
46use tmf::tmf648::TMF648;
47#[cfg(feature = "tmf663")]
48use tmf::tmf663::TMF663;
49#[cfg(feature = "tmf674")]
50use tmf::tmf674::TMF674;
51
52
53use tmflib::{HasId,Uri};
54
55/// Fields for filtering output
56#[derive(Clone, Default, Debug)]
57pub struct QueryOptions {
58 /// Specific set of fields delimited by comma
59 pub fields : Option<String>,
60 /// Limit the number of results returned
61 pub limit : Option<u16>,
62 /// Offset the results returned
63 pub offset : Option<u16>,
64 /// Filter on name
65 pub name : Option<String>,
66}
67
68impl QueryOptions {
69 /// Setting the field on an existing QueryOptions
70 /// ```
71 /// # use tmf_client::QueryOptions;
72 /// let opt = QueryOptions::default()
73 /// .fields("id,name,description".to_string());
74 /// ```
75 pub fn fields(mut self, fields : String) -> QueryOptions {
76 self.fields = Some(fields);
77 self
78 }
79 /// Set the limit on the number of results returned
80 /// ```
81 /// # use tmf_client::QueryOptions;
82 /// let opt = QueryOptions::default()
83 /// .limit(10);
84 /// ```
85 pub fn limit(mut self, limit : u16) -> QueryOptions {
86 self.limit = Some(limit);
87 self
88 }
89
90 /// Set the offset on the number of results returned
91 /// ```
92 /// # use tmf_client::QueryOptions;
93 /// let opt = QueryOptions::default()
94 /// .offset(5);
95 /// ```
96 pub fn offset(mut self, offset : u16) -> QueryOptions {
97 self.offset = Some(offset);
98 self
99 }
100
101 /// Set the name to filter on
102 /// ```
103 /// # use tmf_client::QueryOptions;
104 /// let opt = QueryOptions::default()
105 /// .name("MyService".to_string());
106 /// ```
107 /// This will filter the results to only include those with the specified name.
108 /// If the name is not set, it will not filter on name.
109 ///
110 pub fn name(mut self, name : impl Into<String>) -> QueryOptions {
111 self.name = Some(name.into());
112 self
113 }
114}
115
116impl From<QueryOptions> for String {
117 fn from(val: QueryOptions) -> Self {
118 let limit = match val.limit {
119 Some(l) => format!("limit={l}"),
120 None => String::default(),
121 };
122 let offset = match val.offset {
123 Some(o) => format!("offset={o}"),
124 None => String::default(),
125 };
126 let name = match val.name {
127 Some(n) => format!("name={n}"),
128 None => String::default(),
129 };
130 format!("{limit}&{offset}&{name}")
131 }
132}
133
134/// Standard set of operations for all TMF objects
135pub trait Operations {
136 /// The TMF object type that this trait operates on
137 type TMF : HasId;
138
139 /// Get a specific TMF object by Id
140 /// ```
141 /// # use tmf_client::{TMFClient,Operations};
142 /// let categories = TMFClient::new("http://localhost:8000")
143 /// .tmf620()
144 /// .category()
145 /// .get("ID123");
146 /// ```
147 fn get(&self, id : impl Into<String>) -> Result<Vec<Self::TMF>,TMFError>;
148 /// Get a list of tmf objects applying optional filter
149 /// ```
150 /// # use tmf_client::{TMFClient,QueryOptions,Operations};
151 /// let filter = QueryOptions::default()
152 /// .limit(15)
153 /// .offset(10);
154 /// let categories = TMFClient::new("http://localhost:8000")
155 /// .tmf620()
156 /// .category()
157 /// .list(Some(filter));
158 /// ```
159 fn list(&self, filter : Option<QueryOptions>) -> Result<Vec<Self::TMF>,TMFError>;
160 /// Create a new instance of a TMF object
161 fn create(&self, item : Self::TMF) -> Result<Self::TMF,TMFError>;
162 /// Update an existing TMF Object using the provided patch object
163 fn update(&self, id : impl Into<String>, patch : Self::TMF) -> Result<Self::TMF,TMFError>;
164 /// Delete a specific tmf object by Id
165 /// ```
166 /// # use tmf_client::{TMFClient,Operations};
167 /// let categories = TMFClient::new("http://localhost:8000")
168 /// .tmf620()
169 /// .category()
170 /// .delete("ID123");
171 /// ```
172 fn delete(&self, id : impl Into<String>) -> Result<Self::TMF,TMFError>;
173}
174
175/// Trait to create a new instance of a TMF object
176#[allow(clippy::new_ret_no_self)]
177pub trait HasNew<T : Clone> {
178 /// Create a new instance of the TMF object passin in the destination host Uri
179 fn new(host : Uri) -> T;
180}
181
182/// TMF Client
183pub struct TMFClient {
184 host : String,
185 #[cfg(feature = "tmf620")]
186 tmf620 : Option<TMF620>,
187 #[cfg(feature = "tmf622")]
188 tmf622 : Option<TMF622>,
189 #[cfg(feature = "tmf629")]
190 tmf629 : Option<TMF629>,
191 #[cfg(feature = "tmf632")]
192 tmf632 : Option<TMF632>,
193 #[cfg(feature = "tmf633")]
194 tmf633 : Option<TMF633>,
195 #[cfg(feature = "tmf637")]
196 tmf637 : Option<TMF637>,
197 #[cfg(feature = "tmf638")]
198 tmf638 : Option<TMF638>,
199 #[cfg(feature = "tmf639")]
200 tmf639 : Option<TMF639>,
201 #[cfg(feature = "tmf645")]
202 tmf645 : Option<TMF645>,
203 #[cfg(feature = "tmf648")]
204 tmf648 : Option<TMF648>,
205 #[cfg(feature = "tmf663")]
206 tmf663 : Option<TMF663>,
207 #[cfg(feature = "tmf674")]
208 tmf674 : Option<TMF674>,
209}
210
211// Create a new instance
212fn instantiate<T : Clone + HasNew<T>>(tmf : &mut Option<T>,hostname : String) -> T {
213 match tmf {
214 // If we already have an instance, clone that.
215 Some(t) => t.clone(),
216 // Else we need to create a new one and also store it.
217 None => {
218 let new_tmf = T::new(hostname);
219 tmf.replace(new_tmf.clone());
220 new_tmf
221 },
222 }
223}
224
225impl TMFClient {
226 /// Create a new TMFClient instance
227 /// ```
228 /// # use tmf_client::TMFClient;
229 /// let client = TMFClient::new("http://localhost:8000");
230 /// ```
231 pub fn new(host : impl Into<String>) -> TMFClient {
232 TMFClient {
233 host : host.into(),
234 #[cfg(feature = "tmf620")]
235 tmf620 : None,
236 #[cfg(feature = "tmf622")]
237 tmf622 : None,
238 #[cfg(feature = "tmf629")]
239 tmf629 : None,
240 #[cfg(feature = "tmf632")]
241 tmf632 : None,
242 #[cfg(feature = "tmf633")]
243 tmf633 : None,
244 #[cfg(feature = "tmf637")]
245 tmf637 : None,
246 #[cfg(feature = "tmf638")]
247 tmf638 : None,
248 #[cfg(feature = "tmf639")]
249 tmf639 : None,
250 #[cfg(feature = "tmf645")]
251 tmf645 : None,
252 #[cfg(feature = "tmf648")]
253 tmf648: None,
254 #[cfg(feature = "tmf663")]
255 tmf663: None,
256 #[cfg(feature = "tmf674")]
257 tmf674 : None,
258 }
259 }
260
261
262
263 /// Create access to TMF620 API
264 /// ```
265 /// # use tmf_client::TMFClient;
266 /// let tmf620 = TMFClient::new("http://localhost:8000")
267 /// .tmf620();
268 /// ```
269 #[cfg(feature = "tmf620")]
270 pub fn tmf620(&mut self) -> TMF620 {
271 instantiate(&mut self.tmf620,self.host.clone())
272 }
273
274 /// Create access to TMF622 API
275 /// ```
276 /// # use tmf_client::TMFClient;
277 /// let tmf620 = TMFClient::new("http://localhost:8000")
278 /// .tmf622();
279 /// ```
280 #[cfg(feature = "tmf622")]
281 pub fn tmf622(&mut self) -> TMF622 {
282 instantiate(&mut self.tmf622, self.host.clone())
283 }
284
285 /// Create access to TMF632 API
286 /// ```
287 /// # use tmf_client::TMFClient;
288 /// let tmf632 = TMFClient::new("http://localhost:8000")
289 /// .tmf629();
290 /// ```
291 #[cfg(feature = "tmf629")]
292 pub fn tmf629(&mut self) -> TMF629 {
293 instantiate(&mut self.tmf629, self.host.clone())
294 }
295
296 /// Create access to TMF632 API
297 /// ```
298 /// # use tmf_client::TMFClient;
299 /// let tmf632 = TMFClient::new("http://localhost:8000")
300 /// .tmf632();
301 /// ```
302 #[cfg(feature = "tmf632")]
303 pub fn tmf632(&mut self) -> TMF632 {
304 instantiate(&mut self.tmf632, self.host.clone())
305 }
306
307 /// Create access to TMF633 API
308 /// ```
309 /// # use tmf_client::TMFClient;
310 /// let tmf633 = TMFClient::new("http://localhost:8000")
311 /// .tmf633();
312 /// ```
313 #[cfg(feature = "tmf633")]
314 pub fn tmf633(&mut self) -> TMF633 {
315 instantiate(&mut self.tmf633, self.host.clone())
316 }
317
318 /// Create access to TMF637 API
319 /// ```
320 /// # use tmf_client::TMFClient;
321 /// let tmf637 = TMFClient::new("http://localhost:8000")
322 /// .tmf637();
323 /// ```
324 #[cfg(feature = "tmf637")]
325 pub fn tmf637(&mut self) -> TMF637 {
326 instantiate(&mut self.tmf637, self.host.clone())
327 }
328
329 /// Create access to TMF638 API
330 /// ```
331 /// # use tmf_client::TMFClient;
332 /// let tmf638 = TMFClient::new("http://localhost:8000")
333 /// .tmf638();
334 /// ```
335 #[cfg(feature = "tmf638")]
336 pub fn tmf638(&mut self) -> TMF638 {
337 instantiate(&mut self.tmf638, self.host.clone())
338 }
339
340 /// Create access to TMF639 API
341 /// ```
342 /// # use tmf_client::TMFClient;
343 /// let tmf639 = TMFClient::new("http://localhost:8000")
344 /// .tmf639();
345 /// ```
346 #[cfg(feature = "tmf639")]
347 pub fn tmf639(&mut self) -> TMF639 {
348 instantiate(&mut self.tmf639, self.host.clone())
349 }
350
351 /// Create access to TMF645 API
352 /// ```
353 /// # use tmf_client::TMFClient;
354 /// let tmf645 = TMFClient::new("http://localhost:8000")
355 /// .tmf645();
356 /// ```
357 #[cfg(feature = "tmf645")]
358 pub fn tmf645(&mut self) -> TMF645 {
359 instantiate(&mut self.tmf645, self.host.clone())
360 }
361
362 /// Create access to TMF648 API
363 /// ```
364 /// # use tmf_client::TMFClient;
365 /// let tmf648 = TMFClient::new("http://localhost:8000")
366 /// .tmf648();
367 /// ```
368 #[cfg(feature = "tmf648")]
369 pub fn tmf648(&mut self) -> TMF648 {
370 instantiate(&mut self.tmf648, self.host.clone())
371 }
372
373 /// Create access to TMF663 API
374 /// ```
375 /// # use tmf_client::TMFClient;
376 /// let tmf663 = TMFClient::new("http://localhost:8000")
377 /// .tmf663();
378 /// ```
379 #[cfg(feature = "tmf663")]
380 pub fn tmf663(&mut self) -> TMF663 {
381 instantiate(&mut self.tmf663, self.host.clone())
382 }
383
384 /// Create access to TMF674 API
385 /// ```
386 /// # use tmf_client::TMFClient;
387 /// let tmf674 = TMFClient::new("http://localhost:8000")
388 /// .tmf674();
389 /// ```
390 #[cfg(feature = "tmf674")]
391 pub fn tmf674(&mut self) -> TMF674 {
392 instantiate(&mut self.tmf674, self.host.clone())
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399 #[test]
400 fn test_filter_limit() {
401 let filter = QueryOptions::default().limit(111);
402
403 assert_eq!(filter.limit,Some(111));
404 }
405
406 #[test]
407 fn test_filter_offset() {
408 let filter = QueryOptions::default().offset(222);
409
410 assert_eq!(filter.offset,Some(222));
411 }
412}