1use polyoxide_core::{HttpClient, QueryBuilder, Request};
2
3use crate::{
4 error::GammaError,
5 types::{Market, Tag},
6};
7
8#[derive(Clone)]
10pub struct Markets {
11 pub(crate) http_client: HttpClient,
12}
13
14impl Markets {
15 pub fn get(&self, id: impl Into<String>) -> GetMarket {
17 GetMarket {
18 request: Request::new(
19 self.http_client.clone(),
20 format!("/markets/{}", urlencoding::encode(&id.into())),
21 ),
22 }
23 }
24
25 pub fn get_by_slug(&self, slug: impl Into<String>) -> GetMarket {
27 GetMarket {
28 request: Request::new(
29 self.http_client.clone(),
30 format!("/markets/slug/{}", urlencoding::encode(&slug.into())),
31 ),
32 }
33 }
34
35 pub fn list(&self) -> ListMarkets {
37 ListMarkets {
38 request: Request::new(self.http_client.clone(), "/markets"),
39 }
40 }
41
42 pub fn tags(&self, id: impl Into<String>) -> Request<Vec<Tag>, GammaError> {
44 Request::new(
45 self.http_client.clone(),
46 format!("/markets/{}/tags", urlencoding::encode(&id.into())),
47 )
48 }
49}
50
51pub struct GetMarket {
53 request: Request<Market, GammaError>,
54}
55
56impl GetMarket {
57 pub fn include_tag(mut self, include: bool) -> Self {
59 self.request = self.request.query("include_tag", include);
60 self
61 }
62
63 pub async fn send(self) -> Result<Market, GammaError> {
65 self.request.send().await
66 }
67}
68
69pub struct ListMarkets {
71 request: Request<Vec<Market>, GammaError>,
72}
73
74impl ListMarkets {
75 pub fn limit(mut self, limit: u32) -> Self {
77 self.request = self.request.query("limit", limit);
78 self
79 }
80
81 pub fn offset(mut self, offset: u32) -> Self {
83 self.request = self.request.query("offset", offset);
84 self
85 }
86
87 pub fn order(mut self, order: impl Into<String>) -> Self {
89 self.request = self.request.query("order", order.into());
90 self
91 }
92
93 pub fn ascending(mut self, ascending: bool) -> Self {
95 self.request = self.request.query("ascending", ascending);
96 self
97 }
98
99 pub fn id(mut self, ids: impl IntoIterator<Item = i64>) -> Self {
101 self.request = self.request.query_many("id", ids);
102 self
103 }
104
105 pub fn slug(mut self, slugs: impl IntoIterator<Item = impl ToString>) -> Self {
107 self.request = self.request.query_many("slug", slugs);
108 self
109 }
110
111 pub fn clob_token_ids(mut self, token_ids: impl IntoIterator<Item = impl ToString>) -> Self {
113 self.request = self.request.query_many("clob_token_ids", token_ids);
114 self
115 }
116
117 pub fn condition_ids(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
119 self.request = self.request.query_many("condition_ids", condition_ids);
120 self
121 }
122
123 pub fn market_maker_address(
125 mut self,
126 addresses: impl IntoIterator<Item = impl ToString>,
127 ) -> Self {
128 self.request = self.request.query_many("market_maker_address", addresses);
129 self
130 }
131
132 pub fn liquidity_num_min(mut self, min: f64) -> Self {
134 self.request = self.request.query("liquidity_num_min", min);
135 self
136 }
137
138 pub fn liquidity_num_max(mut self, max: f64) -> Self {
140 self.request = self.request.query("liquidity_num_max", max);
141 self
142 }
143
144 pub fn volume_num_min(mut self, min: f64) -> Self {
146 self.request = self.request.query("volume_num_min", min);
147 self
148 }
149
150 pub fn volume_num_max(mut self, max: f64) -> Self {
152 self.request = self.request.query("volume_num_max", max);
153 self
154 }
155
156 pub fn start_date_min(mut self, date: impl Into<String>) -> Self {
158 self.request = self.request.query("start_date_min", date.into());
159 self
160 }
161
162 pub fn start_date_max(mut self, date: impl Into<String>) -> Self {
164 self.request = self.request.query("start_date_max", date.into());
165 self
166 }
167
168 pub fn end_date_min(mut self, date: impl Into<String>) -> Self {
170 self.request = self.request.query("end_date_min", date.into());
171 self
172 }
173
174 pub fn end_date_max(mut self, date: impl Into<String>) -> Self {
176 self.request = self.request.query("end_date_max", date.into());
177 self
178 }
179
180 pub fn tag_id(mut self, tag_id: i64) -> Self {
182 self.request = self.request.query("tag_id", tag_id);
183 self
184 }
185
186 pub fn related_tags(mut self, include: bool) -> Self {
188 self.request = self.request.query("related_tags", include);
189 self
190 }
191
192 pub fn cyom(mut self, cyom: bool) -> Self {
194 self.request = self.request.query("cyom", cyom);
195 self
196 }
197
198 pub fn uma_resolution_status(mut self, status: impl Into<String>) -> Self {
200 self.request = self.request.query("uma_resolution_status", status.into());
201 self
202 }
203
204 pub fn game_id(mut self, game_id: impl Into<String>) -> Self {
206 self.request = self.request.query("game_id", game_id.into());
207 self
208 }
209
210 pub fn sports_market_types(mut self, types: impl IntoIterator<Item = impl ToString>) -> Self {
212 self.request = self.request.query_many("sports_market_types", types);
213 self
214 }
215
216 pub fn rewards_min_size(mut self, min: f64) -> Self {
218 self.request = self.request.query("rewards_min_size", min);
219 self
220 }
221
222 pub fn question_ids(mut self, question_ids: impl IntoIterator<Item = impl ToString>) -> Self {
224 self.request = self.request.query_many("question_ids", question_ids);
225 self
226 }
227
228 pub fn include_tag(mut self, include: bool) -> Self {
230 self.request = self.request.query("include_tag", include);
231 self
232 }
233
234 pub fn closed(mut self, closed: bool) -> Self {
236 self.request = self.request.query("closed", closed);
237 self
238 }
239
240 pub fn open(mut self, open: bool) -> Self {
242 self.request = self.request.query("closed", !open);
243 self
244 }
245
246 pub fn archived(mut self, archived: bool) -> Self {
248 self.request = self.request.query("archived", archived);
249 self
250 }
251
252 pub async fn send(self) -> Result<Vec<Market>, GammaError> {
254 self.request.send().await
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use crate::Gamma;
261
262 fn gamma() -> Gamma {
263 Gamma::new().unwrap()
264 }
265
266 #[test]
269 fn test_list_markets_full_chain() {
270 let _list = gamma()
272 .markets()
273 .list()
274 .limit(25)
275 .offset(50)
276 .order("volume")
277 .ascending(false)
278 .id(vec![1i64, 2, 3])
279 .slug(vec!["slug-a"])
280 .clob_token_ids(vec!["token-1"])
281 .condition_ids(vec!["cond-1"])
282 .market_maker_address(vec!["0xaddr"])
283 .liquidity_num_min(1000.0)
284 .liquidity_num_max(50000.0)
285 .volume_num_min(100.0)
286 .volume_num_max(10000.0)
287 .start_date_min("2024-01-01")
288 .start_date_max("2025-01-01")
289 .end_date_min("2024-06-01")
290 .end_date_max("2025-12-31")
291 .tag_id(42)
292 .related_tags(true)
293 .cyom(false)
294 .uma_resolution_status("resolved")
295 .game_id("game-1")
296 .sports_market_types(vec!["moneyline"])
297 .rewards_min_size(10.0)
298 .question_ids(vec!["q1"])
299 .include_tag(true)
300 .closed(false)
301 .archived(false);
302 }
303
304 #[test]
305 fn test_open_and_closed_are_inverse() {
306 let _open = gamma().markets().list().open(true);
308 let _closed = gamma().markets().list().closed(false);
309 }
310
311 #[test]
312 fn test_get_market_accepts_string_and_str() {
313 let _req1 = gamma().markets().get("12345");
314 let _req2 = gamma().markets().get(String::from("12345"));
315 }
316
317 #[test]
318 fn test_get_by_slug_accepts_string_and_str() {
319 let _req1 = gamma().markets().get_by_slug("my-slug");
320 let _req2 = gamma().markets().get_by_slug(String::from("my-slug"));
321 }
322
323 #[test]
324 fn test_get_market_with_include_tag() {
325 let _req = gamma().markets().get("12345").include_tag(true);
326 }
327
328 #[test]
329 fn test_market_tags_accepts_str_and_string() {
330 let _req1 = gamma().markets().tags("12345");
331 let _req2 = gamma().markets().tags(String::from("12345"));
332 }
333}