1use async_trait::async_trait;
2use facet::Facet;
3use facet_json::{DeserializeError, JsonError};
4use issuecraft_ql::{CloseReason, ExecutionEngine, ExecutionResult, 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 created_at: time::UtcDateTime,
71 pub content: String,
72 pub author: UserId,
73}
74
75#[derive(Debug, Clone)]
76pub enum AuthenticationInfo {
77 Password { password: String },
78 Token { token: String },
79 Certificate { path: Vec<u8> },
80}
81
82#[derive(Debug, Clone)]
83pub struct LoginInfo {
84 pub user: String,
85 pub auth: AuthenticationInfo,
86}
87
88#[async_trait]
89pub trait Client {
90 async fn login(&mut self, _login: LoginInfo) -> Result<(), ClientError> {
91 Err(ClientError::NotSupported)
92 }
93 async fn logout(&mut self) -> Result<(), ClientError> {
94 Err(ClientError::NotSupported)
95 }
96 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError>;
97}
98
99#[async_trait]
100impl<E: ExecutionEngine + Send> Client for E {
101 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError> {
102 let result = self.execute(query).await?;
103 Ok(result)
104 }
105}
106
107pub trait Backend {
108 fn init(&mut self) {}
109}