Files
novem/src/api/issues.rs

152 lines
4.2 KiB
Rust

use std::ops::Deref;
use graphql_client::{GraphQLQuery, Response};
use reqwest::Method;
use serde::Deserialize;
use crate::{
api::{
self,
issues::pull_request_query::{PullRequestQuerySearchEdgesNode, PullRequestState},
},
query,
};
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(transparent)]
#[repr(transparent)]
pub(crate) struct Id(String);
impl Deref for Id {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Deserialize)]
pub(crate) struct PullRequestPaginatedResponse {
pub(crate) items: Vec<PullRequest>,
pub(crate) start_cursor: Option<String>,
pub(crate) end_cursor: Option<String>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct PullRequest {
pub(crate) title: String,
pub(crate) state: IssueState,
pub(crate) is_draft: bool,
pub(crate) repo_slug: String,
}
#[derive(Debug, Clone, Copy, Deserialize)]
pub(crate) enum IssueState {
Open,
Closed,
Merged,
Unknown,
}
impl std::fmt::Display for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl From<PullRequestState> for IssueState {
fn from(state: PullRequestState) -> Self {
match state {
PullRequestState::OPEN => Self::Open,
PullRequestState::CLOSED => Self::Closed,
PullRequestState::MERGED => Self::Merged,
_ => Self::Unknown,
}
}
}
#[derive(graphql_client::GraphQLQuery)]
#[graphql(
schema_path = "src/api/graphql/schema.json",
query_path = "src/api/graphql/list_pull_requests.graphql"
)]
struct PullRequestQuery;
#[derive(Clone)]
pub(crate) struct ListPullRequests {
pub filter: Option<&'static str>,
pub page: u32,
}
impl query::QueryFn for ListPullRequests {
type Data = PullRequestPaginatedResponse;
type Error = api::Error;
type Context = api::QueryContext;
fn key(&self) -> query::Key {
format!(
"issues/list?pulls=true&page={}&filter={}",
self.page,
self.filter.unwrap_or_default()
)
.into()
}
async fn run(&self, c: &Self::Context) -> Result<Self::Data, Self::Error> {
#[cfg(debug_assertions)]
if c.should_use_fixtures {
return super::mock::list_pull_requests(self.filter, self.page);
}
let query_string = match self.filter {
Some(filter) => format!("is:pr archived:false sort:updated-desc {}", filter),
None => "is:pr archived:false sort:updated-desc".into(),
};
let gql = PullRequestQuery::build_query(pull_request_query::Variables {
query: query_string,
});
let res = c
.github_request(Method::POST, "/graphql")?
.json(&gql)
.send()
.await?;
let data = api::parse_graphql_response::<pull_request_query::ResponseData>(res)
.await?
.data
.unwrap();
Ok(PullRequestPaginatedResponse {
items: data
.search
.edges
.map(|it| {
it.into_iter()
.flatten()
.filter_map(|edge| {
edge.node.and_then(|n| match n {
PullRequestQuerySearchEdgesNode::PullRequest(p) => {
Some(PullRequest {
title: p.title,
state: p.state.into(),
is_draft: p.is_draft,
repo_slug: format!(
"{}/{}",
p.repository.owner.login, p.repository.name
),
})
}
_ => None,
})
})
.collect::<Vec<_>>()
})
.unwrap_or_default(),
start_cursor: data.search.page_info.start_cursor,
end_cursor: data.search.page_info.end_cursor,
})
}
}