1use helper::*;
2
3use crate::errors::ConnpassCliError;
4
5use super::{
6 types::{FetchCountRange, FormatJson},
7 validator::Validator,
8 OrderOption, Query,
9};
10
11pub struct QueryBuilder {
13 event_id: Option<Vec<u32>>,
14 keyword: Option<Vec<String>>,
15 keyword_or: Option<Vec<String>>,
16 ym: Option<Vec<u32>>,
17 ymd: Option<Vec<u32>>,
18 nickname: Option<Vec<String>>,
19 owner_nickname: Option<Vec<String>>,
20 series_id: Option<Vec<u32>>,
21 start: Option<u32>,
22 order: Option<OrderOption>,
23 count: Option<FetchCountRange>,
24 format: Option<FormatJson>,
25}
26
27impl Default for QueryBuilder {
28 fn default() -> Self {
29 Self {
30 event_id: None,
31 keyword: None,
32 keyword_or: None,
33 ym: None,
34 ymd: None,
35 nickname: None,
36 owner_nickname: None,
37 series_id: None,
38 start: None,
39 order: None,
40 count: None,
41 format: None,
42 }
43 }
44}
45
46impl QueryBuilder {
54 pub fn begin() -> Self {
56 QueryBuilder::default()
57 }
58
59 pub fn event_ids(mut self, ids: Vec<u32>) -> Self {
60 self.event_id = Some(ids);
61 self
62 }
63
64 pub fn event_id(mut self, id: u32) -> Self {
65 self.event_id = push_or_create(self.event_id, id);
66 self
67 }
68
69 pub fn keywords(mut self, keywords: Vec<String>) -> Self {
70 self.keyword = Some(keywords);
71 self
72 }
73
74 pub fn keyword(mut self, keyword: impl Into<String>) -> Self {
75 self.keyword = push_or_create(self.keyword, keyword.into());
76 self
77 }
78
79 pub fn keywords_or(mut self, keywords: Vec<String>) -> Self {
80 self.keyword_or = Some(keywords);
81 self
82 }
83
84 pub fn keyword_or(mut self, keyword: impl Into<String>) -> Self {
85 self.keyword_or = push_or_create(self.keyword_or, keyword.into());
86 self
87 }
88
89 pub fn yms(mut self, ym: Vec<u32>) -> Self {
90 self.ym = Some(ym);
91 self
92 }
93
94 pub fn ym(mut self, ym: u32) -> Self {
95 self.ym = push_or_create(self.ym, ym);
96 self
97 }
98
99 pub fn ymds(mut self, ymd: Vec<u32>) -> Self {
100 self.ymd = Some(ymd);
101 self
102 }
103
104 pub fn ymd(mut self, ymd: u32) -> Self {
105 self.ymd = push_or_create(self.ymd, ymd);
106 self
107 }
108
109 pub fn nicknames(mut self, nickname: Vec<String>) -> Self {
110 self.nickname = Some(nickname);
111 self
112 }
113
114 pub fn nickname(mut self, nickname: impl Into<String>) -> Self {
115 self.nickname = push_or_create(self.nickname, nickname.into());
116 self
117 }
118
119 pub fn owner_nicknames(mut self, owner_nickname: Vec<String>) -> Self {
120 self.owner_nickname = Some(owner_nickname);
121 self
122 }
123
124 pub fn owner_nickname(mut self, owner_nickname: impl Into<String>) -> Self {
125 self.owner_nickname = push_or_create(self.owner_nickname, owner_nickname.into());
126 self
127 }
128
129 pub fn series_ids(mut self, series_ids: Vec<u32>) -> Self {
130 self.series_id = Some(series_ids);
131 self
132 }
133
134 pub fn series_id(mut self, series_id: u32) -> Self {
135 self.series_id = push_or_create(self.series_id, series_id);
136 self
137 }
138
139 pub fn start(mut self, start: u32) -> Self {
140 self.start = Some(start);
141 self
142 }
143
144 pub fn order(mut self, order: OrderOption) -> Self {
145 self.order = Some(order);
146 self
147 }
148
149 pub fn count(mut self, count: u8) -> Self {
150 self.count = Some(FetchCountRange(count));
151 self
152 }
153
154 pub fn format(mut self, format: impl Into<String>) -> Self {
155 self.format = Some(FormatJson(format.into()));
156 self
157 }
158
159 pub fn build(self) -> Result<Query, ConnpassCliError> {
167 let mut query = Query {
168 event_id: self.event_id,
169 keyword: self.keyword,
170 keyword_or: self.keyword_or,
171 ym: self.ym,
172 ymd: self.ymd,
173 nickname: self.nickname,
174 owner_nickname: self.owner_nickname,
175 series_id: self.series_id,
176 start: self.start,
177 order: self.order,
178 ..Default::default()
179 };
180
181 if let Some(count) = self.count {
182 query.count = Some(count.validate()?.0);
183 }
184
185 if let Some(format) = self.format {
186 query.format = Some(format.validate()?.0);
187 }
188
189 Ok(query)
190 }
191}
192
193mod helper {
194 pub fn push_or_create<T>(source: Option<Vec<T>>, pushed: T) -> Option<Vec<T>> {
195 match source {
196 Some(mut xs) => {
197 xs.push(pushed);
198 Some(xs)
199 }
200 None => Some(vec![pushed]),
201 }
202 }
203}
204
205#[cfg(test)]
206mod test {
207 use crate::{
208 errors::{ConnpassCliError, ValidationError},
209 query::{types::OrderOption, Query},
210 };
211
212 use super::QueryBuilder;
213
214 #[test]
215 fn test_add_event_ids() {
216 let builder = QueryBuilder::begin().event_ids(vec![1, 2, 3]);
217 assert_eq!(
218 builder.build().unwrap(),
219 Query {
220 event_id: Some(vec![1, 2, 3]),
221 ..Default::default()
222 }
223 );
224 }
225
226 #[test]
227 fn test_add_event_id() {
228 let builder = QueryBuilder::begin().event_id(1);
229 assert_eq!(
230 builder.build().unwrap(),
231 Query {
232 event_id: Some(vec![1]),
233 ..Default::default()
234 }
235 );
236 }
237
238 #[test]
239 fn test_call_multiple_time_event_id() {
240 let builder = QueryBuilder::begin().event_id(1).event_id(2).event_id(3);
241 assert_eq!(
242 builder.build().unwrap(),
243 Query {
244 event_id: Some(vec![1, 2, 3]),
245 ..Default::default()
246 }
247 );
248 }
249
250 #[test]
251 fn test_add_keywords() {
252 let builder = QueryBuilder::begin().keywords(vec![
253 "Python".to_string(),
254 "Rust".to_string(),
255 "Swift".to_string(),
256 ]);
257 assert_eq!(
258 builder.build().unwrap(),
259 Query {
260 keyword: Some(vec![
261 "Python".to_string(),
262 "Rust".to_string(),
263 "Swift".to_string()
264 ]),
265 ..Default::default()
266 }
267 );
268 }
269
270 #[test]
271 fn test_add_keyword() {
272 let builder = QueryBuilder::begin().keyword("Rust");
273 assert_eq!(
274 builder.build().unwrap(),
275 Query {
276 keyword: Some(vec!["Rust".to_string()]),
277 ..Default::default()
278 }
279 );
280 }
281
282 #[test]
283 fn test_call_multiple_time_keyword() {
284 let builder = QueryBuilder::begin()
285 .keyword("Python".to_string())
286 .keyword("Rust".to_string())
287 .keyword("Swift".to_string());
288 assert_eq!(
289 builder.build().unwrap(),
290 Query {
291 keyword: Some(vec![
292 "Python".to_string(),
293 "Rust".to_string(),
294 "Swift".to_string()
295 ]),
296 ..Default::default()
297 }
298 );
299 }
300
301 #[test]
302 fn test_add_keywords_or() {
303 let builder = QueryBuilder::begin().keywords_or(vec![
304 "Python".to_string(),
305 "Rust".to_string(),
306 "Swift".to_string(),
307 ]);
308 assert_eq!(
309 builder.build().unwrap(),
310 Query {
311 keyword_or: Some(vec![
312 "Python".to_string(),
313 "Rust".to_string(),
314 "Swift".to_string()
315 ]),
316 ..Default::default()
317 }
318 );
319 }
320
321 #[test]
322 fn test_add_keyword_or() {
323 let builder = QueryBuilder::begin().keyword_or("Rust");
324 assert_eq!(
325 builder.build().unwrap(),
326 Query {
327 keyword_or: Some(vec!["Rust".to_string()]),
328 ..Default::default()
329 }
330 );
331 }
332
333 #[test]
334 fn test_call_multiple_time_keyword_or() {
335 let builder = QueryBuilder::begin()
336 .keyword_or("Python".to_string())
337 .keyword_or("Rust".to_string())
338 .keyword_or("Swift".to_string());
339 assert_eq!(
340 builder.build().unwrap(),
341 Query {
342 keyword_or: Some(vec![
343 "Python".to_string(),
344 "Rust".to_string(),
345 "Swift".to_string()
346 ]),
347 ..Default::default()
348 }
349 );
350 }
351
352 #[test]
353 fn test_add_yms() {
354 let builder = QueryBuilder::begin().yms(vec![202101, 202102, 202103]);
355 assert_eq!(
356 builder.build().unwrap(),
357 Query {
358 ym: Some(vec![202101, 202102, 202103]),
359 ..Default::default()
360 }
361 );
362 }
363
364 #[test]
365 fn test_add_ym() {
366 let builder = QueryBuilder::begin().ym(202101);
367 assert_eq!(
368 builder.build().unwrap(),
369 Query {
370 ym: Some(vec![202101]),
371 ..Default::default()
372 }
373 );
374 }
375
376 #[test]
377 fn test_call_multiple_time_ym() {
378 let builder = QueryBuilder::begin().ym(202101).ym(202102).ym(202103);
379 assert_eq!(
380 builder.build().unwrap(),
381 Query {
382 ym: Some(vec![202101, 202102, 202103]),
383 ..Default::default()
384 }
385 );
386 }
387
388 #[test]
389 fn test_add_ymds() {
390 let builder = QueryBuilder::begin().ymds(vec![20210101, 20210201, 20210301]);
391 assert_eq!(
392 builder.build().unwrap(),
393 Query {
394 ymd: Some(vec![20210101, 20210201, 20210301]),
395 ..Default::default()
396 }
397 );
398 }
399
400 #[test]
401 fn test_add_ymd() {
402 let builder = QueryBuilder::begin().ymd(20210101);
403 assert_eq!(
404 builder.build().unwrap(),
405 Query {
406 ymd: Some(vec![20210101]),
407 ..Default::default()
408 }
409 );
410 }
411
412 #[test]
413 fn test_call_multiple_time_ymd() {
414 let builder = QueryBuilder::begin()
415 .ymd(20210101)
416 .ymd(20210201)
417 .ymd(20210301);
418 assert_eq!(
419 builder.build().unwrap(),
420 Query {
421 ymd: Some(vec![20210101, 20210201, 20210301]),
422 ..Default::default()
423 }
424 );
425 }
426
427 #[test]
428 fn test_add_nicknames() {
429 let builder = QueryBuilder::begin().nicknames(vec![
430 "Harry".to_string(),
431 "Ron".to_string(),
432 "Hermione".to_string(),
433 ]);
434 assert_eq!(
435 builder.build().unwrap(),
436 Query {
437 nickname: Some(vec![
438 "Harry".to_string(),
439 "Ron".to_string(),
440 "Hermione".to_string()
441 ]),
442 ..Default::default()
443 }
444 );
445 }
446
447 #[test]
448 fn test_add_nickname() {
449 let builder = QueryBuilder::begin().nickname("Harry");
450 assert_eq!(
451 builder.build().unwrap(),
452 Query {
453 nickname: Some(vec!["Harry".to_string()]),
454 ..Default::default()
455 }
456 );
457 }
458
459 #[test]
460 fn test_call_multiple_time_nickname() {
461 let builder = QueryBuilder::begin()
462 .nickname("Harry")
463 .nickname("Ron")
464 .nickname("Hermione");
465 assert_eq!(
466 builder.build().unwrap(),
467 Query {
468 nickname: Some(vec![
469 "Harry".to_string(),
470 "Ron".to_string(),
471 "Hermione".to_string()
472 ]),
473 ..Default::default()
474 }
475 );
476 }
477
478 #[test]
479 fn test_add_owner_nicknames() {
480 let builder = QueryBuilder::begin().owner_nicknames(vec![
481 "Harry".to_string(),
482 "Ron".to_string(),
483 "Hermione".to_string(),
484 ]);
485 assert_eq!(
486 builder.build().unwrap(),
487 Query {
488 owner_nickname: Some(vec![
489 "Harry".to_string(),
490 "Ron".to_string(),
491 "Hermione".to_string()
492 ]),
493 ..Default::default()
494 }
495 );
496 }
497
498 #[test]
499 fn test_add_owner_nickname() {
500 let builder = QueryBuilder::begin().owner_nickname("Harry");
501 assert_eq!(
502 builder.build().unwrap(),
503 Query {
504 owner_nickname: Some(vec!["Harry".to_string()]),
505 ..Default::default()
506 }
507 );
508 }
509
510 #[test]
511 fn test_call_multiple_time_owner_nickname() {
512 let builder = QueryBuilder::begin()
513 .owner_nickname("Harry")
514 .owner_nickname("Ron")
515 .owner_nickname("Hermione");
516 assert_eq!(
517 builder.build().unwrap(),
518 Query {
519 owner_nickname: Some(vec![
520 "Harry".to_string(),
521 "Ron".to_string(),
522 "Hermione".to_string()
523 ]),
524 ..Default::default()
525 }
526 );
527 }
528
529 #[test]
530 fn test_add_series_ids() {
531 let builder = QueryBuilder::begin().series_ids(vec![1, 2, 3]);
532 assert_eq!(
533 builder.build().unwrap(),
534 Query {
535 series_id: Some(vec![1, 2, 3]),
536 ..Default::default()
537 }
538 );
539 }
540
541 #[test]
542 fn test_add_series_id() {
543 let builder = QueryBuilder::begin().series_id(1);
544 assert_eq!(
545 builder.build().unwrap(),
546 Query {
547 series_id: Some(vec![1]),
548 ..Default::default()
549 }
550 );
551 }
552
553 #[test]
554 fn test_call_multiple_time_series_id() {
555 let builder = QueryBuilder::begin().series_id(1).series_id(2).series_id(3);
556 assert_eq!(
557 builder.build().unwrap(),
558 Query {
559 series_id: Some(vec![1, 2, 3]),
560 ..Default::default()
561 }
562 );
563 }
564
565 #[test]
566 fn test_call_start() {
567 let builder = QueryBuilder::begin().start(1);
568 assert_eq!(
569 builder.build().unwrap(),
570 Query {
571 start: Some(1),
572 ..Default::default()
573 }
574 );
575 }
576
577 #[test]
578 fn test_call_order() {
579 let builder = QueryBuilder::begin().order(OrderOption::LastModifiedDate);
580 assert_eq!(
581 builder.build().unwrap(),
582 Query {
583 order: Some(OrderOption::LastModifiedDate),
584 ..Default::default()
585 }
586 );
587 }
588
589 #[test]
590 fn test_call_count() {
591 let builder = QueryBuilder::begin().count(50);
592 assert_eq!(
593 builder.build().unwrap(),
594 Query {
595 count: Some(50),
596 ..Default::default()
597 }
598 );
599 }
600
601 #[test]
602 fn test_validation_count_range() {
603 let builder = QueryBuilder::begin().count(0);
604 assert!(matches!(
605 builder.build(),
606 Err(ConnpassCliError::Validation(ValidationError::OutOfRange {
607 msg: _
608 }))
609 ));
610
611 let builder = QueryBuilder::begin().count(101);
612 assert!(matches!(
613 builder.build(),
614 Err(ConnpassCliError::Validation(ValidationError::OutOfRange {
615 msg: _
616 }))
617 ));
618 }
619
620 #[test]
621 fn test_call_format() {
622 let builder = QueryBuilder::begin().format("json");
623 assert_eq!(
624 builder.build().unwrap(),
625 Query {
626 format: Some("json".to_string()),
627 ..Default::default()
628 }
629 );
630 }
631
632 #[test]
633 fn test_validation_format() {
634 let builder = QueryBuilder::begin().format("yaml");
635 assert!(matches!(
636 builder.build(),
637 Err(ConnpassCliError::Validation(
638 ValidationError::InvalidToken { msg: _ }
639 ))
640 ));
641 }
642}