1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
extern crate serde_urlencoded;

pub mod comments;
pub mod events;
pub mod issues;
pub mod labels;
pub mod users;

use serde::Serialize;

#[derive(Serialize, Debug)]
pub struct Params {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub per_page: Option<u8>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<octocrab::params::State>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub since: Option<chrono::DateTime<chrono::Utc>>,
}

impl Params {
    pub fn to_query(&self) -> String {
        serde_urlencoded::to_string(self).unwrap()
    }
}

impl Default for Params {
    fn default() -> Self {
        Self {
            per_page: 100u8.into(),
            state: None,
            since: None,
        }
    }
}

pub trait RepositryAware {
    fn set_repository(&mut self, name: String);
}

pub trait UrlConstructor {
    fn reponame(&self) -> String;

    fn entrypoint(&self) -> Option<reqwest::Url>;
}

pub trait LoopWriter: UrlConstructor {
    type Model;
    type Record: serde::Serialize + RepositryAware + From<Self::Model>;

    fn write_and_continue<T: std::io::Write>(
        &self,
        mut page: octocrab::Page<Self::Model>,
        wtr: &mut csv::Writer<T>,
    ) -> Option<reqwest::Url> {
        let labels: Vec<Self::Model> = page.take_items();
        for label in labels.into_iter() {
            let mut label: Self::Record = label.into();
            label.set_repository(self.reponame());
            wtr.serialize(&label).expect("Serialize failed");
        }
        page.next
    }
}