1package db
2
3import (
4 "database/sql"
5 "time"
6)
7
8type Issue struct {
9 RepoAt string
10 OwnerDid string
11 IssueId int
12 IssueAt string
13 Created *time.Time
14 Title string
15 Body string
16 Open bool
17}
18
19type Comment struct {
20 OwnerDid string
21 RepoAt string
22 CommentAt string
23 Issue int
24 CommentId int
25 Body string
26 Created *time.Time
27}
28
29func NewIssue(tx *sql.Tx, issue *Issue) error {
30 defer tx.Rollback()
31
32 _, err := tx.Exec(`
33 insert or ignore into repo_issue_seqs (repo_at, next_issue_id)
34 values (?, 1)
35 `, issue.RepoAt)
36 if err != nil {
37 return err
38 }
39
40 var nextId int
41 err = tx.QueryRow(`
42 update repo_issue_seqs
43 set next_issue_id = next_issue_id + 1
44 where repo_at = ?
45 returning next_issue_id - 1
46 `, issue.RepoAt).Scan(&nextId)
47 if err != nil {
48 return err
49 }
50
51 issue.IssueId = nextId
52
53 _, err = tx.Exec(`
54 insert into issues (repo_at, owner_did, issue_id, title, body)
55 values (?, ?, ?, ?, ?)
56 `, issue.RepoAt, issue.OwnerDid, issue.IssueId, issue.Title, issue.Body)
57 if err != nil {
58 return err
59 }
60
61 if err := tx.Commit(); err != nil {
62 return err
63 }
64
65 return nil
66}
67
68func SetIssueAt(e Execer, repoAt string, issueId int, issueAt string) error {
69 _, err := e.Exec(`update issues set issue_at = ? where repo_at = ? and issue_id = ?`, issueAt, repoAt, issueId)
70 return err
71}
72
73func GetIssueAt(e Execer, repoAt string, issueId int) (string, error) {
74 var issueAt string
75 err := e.QueryRow(`select issue_at from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&issueAt)
76 return issueAt, err
77}
78
79func GetIssueId(e Execer, repoAt string) (int, error) {
80 var issueId int
81 err := e.QueryRow(`select next_issue_id from repo_issue_seqs where repo_at = ?`, repoAt).Scan(&issueId)
82 return issueId - 1, err
83}
84
85func GetIssueOwnerDid(e Execer, repoAt string, issueId int) (string, error) {
86 var ownerDid string
87 err := e.QueryRow(`select owner_did from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&ownerDid)
88 return ownerDid, err
89}
90
91func GetIssues(e Execer, repoAt string) ([]Issue, error) {
92 var issues []Issue
93
94 rows, err := e.Query(`select owner_did, issue_id, created, title, body, open from issues where repo_at = ? order by created desc`, repoAt)
95 if err != nil {
96 return nil, err
97 }
98 defer rows.Close()
99
100 for rows.Next() {
101 var issue Issue
102 var createdAt string
103 err := rows.Scan(&issue.OwnerDid, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open)
104 if err != nil {
105 return nil, err
106 }
107
108 createdTime, err := time.Parse(time.RFC3339, createdAt)
109 if err != nil {
110 return nil, err
111 }
112 issue.Created = &createdTime
113
114 issues = append(issues, issue)
115 }
116
117 if err := rows.Err(); err != nil {
118 return nil, err
119 }
120
121 return issues, nil
122}
123
124func GetIssue(e Execer, repoAt string, issueId int) (*Issue, error) {
125 query := `select owner_did, created, title, body, open from issues where repo_at = ? and issue_id = ?`
126 row := e.QueryRow(query, repoAt, issueId)
127
128 var issue Issue
129 var createdAt string
130 err := row.Scan(&issue.OwnerDid, &createdAt, &issue.Title, &issue.Body, &issue.Open)
131 if err != nil {
132 return nil, err
133 }
134
135 createdTime, err := time.Parse(time.RFC3339, createdAt)
136 if err != nil {
137 return nil, err
138 }
139 issue.Created = &createdTime
140
141 return &issue, nil
142}
143
144func GetIssueWithComments(e Execer, repoAt string, issueId int) (*Issue, []Comment, error) {
145 query := `select owner_did, issue_id, created, title, body, open from issues where repo_at = ? and issue_id = ?`
146 row := e.QueryRow(query, repoAt, issueId)
147
148 var issue Issue
149 var createdAt string
150 err := row.Scan(&issue.OwnerDid, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open)
151 if err != nil {
152 return nil, nil, err
153 }
154
155 createdTime, err := time.Parse(time.RFC3339, createdAt)
156 if err != nil {
157 return nil, nil, err
158 }
159 issue.Created = &createdTime
160
161 comments, err := GetComments(e, repoAt, issueId)
162 if err != nil {
163 return nil, nil, err
164 }
165
166 return &issue, comments, nil
167}
168
169func NewComment(e Execer, comment *Comment) error {
170 query := `insert into comments (owner_did, repo_at, comment_at, issue_id, comment_id, body) values (?, ?, ?, ?, ?, ?)`
171 _, err := e.Exec(
172 query,
173 comment.OwnerDid,
174 comment.RepoAt,
175 comment.CommentAt,
176 comment.Issue,
177 comment.CommentId,
178 comment.Body,
179 )
180 return err
181}
182
183func GetComments(e Execer, repoAt string, issueId int) ([]Comment, error) {
184 var comments []Comment
185
186 rows, err := e.Query(`select owner_did, issue_id, comment_id, comment_at, body, created from comments where repo_at = ? and issue_id = ? order by created asc`, repoAt, issueId)
187 if err == sql.ErrNoRows {
188 return []Comment{}, nil
189 }
190 if err != nil {
191 return nil, err
192 }
193 defer rows.Close()
194
195 for rows.Next() {
196 var comment Comment
197 var createdAt string
198 err := rows.Scan(&comment.OwnerDid, &comment.Issue, &comment.CommentId, &comment.CommentAt, &comment.Body, &createdAt)
199 if err != nil {
200 return nil, err
201 }
202
203 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
204 if err != nil {
205 return nil, err
206 }
207 comment.Created = &createdAtTime
208
209 comments = append(comments, comment)
210 }
211
212 if err := rows.Err(); err != nil {
213 return nil, err
214 }
215
216 return comments, nil
217}
218
219func CloseIssue(e Execer, repoAt string, issueId int) error {
220 _, err := e.Exec(`update issues set open = 0 where repo_at = ? and issue_id = ?`, repoAt, issueId)
221 return err
222}
223
224func ReopenIssue(e Execer, repoAt string, issueId int) error {
225 _, err := e.Exec(`update issues set open = 1 where repo_at = ? and issue_id = ?`, repoAt, issueId)
226 return err
227}