1use async_trait::async_trait;
2use facet::Facet;
3use facet_json::{DeserializeError, JsonError};
4use issuecraft_ql::{CloseReason, ExecutionEngine, ExecutionResult, IssueId, ProjectId, UserId};
5
6#[derive(thiserror::Error, Debug)]
7pub enum ClientError {
8 #[error("Not implemented")]
9 NotImplemented,
10 #[error("This action is not supported by the chosen backend")]
11 NotSupported,
12 #[error("IQL error: {0}")]
13 IqlError(#[from] issuecraft_ql::IqlError),
14 #[error("Deserialization error: {0}")]
15 DeserializationError(#[from] DeserializeError<JsonError>),
16 #[error("Client specific: {0}")]
17 ClientSpecific(String),
18}
19
20#[derive(Debug, Clone, Facet)]
21pub struct UserInfo {
22 pub name: String,
23 pub display: Option<String>,
24 pub email: String,
25}
26
27#[derive(Debug, Clone, Facet)]
28pub struct ProjectInfo {
29 pub description: Option<String>,
30 pub owner: UserId,
31 pub display: Option<String>,
32}
33
34#[derive(Debug, Clone, Facet)]
35#[repr(C)]
36pub enum IssueStatus {
37 Open,
38 Assigned,
39 Blocked,
40 Closed { reason: CloseReason },
41}
42
43#[derive(Debug, Clone, Facet)]
44#[repr(C)]
45pub enum Priority {
46 Low,
47 Medium,
48 High,
49 Critical,
50}
51
52#[derive(Debug, Clone, Facet)]
53pub struct IssueInfo {
54 pub title: String,
55 pub description: Option<String>,
56 pub status: IssueStatus,
57 pub project: ProjectId,
58 pub priority: Option<Priority>,
59 pub assignee: Option<UserId>,
60}
61
62impl IssueInfo {
63 pub fn is_closed(&self) -> bool {
64 matches!(self.status, IssueStatus::Closed { .. })
65 }
66}
67
68#[derive(Debug, Clone, Facet)]
69pub struct CommentInfo {
70 pub issue: IssueId,
71 pub created_at: time::UtcDateTime,
72 pub content: String,
73 pub author: UserId,
74}
75
76#[derive(Debug, Clone)]
77pub enum AuthenticationInfo {
78 Password { password: String },
79 Token { token: String },
80 Certificate { path: Vec<u8> },
81}
82
83#[derive(Debug, Clone)]
84pub struct LoginInfo {
85 pub user: String,
86 pub auth: AuthenticationInfo,
87}
88
89#[async_trait]
90pub trait Client {
91 async fn login(&mut self, _login: LoginInfo) -> Result<(), ClientError> {
92 Err(ClientError::NotSupported)
93 }
94 async fn logout(&mut self) -> Result<(), ClientError> {
95 Err(ClientError::NotSupported)
96 }
97 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError>;
98}
99
100#[async_trait]
101impl<E: ExecutionEngine + Send> Client for E {
102 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError> {
103 let result = self.execute(query).await?;
104 Ok(result)
105 }
106}
107
108pub trait Backend {
109 fn init(&mut self) {}
110}