Compare commits

..

8 Commits

9 changed files with 130 additions and 32 deletions

4
.gitignore vendored
View File

@ -1 +1,5 @@
.vscode/ .vscode/
go.work
go.work.sum

View File

@ -13,8 +13,8 @@ import (
func main() { func main() {
token := os.Getenv("SORARE_TOKEN") token := os.Getenv("JWTTOKEN")
audience := os.Getenv("SORARE_AUDIENCE") audience := os.Getenv("JWTAUDIENCE")
if token == "" { if token == "" {
log.Fatal("No token provided") log.Fatal("No token provided")
} }

View File

@ -17,6 +17,7 @@ type Football struct {
ClubsReady *graphql.Query[[]Club, graphql.EmptyParams] ClubsReady *graphql.Query[[]Club, graphql.EmptyParams]
Competition *graphql.Query[Competition, graphql.SlugParams] Competition *graphql.Query[Competition, graphql.SlugParams]
Game *graphql.Query[GameWithFormation, graphql.IdParams] Game *graphql.Query[GameWithFormation, graphql.IdParams]
GamesFormation *GamesFormationQuery
MyLiveGames *graphql.Query[[]Game, graphql.EmptyParams] MyLiveGames *graphql.Query[[]Game, graphql.EmptyParams]
NationalTeam *graphql.Query[NationalTeam, graphql.SlugParams] NationalTeam *graphql.Query[NationalTeam, graphql.SlugParams]
NationalTeams *graphql.Query[[]NationalTeam, graphql.SlugsParams] NationalTeams *graphql.Query[[]NationalTeam, graphql.SlugsParams]
@ -77,6 +78,9 @@ func NewFootball(c *graphql.Client) *Football {
"game", "game",
[]string{"football"}, []string{"football"},
), ),
GamesFormation: NewGamesFormationQuery(
c,
),
MyLiveGames: graphql.NewQuery[[]Game, graphql.EmptyParams]( MyLiveGames: graphql.NewQuery[[]Game, graphql.EmptyParams](
c, c,
"myLiveGames", "myLiveGames",

View File

@ -0,0 +1,74 @@
package football
import (
"context"
"fmt"
"github.com/pkg/errors"
"git.lehouerou.net/laurent/sorare/graphql"
)
type GamesFormationQuery struct {
c *graphql.Client
}
type GameFormation struct {
Id graphql.Id `graphql:"id"`
AwayTeam struct {
Team struct {
Slug string `graphql:"slug"`
} `graphql:"... on TeamInterface"`
} `graphql:"awayTeam"`
AwayFormation struct {
Bench []struct {
Slug string `graphql:"slug"`
} `graphql:"bench"`
StartingLineup [][]struct {
Slug string `graphql:"slug"`
} `graphql:"startingLineup"`
} `graphql:"awayFormation"`
HomeTeam struct {
Team struct {
Slug string `graphql:"slug"`
} `graphql:"... on TeamInterface"`
} `graphql:"homeTeam"`
HomeFormation struct {
Bench []struct {
Slug string `graphql:"slug"`
} `graphql:"bench"`
StartingLineup [][]struct {
Slug string `graphql:"slug"`
} `graphql:"startingLineup"`
} `graphql:"homeFormation"`
}
func NewGamesFormationQuery(c *graphql.Client) *GamesFormationQuery {
return &GamesFormationQuery{
c: c,
}
}
func (r *GamesFormationQuery) Get(ctx context.Context, gameIds []string) ([]GameFormation, error) {
var q struct {
Football [][2]interface{} `graphql:"football"`
}
q.Football = make([][2]interface{}, len(gameIds))
for i, id := range gameIds {
var game GameFormation
q.Football[i] = [2]interface{}{fmt.Sprintf("game%d:game(id:\"%s\")", i, id), &game}
}
err := r.c.Query(ctx, &q, nil)
if err != nil {
return nil, errors.Wrap(err, "querying games")
}
var res []GameFormation
for _, g := range q.Football {
res = append(res, *g[1].(*GameFormation))
}
return res, nil
}

3
go.mod
View File

@ -15,6 +15,8 @@ require (
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
) )
require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
require ( require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/compress v1.16.7 // indirect
@ -22,6 +24,5 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
golang.org/x/net v0.21.0 // indirect golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect golang.org/x/sys v0.18.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
nhooyr.io/websocket v1.8.7 // indirect nhooyr.io/websocket v1.8.7 // indirect
) )

View File

@ -80,6 +80,21 @@ func (c *Client) Query(
return c.gql.Query(ctx, q, variables, options...) return c.gql.Query(ctx, q, variables, options...)
} }
func (c *Client) QueryRaw(
ctx context.Context,
q interface{},
variables interface{},
options ...graphql.Option,
) ([]byte, error) {
err := c.rl.Wait(ctx)
if err != nil {
return nil, errors.Wrap(err, "waiting for rate limit")
}
c.lock.Lock()
defer c.lock.Unlock()
return c.gql.QueryRaw(ctx, q, variables, options...)
}
func (c *Client) Mutate( func (c *Client) Mutate(
ctx context.Context, ctx context.Context,
q interface{}, q interface{},

View File

@ -41,7 +41,7 @@ func (m *Mutation[Payload, Params]) WithQueryParam(
func (m *Mutation[Payload, Params]) Execute(ctx context.Context, params Params) (Payload, error) { func (m *Mutation[Payload, Params]) Execute(ctx context.Context, params Params) (Payload, error) {
paramsMap := convertParamsToMap[Params](params) paramsMap := convertParamsToMap(params)
for k, v := range m.additionalPayloadParams { for k, v := range m.additionalPayloadParams {
paramsMap[k] = v paramsMap[k] = v
} }
@ -53,7 +53,7 @@ func (m *Mutation[Payload, Params]) Execute(ctx context.Context, params Params)
} }
gqltype = fmt.Sprintf("%s(%s)", gqltype, strings.Join(keys, ",")) gqltype = fmt.Sprintf("%s(%s)", gqltype, strings.Join(keys, ","))
} }
q := NewPayload[Payload, Params](gqltype) q := NewPayload[Payload](gqltype)
for k, v := range m.additionalQueryParams { for k, v := range m.additionalQueryParams {
paramsMap[k] = v paramsMap[k] = v
} }

View File

@ -1,10 +1,10 @@
package graphql package graphql
type Payload[T any, P any] struct { type Payload[T any] struct {
OutermostLayer ContainerLayer[T, P] OutermostLayer ContainerLayer[T]
} }
func (q *Payload[T, P]) GetValue() T { func (q *Payload[T]) GetValue() T {
if q.OutermostLayer == nil { if q.OutermostLayer == nil {
var res T var res T
return res return res
@ -16,74 +16,74 @@ func (q *Payload[T, P]) GetValue() T {
return layer.GetValue() return layer.GetValue()
} }
func NewPayload[T any, P any](gqlType string, containerLayers ...string) *Payload[T, P] { func NewPayload[T any](gqlType string, containerLayers ...string) *Payload[T] {
if len(containerLayers) == 0 { if len(containerLayers) == 0 {
return &Payload[T, P]{ return &Payload[T]{
OutermostLayer: NewWrapper[T, P](gqlType), OutermostLayer: NewWrapper[T](gqlType),
} }
} }
var buildLayer func(index int) ContainerLayer[T, P] var buildLayer func(index int) ContainerLayer[T]
buildLayer = func(index int) ContainerLayer[T, P] { buildLayer = func(index int) ContainerLayer[T] {
if index == len(containerLayers) { if index == len(containerLayers) {
return NewWrapper[T, P](gqlType) return NewWrapper[T](gqlType)
} }
return &NestedLayer[T, P]{ return &NestedLayer[T]{
gqlType: containerLayers[index], gqlType: containerLayers[index],
InnerLayer: buildLayer(index + 1), InnerLayer: buildLayer(index + 1),
} }
} }
return &Payload[T, P]{OutermostLayer: buildLayer(0)} return &Payload[T]{OutermostLayer: buildLayer(0)}
} }
type ContainerLayer[T any, P any] interface { type ContainerLayer[T any] interface {
GetInnerLayer() ContainerLayer[T, P] GetInnerLayer() ContainerLayer[T]
GetValue() T GetValue() T
GetGraphQLType() string GetGraphQLType() string
} }
type NestedLayer[T any, P any] struct { type NestedLayer[T any] struct {
gqlType string `graphql:"-"` gqlType string `graphql:"-"`
InnerLayer ContainerLayer[T, P] InnerLayer ContainerLayer[T]
} }
func (nl *NestedLayer[T, P]) GetInnerLayer() ContainerLayer[T, P] { func (nl *NestedLayer[T]) GetInnerLayer() ContainerLayer[T] {
return nl.InnerLayer return nl.InnerLayer
} }
func (nl *NestedLayer[T, P]) GetValue() T { func (nl *NestedLayer[T]) GetValue() T {
var res T var res T
return res return res
} }
func (nl *NestedLayer[T, P]) GetGraphQLType() string { func (nl *NestedLayer[T]) GetGraphQLType() string {
return nl.gqlType return nl.gqlType
} }
type Wrapper[T any, P any] struct { type Wrapper[T any] struct {
gqlType string `graphql:"-"` gqlType string `graphql:"-"`
Value T Value T
} }
func (w Wrapper[T, P]) GetInnerLayer() ContainerLayer[T, P] { func (w Wrapper[T]) GetInnerLayer() ContainerLayer[T] {
return nil return nil
} }
func (w Wrapper[T, P]) GetValue() T { func (w Wrapper[T]) GetValue() T {
return w.Value return w.Value
} }
func (w Wrapper[T, P]) GetGraphQLWrapped() T { func (w Wrapper[T]) GetGraphQLWrapped() T {
return w.Value return w.Value
} }
func (w Wrapper[T, P]) GetGraphQLType() string { func (w Wrapper[T]) GetGraphQLType() string {
return w.gqlType return w.gqlType
} }
func NewWrapper[T any, P any](gqlType string) *Wrapper[T, P] { func NewWrapper[T any](gqlType string) *Wrapper[T] {
return &Wrapper[T, P]{ return &Wrapper[T]{
gqlType: gqlType, gqlType: gqlType,
} }
} }

View File

@ -50,7 +50,7 @@ func (r *Query[ReturnType, Params]) WithQueryParam(
func (r *Query[ReturnType, Params]) Get(ctx context.Context, params Params) (ReturnType, error) { func (r *Query[ReturnType, Params]) Get(ctx context.Context, params Params) (ReturnType, error) {
paramsMap := convertParamsToMap[Params](params) paramsMap := convertParamsToMap(params)
for k, v := range r.additionalPayloadParams { for k, v := range r.additionalPayloadParams {
paramsMap[k] = v paramsMap[k] = v
} }
@ -65,7 +65,7 @@ func (r *Query[ReturnType, Params]) Get(ctx context.Context, params Params) (Ret
for k, v := range r.additionalQueryParams { for k, v := range r.additionalQueryParams {
paramsMap[k] = v paramsMap[k] = v
} }
q := NewPayload[ReturnType, Params](gqltype, r.containerLayers...) q := NewPayload[ReturnType](gqltype, r.containerLayers...)
err := r.c.Query(ctx, q, paramsMap) err := r.c.Query(ctx, q, paramsMap)
if err != nil { if err != nil {
var res ReturnType var res ReturnType