Skip to content

Commit f9d74db

Browse files
committed
Moar leaderboard optimizations
1 parent fffd548 commit f9d74db

File tree

4 files changed

+280
-65
lines changed

4 files changed

+280
-65
lines changed

backend/cmd/server/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ func main() {
136136
slog.Info("RoleService initialized with caching")
137137

138138
// Initialize LeaderboardService
139-
leaderboardService := services.NewLeaderboardService(db.Queries, cacheInstance.Cache)
140-
slog.Info("LeaderboardService initialized with caching")
139+
leaderboardService := services.NewLeaderboardService(db.Queries, cacheInstance.Cache, dataLoaders)
140+
slog.Info("LeaderboardService initialized with caching and loaders")
141141

142142
// Initialize GraphQL resolver
143143
apiResolver := &api.Resolver{

backend/internal/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ func Load() (*Config, error) {
9696
URL: getEnv("DATABASE_URL", ""),
9797
MaxOpenConns: getEnvAsInt("DB_MAX_OPEN_CONNS", 25),
9898
MaxIdleConns: getEnvAsInt("DB_MAX_IDLE_CONNS", 5),
99-
ConnMaxLifetime: getEnvAsDuration("DB_CONN_MAX_LIFETIME", 5*time.Minute),
100-
ConnMaxIdleTime: getEnvAsDuration("DB_CONN_MAX_IDLE_TIME", 5*time.Minute),
99+
ConnMaxLifetime: getEnvAsDuration("DB_CONN_MAX_LIFETIME", 10*time.Minute),
100+
ConnMaxIdleTime: getEnvAsDuration("DB_CONN_MAX_IDLE_TIME", 1*time.Minute),
101101
LogQueries: getEnvAsBool("DB_LOG_QUERIES", false),
102102
},
103103
JWT: JWTConfig{

backend/internal/services/leaderboard.go

Lines changed: 128 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/bcc-media/wayfarer/internal/cache"
1212
"github.com/bcc-media/wayfarer/internal/database/sqlc"
1313
"github.com/bcc-media/wayfarer/internal/graph/api/model"
14+
"github.com/bcc-media/wayfarer/internal/loaders"
1415
)
1516

1617
// LeaderboardQuerier defines the database operations needed for leaderboards
@@ -62,13 +63,15 @@ type LeaderboardQuerier interface {
6263
type LeaderboardService struct {
6364
queries LeaderboardQuerier
6465
cache *cache.Cache
66+
loaders *loaders.Loaders
6567
}
6668

6769
// NewLeaderboardService creates a new leaderboard service
68-
func NewLeaderboardService(queries LeaderboardQuerier, c *cache.Cache) *LeaderboardService {
70+
func NewLeaderboardService(queries LeaderboardQuerier, c *cache.Cache, l *loaders.Loaders) *LeaderboardService {
6971
return &LeaderboardService{
7072
queries: queries,
7173
cache: c,
74+
loaders: l,
7275
}
7376
}
7477

@@ -214,11 +217,17 @@ func (s *LeaderboardService) getProjectTeamLeaderboard(ctx context.Context, para
214217
// Find "me" in cached results
215218
var meEntry *LeaderboardEntry
216219
if params.UserID != "" {
217-
// Get my team ID first
218-
posParams := s.buildProjectTeamPositionParams(params)
219-
myPos, err := s.queries.FindMyProjectTeamPosition(ctx, posParams)
220-
if err == nil && myPos != nil {
221-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
220+
// Use loader to get user's teams
221+
thunk := s.loaders.TeamsByUserLoader.Load(ctx, params.UserID)
222+
teams, err := thunk()
223+
if err == nil && teams != nil {
224+
// Find team in this project
225+
for _, team := range teams {
226+
if team.ProjectID == params.ContextID {
227+
meEntry = findMeInLeaderboard(fullLeaderboard, team.ID)
228+
break
229+
}
230+
}
222231
}
223232
}
224233

@@ -261,11 +270,17 @@ func (s *LeaderboardService) getProjectTeamLeaderboard(ctx context.Context, para
261270
// Find "me" in results
262271
var meEntry *LeaderboardEntry
263272
if params.UserID != "" {
264-
// Get my team ID first
265-
posParams := s.buildProjectTeamPositionParams(params)
266-
myPos, err := s.queries.FindMyProjectTeamPosition(ctx, posParams)
267-
if err == nil && myPos != nil {
268-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
273+
// Use loader to get user's teams
274+
thunk := s.loaders.TeamsByUserLoader.Load(ctx, params.UserID)
275+
teams, err := thunk()
276+
if err == nil && teams != nil {
277+
// Find team in this project
278+
for _, team := range teams {
279+
if team.ProjectID == params.ContextID {
280+
meEntry = findMeInLeaderboard(fullLeaderboard, team.ID)
281+
break
282+
}
283+
}
269284
}
270285
}
271286

@@ -293,11 +308,17 @@ func (s *LeaderboardService) getProjectSuperTeamLeaderboard(ctx context.Context,
293308
// Find "me" in cached results
294309
var meEntry *LeaderboardEntry
295310
if params.UserID != "" {
296-
// Get my superteam ID first
297-
posParams := s.buildProjectSuperTeamPositionParams(params)
298-
myPos, err := s.queries.FindMyProjectSuperTeamPosition(ctx, posParams)
299-
if err == nil && myPos != nil {
300-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
311+
// Use loader to get user's superteams
312+
thunk := s.loaders.SuperTeamsByUserLoader.Load(ctx, params.UserID)
313+
superTeams, err := thunk()
314+
if err == nil && superTeams != nil {
315+
// Find superteam in this project
316+
for _, superTeam := range superTeams {
317+
if superTeam.ProjectID == params.ContextID {
318+
meEntry = findMeInLeaderboard(fullLeaderboard, superTeam.ID)
319+
break
320+
}
321+
}
301322
}
302323
}
303324

@@ -340,11 +361,17 @@ func (s *LeaderboardService) getProjectSuperTeamLeaderboard(ctx context.Context,
340361
// Find "me" in results
341362
var meEntry *LeaderboardEntry
342363
if params.UserID != "" {
343-
// Get my superteam ID first
344-
posParams := s.buildProjectSuperTeamPositionParams(params)
345-
myPos, err := s.queries.FindMyProjectSuperTeamPosition(ctx, posParams)
346-
if err == nil && myPos != nil {
347-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
364+
// Use loader to get user's superteams
365+
thunk := s.loaders.SuperTeamsByUserLoader.Load(ctx, params.UserID)
366+
superTeams, err := thunk()
367+
if err == nil && superTeams != nil {
368+
// Find superteam in this project
369+
for _, superTeam := range superTeams {
370+
if superTeam.ProjectID == params.ContextID {
371+
meEntry = findMeInLeaderboard(fullLeaderboard, superTeam.ID)
372+
break
373+
}
374+
}
348375
}
349376
}
350377

@@ -372,11 +399,11 @@ func (s *LeaderboardService) getProjectChurchLeaderboard(ctx context.Context, pa
372399
// Find "me" in cached results
373400
var meEntry *LeaderboardEntry
374401
if params.UserID != "" {
375-
// Get my church ID first
376-
posParams := s.buildProjectChurchPositionParams(params)
377-
myPos, err := s.queries.FindMyProjectChurchPosition(ctx, posParams)
378-
if err == nil && myPos != nil {
379-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
402+
// Use loader to get user (includes ChurchID)
403+
thunk := s.loaders.UserByIDLoader.Load(ctx, params.UserID)
404+
user, err := thunk()
405+
if err == nil && user != nil {
406+
meEntry = findMeInLeaderboard(fullLeaderboard, user.ChurchID)
380407
}
381408
}
382409

@@ -419,11 +446,11 @@ func (s *LeaderboardService) getProjectChurchLeaderboard(ctx context.Context, pa
419446
// Find "me" in results
420447
var meEntry *LeaderboardEntry
421448
if params.UserID != "" {
422-
// Get my church ID first
423-
posParams := s.buildProjectChurchPositionParams(params)
424-
myPos, err := s.queries.FindMyProjectChurchPosition(ctx, posParams)
425-
if err == nil && myPos != nil {
426-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
449+
// Use loader to get user (includes ChurchID)
450+
thunk := s.loaders.UserByIDLoader.Load(ctx, params.UserID)
451+
user, err := thunk()
452+
if err == nil && user != nil {
453+
meEntry = findMeInLeaderboard(fullLeaderboard, user.ChurchID)
427454
}
428455
}
429456

@@ -522,11 +549,21 @@ func (s *LeaderboardService) getEventTeamLeaderboard(ctx context.Context, params
522549
// Find "me" in cached results
523550
var meEntry *LeaderboardEntry
524551
if params.UserID != "" {
525-
// Get my team ID first
526-
posParams := s.buildEventTeamPositionParams(params)
527-
myPos, err := s.queries.FindMyEventTeamPosition(ctx, posParams)
528-
if err == nil && myPos != nil {
529-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
552+
// Get event to find its project, then get user's teams
553+
eventThunk := s.loaders.EventByIDLoader.Load(ctx, params.ContextID)
554+
event, err := eventThunk()
555+
if err == nil && event != nil {
556+
teamsThunk := s.loaders.TeamsByUserLoader.Load(ctx, params.UserID)
557+
teams, err := teamsThunk()
558+
if err == nil && teams != nil {
559+
// Find team in this event's project
560+
for _, team := range teams {
561+
if team.ProjectID == event.ProjectID {
562+
meEntry = findMeInLeaderboard(fullLeaderboard, team.ID)
563+
break
564+
}
565+
}
566+
}
530567
}
531568
}
532569

@@ -569,11 +606,21 @@ func (s *LeaderboardService) getEventTeamLeaderboard(ctx context.Context, params
569606
// Find "me" in results
570607
var meEntry *LeaderboardEntry
571608
if params.UserID != "" {
572-
// Get my team ID first
573-
posParams := s.buildEventTeamPositionParams(params)
574-
myPos, err := s.queries.FindMyEventTeamPosition(ctx, posParams)
575-
if err == nil && myPos != nil {
576-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
609+
// Get event to find its project, then get user's teams
610+
eventThunk := s.loaders.EventByIDLoader.Load(ctx, params.ContextID)
611+
event, err := eventThunk()
612+
if err == nil && event != nil {
613+
teamsThunk := s.loaders.TeamsByUserLoader.Load(ctx, params.UserID)
614+
teams, err := teamsThunk()
615+
if err == nil && teams != nil {
616+
// Find team in this event's project
617+
for _, team := range teams {
618+
if team.ProjectID == event.ProjectID {
619+
meEntry = findMeInLeaderboard(fullLeaderboard, team.ID)
620+
break
621+
}
622+
}
623+
}
577624
}
578625
}
579626

@@ -601,11 +648,21 @@ func (s *LeaderboardService) getEventSuperTeamLeaderboard(ctx context.Context, p
601648
// Find "me" in cached results
602649
var meEntry *LeaderboardEntry
603650
if params.UserID != "" {
604-
// Get my superteam ID first
605-
posParams := s.buildEventSuperTeamPositionParams(params)
606-
myPos, err := s.queries.FindMyEventSuperTeamPosition(ctx, posParams)
607-
if err == nil && myPos != nil {
608-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
651+
// Get event to find its project, then get user's superteams
652+
eventThunk := s.loaders.EventByIDLoader.Load(ctx, params.ContextID)
653+
event, err := eventThunk()
654+
if err == nil && event != nil {
655+
superTeamsThunk := s.loaders.SuperTeamsByUserLoader.Load(ctx, params.UserID)
656+
superTeams, err := superTeamsThunk()
657+
if err == nil && superTeams != nil {
658+
// Find superteam in this event's project
659+
for _, superTeam := range superTeams {
660+
if superTeam.ProjectID == event.ProjectID {
661+
meEntry = findMeInLeaderboard(fullLeaderboard, superTeam.ID)
662+
break
663+
}
664+
}
665+
}
609666
}
610667
}
611668

@@ -648,11 +705,21 @@ func (s *LeaderboardService) getEventSuperTeamLeaderboard(ctx context.Context, p
648705
// Find "me" in results
649706
var meEntry *LeaderboardEntry
650707
if params.UserID != "" {
651-
// Get my superteam ID first
652-
posParams := s.buildEventSuperTeamPositionParams(params)
653-
myPos, err := s.queries.FindMyEventSuperTeamPosition(ctx, posParams)
654-
if err == nil && myPos != nil {
655-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
708+
// Get event to find its project, then get user's superteams
709+
eventThunk := s.loaders.EventByIDLoader.Load(ctx, params.ContextID)
710+
event, err := eventThunk()
711+
if err == nil && event != nil {
712+
superTeamsThunk := s.loaders.SuperTeamsByUserLoader.Load(ctx, params.UserID)
713+
superTeams, err := superTeamsThunk()
714+
if err == nil && superTeams != nil {
715+
// Find superteam in this event's project
716+
for _, superTeam := range superTeams {
717+
if superTeam.ProjectID == event.ProjectID {
718+
meEntry = findMeInLeaderboard(fullLeaderboard, superTeam.ID)
719+
break
720+
}
721+
}
722+
}
656723
}
657724
}
658725

@@ -680,11 +747,11 @@ func (s *LeaderboardService) getEventChurchLeaderboard(ctx context.Context, para
680747
// Find "me" in cached results
681748
var meEntry *LeaderboardEntry
682749
if params.UserID != "" {
683-
// Get my church ID first
684-
posParams := s.buildEventChurchPositionParams(params)
685-
myPos, err := s.queries.FindMyEventChurchPosition(ctx, posParams)
686-
if err == nil && myPos != nil {
687-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
750+
// Use loader to get user (includes ChurchID)
751+
thunk := s.loaders.UserByIDLoader.Load(ctx, params.UserID)
752+
user, err := thunk()
753+
if err == nil && user != nil {
754+
meEntry = findMeInLeaderboard(fullLeaderboard, user.ChurchID)
688755
}
689756
}
690757

@@ -727,11 +794,11 @@ func (s *LeaderboardService) getEventChurchLeaderboard(ctx context.Context, para
727794
// Find "me" in results
728795
var meEntry *LeaderboardEntry
729796
if params.UserID != "" {
730-
// Get my church ID first
731-
posParams := s.buildEventChurchPositionParams(params)
732-
myPos, err := s.queries.FindMyEventChurchPosition(ctx, posParams)
733-
if err == nil && myPos != nil {
734-
meEntry = findMeInLeaderboard(fullLeaderboard, myPos.EntityID)
797+
// Use loader to get user (includes ChurchID)
798+
thunk := s.loaders.UserByIDLoader.Load(ctx, params.UserID)
799+
user, err := thunk()
800+
if err == nil && user != nil {
801+
meEntry = findMeInLeaderboard(fullLeaderboard, user.ChurchID)
735802
}
736803
}
737804

0 commit comments

Comments
 (0)