1package db
2
3import (
4 "fmt"
5 "time"
6)
7
8type RepoEvent struct {
9 Repo *Repo
10 Source *Repo
11}
12
13type ProfileTimeline struct {
14 ByMonth []ByMonth
15}
16
17type ByMonth struct {
18 RepoEvents []RepoEvent
19 IssueEvents IssueEvents
20 PullEvents PullEvents
21}
22
23func (b ByMonth) IsEmpty() bool {
24 return len(b.RepoEvents) == 0 &&
25 len(b.IssueEvents.Items) == 0 &&
26 len(b.PullEvents.Items) == 0
27}
28
29type IssueEvents struct {
30 Items []*Issue
31}
32
33type IssueEventStats struct {
34 Open int
35 Closed int
36}
37
38func (i IssueEvents) Stats() IssueEventStats {
39 var open, closed int
40 for _, issue := range i.Items {
41 if issue.Open {
42 open += 1
43 } else {
44 closed += 1
45 }
46 }
47
48 return IssueEventStats{
49 Open: open,
50 Closed: closed,
51 }
52}
53
54type PullEvents struct {
55 Items []*Pull
56}
57
58func (p PullEvents) Stats() PullEventStats {
59 var open, merged, closed int
60 for _, pull := range p.Items {
61 switch pull.State {
62 case PullOpen:
63 open += 1
64 case PullMerged:
65 merged += 1
66 case PullClosed:
67 closed += 1
68 }
69 }
70
71 return PullEventStats{
72 Open: open,
73 Merged: merged,
74 Closed: closed,
75 }
76}
77
78type PullEventStats struct {
79 Closed int
80 Open int
81 Merged int
82}
83
84const TimeframeMonths = 3
85
86func MakeProfileTimeline(e Execer, forDid string) (*ProfileTimeline, error) {
87 timeline := ProfileTimeline{
88 ByMonth: make([]ByMonth, TimeframeMonths),
89 }
90 currentMonth := time.Now().Month()
91 timeframe := fmt.Sprintf("-%d months", TimeframeMonths)
92
93 pulls, err := GetPullsByOwnerDid(e, forDid, timeframe)
94 if err != nil {
95 return nil, fmt.Errorf("error getting pulls by owner did: %w", err)
96 }
97
98 // group pulls by month
99 for _, pull := range pulls {
100 pullMonth := pull.Created.Month()
101
102 if currentMonth-pullMonth > TimeframeMonths {
103 // shouldn't happen; but times are weird
104 continue
105 }
106
107 idx := currentMonth - pullMonth
108 items := &timeline.ByMonth[idx].PullEvents.Items
109
110 *items = append(*items, &pull)
111 }
112
113 issues, err := GetIssuesByOwnerDid(e, forDid, timeframe)
114 if err != nil {
115 return nil, fmt.Errorf("error getting issues by owner did: %w", err)
116 }
117
118 for _, issue := range issues {
119 issueMonth := issue.Created.Month()
120
121 if currentMonth-issueMonth > TimeframeMonths {
122 // shouldn't happen; but times are weird
123 continue
124 }
125
126 idx := currentMonth - issueMonth
127 items := &timeline.ByMonth[idx].IssueEvents.Items
128
129 *items = append(*items, &issue)
130 }
131
132 repos, err := GetAllReposByDid(e, forDid)
133 if err != nil {
134 return nil, fmt.Errorf("error getting all repos by did: %w", err)
135 }
136
137 for _, repo := range repos {
138 // TODO: get this in the original query; requires COALESCE because nullable
139 var sourceRepo *Repo
140 if repo.Source != "" {
141 sourceRepo, err = GetRepoByAtUri(e, repo.Source)
142 if err != nil {
143 return nil, err
144 }
145 }
146
147 repoMonth := repo.Created.Month()
148
149 if currentMonth-repoMonth > TimeframeMonths {
150 // shouldn't happen; but times are weird
151 continue
152 }
153
154 idx := currentMonth - repoMonth
155
156 items := &timeline.ByMonth[idx].RepoEvents
157 *items = append(*items, RepoEvent{
158 Repo: &repo,
159 Source: sourceRepo,
160 })
161 }
162
163 return &timeline, nil
164}