fmp_rs/endpoints/
company_search.rs

1//! Company search endpoints
2
3use crate::client::FmpClient;
4use crate::error::Result;
5use crate::models::company::CompanySearchResult;
6use serde::Serialize;
7
8/// Company search API endpoints
9pub struct CompanySearch {
10    client: FmpClient,
11}
12
13impl CompanySearch {
14    pub(crate) fn new(client: FmpClient) -> Self {
15        Self { client }
16    }
17
18    /// Search for companies by name or symbol
19    ///
20    /// # Example
21    /// ```no_run
22    /// # use fmp_rs::FmpClient;
23    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
24    /// let client = FmpClient::new()?;
25    /// let results = client.company_search().search("Apple", None, None).await?;
26    /// # Ok(())
27    /// # }
28    /// ```
29    pub async fn search(
30        &self,
31        query: &str,
32        limit: Option<u32>,
33        exchange: Option<&str>,
34    ) -> Result<Vec<CompanySearchResult>> {
35        #[derive(Serialize)]
36        struct Query<'a> {
37            query: &'a str,
38            #[serde(skip_serializing_if = "Option::is_none")]
39            limit: Option<u32>,
40            #[serde(skip_serializing_if = "Option::is_none")]
41            exchange: Option<&'a str>,
42            apikey: &'a str,
43        }
44
45        let url = self.client.build_url("/search");
46        self.client
47            .get_with_query(
48                &url,
49                &Query {
50                    query,
51                    limit,
52                    exchange,
53                    apikey: self.client.api_key(),
54                },
55            )
56            .await
57    }
58
59    /// Search for companies by ticker symbol
60    pub async fn search_symbol(
61        &self,
62        query: &str,
63        limit: Option<u32>,
64        exchange: Option<&str>,
65    ) -> Result<Vec<CompanySearchResult>> {
66        #[derive(Serialize)]
67        struct Query<'a> {
68            query: &'a str,
69            #[serde(skip_serializing_if = "Option::is_none")]
70            limit: Option<u32>,
71            #[serde(skip_serializing_if = "Option::is_none")]
72            exchange: Option<&'a str>,
73            apikey: &'a str,
74        }
75
76        let url = self.client.build_url("/search-symbol");
77        self.client
78            .get_with_query(
79                &url,
80                &Query {
81                    query,
82                    limit,
83                    exchange,
84                    apikey: self.client.api_key(),
85                },
86            )
87            .await
88    }
89
90    /// Search for companies by CIK number
91    pub async fn search_cik(
92        &self,
93        cik: &str,
94        limit: Option<u32>,
95    ) -> Result<Vec<CompanySearchResult>> {
96        #[derive(Serialize)]
97        struct Query<'a> {
98            cik: &'a str,
99            #[serde(skip_serializing_if = "Option::is_none")]
100            limit: Option<u32>,
101            apikey: &'a str,
102        }
103
104        let url = self.client.build_url("/search-cik");
105        self.client
106            .get_with_query(
107                &url,
108                &Query {
109                    cik,
110                    limit,
111                    apikey: self.client.api_key(),
112                },
113            )
114            .await
115    }
116
117    /// Search for companies by CUSIP
118    pub async fn search_cusip(&self, cusip: &str) -> Result<Vec<CompanySearchResult>> {
119        #[derive(Serialize)]
120        struct Query<'a> {
121            cusip: &'a str,
122            apikey: &'a str,
123        }
124
125        let url = self.client.build_url("/search-cusip");
126        self.client
127            .get_with_query(
128                &url,
129                &Query {
130                    cusip,
131                    apikey: self.client.api_key(),
132                },
133            )
134            .await
135    }
136
137    /// Search for companies by ISIN
138    pub async fn search_isin(&self, isin: &str) -> Result<Vec<CompanySearchResult>> {
139        #[derive(Serialize)]
140        struct Query<'a> {
141            isin: &'a str,
142            apikey: &'a str,
143        }
144
145        let url = self.client.build_url("/search-isin");
146        self.client
147            .get_with_query(
148                &url,
149                &Query {
150                    isin,
151                    apikey: self.client.api_key(),
152                },
153            )
154            .await
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[tokio::test]
163    #[ignore = "requires FMP API key"]
164    async fn test_search() {
165        let client = FmpClient::new().unwrap();
166        let results = client
167            .company_search()
168            .search("Apple", Some(10), None)
169            .await;
170        assert!(results.is_ok());
171    }
172
173    #[test]
174    fn test_search_builds_correct_url() {
175        let client = FmpClient::builder().api_key("test_key").build().unwrap();
176        let search = CompanySearch::new(client);
177        // Just verify we can create the search instance
178        assert_eq!(search.client.api_key(), "test_key");
179    }
180}