832 lines
25 KiB
Go
832 lines
25 KiB
Go
|
package sorare_utils
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"git.lehouerou.net/laurent/sorare"
|
||
|
"git.lehouerou.net/laurent/sorare/football"
|
||
|
"git.lehouerou.net/laurent/sorare/graphql"
|
||
|
gql "github.com/llehouerou/go-graphql-client"
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
"github.com/samber/lo"
|
||
|
|
||
|
"git.lehouerou.net/laurent/sorarebuddy/db"
|
||
|
"git.lehouerou.net/laurent/sorarebuddy/model"
|
||
|
)
|
||
|
|
||
|
type Updater struct {
|
||
|
s *sorare.Sorare
|
||
|
db *db.Client
|
||
|
|
||
|
countrySlugsToRead []string
|
||
|
competitionSlugsToRead []string
|
||
|
teamSlugsToRead []string
|
||
|
playerSlugsToRead []string
|
||
|
gamesFromFixtureSlugToRead []string
|
||
|
gamesToRead []string
|
||
|
gameFormationsToRead []string
|
||
|
gameScoresToReadFromMap map[string][]string
|
||
|
|
||
|
countryCache []sorare.Country
|
||
|
competitionCache []football.Competition
|
||
|
clubCache []football.Club
|
||
|
nationalTeamCache []football.NationalTeam
|
||
|
playerCache []football.Player
|
||
|
gameCache []football.Game
|
||
|
gamePlayersCache []model.GamePlayer
|
||
|
gameScoreCache []model.GamePlayerScore
|
||
|
}
|
||
|
|
||
|
type updaterOptions struct {
|
||
|
UpdateOnlyMissingCountries bool
|
||
|
UpdateOnlyMissingCompetitions bool
|
||
|
UpdateOnlyMissingTeams bool
|
||
|
UpdateOnlyMissingPlayers bool
|
||
|
}
|
||
|
type UpdaterOption func(*updaterOptions) *updaterOptions
|
||
|
|
||
|
func WithUpdateOnlyMissingCountries(value bool) UpdaterOption {
|
||
|
return func(o *updaterOptions) *updaterOptions {
|
||
|
o.UpdateOnlyMissingCountries = value
|
||
|
return o
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithUpdateOnlyMissingCompetitions(value bool) UpdaterOption {
|
||
|
return func(o *updaterOptions) *updaterOptions {
|
||
|
o.UpdateOnlyMissingCompetitions = value
|
||
|
return o
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithUpdateOnlyMissingTeams(value bool) UpdaterOption {
|
||
|
return func(o *updaterOptions) *updaterOptions {
|
||
|
o.UpdateOnlyMissingTeams = value
|
||
|
return o
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithUpdateOnlyMissingPlayers(value bool) UpdaterOption {
|
||
|
return func(o *updaterOptions) *updaterOptions {
|
||
|
o.UpdateOnlyMissingPlayers = value
|
||
|
return o
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func NewUpdater(s *sorare.Sorare, db *db.Client, opts ...UpdaterOption) *Updater {
|
||
|
return &Updater{
|
||
|
s: s,
|
||
|
db: db,
|
||
|
gameScoresToReadFromMap: make(map[string][]string),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (u *Updater) Reset() {
|
||
|
u.countrySlugsToRead = nil
|
||
|
u.competitionSlugsToRead = nil
|
||
|
u.teamSlugsToRead = nil
|
||
|
u.playerSlugsToRead = nil
|
||
|
u.gamesFromFixtureSlugToRead = nil
|
||
|
u.gamesToRead = nil
|
||
|
u.gameFormationsToRead = nil
|
||
|
for k := range u.gameScoresToReadFromMap {
|
||
|
delete(u.gameScoresToReadFromMap, k)
|
||
|
}
|
||
|
|
||
|
u.countryCache = nil
|
||
|
u.competitionCache = nil
|
||
|
u.clubCache = nil
|
||
|
u.nationalTeamCache = nil
|
||
|
u.playerCache = nil
|
||
|
u.gameCache = nil
|
||
|
u.gamePlayersCache = nil
|
||
|
u.gameScoreCache = nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) Update(ctx context.Context, opts ...UpdaterOption) error {
|
||
|
options := updaterOptions{
|
||
|
UpdateOnlyMissingCountries: true,
|
||
|
UpdateOnlyMissingCompetitions: true,
|
||
|
UpdateOnlyMissingTeams: false,
|
||
|
UpdateOnlyMissingPlayers: false,
|
||
|
}
|
||
|
for _, opt := range opts {
|
||
|
options = *opt(&options)
|
||
|
}
|
||
|
|
||
|
if err := u.readGamesFromFixture(ctx); err != nil {
|
||
|
return errors.Wrap(err, "reading games from fixture")
|
||
|
}
|
||
|
|
||
|
if err := u.readGames(ctx); err != nil {
|
||
|
return errors.Wrap(err, "reading games")
|
||
|
}
|
||
|
|
||
|
if err := u.readGamePlayers(ctx); err != nil {
|
||
|
return errors.Wrap(err, "reading game players")
|
||
|
}
|
||
|
|
||
|
if err := u.readGameScoresFromMap(ctx); err != nil {
|
||
|
return errors.Wrap(err, "reading game scores")
|
||
|
}
|
||
|
|
||
|
if err := u.readPlayers(ctx, options.UpdateOnlyMissingPlayers); err != nil {
|
||
|
return errors.Wrap(err, "reading players")
|
||
|
}
|
||
|
|
||
|
if err := u.readTeams(ctx, options.UpdateOnlyMissingTeams); err != nil {
|
||
|
return errors.Wrap(err, "reading teams")
|
||
|
}
|
||
|
|
||
|
if err := u.readCompetitions(ctx, options.UpdateOnlyMissingCompetitions); err != nil {
|
||
|
return errors.Wrap(err, "reading competitions")
|
||
|
}
|
||
|
|
||
|
if err := u.readCountries(ctx, options.UpdateOnlyMissingCountries); err != nil {
|
||
|
return errors.Wrap(err, "reading countries")
|
||
|
}
|
||
|
|
||
|
if err := u.writeCountries(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing countries")
|
||
|
}
|
||
|
|
||
|
if err := u.writeCompetitions(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing competitions")
|
||
|
}
|
||
|
|
||
|
if err := u.writeTeams(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing teams")
|
||
|
}
|
||
|
|
||
|
if err := u.writePlayers(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing players")
|
||
|
}
|
||
|
|
||
|
if err := u.writeGames(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing games")
|
||
|
}
|
||
|
|
||
|
if err := u.writeGamePlayers(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing game players")
|
||
|
}
|
||
|
|
||
|
if err := u.writeGameScores(ctx); err != nil {
|
||
|
return errors.Wrap(err, "writing game scores")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddCountriesToRead(slugs ...string) {
|
||
|
slugs = lo.Filter(slugs, func(slug string, index int) bool {
|
||
|
return slug != ""
|
||
|
})
|
||
|
u.countrySlugsToRead = lo.Uniq(append(u.countrySlugsToRead, slugs...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readCountries(ctx context.Context, onlyMissings bool) error {
|
||
|
if len(u.countrySlugsToRead) == 0 {
|
||
|
log.Debug().Msg("no countries to read")
|
||
|
return nil
|
||
|
}
|
||
|
log.Debug().Msgf("reading %d countries...", len(u.countrySlugsToRead))
|
||
|
slugs := u.countrySlugsToRead
|
||
|
u.countrySlugsToRead = nil
|
||
|
|
||
|
if onlyMissings {
|
||
|
log.Debug().Msgf("filtering countries in db...")
|
||
|
slugsNotInDb, err := u.db.Countries.GetCountrySlugsNotInDb(ctx, slugs)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "getting countries not in db")
|
||
|
}
|
||
|
slugs = slugsNotInDb
|
||
|
log.Debug().Msgf("%d countries not in db", len(slugs))
|
||
|
}
|
||
|
|
||
|
log.Debug().Msgf("getting countries from sorare...")
|
||
|
u.countryCache = nil
|
||
|
for i, chunk := range lo.Chunk(slugs, 100) {
|
||
|
log.Debug().Msgf("\tbatch %d/%d", i+1, (len(slugs)/100)+1)
|
||
|
c, err := u.s.Countries.Get(ctx, graphql.SlugsParams{Slugs: chunk})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
u.countryCache = append(u.countryCache, c...)
|
||
|
}
|
||
|
log.Debug().Msgf("%d countries fetched from sorare", len(u.countryCache))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeCountries(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting countries into db...")
|
||
|
err := u.db.Countries.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.Map(u.countryCache, func(country sorare.Country, index int) model.Country {
|
||
|
return model.Country{
|
||
|
Slug: country.Slug,
|
||
|
Code: country.Code,
|
||
|
DisplayName: country.Name,
|
||
|
ThreeLetterCode: country.ThreeLetterCode,
|
||
|
FlagFlat64Url: country.FlagFlat64Url,
|
||
|
FlagFlat32Url: country.FlagFlat32Url,
|
||
|
FlagRound64Url: country.FlagRound64Url,
|
||
|
FlagRound32Url: country.FlagRound32Url,
|
||
|
}
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting countries")
|
||
|
}
|
||
|
log.Debug().Msgf("%d countries inserted", len(u.countryCache))
|
||
|
u.countryCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddCompetitionsToRead(slugs ...string) {
|
||
|
slugs = lo.Filter(slugs, func(slug string, index int) bool {
|
||
|
return slug != ""
|
||
|
})
|
||
|
u.competitionSlugsToRead = lo.Uniq(append(u.competitionSlugsToRead, slugs...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readCompetitions(ctx context.Context, onlyMissings bool) error {
|
||
|
if len(u.competitionSlugsToRead) == 0 {
|
||
|
log.Debug().Msg("no competitions to read")
|
||
|
return nil
|
||
|
}
|
||
|
log.Debug().Msgf("reading %d competitions...", len(u.competitionSlugsToRead))
|
||
|
slugs := u.competitionSlugsToRead
|
||
|
u.competitionSlugsToRead = nil
|
||
|
|
||
|
if onlyMissings {
|
||
|
log.Debug().Msgf("filtering competitions not in db...")
|
||
|
slugsNotInDb, err := u.db.Competitions.GetCompetitionSlugsNotInDb(ctx, slugs)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "getting competitions not in db")
|
||
|
}
|
||
|
slugs = slugsNotInDb
|
||
|
log.Debug().Msgf("%d competitions not in db", len(slugs))
|
||
|
}
|
||
|
|
||
|
log.Debug().Msgf("getting competitions...")
|
||
|
u.competitionCache = nil
|
||
|
for _, slug := range slugs {
|
||
|
log.Debug().Msgf("\tcompetition %s", slug)
|
||
|
c, err := u.s.Football.Competition.Get(ctx, graphql.SlugParams{Slug: slug})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
u.competitionCache = append(u.competitionCache, c)
|
||
|
}
|
||
|
log.Debug().Msgf("found %d competitions", len(u.competitionCache))
|
||
|
|
||
|
u.AddCountriesToRead(lo.Map(u.competitionCache, func(c football.Competition, index int) string {
|
||
|
return c.Country.Slug
|
||
|
})...)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeCompetitions(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting competitions into db...")
|
||
|
|
||
|
err := u.db.Competitions.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.Map(u.competitionCache, func(competition football.Competition, index int) model.Competition {
|
||
|
return model.Competition{
|
||
|
Slug: competition.Slug,
|
||
|
CompetitionFormat: competition.Format,
|
||
|
CompetitionType: competition.Type,
|
||
|
DisplayName: competition.DisplayName,
|
||
|
PictureUrl: competition.PictureUrl,
|
||
|
LogoUrl: competition.LogoUrl,
|
||
|
CountrySlug: competition.Country.Slug,
|
||
|
}
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting competitions")
|
||
|
}
|
||
|
log.Debug().Msgf("%d competitions inserted", len(u.competitionCache))
|
||
|
u.competitionCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddTeamsToRead(slugs ...string) {
|
||
|
slugs = lo.Filter(slugs, func(slug string, index int) bool {
|
||
|
return slug != ""
|
||
|
})
|
||
|
u.teamSlugsToRead = lo.Uniq(append(u.teamSlugsToRead, slugs...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readTeams(ctx context.Context, onlyMissings bool) error {
|
||
|
if len(u.teamSlugsToRead) == 0 {
|
||
|
log.Debug().Msg("no teams to read")
|
||
|
return nil
|
||
|
}
|
||
|
log.Debug().Msgf("reading %d teams...", len(u.teamSlugsToRead))
|
||
|
slugs := u.teamSlugsToRead
|
||
|
u.teamSlugsToRead = nil
|
||
|
|
||
|
log.Debug().Msgf("getting clubs...")
|
||
|
if onlyMissings {
|
||
|
log.Debug().Msgf("filtering clubs not in db...")
|
||
|
slugsNotInDb, err := u.db.Teams.GetTeamSlugsNotInDb(ctx, slugs)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "getting teams not in db")
|
||
|
}
|
||
|
slugs = slugsNotInDb
|
||
|
log.Debug().Msgf("%d clubs not in db", len(slugs))
|
||
|
}
|
||
|
|
||
|
u.clubCache = nil
|
||
|
for i, chunk := range lo.Chunk(slugs, 100) {
|
||
|
log.Debug().Msgf("\tbatch %d/%d", i+1, (len(slugs)/100)+1)
|
||
|
t, err := u.s.Football.Clubs.Get(ctx, graphql.SlugsParams{Slugs: chunk})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
u.clubCache = append(u.clubCache, t...)
|
||
|
}
|
||
|
log.Debug().Msgf("found %d clubs", len(u.clubCache))
|
||
|
slugsLeft := lo.Without(slugs, lo.Map(u.clubCache, func(club football.Club, index int) string {
|
||
|
return club.Slug
|
||
|
})...)
|
||
|
u.nationalTeamCache = nil
|
||
|
log.Debug().Msgf("getting national teams...")
|
||
|
log.Debug().Msgf("slugs left: %d", len(slugsLeft))
|
||
|
for i, chunk := range lo.Chunk(slugsLeft, 100) {
|
||
|
log.Debug().Msgf("\tbatch %d/%d", i+1, (len(slugsLeft)/100)+1)
|
||
|
t, err := u.s.Football.NationalTeams.Get(ctx, graphql.SlugsParams{Slugs: chunk})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
u.nationalTeamCache = append(u.nationalTeamCache, t...)
|
||
|
}
|
||
|
log.Debug().Msgf("found %d national teams", len(u.nationalTeamCache))
|
||
|
|
||
|
u.AddCompetitionsToRead(lo.Map(u.clubCache, func(club football.Club, index int) string {
|
||
|
return club.DomesticLeague.Slug
|
||
|
})...)
|
||
|
|
||
|
u.AddCountriesToRead(lo.Map(u.clubCache, func(club football.Club, index int) string {
|
||
|
return club.Country.Slug
|
||
|
})...)
|
||
|
|
||
|
u.AddCountriesToRead(lo.Map(u.nationalTeamCache, func(nationalTeam football.NationalTeam, index int) string {
|
||
|
return nationalTeam.Country.Slug
|
||
|
})...)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeTeams(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting teams into db...")
|
||
|
err := u.db.Teams.CreateOrUpdateMany(ctx, lo.Union(
|
||
|
lo.Map(u.clubCache, func(club football.Club, index int) model.Team {
|
||
|
return model.Team{
|
||
|
Slug: club.Slug,
|
||
|
DisplayName: club.Name,
|
||
|
CountrySlug: club.Country.Slug,
|
||
|
DomesticLeagueSlug: func() *string {
|
||
|
if club.DomesticLeague.Slug == "" {
|
||
|
return nil
|
||
|
}
|
||
|
return &club.DomesticLeague.Slug
|
||
|
}(),
|
||
|
ShortName: club.ShortName,
|
||
|
PictureUrl: club.PictureUrl,
|
||
|
TeamType: "club",
|
||
|
}
|
||
|
}),
|
||
|
lo.Map(u.nationalTeamCache, func(nationalTeam football.NationalTeam, index int) model.Team {
|
||
|
return model.Team{
|
||
|
Slug: nationalTeam.Slug,
|
||
|
DisplayName: nationalTeam.Name,
|
||
|
CountrySlug: nationalTeam.Country.Slug,
|
||
|
DomesticLeagueSlug: nil,
|
||
|
ShortName: nationalTeam.ShortName,
|
||
|
PictureUrl: nationalTeam.PictureUrl,
|
||
|
TeamType: "national",
|
||
|
}
|
||
|
}),
|
||
|
))
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting teams")
|
||
|
}
|
||
|
log.Debug().Msgf("%d teams inserted", len(u.clubCache)+len(u.nationalTeamCache))
|
||
|
u.clubCache = nil
|
||
|
u.nationalTeamCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddPlayersToRead(slugs ...string) {
|
||
|
slugs = lo.Filter(slugs, func(slug string, index int) bool {
|
||
|
return slug != ""
|
||
|
})
|
||
|
u.playerSlugsToRead = lo.Uniq(append(u.playerSlugsToRead, slugs...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readPlayers(ctx context.Context, onlyMissings bool) error {
|
||
|
if len(u.playerSlugsToRead) == 0 {
|
||
|
log.Debug().Msg("no players to read")
|
||
|
return nil
|
||
|
}
|
||
|
slugs := u.playerSlugsToRead
|
||
|
u.playerSlugsToRead = nil
|
||
|
|
||
|
log.Debug().Msgf("updating %d players", len(slugs))
|
||
|
|
||
|
if onlyMissings {
|
||
|
log.Debug().Msgf("filtering players not in db...")
|
||
|
slugsNotInDb, err := u.db.Players.GetPlayerSlugsNotInDb(ctx, slugs)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "getting players not in db")
|
||
|
}
|
||
|
slugs = slugsNotInDb
|
||
|
log.Debug().Msgf("%d players not in db", len(slugs))
|
||
|
}
|
||
|
|
||
|
log.Debug().Msgf("getting players from sorare...")
|
||
|
u.playerCache = nil
|
||
|
for i, chunk := range lo.Chunk(slugs, 65) {
|
||
|
log.Debug().Msgf("\tbatch %d/%d", i+1, (len(slugs)/65)+1)
|
||
|
p, err := u.s.Football.Players.Get(ctx, graphql.SlugsParams{Slugs: chunk})
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "getting players batch %d", i)
|
||
|
}
|
||
|
u.playerCache = append(u.playerCache, p...)
|
||
|
}
|
||
|
log.Debug().Msgf("found %d players", len(u.playerCache))
|
||
|
|
||
|
u.AddTeamsToRead(lo.FlatMap(u.playerCache, func(player football.Player, index int) []string {
|
||
|
var res []string
|
||
|
res = append(res, player.ActiveClub.Slug)
|
||
|
res = append(res, player.ActiveNationalTeam.Slug)
|
||
|
res = append(res, lo.Map(player.Memberships, func(membership football.Membership, index int) string {
|
||
|
if membership.MembershipTeam.Club.Slug != "" {
|
||
|
return membership.MembershipTeam.Club.Slug
|
||
|
} else if membership.MembershipTeam.NationalTeam.Slug != "" {
|
||
|
return membership.MembershipTeam.NationalTeam.Slug
|
||
|
}
|
||
|
return ""
|
||
|
})...)
|
||
|
return res
|
||
|
})...)
|
||
|
|
||
|
u.AddCompetitionsToRead(lo.Map(u.playerCache, func(player football.Player, index int) string {
|
||
|
var res string
|
||
|
for _, competition := range player.ActiveClub.ActiveCompetitions {
|
||
|
if competition.Format == "DOMESTIC_LEAGUE" {
|
||
|
res = competition.Slug
|
||
|
}
|
||
|
}
|
||
|
return res
|
||
|
})...)
|
||
|
|
||
|
u.AddCountriesToRead(lo.Map(u.playerCache, func(player football.Player, index int) string {
|
||
|
return player.Country.Slug
|
||
|
})...)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writePlayers(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting players into db...")
|
||
|
err := u.db.Players.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.Map(u.playerCache, func(player football.Player, index int) model.Player {
|
||
|
res := model.Player{
|
||
|
Slug: player.Slug,
|
||
|
DisplayName: player.DisplayName,
|
||
|
BirthDate: player.BirthDate,
|
||
|
CountrySlug: player.Country.Slug,
|
||
|
AvatarUrl: player.AvatarUrl,
|
||
|
FieldPosition: string(player.Position),
|
||
|
Status: string(player.PlayingStatus),
|
||
|
ShirtNumber: int(player.ShirtNumber),
|
||
|
ActiveNationalTeamSlug: func() *string {
|
||
|
if player.ActiveNationalTeam.Slug == "" {
|
||
|
return nil
|
||
|
}
|
||
|
return &player.ActiveNationalTeam.Slug
|
||
|
}(),
|
||
|
}
|
||
|
for _, competition := range player.ActiveClub.ActiveCompetitions {
|
||
|
if competition.Format == "DOMESTIC_LEAGUE" {
|
||
|
res.DomesticLeagueSlug = &competition.Slug
|
||
|
}
|
||
|
}
|
||
|
if player.ActiveClub.Slug != "" {
|
||
|
res.TeamSlug = &player.ActiveClub.Slug
|
||
|
}
|
||
|
return res
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting players")
|
||
|
}
|
||
|
log.Debug().Msgf("%d players inserted", len(u.playerCache))
|
||
|
|
||
|
log.Debug().Msgf("inserting players card supply into db...")
|
||
|
err = u.db.CardSupplies.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.FlatMap(u.playerCache, func(player football.Player, index int) []model.CardSupply {
|
||
|
var res []model.CardSupply
|
||
|
for _, supply := range player.CardSupply {
|
||
|
res = append(res, model.CardSupply{
|
||
|
PlayerSlug: player.Slug,
|
||
|
SeasonStartYear: supply.Season.StartYear,
|
||
|
Limited: supply.Limited,
|
||
|
Rare: supply.Rare,
|
||
|
SuperRare: supply.SuperRare,
|
||
|
Unique: supply.Unique,
|
||
|
LastUpdated: time.Now(),
|
||
|
})
|
||
|
}
|
||
|
return res
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting players card supply")
|
||
|
}
|
||
|
log.Debug().Msgf("%d players card supply inserted", len(u.playerCache))
|
||
|
|
||
|
log.Debug().Msgf("inserting players club_memberships into db...")
|
||
|
err = u.db.Memberships.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.FlatMap(u.playerCache, func(player football.Player, index int) []model.Membership {
|
||
|
var res []model.Membership
|
||
|
for _, membership := range player.Memberships {
|
||
|
new := model.Membership{
|
||
|
Id: membership.Id.Value,
|
||
|
PlayerSlug: player.Slug,
|
||
|
StartDate: membership.StartDate,
|
||
|
EndDate: membership.EndDate,
|
||
|
}
|
||
|
if membership.MembershipTeam.TypeName == "Club" {
|
||
|
new.TeamSlug = membership.MembershipTeam.Club.Slug
|
||
|
new.MembershipType = "club"
|
||
|
} else if membership.MembershipTeam.TypeName == "NationalTeam" {
|
||
|
new.TeamSlug = membership.MembershipTeam.NationalTeam.Slug
|
||
|
new.MembershipType = "national"
|
||
|
} else {
|
||
|
continue
|
||
|
}
|
||
|
res = append(res, new)
|
||
|
}
|
||
|
return res
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting players club_memberships")
|
||
|
}
|
||
|
log.Debug().Msgf("%d players club_memberships inserted", len(u.playerCache))
|
||
|
|
||
|
u.playerCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddGamesFromFixtureToRead(slugs ...string) {
|
||
|
slugs = lo.Filter(slugs, func(slug string, index int) bool {
|
||
|
return slug != ""
|
||
|
})
|
||
|
u.gamesFromFixtureSlugToRead = lo.Uniq(append(u.gamesFromFixtureSlugToRead, slugs...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readGamesFromFixture(ctx context.Context) error {
|
||
|
if len(u.gamesFromFixtureSlugToRead) == 0 {
|
||
|
log.Debug().Msg("no games from fixture to read")
|
||
|
return nil
|
||
|
}
|
||
|
slugs := u.gamesFromFixtureSlugToRead
|
||
|
u.gamesFromFixtureSlugToRead = nil
|
||
|
|
||
|
log.Debug().Msgf("updating games for fixtures %v", slugs)
|
||
|
u.gameCache = nil
|
||
|
for _, slug := range slugs {
|
||
|
log.Debug().Msgf("getting games for fixture %s...", slug)
|
||
|
g, err := u.s.Football.So5.FixtureGames(slug).Get(ctx, graphql.EmptyParams{})
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "getting games for fixture %s", slug)
|
||
|
}
|
||
|
g = lo.Filter(g, func(game football.Game, index int) bool {
|
||
|
return game.Id.Value != ""
|
||
|
})
|
||
|
log.Debug().Msgf("found %d games", len(g))
|
||
|
u.gameCache = append(u.gameCache, g...)
|
||
|
}
|
||
|
u.gameCache = lo.Filter(u.gameCache, func(game football.Game, index int) bool {
|
||
|
return game.So5Fixture.Slug != ""
|
||
|
})
|
||
|
u.gameCache = lo.UniqBy(u.gameCache, func(game football.Game) string {
|
||
|
return game.Id.Value
|
||
|
})
|
||
|
u.AddTeamsToRead(lo.Union(
|
||
|
lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.AwayTeam.Team.Slug
|
||
|
}),
|
||
|
lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.HomeTeam.Team.Slug
|
||
|
}),
|
||
|
)...)
|
||
|
u.AddCompetitionsToRead(lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.Competition.Slug
|
||
|
})...)
|
||
|
u.AddGameFormationsToRead(lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.Id.Value
|
||
|
})...)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeGames(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting games into db...")
|
||
|
err := u.db.Games.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
lo.Map(u.gameCache, func(game football.Game, index int) model.Game {
|
||
|
return NewGameFromSorare(game)
|
||
|
}),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting games")
|
||
|
}
|
||
|
log.Debug().Msgf("%d games inserted", len(u.gameCache))
|
||
|
u.gameCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddGameFormationsToRead(ids ...string) {
|
||
|
ids = lo.Filter(ids, func(id string, index int) bool {
|
||
|
return id != ""
|
||
|
})
|
||
|
u.gameFormationsToRead = lo.Uniq(append(u.gameFormationsToRead, ids...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readGamePlayers(ctx context.Context) error {
|
||
|
if len(u.gameFormationsToRead) == 0 {
|
||
|
log.Debug().Msg("no game formations to read")
|
||
|
return nil
|
||
|
}
|
||
|
ids := u.gameFormationsToRead
|
||
|
u.gameFormationsToRead = nil
|
||
|
playerSlugsByGameMap := make(map[string][]string)
|
||
|
for _, chunk := range lo.Chunk(ids, 50) {
|
||
|
gamesWithFormation, err := u.s.Football.GamesFormation.Get(ctx, chunk)
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "getting games with formation for games %v", ids)
|
||
|
}
|
||
|
for _, game := range gamesWithFormation {
|
||
|
newplayers := model.ExtractPlayersFromGameWithFormation(game)
|
||
|
log.Debug().Msgf("\t%s -> %d players", game.Id.Value, len(newplayers))
|
||
|
playerSlugsByGameMap[game.Id.Value] = lo.Map(
|
||
|
newplayers,
|
||
|
func(player model.GamePlayer, index int) string {
|
||
|
return player.PlayerSlug
|
||
|
},
|
||
|
)
|
||
|
u.gamePlayersCache = append(u.gamePlayersCache, newplayers...)
|
||
|
}
|
||
|
}
|
||
|
u.gamePlayersCache = lo.UniqBy(u.gamePlayersCache, func(player model.GamePlayer) string {
|
||
|
return player.GameId + "-" + player.PlayerSlug
|
||
|
})
|
||
|
u.AddPlayersToRead(lo.Map(u.gamePlayersCache, func(player model.GamePlayer, index int) string {
|
||
|
return player.PlayerSlug
|
||
|
})...)
|
||
|
u.AddGameScoresFromMapToRead(playerSlugsByGameMap)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeGamePlayers(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting game players into db...")
|
||
|
err := u.db.GamePlayers.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
u.gamePlayersCache,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting game players")
|
||
|
}
|
||
|
log.Debug().Msgf("%d game players inserted", len(u.gamePlayersCache))
|
||
|
u.gamePlayersCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddGameScoresFromMapToRead(gameScores map[string][]string) {
|
||
|
for gameId, playerSlugs := range gameScores {
|
||
|
u.gameScoresToReadFromMap[gameId] = append(u.gameScoresToReadFromMap[gameId], playerSlugs...)
|
||
|
}
|
||
|
for gameId, playerSlugs := range u.gameScoresToReadFromMap {
|
||
|
u.gameScoresToReadFromMap[gameId] = lo.Uniq(playerSlugs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readGameScoresFromMap(ctx context.Context) error {
|
||
|
if len(u.gameScoresToReadFromMap) == 0 {
|
||
|
log.Debug().Msg("no game scores to read")
|
||
|
return nil
|
||
|
}
|
||
|
for gameId, playerSlugs := range u.gameScoresToReadFromMap {
|
||
|
if len(playerSlugs) == 0 {
|
||
|
delete(u.gameScoresToReadFromMap, gameId)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gameIdList := lo.MapToSlice(u.gameScoresToReadFromMap, func(key string, value []string) string {
|
||
|
return key
|
||
|
})
|
||
|
|
||
|
for _, gameIds := range lo.Chunk(gameIdList, 2) {
|
||
|
log.Debug().Msgf("getting scores for games %v", gameIds)
|
||
|
params := make(map[string][]string)
|
||
|
for _, gameId := range gameIds {
|
||
|
if u.gameScoresToReadFromMap[gameId] != nil && len(u.gameScoresToReadFromMap[gameId]) > 0 {
|
||
|
params[gameId] = u.gameScoresToReadFromMap[gameId]
|
||
|
}
|
||
|
}
|
||
|
if len(params) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
scores, err := u.s.Football.GamesScores.Get(ctx, params)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "getting scores")
|
||
|
}
|
||
|
scores = lo.Filter(scores, func(score football.So5Score, index int) bool {
|
||
|
return score.Player.Slug != "" && score.Game.Id.Value != ""
|
||
|
})
|
||
|
u.gameScoreCache = append(u.gameScoreCache, lo.Map(
|
||
|
scores,
|
||
|
func(score football.So5Score, index int) model.GamePlayerScore {
|
||
|
return NewGamePlayerScoreFromSorare(score.Game.Id.Value, score)
|
||
|
},
|
||
|
)...)
|
||
|
}
|
||
|
for k := range u.gameScoresToReadFromMap {
|
||
|
delete(u.gameScoresToReadFromMap, k)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) writeGameScores(ctx context.Context) error {
|
||
|
log.Debug().Msg("inserting game scores from map into db...")
|
||
|
err := u.db.GamePlayerScores.CreateOrUpdateMany(
|
||
|
ctx,
|
||
|
u.gameScoreCache,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "inserting game scores from map")
|
||
|
}
|
||
|
log.Debug().Msgf("%d game scores from map inserted", len(u.gameScoreCache))
|
||
|
u.gameScoreCache = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (u *Updater) AddGamesToRead(ids ...string) {
|
||
|
ids = lo.Filter(ids, func(id string, index int) bool {
|
||
|
return id != ""
|
||
|
})
|
||
|
u.gamesToRead = lo.Uniq(append(u.gamesToRead, ids...))
|
||
|
}
|
||
|
|
||
|
func (u *Updater) readGames(ctx context.Context) error {
|
||
|
if len(u.gamesToRead) == 0 {
|
||
|
log.Debug().Msg("no games to read")
|
||
|
return nil
|
||
|
}
|
||
|
ids := u.gamesToRead
|
||
|
u.gamesToRead = nil
|
||
|
|
||
|
log.Debug().Msgf("updating games %v", ids)
|
||
|
u.gameCache = nil
|
||
|
for _, id := range ids {
|
||
|
g, err := u.s.Football.Game.Get(ctx, graphql.IdParams{Id: gql.ID(id)})
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "getting game %s", id)
|
||
|
}
|
||
|
u.gameCache = append(u.gameCache, g.Game)
|
||
|
}
|
||
|
u.gameCache = lo.Filter(u.gameCache, func(game football.Game, index int) bool {
|
||
|
return game.So5Fixture.Slug != ""
|
||
|
})
|
||
|
u.gameCache = lo.UniqBy(u.gameCache, func(game football.Game) string {
|
||
|
return game.Id.Value
|
||
|
})
|
||
|
u.AddTeamsToRead(lo.Union(
|
||
|
lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.AwayTeam.Team.Slug
|
||
|
}),
|
||
|
lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.HomeTeam.Team.Slug
|
||
|
}),
|
||
|
)...)
|
||
|
u.AddCompetitionsToRead(lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.Competition.Slug
|
||
|
})...)
|
||
|
u.AddGameFormationsToRead(lo.Map(u.gameCache, func(game football.Game, index int) string {
|
||
|
return game.Id.Value
|
||
|
})...)
|
||
|
return nil
|
||
|
}
|