g1t/services/work/src/rows.rs

241 lines7,068 bytesCodeBlame
1//! Rows as they come out of D1, and their conversion to contract types.
2
3use g1t_contracts::User;
4use g1t_contracts::repos::RepoPath;
5use g1t_contracts::work::{
6 CheckStatus, Comment, CommentKind, Issue, IssueReason, Pull, PullStatus, Runtime, SessionEntry,
7 SessionEntryKind, State, Verdict,
8};
9use serde::Deserialize;
10
11pub(crate) fn user(id: String, username: String) -> User {
12 User {
13 id,
14 username,
15 ..User::default()
16 }
17}
18
19#[derive(Deserialize)]
20pub struct IssueRow {
21 pub id: String,
22 pub repo_id: String,
23 pub number: u32,
24 pub title: String,
25 pub body: String,
26 /// JSON array of label names.
27 pub labels: String,
28 /// JSON array of commands.
29 pub checks: String,
30 pub state: State,
31 pub reason: Option<IssueReason>,
32 pub resolved_by: Option<u32>,
33 pub author_id: String,
34 pub author_name: String,
35 pub created_at: String,
36 pub updated_at: String,
37 pub closed_at: Option<String>,
38 pub pull_count: u32,
39 pub comment_count: u32,
40 /// JSON array of usernames.
41 pub assignees: String,
42 /// JSON array of issue numbers.
43 pub blocked_by: String,
44 /// JSON of who queued it for a g1t agent, if anyone has.
45 pub queued_by: Option<String>,
46 pub agent: Option<String>,
47}
48
49impl From<IssueRow> for Issue {
50 fn from(row: IssueRow) -> Self {
51 Issue {
52 id: row.id,
53 repo_id: row.repo_id,
54 number: row.number,
55 title: row.title,
56 body: row.body,
57 labels: serde_json::from_str(&row.labels).unwrap_or_default(),
58 checks: serde_json::from_str(&row.checks).unwrap_or_default(),
59 state: row.state,
60 reason: row.reason,
61 resolved_by: row.resolved_by,
62 author: user(row.author_id, row.author_name),
63 created_at: row.created_at,
64 updated_at: row.updated_at,
65 closed_at: row.closed_at,
66 pull_count: row.pull_count,
67 comment_count: row.comment_count,
68 assignees: serde_json::from_str(&row.assignees).unwrap_or_default(),
69 blocked_by: serde_json::from_str(&row.blocked_by).unwrap_or_default(),
70 queued: row.queued_by.is_some(),
71 agent: row.agent,
72 }
73 }
74}
75
76/// The remembered assessment of a pull request, read beside its row.
77#[derive(Deserialize)]
78pub struct Snapshot {
79 pub stage: Option<g1t_contracts::work::Stage>,
80 pub stage_detail: Option<String>,
81 #[serde(default)]
82 pub revisions: u32,
83 /// Whether g1t is seeing it through at all.
84 #[serde(default)]
85 pub managed: u32,
86}
87
88/// A pull request's columns, with its confidence (confidence.rs) beside
89/// them: what every read of a [`PullRow`] selects.
90pub const PULL_COLUMNS: &str =
91 "pulls.*, (SELECT detail FROM pull_confidence WHERE pull_confidence.pull_id = pulls.id) AS confidence";
92
93#[derive(Deserialize)]
94pub struct PullRow {
95 pub id: String,
96 pub repo_id: String,
97 pub number: u32,
98 pub issue_number: Option<u32>,
99 pub title: String,
100 pub body: Option<String>,
101 pub agent: String,
102 pub runtime: Runtime,
103 pub status: PullStatus,
104 pub fork_repo_id: Option<String>,
105 pub fork_namespace: Option<String>,
106 pub fork_name: Option<String>,
107 pub source_branch: Option<String>,
108 pub head_commit: Option<String>,
109 pub merge_base: Option<String>,
110 pub merged_by: Option<String>,
111 pub merged_at: Option<String>,
112 pub superseded_by: Option<u32>,
113 pub check_status: Option<CheckStatus>,
114 /// JSON array of changed files; `None` until first worked out.
115 pub files: Option<String>,
116 /// JSON arrays of usernames.
117 pub assignees: String,
118 pub reviewers: String,
119 pub author_id: String,
120 pub author_name: String,
121 pub created_at: String,
122 pub updated_at: String,
123 /// JSON of its confidence, once worked out.
124 #[serde(default)]
125 pub confidence: Option<String>,
126}
127
128impl From<PullRow> for Pull {
129 fn from(row: PullRow) -> Self {
130 Pull {
131 id: row.id,
132 repo_id: row.repo_id,
133 number: row.number,
134 issue: row.issue_number,
135 title: row.title,
136 body: row.body,
137 agent: row.agent,
138 runtime: row.runtime,
139 status: row.status,
140 fork: row
141 .fork_namespace
142 .zip(row.fork_name)
143 .map(|(namespace, name)| RepoPath { namespace, name }),
144 fork_repo_id: row.fork_repo_id,
145 branch: row.source_branch,
146 head_commit: row.head_commit,
147 merge_base: row.merge_base,
148 merged_by: row.merged_by,
149 merged_at: row.merged_at,
150 superseded_by: row.superseded_by,
151 check_status: row.check_status,
152 files: row
153 .files
154 .as_deref()
155 .and_then(|files| serde_json::from_str(files).ok())
156 .unwrap_or_default(),
157 assignees: serde_json::from_str(&row.assignees).unwrap_or_default(),
158 reviewers: serde_json::from_str(&row.reviewers).unwrap_or_default(),
159 author: user(row.author_id, row.author_name),
160 created_at: row.created_at,
161 updated_at: row.updated_at,
162 confidence: row
163 .confidence
164 .as_deref()
165 .and_then(|detail| serde_json::from_str(detail).ok()),
166 }
167 }
168}
169
170#[derive(Deserialize)]
171pub struct CommentRow {
172 pub id: String,
173 pub kind: CommentKind,
174 pub author_id: String,
175 pub author_name: String,
176 pub body: String,
177 pub path: Option<String>,
178 pub line: Option<u32>,
179 pub verdict: Option<Verdict>,
180 pub created_at: String,
181}
182
183impl From<CommentRow> for Comment {
184 fn from(row: CommentRow) -> Self {
185 Comment {
186 id: row.id,
187 kind: row.kind,
188 author: user(row.author_id, row.author_name),
189 body: row.body,
190 path: row.path,
191 line: row.line,
192 verdict: row.verdict,
193 created_at: row.created_at,
194 }
195 }
196}
197
198#[derive(Deserialize)]
199pub struct SessionRow {
200 pub seq: u32,
201 pub kind: SessionEntryKind,
202 pub text: String,
203 pub tool: Option<String>,
204 pub commit: Option<String>,
205 pub at: String,
206}
207
208impl From<SessionRow> for SessionEntry {
209 fn from(row: SessionRow) -> Self {
210 SessionEntry {
211 seq: row.seq,
212 kind: row.kind,
213 text: row.text,
214 tool: row.tool,
215 commit: row.commit,
216 at: row.at,
217 }
218 }
219}
220
221/// A pull request whose head a push moved.
222#[derive(Deserialize)]
223pub struct MovedRow {
224 pub id: String,
225 pub repo_id: String,
226 pub number: u32,
227 pub issue_number: Option<u32>,
228 pub status: PullStatus,
229}
230
231/// A single number selected as `n`.
232#[derive(Deserialize)]
233pub struct NumberRow {
234 pub n: u32,
235}
236
237/// A single string selected as `value`.
238#[derive(Deserialize)]
239pub struct ValueRow {
240 pub value: String,
241}