Skip to content
Clone

feat(models): extend pull request schema for the pull request api

- pull_request: head_repo_id/head_label for cross-repo heads, is_draft,
  merge_method, squash_commit_sha, auto_merge; issue_id becomes nullable so a
  pull request no longer has to borrow the issue numbering pipeline
- pull_request_review: Pending and Dismissed review states
- pull_request_comment: nullable path/commit_sha for general discussion
  comments, parent_comment_id threads, side/original_line, resolved_at/by
- new tables pull_request_reviewer, pull_request_label, pull_request_assignee
- schema_extras.sql gains the list/lookup indexes plus inline-comment shape,
  side and merged-consistency checks; schema_pre_sync.sql carries the
  NOT NULL relaxations the entity sync cannot express
ZhenYi committed
parent eca6c76 commit d935855 Browse files

9 files changed

+275 −5

File tree 9
Modified lib/models/src/pull_request/mod.rs View lib/models/src/pull_request/mod.rs
@@ -1,4 +1,7 @@
1pub mod pull_request_assignee;
12pub mod pull_request_comment;
23pub mod pull_request_event_line;
4pub mod pull_request_label;
35pub mod pull_request_review;
6pub mod pull_request_reviewer;
47pub mod pull_requests;
Added lib/models/src/pull_request/pull_request_assignee.rs View lib/models/src/pull_request/pull_request_assignee.rs
@@ -0,0 +1,22 @@
1use sea_orm::entity::prelude::*;
2use time::OffsetDateTime;
3use uuid::Uuid;
4
5#[sea_orm::model]
6#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
7#[sea_orm(table_name = "pull_request_assignee")]
8pub struct Model {
9 #[sea_orm(primary_key, auto_increment = false)]
10 pub id: Uuid,
11 #[sea_orm(unique_key = "pull_assignee")]
12 pub pull_request_id: Uuid,
13 #[sea_orm(unique_key = "pull_assignee")]
14 pub user_id: Uuid,
15 pub created_at: OffsetDateTime,
16 #[sea_orm(belongs_to, from = "pull_request_id", to = "id")]
17 pub pull_request: BelongsTo<super::pull_requests::Entity>,
18 #[sea_orm(belongs_to, from = "user_id", to = "uid")]
19 pub user: BelongsTo<super::super::users::user::Entity>,
20}
21
22impl ActiveModelBehavior for ActiveModel {}
Modified lib/models/src/pull_request/pull_request_comment.rs View lib/models/src/pull_request/pull_request_comment.rs
@@ -11,10 +11,16 @@
1111 pub pull_request_id: Uuid,
1212 pub user_id: Uuid,
1313 pub review_id: Option<Uuid>,
14 pub commit_sha: String,
15 pub path: String,
14 pub parent_comment_id: Option<Uuid>,
15 pub commit_sha: Option<String>,
16 pub original_commit_sha: Option<String>,
17 pub path: Option<String>,
18 pub side: Option<String>,
1619 pub line: Option<i32>,
20 pub original_line: Option<i32>,
1721 pub body: String,
22 pub resolved_at: Option<OffsetDateTime>,
23 pub resolved_by: Option<Uuid>,
1824 pub created_at: OffsetDateTime,
1925 pub updated_at: Option<OffsetDateTime>,
2026 #[sea_orm(belongs_to, from = "pull_request_id", to = "id")]
@@ -23,6 +29,13 @@
2329 pub user: BelongsTo<super::super::users::user::Entity>,
2430 #[sea_orm(belongs_to, from = "review_id", to = "id")]
2531 pub review: BelongsTo<Option<super::pull_request_review::Entity>>,
32 #[sea_orm(
33 belongs_to,
34 relation_enum = "Parent",
35 from = "parent_comment_id",
36 to = "id"
37 )]
38 pub parent: BelongsTo<Option<super::pull_request_comment::Entity>>,
2639}
2740
2841impl ActiveModelBehavior for ActiveModel {}
Added lib/models/src/pull_request/pull_request_label.rs View lib/models/src/pull_request/pull_request_label.rs
@@ -0,0 +1,22 @@
1use sea_orm::entity::prelude::*;
2use time::OffsetDateTime;
3use uuid::Uuid;
4
5#[sea_orm::model]
6#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
7#[sea_orm(table_name = "pull_request_label")]
8pub struct Model {
9 #[sea_orm(primary_key, auto_increment = false)]
10 pub id: Uuid,
11 #[sea_orm(unique_key = "pull_label")]
12 pub pull_request_id: Uuid,
13 #[sea_orm(unique_key = "pull_label")]
14 pub label_id: Uuid,
15 pub created_at: OffsetDateTime,
16 #[sea_orm(belongs_to, from = "pull_request_id", to = "id")]
17 pub pull_request: BelongsTo<super::pull_requests::Entity>,
18 #[sea_orm(belongs_to, from = "label_id", to = "id")]
19 pub label: BelongsTo<super::super::issue::issue_label::Entity>,
20}
21
22impl ActiveModelBehavior for ActiveModel {}
Modified lib/models/src/pull_request/pull_request_review.rs View lib/models/src/pull_request/pull_request_review.rs
@@ -4,8 +4,19 @@
44use uuid::Uuid;
55
66#[derive(
7 Debug, Clone, Copy, PartialEq, Eq, Default, EnumIter, DeriveActiveEnum, Serialize, Deserialize,
7 Debug,
8 Clone,
9 Copy,
10 PartialEq,
11 Eq,
12 Default,
13 EnumIter,
14 DeriveActiveEnum,
15 Serialize,
16 Deserialize,
17 utoipa::ToSchema,
818)]
19#[serde(rename_all = "snake_case")]
920#[sea_orm(rs_type = "i16", db_type = "SmallInteger")]
1021pub enum ReviewState {
1122 #[default]
@@ -15,6 +26,10 @@
1526 ChangesRequested,
1627 #[sea_orm(num_value = 2)]
1728 Commented,
29 #[sea_orm(num_value = 3)]
30 Pending,
31 #[sea_orm(num_value = 4)]
32 Dismissed,
1833}
1934
2035#[sea_orm::model]
Added lib/models/src/pull_request/pull_request_reviewer.rs View lib/models/src/pull_request/pull_request_reviewer.rs
@@ -0,0 +1,66 @@
1use sea_orm::entity::prelude::*;
2use serde::{Deserialize, Serialize};
3use time::OffsetDateTime;
4use uuid::Uuid;
5
6#[derive(
7 Debug,
8 Clone,
9 Copy,
10 PartialEq,
11 Eq,
12 Default,
13 EnumIter,
14 DeriveActiveEnum,
15 Serialize,
16 Deserialize,
17 utoipa::ToSchema,
18)]
19#[serde(rename_all = "snake_case")]
20#[sea_orm(rs_type = "i16", db_type = "SmallInteger")]
21pub enum ReviewerState {
22 #[default]
23 #[sea_orm(num_value = 0)]
24 Requested,
25 #[sea_orm(num_value = 1)]
26 Approved,
27 #[sea_orm(num_value = 2)]
28 ChangesRequested,
29 #[sea_orm(num_value = 3)]
30 Commented,
31 #[sea_orm(num_value = 4)]
32 Dismissed,
33}
34
35#[sea_orm::model]
36#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
37#[sea_orm(table_name = "pull_request_reviewer")]
38pub struct Model {
39 #[sea_orm(primary_key, auto_increment = false)]
40 pub id: Uuid,
41 #[sea_orm(unique_key = "pull_reviewer")]
42 pub pull_request_id: Uuid,
43 #[sea_orm(unique_key = "pull_reviewer")]
44 pub user_id: Uuid,
45 #[sea_orm(default_value = "0")]
46 pub state: ReviewerState,
47 #[sea_orm(default_value = "true")]
48 pub required: bool,
49 pub review_id: Option<Uuid>,
50 pub requested_by_id: Uuid,
51 pub created_at: OffsetDateTime,
52 pub updated_at: Option<OffsetDateTime>,
53 #[sea_orm(belongs_to, from = "pull_request_id", to = "id")]
54 pub pull_request: BelongsTo<super::pull_requests::Entity>,
55 #[sea_orm(belongs_to, relation_enum = "Reviewer", from = "user_id", to = "uid")]
56 pub user: BelongsTo<super::super::users::user::Entity>,
57 #[sea_orm(
58 belongs_to,
59 relation_enum = "RequestedBy",
60 from = "requested_by_id",
61 to = "uid"
62 )]
63 pub requested_by: BelongsTo<super::super::users::user::Entity>,
64}
65
66impl ActiveModelBehavior for ActiveModel {}
Modified lib/models/src/pull_request/pull_requests.rs View lib/models/src/pull_request/pull_requests.rs
@@ -1,7 +1,33 @@
11use sea_orm::entity::prelude::*;
2use serde::{Deserialize, Serialize};
23use time::OffsetDateTime;
34use uuid::Uuid;
45
6#[derive(
7 Debug,
8 Clone,
9 Copy,
10 PartialEq,
11 Eq,
12 Default,
13 EnumIter,
14 DeriveActiveEnum,
15 Serialize,
16 Deserialize,
17 utoipa::ToSchema,
18)]
19#[serde(rename_all = "snake_case")]
20#[sea_orm(rs_type = "i16", db_type = "SmallInteger")]
21pub enum MergeMethod {
22 #[default]
23 #[sea_orm(num_value = 0)]
24 Merge,
25 #[sea_orm(num_value = 1)]
26 Squash,
27 #[sea_orm(num_value = 2)]
28 Rebase,
29}
30
531#[sea_orm::model]
632#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
733#[sea_orm(table_name = "pull_request")]
@@ -10,7 +36,7 @@
1036 pub id: Uuid,
1137 #[sea_orm(unique_key = "repo_number")]
1238 pub repo_id: Uuid,
13 pub issue_id: Uuid,
39 pub issue_id: Option<Uuid>,
1440 #[sea_orm(unique_key = "repo_number")]
1541 pub autoincrement_id: i32,
1642 pub author_id: Uuid,
@@ -18,10 +44,19 @@
1844 pub body: String,
1945 pub head_branch: String,
2046 pub head_sha: String,
47 pub head_repo_id: Option<Uuid>,
48 pub head_label: Option<String>,
2149 pub base_branch: String,
2250 pub base_sha: String,
51 #[sea_orm(default_value = "false")]
52 pub is_draft: bool,
53 #[sea_orm(default_value = "0")]
54 pub merge_method: MergeMethod,
2355 pub has_merged: bool,
2456 pub merged_commit_sha: Option<String>,
57 pub squash_commit_sha: Option<String>,
58 #[sea_orm(default_value = "false")]
59 pub auto_merge: bool,
2560 pub additions: i32,
2661 pub deletions: i32,
2762 pub files_changed: i32,
@@ -33,8 +68,15 @@
3368 pub closed_at: Option<OffsetDateTime>,
3469 #[sea_orm(belongs_to, from = "repo_id", to = "id")]
3570 pub repo: BelongsTo<super::super::repo::repos::Entity>,
71 #[sea_orm(
72 belongs_to,
73 relation_enum = "HeadRepo",
74 from = "head_repo_id",
75 to = "id"
76 )]
77 pub head_repo: BelongsTo<Option<super::super::repo::repos::Entity>>,
3678 #[sea_orm(belongs_to, from = "issue_id", to = "id")]
37 pub issue: BelongsTo<super::super::issue::issue_item::Entity>,
79 pub issue: BelongsTo<Option<super::super::issue::issue_item::Entity>>,
3880 #[sea_orm(belongs_to, relation_enum = "Author", from = "author_id", to = "uid")]
3981 pub author: BelongsTo<super::super::users::user::Entity>,
4082 #[sea_orm(belongs_to, relation_enum = "Merger", from = "merger_id", to = "uid")]
Modified lib/models/schema_extras.sql View lib/models/schema_extras.sql
@@ -194,3 +194,64 @@
194194
195195UPDATE user_access_key SET scope = 'write' WHERE scope IN ('repo', 'all');
196196UPDATE user_access_key SET scope = 'read' WHERE scope NOT IN ('read', 'write');
197
198-- ---------------------------------------------------------------------------
199-- Pull Request domain (lib/pulls): list/filter lookups and inline-comment
200-- shape guards that entity attributes cannot express.
201-- ---------------------------------------------------------------------------
202CREATE INDEX IF NOT EXISTS idx_pull_request_repo_state
203 ON pull_request (repo_id, has_merged, closed_at);
204CREATE INDEX IF NOT EXISTS idx_pull_request_repo_author
205 ON pull_request (repo_id, author_id);
206CREATE INDEX IF NOT EXISTS idx_pull_request_head
207 ON pull_request (head_repo_id, head_branch);
208CREATE INDEX IF NOT EXISTS idx_pull_request_author_created
209 ON pull_request (author_id, created_at DESC);
210CREATE INDEX IF NOT EXISTS idx_pull_request_issue
211 ON pull_request (issue_id);
212CREATE INDEX IF NOT EXISTS idx_pull_request_review_pr
213 ON pull_request_review (pull_request_id, created_at);
214CREATE INDEX IF NOT EXISTS idx_pull_request_review_user
215 ON pull_request_review (user_id, pull_request_id);
216CREATE INDEX IF NOT EXISTS idx_pull_request_comment_pr
217 ON pull_request_comment (pull_request_id, created_at);
218CREATE INDEX IF NOT EXISTS idx_pull_request_comment_file
219 ON pull_request_comment (pull_request_id, path, line);
220CREATE INDEX IF NOT EXISTS idx_pull_request_comment_parent
221 ON pull_request_comment (parent_comment_id);
222CREATE INDEX IF NOT EXISTS idx_pull_request_reviewer_user
223 ON pull_request_reviewer (user_id, state);
224CREATE INDEX IF NOT EXISTS idx_pull_request_reviewer_pr
225 ON pull_request_reviewer (pull_request_id, state);
226CREATE INDEX IF NOT EXISTS idx_pull_request_assignee_user
227 ON pull_request_assignee (user_id);
228CREATE INDEX IF NOT EXISTS idx_pull_request_event_pr
229 ON pull_request_event_line (pull_request_id, created_at);
230CREATE INDEX IF NOT EXISTS idx_pull_request_label_pr
231 ON pull_request_label (pull_request_id);
232CREATE INDEX IF NOT EXISTS idx_issue_relation_pull_pr
233 ON issue_relation_pull (pull_request_id);
234
235DO $$ BEGIN
236 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'pull_request_comment_inline_shape') THEN
237 ALTER TABLE pull_request_comment
238 ADD CONSTRAINT pull_request_comment_inline_shape
239 CHECK ((path IS NULL) = (commit_sha IS NULL));
240 END IF;
241END $$;
242
243DO $$ BEGIN
244 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'pull_request_comment_side') THEN
245 ALTER TABLE pull_request_comment
246 ADD CONSTRAINT pull_request_comment_side
247 CHECK (side IS NULL OR side IN ('left', 'right'));
248 END IF;
249END $$;
250
251DO $$ BEGIN
252 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'pull_request_merged_consistent') THEN
253 ALTER TABLE pull_request
254 ADD CONSTRAINT pull_request_merged_consistent
255 CHECK ((has_merged = false) OR merged_at IS NOT NULL);
256 END IF;
257END $$;
Modified lib/models/schema_pre_sync.sql View lib/models/schema_pre_sync.sql
@@ -43,3 +43,29 @@
4343 ALTER TABLE chat_message_reminder ADD COLUMN IF NOT EXISTS note TEXT;
4444 END IF;
4545END $$;
46
47-- pull_request domain (PR API): the sync layer cannot relax NOT NULL nor add
48-- NOT NULL DEFAULT columns on populated tables, so both are applied here.
49DO $$ BEGIN
50 IF to_regclass('pull_request') IS NOT NULL THEN
51 ALTER TABLE pull_request ALTER COLUMN issue_id DROP NOT NULL;
52 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS head_repo_id UUID;
53 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS head_label VARCHAR;
54 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS is_draft BOOLEAN NOT NULL DEFAULT false;
55 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS merge_method SMALLINT NOT NULL DEFAULT 0;
56 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS squash_commit_sha VARCHAR;
57 ALTER TABLE pull_request ADD COLUMN IF NOT EXISTS auto_merge BOOLEAN NOT NULL DEFAULT false;
58 END IF;
59END $$;
60DO $$ BEGIN
61 IF to_regclass('pull_request_comment') IS NOT NULL THEN
62 ALTER TABLE pull_request_comment ALTER COLUMN commit_sha DROP NOT NULL;
63 ALTER TABLE pull_request_comment ALTER COLUMN path DROP NOT NULL;
64 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS parent_comment_id UUID;
65 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS original_commit_sha VARCHAR;
66 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS side VARCHAR;
67 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS original_line INTEGER;
68 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS resolved_at TIMESTAMP WITH TIME ZONE;
69 ALTER TABLE pull_request_comment ADD COLUMN IF NOT EXISTS resolved_by UUID;
70 END IF;
71END $$;