Skip to content

Commit

Permalink
feat(wip): implement query for fetching user project stats (see #302)…
Browse files Browse the repository at this point in the history
… [skip ci]
  • Loading branch information
muety committed Sep 22, 2023
1 parent c925a6d commit e21d9b2
Show file tree
Hide file tree
Showing 7 changed files with 1,335 additions and 1,262 deletions.
2,533 changes: 1,271 additions & 1,262 deletions coverage/coverage.out

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions mocks/heartbeat_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,8 @@ func (m *HeartbeatServiceMock) DeleteByUserBefore(u *models.User, t time.Time) e
args := m.Called(u, t)
return args.Error(0)
}

func (m *HeartbeatServiceMock) GetUserProjectStats(u *models.User, t time.Time, i int, i2 int) ([]*models.ProjectStats, error) {
args := m.Called(u, t, i, i2)
return args.Get(0).([]*models.ProjectStats), args.Error(1)
}
10 changes: 10 additions & 0 deletions models/project_stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package models

type ProjectStats struct {
UserId string
Project string
TopLanguage string
Count int64
First CustomTime
Last CustomTime
}
32 changes: 32 additions & 0 deletions repositories/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,35 @@ func (r *HeartbeatRepository) DeleteByUserBefore(user *models.User, t time.Time)
}
return nil
}

func (r *HeartbeatRepository) GetUserProjectStats(user *models.User, before time.Time, limit, offset int) ([]*models.ProjectStats, error) {
var projectStats []*models.ProjectStats

if err := r.db.
Raw(`
with top_langs as (
select distinct project,
first_value(language) over (partition by project order by count(*) desc) as top_language
from heartbeats
where user_id = ?
and language is not null and language != ''
and project is not null and project != ''
and time <= ?
group by project, language
limit ? offset ?
)
select project, ? as user_id, min(time) as first, max(time) as last, count(*) as count, top_language
from heartbeats
left join top_langs using (project)
where user_id = ?
and project != ''
and time <= ?
group by project, top_language
order by last desc
limit ? offset ?;
`, user.ID, before, limit, offset, user.ID, user.ID, before, limit, offset).
Scan(&projectStats).Error; err != nil {
return nil, err
}
return projectStats, nil
}
1 change: 1 addition & 0 deletions repositories/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type IHeartbeatRepository interface {
DeleteBefore(time.Time) error
DeleteByUser(*models.User) error
DeleteByUserBefore(*models.User, time.Time) error
GetUserProjectStats(*models.User, time.Time, int, int) ([]*models.ProjectStats, error)
}

type IDiagnosticsRepository interface {
Expand Down
15 changes: 15 additions & 0 deletions services/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/muety/wakapi/config"
"github.com/muety/wakapi/repositories"
"github.com/patrickmn/go-cache"
"math"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -198,6 +199,20 @@ func (srv *HeartbeatService) DeleteByUserBefore(user *models.User, t time.Time)
return srv.repository.DeleteByUserBefore(user, t)
}

func (srv *HeartbeatService) GetUserProjectStats(user *models.User, before time.Time, limit, offset int) ([]*models.ProjectStats, error) {
if limit <= 0 {
limit = math.MaxInt32
}
if offset <= 0 {
offset = 0
}
if before.IsZero() {
before = time.Now()
}

return srv.repository.GetUserProjectStats(user, before, limit, offset)
}

func (srv *HeartbeatService) augmented(heartbeats []*models.Heartbeat, userId string) ([]*models.Heartbeat, error) {
languageMapping, err := srv.languageMappingSrvc.ResolveByUser(userId)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions services/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type IHeartbeatService interface {
DeleteBefore(time.Time) error
DeleteByUser(*models.User) error
DeleteByUserBefore(*models.User, time.Time) error
GetUserProjectStats(*models.User, time.Time, int, int) ([]*models.ProjectStats, error)
}

type IDiagnosticsService interface {
Expand Down

0 comments on commit e21d9b2

Please sign in to comment.