Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

50 linesCodeBlameRaw
1//! A workspace's sequence of numbers (`work_counters`), which its work
2//! items and its repositories' new pull requests share.
3
4use worker::Result;
5use worker::wasm_bindgen::JsValue;
6
7use crate::Work;
8use crate::rows::{NumberRow, ValueRow};
9
10/// The next number of workspace `?1`'s sequence, taken in one statement so
11/// two openings never get the same one. A pull request of repository `?2`
12/// never takes a number one of that repository's has, a pull request's or
13/// an old issue's (a repository moved in from another workspace, or
14/// restored, brings its own), and a workspace's first number comes after
15/// every number its repositories used before work items moved to the
16/// workspace. While the job that moves them runs, which repositories are
17/// the workspace's is not known yet: a number then comes after every
18/// number any repository used, so it is above the floor the job finds.
19pub(crate) const NEXT_NUMBER: &str = "INSERT INTO work_counters (workspace, last)
20 SELECT ?1, MAX(COALESCE(MAX(c.last), 0), COALESCE((SELECT MAX(number) FROM pulls WHERE repo_id = ?2), 0),
21 COALESCE((SELECT MAX(legacy_number) FROM work_item_repos WHERE repo_id = ?2), 0)) + 1
22 FROM counters c
23 WHERE c.repo_id = ?2 OR c.repo_id IN (SELECT repo_id FROM repo_workspaces WHERE workspace = ?1)
24 OR EXISTS (SELECT 1 FROM work_jobs WHERE name = 'work_items' AND done_at IS NULL)
25 ON CONFLICT (workspace) DO UPDATE SET last = MAX(work_counters.last + 1, excluded.last)
26 RETURNING last AS n";
27
28impl Work {
29 /// The next number of `workspace`'s sequence, for a work item, or for
30 /// a pull request of `repo_id` ([`NEXT_NUMBER`]).
31 pub(super) async fn next_number(&self, workspace: &str, repo_id: Option<&str>) -> Result<u32> {
32 let row = self
33 .db
34 .prepare(NEXT_NUMBER)
35 .bind(&[workspace.to_lowercase().into(), repo_id.map_or(JsValue::NULL, JsValue::from)])?
36 .first::<NumberRow>(None)
37 .await?;
38 row.map(|row| row.n).ok_or_else(|| worker::Error::RustError("no number was assigned".into()))
39 }
40
41 /// Whether the job that moved issues into work items is done.
42 pub(super) async fn items_moved(&self) -> Result<bool> {
43 Ok(self
44 .db
45 .prepare("SELECT done_at AS value FROM work_jobs WHERE name = 'work_items' AND done_at IS NOT NULL")
46 .first::<ValueRow>(None)
47 .await?
48 .is_some())
49 }
50}