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 #[facet( skip_serializing_if = Option::is_none)]
24 pub display: Option<String>,
25 pub email: String,
26}
27
28#[derive(Debug, Clone, Facet)]
29pub struct ProjectInfo {
30 #[facet(skip_serializing_if = Option::is_none)]
31 pub description: Option<String>,
32 pub owner: UserId,
33 #[facet(skip_serializing_if = Option::is_none)]
34 pub display: Option<String>,
35}
36
37#[derive(Debug, Clone, Facet)]
38#[repr(C)]
39pub enum IssueStatus {
40 Open,
41 Assigned,
42 Blocked,
43 Closed { reason: CloseReason },
44}
45
46#[derive(Debug, Clone, Facet)]
47#[repr(C)]
48pub enum Priority {
49 Low,
50 Medium,
51 High,
52 Critical,
53}
54
55#[derive(Debug, Clone, Facet)]
56pub struct IssueInfo {
57 pub title: String,
58 #[facet(skip_serializing_if = Option::is_none)]
59 pub description: Option<String>,
60 pub status: IssueStatus,
61 pub project: ProjectId,
62 #[facet(skip_serializing_if = Option::is_none)]
63 pub priority: Option<Priority>,
64 #[facet(skip_serializing_if = Option::is_none)]
65 pub assignee: Option<UserId>,
66}
67
68impl IssueInfo {
69 pub fn is_closed(&self) -> bool {
70 matches!(self.status, IssueStatus::Closed { .. })
71 }
72}
73
74#[derive(Debug, Clone, Facet)]
75pub struct CommentInfo {
76 pub issue: IssueId,
77 pub created_at: time::UtcDateTime,
78 pub content: String,
79 pub author: UserId,
80}
81
82#[derive(Debug, Clone)]
83pub enum AuthenticationInfo {
84 Password { password: String },
85 Token { token: String },
86 Certificate { path: Vec<u8> },
87}
88
89#[derive(Debug, Clone)]
90pub struct LoginInfo {
91 pub user: String,
92 pub auth: AuthenticationInfo,
93}
94
95#[async_trait]
96pub trait Client {
97 async fn login(&mut self, _login: LoginInfo) -> Result<(), ClientError> {
98 Err(ClientError::NotSupported)
99 }
100 async fn logout(&mut self) -> Result<(), ClientError> {
101 Err(ClientError::NotSupported)
102 }
103 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError>;
104}
105
106#[async_trait]
107impl<E: ExecutionEngine + Send> Client for E {
108 async fn query(&mut self, query: &str) -> Result<ExecutionResult, ClientError> {
109 let result = self.execute(query).await?;
110 Ok(result)
111 }
112}
113
114pub trait Backend {
115 fn init(&mut self) {}
116}