pexels_api/videos/
search.rs

1use crate::{
2    Locale, Orientation, Pexels, PexelsError, Size, VideoResponse, PEXELS_API, PEXELS_VIDEO_PATH,
3};
4use url::Url;
5
6/// The path for the search endpoint.
7const PEXELS_VIDEO_SEARCH_PATH: &str = "search";
8
9/// Represents a search request to the Pexels API for videos.
10pub struct Search<'a> {
11    query: &'a str,
12    page: Option<usize>,
13    per_page: Option<usize>,
14    orientation: Option<Orientation>,
15    size: Option<Size>,
16    locale: Option<Locale>,
17}
18
19impl<'a> Search<'a> {
20    /// Creates [`SearchBuilder`] for building URI's.
21    pub fn builder() -> SearchBuilder<'a> {
22        SearchBuilder::default()
23    }
24
25    /// Creates a URI from the provided parameters.
26    pub fn create_uri(&self) -> crate::BuilderResult {
27        let uri = format!("{}/{}/{}", PEXELS_API, PEXELS_VIDEO_PATH, PEXELS_VIDEO_SEARCH_PATH);
28
29        let mut url = Url::parse(uri.as_str())?;
30
31        url.query_pairs_mut().append_pair("query", self.query);
32
33        if let Some(page) = &self.page {
34            url.query_pairs_mut().append_pair("page", page.to_string().as_str());
35        }
36
37        if let Some(per_page) = &self.per_page {
38            url.query_pairs_mut().append_pair("per_page", per_page.to_string().as_str());
39        }
40
41        if let Some(orientation) = &self.orientation {
42            url.query_pairs_mut().append_pair("orientation", orientation.as_str());
43        }
44
45        if let Some(size) = &self.size {
46            url.query_pairs_mut().append_pair("size", size.as_str());
47        }
48
49        if let Some(locale) = &self.locale {
50            url.query_pairs_mut().append_pair("locale", locale.as_str());
51        }
52
53        Ok(url.into())
54    }
55
56    /// Fetches the list of videos based on the search query from the Pexels API.
57    pub async fn fetch(&self, client: &Pexels) -> Result<VideoResponse, PexelsError> {
58        let url = self.create_uri()?;
59        let response = client.make_request(url.as_str()).await?;
60        let response_video: VideoResponse = serde_json::from_value(response)?;
61        Ok(response_video)
62    }
63}
64
65/// Builder for [`Search`].
66#[derive(Default)]
67pub struct SearchBuilder<'a> {
68    query: &'a str,
69    page: Option<usize>,
70    per_page: Option<usize>,
71    orientation: Option<Orientation>,
72    size: Option<Size>,
73    locale: Option<Locale>,
74}
75
76impl<'a> SearchBuilder<'a> {
77    /// Create a new [`SearchBuilder`].
78    pub fn new() -> Self {
79        Self { query: "", page: None, per_page: None, orientation: None, size: None, locale: None }
80    }
81
82    /// Sets the search query.
83    pub fn query(mut self, query: &'a str) -> Self {
84        self.query = query;
85        self
86    }
87
88    /// Sets the page number for the request.
89    pub fn page(mut self, page: usize) -> Self {
90        self.page = Some(page);
91        self
92    }
93
94    /// Sets the number of results per page for the request.
95    pub fn per_page(mut self, per_page: usize) -> Self {
96        self.per_page = Some(per_page);
97        self
98    }
99
100    /// Sets the desired video orientation.
101    pub fn orientation(mut self, orientation: Orientation) -> Self {
102        self.orientation = Some(orientation);
103        self
104    }
105
106    /// Sets the minimum video size.
107    pub fn size(mut self, size: Size) -> Self {
108        self.size = Some(size);
109        self
110    }
111
112    /// Sets the locale of the search.
113    pub fn locale(mut self, locale: Locale) -> Self {
114        self.locale = Some(locale);
115        self
116    }
117
118    /// Builds a `Search` instance from the `SearchBuilder`.
119    pub fn build(self) -> Search<'a> {
120        Search {
121            query: self.query,
122            page: self.page,
123            per_page: self.per_page,
124            orientation: self.orientation,
125            size: self.size,
126            locale: self.locale,
127        }
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use crate::videos::search::SearchBuilder;
134    use crate::{Locale, Orientation, Size};
135
136    #[test]
137    fn test_query() {
138        let uri = SearchBuilder::new().query("bar").build();
139        assert_eq!("https://api.pexels.com/videos/search?query=bar", uri.create_uri().unwrap());
140    }
141
142    #[test]
143    fn test_page() {
144        let uri = SearchBuilder::new().page(1).build();
145        assert_eq!("https://api.pexels.com/videos/search?query=&page=1", uri.create_uri().unwrap());
146    }
147
148    #[test]
149    fn test_per_page() {
150        let uri = SearchBuilder::new().per_page(1).build();
151        assert_eq!(
152            "https://api.pexels.com/videos/search?query=&per_page=1",
153            uri.create_uri().unwrap()
154        );
155    }
156
157    #[test]
158    fn test_orientation() {
159        let uri = SearchBuilder::new().orientation(Orientation::Landscape).build();
160        assert_eq!(
161            "https://api.pexels.com/videos/search?query=&orientation=landscape",
162            uri.create_uri().unwrap()
163        );
164    }
165
166    #[test]
167    fn test_size() {
168        let uri = SearchBuilder::new().size(Size::Small).build();
169        assert_eq!(
170            "https://api.pexels.com/videos/search?query=&size=small",
171            uri.create_uri().unwrap()
172        );
173    }
174
175    #[test]
176    fn test_locale() {
177        let uri = SearchBuilder::new().locale(Locale::sv_SE).build();
178        assert_eq!(
179            "https://api.pexels.com/videos/search?query=&locale=sv-SE",
180            uri.create_uri().unwrap()
181        );
182    }
183}