Skip to content

Commit 66d4c45

Browse files
committed
feat: Simplified the logic around merges
1 parent d5d53b8 commit 66d4c45

File tree

9 files changed

+63
-99
lines changed

9 files changed

+63
-99
lines changed

aggregated_files.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,23 @@ func createPathFileMap(files AggregatedFiles) map[string]AggregatedFile {
1414
return pathFileMap
1515
}
1616

17-
// merge takes two slices of aggregated files, merges them, and returns the result.
1817
func (a AggregatedFiles) merge(b AggregatedFiles) AggregatedFiles {
19-
mergedFiles := make([]AggregatedFile, 0)
2018
aFileMap := createPathFileMap(a)
2119
bFileMap := createPathFileMap(b)
2220

23-
// Add files that are unique for "a", and merge collisions.
24-
for _, aFile := range a {
25-
if bFile, ok := bFileMap[aFile.Path]; ok {
26-
mergedFiles = append(mergedFiles, aFile.merge(bFile))
27-
continue
28-
}
29-
mergedFiles = append(mergedFiles, aFile)
21+
allPaths := make(map[string]bool)
22+
for path := range aFileMap {
23+
allPaths[path] = true
3024
}
31-
32-
// Add the files that are unique for "b".
33-
for _, bFile := range b {
34-
if _, ok := aFileMap[bFile.Path]; !ok {
35-
mergedFiles = append(mergedFiles, bFile)
36-
}
25+
for path := range bFileMap {
26+
allPaths[path] = true
3727
}
3828

29+
mergedFiles := make([]AggregatedFile, 0, len(allPaths))
30+
for path := range allPaths {
31+
aFile := aFileMap[path]
32+
bFile := bFileMap[path]
33+
mergedFiles = append(mergedFiles, aFile.merge(bFile))
34+
}
3935
return mergedFiles
4036
}

aggregated_session.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package pulse
55
type AggregatedSession struct {
66
ID string `bson:"_id,omitempty"`
77
Period Period `bson:"period"`
8-
Date int64 `bson:"date"`
8+
EpochDateMs int64 `bson:"date"`
99
DateString string `bson:"date_string"`
1010
TotalTimeMs int64 `bson:"total_time_ms"`
1111
Repositories Repositories `bson:"repositories"`
@@ -15,7 +15,7 @@ type AggregatedSession struct {
1515
func (a AggregatedSession) merge(b AggregatedSession, date int64, timePeriod Period) AggregatedSession {
1616
mergedSession := AggregatedSession{
1717
Period: timePeriod,
18-
Date: date,
18+
EpochDateMs: date,
1919
DateString: a.DateString,
2020
TotalTimeMs: a.TotalTimeMs + b.TotalTimeMs,
2121
Repositories: a.Repositories.merge(b.Repositories),

aggregated_sessions.go

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,32 @@ import (
77

88
type AggregatedSessions []AggregatedSession
99

10-
type truncateTimeFunc func(AggregatedSession) int64
11-
12-
// merge takes a slice of aggregated sessions as well as a truncate function,
13-
// which is used to cluster and merge the sessions by time period.
14-
func merge(sessions AggregatedSessions, truncate truncateTimeFunc, timePeriod Period) AggregatedSessions {
15-
sessionMap := make(map[int64]AggregatedSession)
10+
func merge(sessions AggregatedSessions, truncate func(int64) int64, timePeriod Period) AggregatedSessions {
11+
truncatedDateAggregatedSession := make(map[int64]AggregatedSession)
1612
for _, s := range sessions {
17-
key := truncate(s)
18-
if session, ok := sessionMap[key]; !ok {
19-
sessionMap[key] = s
20-
} else {
21-
sessionMap[key] = s.merge(session, truncate(s), timePeriod)
22-
}
13+
truncatedDate := truncate(s.EpochDateMs)
14+
currentSession := truncatedDateAggregatedSession[truncatedDate]
15+
truncatedDateAggregatedSession[truncatedDate] = s.merge(currentSession, truncatedDate, timePeriod)
2316
}
24-
25-
return maps.Values(sessionMap)
17+
return maps.Values(truncatedDateAggregatedSession)
2618
}
2719

2820
// MergeByDay merges sessions that occurred the same day.
2921
func (s AggregatedSessions) MergeByDay() AggregatedSessions {
30-
truncateFunc := func(s AggregatedSession) int64 {
31-
return truncate.Day(s.Date)
32-
}
33-
return merge(s, truncateFunc, Day)
22+
return merge(s, truncate.Day, Day)
3423
}
3524

3625
// MergeByWeek merges sessions that occurred the same week.
3726
func (s AggregatedSessions) MergeByWeek() AggregatedSessions {
38-
truncateFunc := func(s AggregatedSession) int64 {
39-
return truncate.Week(s.Date)
40-
}
41-
return merge(s, truncateFunc, Week)
27+
return merge(s, truncate.Week, Week)
4228
}
4329

4430
// MergeByWeek merges sessions that occurred the same month.
4531
func (s AggregatedSessions) MergeByMonth() AggregatedSessions {
46-
truncateFunc := func(s AggregatedSession) int64 {
47-
return truncate.Month(s.Date)
48-
}
49-
return merge(s, truncateFunc, Month)
32+
return merge(s, truncate.Month, Month)
5033
}
5134

5235
// MergeByYear merges sessions that occurred the same year.
5336
func (s AggregatedSessions) MergeByYear() AggregatedSessions {
54-
truncateFunc := func(s AggregatedSession) int64 {
55-
return truncate.Year(s.Date)
56-
}
57-
return merge(s, truncateFunc, Year)
37+
return merge(s, truncate.Year, Year)
5838
}

buffer_stack.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ func (b *bufferStack) files() Files {
3232

3333
// Merge the buffers by filepath.
3434
for _, buffer := range b.buffers {
35-
if file, exists := pathFile[buffer.Filepath]; !exists {
35+
file, exists := pathFile[buffer.Filepath]
36+
if !exists {
3637
sortOrder = append(sortOrder, buffer.Filepath)
3738
pathFile[buffer.Filepath] = fileFromBuffer(buffer)
38-
} else {
39-
file.Duration += buffer.Duration()
40-
pathFile[buffer.Filepath] = file
39+
continue
4140
}
41+
file.Duration += buffer.Duration()
42+
pathFile[buffer.Filepath] = file
4243
}
4344

4445
// Return the buffers in the original order.

mongo/mongo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ func createDateFilter(minDate, maxDate int64) primitive.D {
5858
func dateRange(sessions []pulse.AggregatedSession) (minDate, maxDate int64) {
5959
minDate, maxDate = math.MaxInt64, math.MinInt64
6060
for _, s := range sessions {
61-
minDate = min(minDate, s.Date)
62-
maxDate = max(maxDate, s.Date)
61+
minDate = min(minDate, s.EpochDateMs)
62+
maxDate = max(maxDate, s.EpochDateMs)
6363
}
6464
return minDate, maxDate
6565
}

repositories.go

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ type Repositories []Repository
55

66
// repositories take a slice of sessions and returns the repositories.
77
func repositories(sessions Sessions) Repositories {
8-
filesByRepo := repositoryPathFile(sessions)
9-
repos := make(Repositories, 0)
10-
11-
for repositoryName, filenameFileMap := range filesByRepo {
12-
var durationMs int64
13-
files := make([]AggregatedFile, 0)
14-
for _, file := range filenameFileMap {
15-
files = append(files, file)
16-
durationMs += file.DurationMs
8+
namesWithFiles := repositoryNamesWithFiles(sessions)
9+
repos := make(Repositories, 0, len(namesWithFiles))
10+
11+
for repositoryName, filepathFile := range namesWithFiles {
12+
files := make(AggregatedFiles, 0, len(filepathFile))
13+
repo := Repository{Name: repositoryName, Files: files}
14+
for _, file := range filepathFile {
15+
repo.Files = append(repo.Files, file)
16+
repo.DurationMs += file.DurationMs
1717
}
18-
repo := Repository{Name: repositoryName, Files: files, DurationMs: durationMs}
1918
repos = append(repos, repo)
2019
}
2120

@@ -34,25 +33,20 @@ func repositoriesByName(repos Repositories) map[string]Repository {
3433

3534
// merge takes two lists of repositories, merges them, and returns the result.
3635
func (r Repositories) merge(b Repositories) Repositories {
37-
mergedRepositories := make([]Repository, 0)
38-
aRepoMap, bRepoMap := repositoriesByName(r), repositoriesByName(b)
39-
40-
// Add repos that are unique for a and merge collisions.
41-
for _, aRepo := range r {
42-
if bRepo, ok := bRepoMap[aRepo.Name]; !ok {
43-
mergedRepositories = append(mergedRepositories, aRepo)
44-
} else {
45-
mergedRepositories = append(mergedRepositories, aRepo.merge(bRepo))
46-
}
36+
aNames, bNames := repositoriesByName(r), repositoriesByName(b)
37+
allNames := make(map[string]bool)
38+
for name := range aNames {
39+
allNames[name] = true
4740
}
48-
49-
// The merging is done at this point. Here we'll add the
50-
// repositories that are unique to the new session.
51-
for _, newRepo := range b {
52-
if _, ok := aRepoMap[newRepo.Name]; !ok {
53-
mergedRepositories = append(mergedRepositories, newRepo)
54-
}
41+
for name := range bNames {
42+
allNames[name] = true
5543
}
5644

45+
mergedRepositories := make([]Repository, 0)
46+
for name := range allNames {
47+
aRepo := aNames[name]
48+
bRepo := bNames[name]
49+
mergedRepositories = append(mergedRepositories, aRepo.merge(bRepo))
50+
}
5751
return mergedRepositories
5852
}

repository.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ func (r Repository) merge(b Repository) Repository {
1818
}
1919
}
2020

21-
// repositoryPathFile processes a slice of coding sessions by creating a nested
21+
// repositoryNamesWithFiles processes a slice of coding sessions by creating a nested
2222
// map that organizes and merges file data. The outer map's keys are repository
2323
// names. Each associated value is another map, where the keys are relative file
2424
// paths within the repository, and the values are the corresponding file data.
2525
// Files are merged automatically if they have been modified in multiple sessions.
26-
func repositoryPathFile(sessions []Session) map[string]map[string]AggregatedFile {
26+
func repositoryNamesWithFiles(sessions []Session) map[string]map[string]AggregatedFile {
2727
repoPathFile := make(map[string]map[string]AggregatedFile)
2828
for _, session := range sessions {
2929
for _, file := range session.Files {
@@ -41,13 +41,9 @@ func repositoryPathFile(sessions []Session) map[string]map[string]AggregatedFile
4141
repoPathFile[file.Repository] = make(map[string]AggregatedFile)
4242
}
4343

44-
// Check if it is the first time we're seeing this file in this
45-
// repository. If it is not the first time, we'll merge them.
46-
if f, ok := repoPathFile[file.Repository][file.Path]; !ok {
47-
repoPathFile[file.Repository][file.Path] = aggregatedFile
48-
} else {
49-
repoPathFile[file.Repository][file.Path] = f.merge(aggregatedFile)
50-
}
44+
// Merge the aggregatedFile with a previous file, or the zero value of a file.
45+
f := repoPathFile[file.Repository][file.Path]
46+
repoPathFile[file.Repository][file.Path] = f.merge(aggregatedFile)
5147
}
5248
}
5349

sessions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (s Sessions) Aggregate() AggregatedSessions {
4343
}
4444
session := AggregatedSession{
4545
Period: Day,
46-
Date: date,
46+
EpochDateMs: date,
4747
DateString: time.UnixMilli(date).Format("2006-01-02"),
4848
TotalTimeMs: totalTimeMs,
4949
Repositories: repositories(tempSessions),

truncate/truncate.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,21 @@ func Day(timestamp int64) int64 {
1111

1212
// Week truncates the timestamp to the start of the week.
1313
func Week(timestamp int64) int64 {
14-
t := time.Unix(0, timestamp*int64(time.Millisecond))
14+
t := time.UnixMilli(timestamp)
1515
for t.Weekday() != time.Monday {
1616
t = t.AddDate(0, 0, -1)
1717
}
18-
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
19-
return t.UnixMilli()
18+
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()).UnixMilli()
2019
}
2120

2221
// Month truncates the timestamp to the start of the month.
2322
func Month(timestamp int64) int64 {
24-
t := time.Unix(0, timestamp*int64(time.Millisecond))
25-
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
26-
return t.UnixMilli()
23+
t := time.UnixMilli(timestamp)
24+
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location()).UnixMilli()
2725
}
2826

2927
// Year truncates the timestamp to the start of the year.
3028
func Year(timestamp int64) int64 {
31-
t := time.Unix(0, timestamp*int64(time.Millisecond))
32-
t = time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, t.Location())
33-
return t.UnixMilli()
29+
t := time.UnixMilli(timestamp)
30+
return time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, t.Location()).UnixMilli()
3431
}

0 commit comments

Comments
 (0)