forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package db
2
3import (
4 "context"
5 "sort"
6 "time"
7
8 "go.opentelemetry.io/otel/attribute"
9 "go.opentelemetry.io/otel/trace"
10)
11
12type TimelineEvent struct {
13 *Repo
14 *Follow
15 *Star
16
17 EventAt time.Time
18
19 // optional: populate only if Repo is a fork
20 Source *Repo
21}
22
23// TODO: this gathers heterogenous events from different sources and aggregates
24// them in code; if we did this entirely in sql, we could order and limit and paginate easily
25func MakeTimeline(ctx context.Context, e Execer) ([]TimelineEvent, error) {
26 span := trace.SpanFromContext(ctx)
27 defer span.End()
28
29 var events []TimelineEvent
30 limit := 50
31
32 span.SetAttributes(attribute.Int("timeline.limit", limit))
33
34 repos, err := GetAllRepos(ctx, e, limit)
35 if err != nil {
36 span.RecordError(err)
37 span.SetAttributes(attribute.String("error.from", "GetAllRepos"))
38 return nil, err
39 }
40 span.SetAttributes(attribute.Int("timeline.repos.count", len(repos)))
41
42 follows, err := GetAllFollows(e, limit)
43 if err != nil {
44 span.RecordError(err)
45 span.SetAttributes(attribute.String("error.from", "GetAllFollows"))
46 return nil, err
47 }
48 span.SetAttributes(attribute.Int("timeline.follows.count", len(follows)))
49
50 stars, err := GetAllStars(e, limit)
51 if err != nil {
52 span.RecordError(err)
53 span.SetAttributes(attribute.String("error.from", "GetAllStars"))
54 return nil, err
55 }
56 span.SetAttributes(attribute.Int("timeline.stars.count", len(stars)))
57
58 for _, repo := range repos {
59 var sourceRepo *Repo
60 if repo.Source != "" {
61 sourceRepo, err = GetRepoByAtUri(ctx, e, repo.Source)
62 if err != nil {
63 span.RecordError(err)
64 span.SetAttributes(
65 attribute.String("error.from", "GetRepoByAtUri"),
66 attribute.String("repo.source", repo.Source),
67 )
68 return nil, err
69 }
70 }
71
72 events = append(events, TimelineEvent{
73 Repo: &repo,
74 EventAt: repo.Created,
75 Source: sourceRepo,
76 })
77 }
78
79 for _, follow := range follows {
80 events = append(events, TimelineEvent{
81 Follow: &follow,
82 EventAt: follow.FollowedAt,
83 })
84 }
85
86 for _, star := range stars {
87 events = append(events, TimelineEvent{
88 Star: &star,
89 EventAt: star.Created,
90 })
91 }
92
93 sort.Slice(events, func(i, j int) bool {
94 return events[i].EventAt.After(events[j].EventAt)
95 })
96
97 // Limit the slice to 100 events
98 if len(events) > limit {
99 events = events[:limit]
100 }
101
102 span.SetAttributes(attribute.Int("timeline.events.total", len(events)))
103
104 return events, nil
105}