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}