redmine_api/api/
queries.rs

1//! Queries Rest API Endpoint definitions
2//!
3//! [Redmine Documentation](https://www.redmine.org/projects/redmine/wiki/Rest_Queries)
4//!
5//! - [x] all (visible) custom queries endpoint
6
7use derive_builder::Builder;
8use reqwest::Method;
9use std::borrow::Cow;
10
11use crate::api::{Endpoint, Pageable, ReturnsJsonResponse};
12
13/// a type for query to use as an API return type
14///
15/// alternatively you can use your own type limited to the fields you need
16#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17pub struct Query {
18    /// numeric id
19    pub id: u64,
20    /// display name
21    pub name: String,
22    /// is this query public
23    pub is_public: bool,
24    /// the project for project-specific queries
25    pub project_id: Option<u64>,
26}
27
28/// The endpoint to retrieve all queries visible to the current user
29///
30/// to actually use them pass the query_id to the ListIssues endpoint
31#[derive(Debug, Clone, Builder)]
32#[builder(setter(strip_option))]
33pub struct ListQueries {}
34
35impl ReturnsJsonResponse for ListQueries {}
36impl Pageable for ListQueries {
37    fn response_wrapper_key(&self) -> String {
38        "queries".to_string()
39    }
40}
41
42impl ListQueries {
43    /// Create a builder for the endpoint.
44    #[must_use]
45    pub fn builder() -> ListQueriesBuilder {
46        ListQueriesBuilder::default()
47    }
48}
49
50impl Endpoint for ListQueries {
51    fn method(&self) -> Method {
52        Method::GET
53    }
54
55    fn endpoint(&self) -> Cow<'static, str> {
56        "queries.json".into()
57    }
58}
59
60/// helper struct for outer layers with a queries field holding the inner data
61#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
62pub struct QueriesWrapper<T> {
63    /// to parse JSON with queries key
64    pub queries: Vec<T>,
65}
66
67#[cfg(test)]
68mod test {
69    use super::*;
70    use pretty_assertions::assert_eq;
71    use std::error::Error;
72    use tracing_test::traced_test;
73
74    #[traced_test]
75    #[test]
76    fn test_list_queries_first_page() -> Result<(), Box<dyn Error>> {
77        dotenvy::dotenv()?;
78        let redmine = crate::api::Redmine::from_env()?;
79        let endpoint = ListQueries::builder().build()?;
80        redmine.json_response_body_page::<_, Query>(&endpoint, 0, 25)?;
81        Ok(())
82    }
83
84    #[traced_test]
85    #[test]
86    fn test_list_queries_all_pages() -> Result<(), Box<dyn Error>> {
87        dotenvy::dotenv()?;
88        let redmine = crate::api::Redmine::from_env()?;
89        let endpoint = ListQueries::builder().build()?;
90        redmine.json_response_body_all_pages::<_, Query>(&endpoint)?;
91        Ok(())
92    }
93
94    /// this tests if any of the results contain a field we are not deserializing
95    ///
96    /// this will only catch fields we missed if they are part of the response but
97    /// it is better than nothing
98    #[traced_test]
99    #[test]
100    fn test_completeness_query_type() -> Result<(), Box<dyn Error>> {
101        dotenvy::dotenv()?;
102        let redmine = crate::api::Redmine::from_env()?;
103        let endpoint = ListQueries::builder().build()?;
104        let values: Vec<serde_json::Value> = redmine.json_response_body_all_pages(&endpoint)?;
105        for value in values {
106            let o: Query = serde_json::from_value(value.clone())?;
107            let reserialized = serde_json::to_value(o)?;
108            assert_eq!(value, reserialized);
109        }
110        Ok(())
111    }
112}