diff --git a/internal/cron/tasks/helpers.go b/internal/cron/tasks/helpers.go index 38efb20..e727803 100644 --- a/internal/cron/tasks/helpers.go +++ b/internal/cron/tasks/helpers.go @@ -99,18 +99,6 @@ type searchableByID interface { len() int } -func makePlayersSearchable(players []*models.Player) searchableByID { - return playersSearchableByID{ - players: players, - } -} - -func makeTribesSearchable(tribes []*models.Tribe) searchableByID { - return tribesSearchableByID{ - tribes: tribes, - } -} - func searchByID(haystack searchableByID, id int) int { low := 0 high := haystack.len() - 1 diff --git a/internal/cron/tasks/task_update_server_data.go b/internal/cron/tasks/task_update_server_data.go index e6d070f..44c4ba1 100644 --- a/internal/cron/tasks/task_update_server_data.go +++ b/internal/cron/tasks/task_update_server_data.go @@ -107,13 +107,13 @@ func (w *workerUpdateServerData) loadPlayers(od map[int]*models.OpponentsDefeate result.ids[index] = player.ID } - searchableNewPlayers := &playersSearchableByID{result.players} + searchablePlayers := &playersSearchableByID{result.players} if err := w.db. Model(&models.Player{}). Column("id"). Where("exists = true"). ForEach(func(player *models.Player) error { - if index := searchByID(searchableNewPlayers, player.ID); index < 0 { + if index := searchByID(searchablePlayers, player.ID); index < 0 { result.deletedPlayers = append(result.deletedPlayers, player.ID) } return nil @@ -124,12 +124,24 @@ func (w *workerUpdateServerData) loadPlayers(od map[int]*models.OpponentsDefeate return result, nil } -func (w *workerUpdateServerData) loadTribes(od map[int]*models.OpponentsDefeated, numberOfVillages int) ([]*models.Tribe, error) { - tribes, err := w.dataloader.LoadTribes() +type loadTribesResult struct { + ids []int + tribes []*models.Tribe + deletedTribes []int + numberOfTribes int +} + +func (w *workerUpdateServerData) loadTribes(od map[int]*models.OpponentsDefeated, numberOfVillages int) (loadTribesResult, error) { + var err error + result := loadTribesResult{} + result.tribes, err = w.dataloader.LoadTribes() if err != nil { - return nil, err + return result, errors.Wrap(err, "workerUpdateServerData.loadTribes") } - for _, tribe := range tribes { + + result.numberOfTribes = len(result.tribes) + result.ids = make([]int, result.numberOfTribes) + for index, tribe := range result.tribes { tribeOD, ok := od[tribe.ID] if ok { tribe.OpponentsDefeated = *tribeOD @@ -139,8 +151,24 @@ func (w *workerUpdateServerData) loadTribes(od map[int]*models.OpponentsDefeated } else { tribe.Dominance = 0 } + result.ids[index] = tribe.ID } - return tribes, nil + + searchableTribes := &tribesSearchableByID{result.tribes} + if err := w.db. + Model(&models.Tribe{}). + Column("id"). + Where("exists = true"). + ForEach(func(tribe *models.Tribe) error { + if index := searchByID(searchableTribes, tribe.ID); index < 0 { + result.deletedTribes = append(result.deletedTribes, tribe.ID) + } + return nil + }); err != nil { + return result, errors.Wrap(err, "workerUpdateServerData.loadTribes: Tribes that have been deleted couldn't be detected") + } + + return result, nil } func (w *workerUpdateServerData) calculateODifference(od1 models.OpponentsDefeated, od2 models.OpponentsDefeated) models.OpponentsDefeated { @@ -161,7 +189,7 @@ func (w *workerUpdateServerData) calculateTodaysTribeStats( history []*models.TribeHistory, ) []*models.DailyTribeStats { var todaysStats []*models.DailyTribeStats - searchableTribes := makeTribesSearchable(tribes) + searchableTribes := &tribesSearchableByID{tribes} for _, historyRecord := range history { if index := searchByID(searchableTribes, historyRecord.TribeID); index != -1 { @@ -183,10 +211,12 @@ func (w *workerUpdateServerData) calculateTodaysTribeStats( return todaysStats } -func (w *workerUpdateServerData) calculateDailyPlayerStats(players []*models.Player, - history []*models.PlayerHistory) []*models.DailyPlayerStats { +func (w *workerUpdateServerData) calculateDailyPlayerStats( + players []*models.Player, + history []*models.PlayerHistory, +) []*models.DailyPlayerStats { var todaysStats []*models.DailyPlayerStats - searchablePlayers := makePlayersSearchable(players) + searchablePlayers := &playersSearchableByID{players} for _, historyRecord := range history { if index := searchByID(searchablePlayers, historyRecord.PlayerID); index != -1 { @@ -222,11 +252,10 @@ func (w *workerUpdateServerData) update() error { } numberOfVillages := len(villages) - tribes, err := w.loadTribes(tod, countPlayerVillages(villages)) + tribesResult, err := w.loadTribes(tod, countPlayerVillages(villages)) if err != nil { return errors.Wrap(err, "workerUpdateServerData.update") } - numberOfTribes := len(tribes) playersResult, err := w.loadPlayers(pod) if err != nil { @@ -249,13 +278,19 @@ func (w *workerUpdateServerData) update() error { } return w.db.RunInTransaction(context.Background(), func(tx *pg.Tx) error { - if len(tribes) > 0 { - ids := make([]int, len(tribes)) - for index, tribe := range tribes { - ids[index] = tribe.ID + if len(tribesResult.deletedTribes) > 0 { + if _, err := tx.Model(&models.Tribe{}). + Where("tribe.id = ANY (?)", pg.Array(tribesResult.deletedTribes)). + Set("exists = false"). + Set("deleted_at = now()"). + Set("dominance = 0"). + Update(); err != nil && err != pg.ErrNoRows { + return errors.Wrap(err, "couldn't update non-existent tribes") } + } - if _, err := tx.Model(&tribes). + if tribesResult.numberOfTribes > 0 { + if _, err := tx.Model(&tribesResult.tribes). OnConflict("(id) DO UPDATE"). Set("name = EXCLUDED.name"). Set("tag = EXCLUDED.tag"). @@ -271,14 +306,6 @@ func (w *workerUpdateServerData) update() error { Insert(); err != nil { return errors.Wrap(err, "couldn't insert tribes") } - if _, err := tx.Model(&tribes). - Where("NOT (tribe.id = ANY (?))", pg.Array(ids)). - Set("exists = false"). - Set("deleted_at = now()"). - Set("dominance = 0"). - Update(); err != nil && err != pg.ErrNoRows { - return errors.Wrap(err, "couldn't update non-existent tribes") - } var tribesHistory []*models.TribeHistory if err := tx. @@ -291,7 +318,7 @@ func (w *workerUpdateServerData) update() error { Select(); err != nil && err != pg.ErrNoRows { return errors.Wrap(err, "couldn't select tribe history records") } - todaysTribeStats := w.calculateTodaysTribeStats(tribes, tribesHistory) + todaysTribeStats := w.calculateTodaysTribeStats(tribesResult.tribes, tribesHistory) if len(todaysTribeStats) > 0 { if _, err := tx. Model(&todaysTribeStats). @@ -385,7 +412,7 @@ func (w *workerUpdateServerData) update() error { Set("building_config = ?", buildingCfg). Set("config = ?", cfg). Set("number_of_players = ?", playersResult.numberOfPlayers). - Set("number_of_tribes = ?", numberOfTribes). + Set("number_of_tribes = ?", tribesResult.numberOfTribes). Set("number_of_villages = ?", numberOfVillages). Returning("*"). WherePK().