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