add langversionloader, update dataloaders_to_context middleware, add to server graphql type LangVersion field

This commit is contained in:
Dawid Wysokiński 2020-06-18 16:44:02 +02:00
parent 0ece3a49cf
commit be52ae19c9
14 changed files with 378 additions and 52 deletions

5
go.mod
View File

@ -13,9 +13,12 @@ require (
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pkg/errors v0.9.1
github.com/segmentio/encoding v0.1.13 // indirect
github.com/tribalwarshelp/shared v0.0.0-20200607152914-8ab83c6d1364
github.com/tribalwarshelp/shared v0.0.0-20200618135703-8b0fda79025b
github.com/vektah/dataloaden v0.3.0 // indirect
github.com/vektah/gqlparser/v2 v2.0.1
golang.org/x/mod v0.3.0 // indirect
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34 // indirect
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)

15
go.sum
View File

@ -170,6 +170,8 @@ github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYm
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/tribalwarshelp/shared v0.0.0-20200607152914-8ab83c6d1364 h1:Pi3n/0FkrHrBO0oW9Lp6kRAEc4qKe7p8lohrEv4GOXE=
github.com/tribalwarshelp/shared v0.0.0-20200607152914-8ab83c6d1364/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
github.com/tribalwarshelp/shared v0.0.0-20200618135703-8b0fda79025b h1:megohIF+3rsva+9CNxlhdAbMKX0kjUaig2P5TSxH0fQ=
github.com/tribalwarshelp/shared v0.0.0-20200618135703-8b0fda79025b/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
@ -177,6 +179,8 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
github.com/vektah/dataloaden v0.3.0 h1:ZfVN2QD6swgvp+tDqdH/OIT/wu3Dhu0cus0k5gIZS84=
github.com/vektah/dataloaden v0.3.0/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
github.com/vmihailenco/bufpool v0.1.5/go.mod h1:fL9i/PRTuS7AELqAHwSU1Zf1c70xhkhGe/cD5ud9pJk=
@ -191,6 +195,7 @@ github.com/vmihailenco/msgpack/v5 v5.0.0-alpha.2/go.mod h1:LDfrk4wJpSFwkzNOJxrCW
github.com/vmihailenco/tagparser v0.1.0/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/otel v0.6.0 h1:+vkHm/XwJ7ekpISV2Ixew93gCrxTbuwTF5rSewnLLgw=
go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -207,6 +212,10 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -220,6 +229,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222033325-078779b8f2d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@ -229,6 +239,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -252,8 +263,12 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2 h1:FD4wDsP+CQUqh2V12OBOt90pLHVToe58P++fUu3ggV4=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -0,0 +1,56 @@
package dataloaders
import (
"context"
"time"
"github.com/tribalwarshelp/api/langversion"
"github.com/tribalwarshelp/api/player"
"github.com/tribalwarshelp/api/tribe"
"github.com/tribalwarshelp/api/village"
"github.com/tribalwarshelp/shared/models"
)
type DataLoaders struct {
LangVersionByTag LangVersionLoader
}
type Config struct {
PlayerRepo player.Repository
TribeRepo tribe.Repository
VillageRepo village.Repository
LangVersionRepo langversion.Repository
}
func New(cfg Config) *DataLoaders {
return &DataLoaders{
LangVersionByTag: LangVersionLoader{
wait: 2 * time.Millisecond,
maxBatch: 0,
fetch: func(tagsS []string) ([]*models.LangVersion, []error) {
tags := []models.LanguageTag{}
for _, tag := range tagsS {
tags = append(tags, models.LanguageTag(tag))
}
langVersions, _, err := cfg.LangVersionRepo.Fetch(context.Background(), &models.LangVersionFilter{
Tag: tags,
})
if err != nil {
return nil, []error{err}
}
langVersionByTag := make(map[models.LanguageTag]*models.LangVersion)
for _, langVersion := range langVersions {
langVersionByTag[langVersion.Tag] = langVersion
}
inOrder := make([]*models.LangVersion, len(tagsS))
for i, tag := range tags {
inOrder[i] = langVersionByTag[tag]
}
return inOrder, nil
},
},
}
}

View File

@ -0,0 +1,224 @@
// Code generated by github.com/vektah/dataloaden, DO NOT EDIT.
package dataloaders
import (
"sync"
"time"
"github.com/tribalwarshelp/shared/models"
)
// LangVersionLoaderConfig captures the config to create a new LangVersionLoader
type LangVersionLoaderConfig struct {
// Fetch is a method that provides the data for the loader
Fetch func(keys []string) ([]*models.LangVersion, []error)
// Wait is how long wait before sending a batch
Wait time.Duration
// MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit
MaxBatch int
}
// NewLangVersionLoader creates a new LangVersionLoader given a fetch, wait, and maxBatch
func NewLangVersionLoader(config LangVersionLoaderConfig) *LangVersionLoader {
return &LangVersionLoader{
fetch: config.Fetch,
wait: config.Wait,
maxBatch: config.MaxBatch,
}
}
// LangVersionLoader batches and caches requests
type LangVersionLoader struct {
// this method provides the data for the loader
fetch func(keys []string) ([]*models.LangVersion, []error)
// how long to done before sending a batch
wait time.Duration
// this will limit the maximum number of keys to send in one batch, 0 = no limit
maxBatch int
// INTERNAL
// lazily created cache
cache map[string]*models.LangVersion
// the current batch. keys will continue to be collected until timeout is hit,
// then everything will be sent to the fetch method and out to the listeners
batch *langVersionLoaderBatch
// mutex to prevent races
mu sync.Mutex
}
type langVersionLoaderBatch struct {
keys []string
data []*models.LangVersion
error []error
closing bool
done chan struct{}
}
// Load a LangVersion by key, batching and caching will be applied automatically
func (l *LangVersionLoader) Load(key string) (*models.LangVersion, error) {
return l.LoadThunk(key)()
}
// LoadThunk returns a function that when called will block waiting for a LangVersion.
// This method should be used if you want one goroutine to make requests to many
// different data loaders without blocking until the thunk is called.
func (l *LangVersionLoader) LoadThunk(key string) func() (*models.LangVersion, error) {
l.mu.Lock()
if it, ok := l.cache[key]; ok {
l.mu.Unlock()
return func() (*models.LangVersion, error) {
return it, nil
}
}
if l.batch == nil {
l.batch = &langVersionLoaderBatch{done: make(chan struct{})}
}
batch := l.batch
pos := batch.keyIndex(l, key)
l.mu.Unlock()
return func() (*models.LangVersion, error) {
<-batch.done
var data *models.LangVersion
if pos < len(batch.data) {
data = batch.data[pos]
}
var err error
// its convenient to be able to return a single error for everything
if len(batch.error) == 1 {
err = batch.error[0]
} else if batch.error != nil {
err = batch.error[pos]
}
if err == nil {
l.mu.Lock()
l.unsafeSet(key, data)
l.mu.Unlock()
}
return data, err
}
}
// LoadAll fetches many keys at once. It will be broken into appropriate sized
// sub batches depending on how the loader is configured
func (l *LangVersionLoader) LoadAll(keys []string) ([]*models.LangVersion, []error) {
results := make([]func() (*models.LangVersion, error), len(keys))
for i, key := range keys {
results[i] = l.LoadThunk(key)
}
langVersions := make([]*models.LangVersion, len(keys))
errors := make([]error, len(keys))
for i, thunk := range results {
langVersions[i], errors[i] = thunk()
}
return langVersions, errors
}
// LoadAllThunk returns a function that when called will block waiting for a LangVersions.
// This method should be used if you want one goroutine to make requests to many
// different data loaders without blocking until the thunk is called.
func (l *LangVersionLoader) LoadAllThunk(keys []string) func() ([]*models.LangVersion, []error) {
results := make([]func() (*models.LangVersion, error), len(keys))
for i, key := range keys {
results[i] = l.LoadThunk(key)
}
return func() ([]*models.LangVersion, []error) {
langVersions := make([]*models.LangVersion, len(keys))
errors := make([]error, len(keys))
for i, thunk := range results {
langVersions[i], errors[i] = thunk()
}
return langVersions, errors
}
}
// Prime the cache with the provided key and value. If the key already exists, no change is made
// and false is returned.
// (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).)
func (l *LangVersionLoader) Prime(key string, value *models.LangVersion) bool {
l.mu.Lock()
var found bool
if _, found = l.cache[key]; !found {
// make a copy when writing to the cache, its easy to pass a pointer in from a loop var
// and end up with the whole cache pointing to the same value.
cpy := *value
l.unsafeSet(key, &cpy)
}
l.mu.Unlock()
return !found
}
// Clear the value at key from the cache, if it exists
func (l *LangVersionLoader) Clear(key string) {
l.mu.Lock()
delete(l.cache, key)
l.mu.Unlock()
}
func (l *LangVersionLoader) unsafeSet(key string, value *models.LangVersion) {
if l.cache == nil {
l.cache = map[string]*models.LangVersion{}
}
l.cache[key] = value
}
// keyIndex will return the location of the key in the batch, if its not found
// it will add the key to the batch
func (b *langVersionLoaderBatch) keyIndex(l *LangVersionLoader, key string) int {
for i, existingKey := range b.keys {
if key == existingKey {
return i
}
}
pos := len(b.keys)
b.keys = append(b.keys, key)
if pos == 0 {
go b.startTimer(l)
}
if l.maxBatch != 0 && pos >= l.maxBatch-1 {
if !b.closing {
b.closing = true
l.batch = nil
go b.end(l)
}
}
return pos
}
func (b *langVersionLoaderBatch) startTimer(l *LangVersionLoader) {
time.Sleep(l.wait)
l.mu.Lock()
// we must have hit a batch limit and are already finalizing this batch
if b.closing {
l.mu.Unlock()
return
}
l.batch = nil
l.mu.Unlock()
b.end(l)
}
func (b *langVersionLoaderBatch) end(l *LangVersionLoader) {
b.data, b.error = l.fetch(b.keys)
close(b.done)
}

View File

@ -4,26 +4,17 @@ import (
"context"
"time"
"github.com/tribalwarshelp/api/player"
"github.com/tribalwarshelp/api/tribe"
"github.com/tribalwarshelp/api/village"
"github.com/tribalwarshelp/shared/models"
)
type DataLoaders struct {
type ServerDataLoaders struct {
PlayerByID PlayerLoader
TribeByID TribeLoader
VillageByID VillageLoader
}
type Config struct {
PlayerRepo player.Repository
TribeRepo tribe.Repository
VillageRepo village.Repository
}
func New(server string, cfg Config) *DataLoaders {
return &DataLoaders{
func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
return &ServerDataLoaders{
PlayerByID: PlayerLoader{
wait: 2 * time.Millisecond,
maxBatch: 0,

View File

@ -39,6 +39,7 @@ type ResolverRoot interface {
Ennoblement() EnnoblementResolver
Player() PlayerResolver
Query() QueryResolver
Server() ServerResolver
Village() VillageResolver
}
@ -103,10 +104,10 @@ type ComplexityRoot struct {
}
Server struct {
ID func(childComplexity int) int
Key func(childComplexity int) int
LangVersionTag func(childComplexity int) int
Status func(childComplexity int) int
ID func(childComplexity int) int
Key func(childComplexity int) int
LangVersion func(childComplexity int) int
Status func(childComplexity int) int
}
ServersList struct {
@ -174,6 +175,9 @@ type QueryResolver interface {
Villages(ctx context.Context, server string, filter *models.VillageFilter) (*VillagesList, error)
Village(ctx context.Context, server string, id int) (*models.Village, error)
}
type ServerResolver interface {
LangVersion(ctx context.Context, obj *models.Server) (*models.LangVersion, error)
}
type VillageResolver interface {
Player(ctx context.Context, obj *models.Village) (*models.Player, error)
}
@ -528,12 +532,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Server.Key(childComplexity), true
case "Server.langVersionTag":
if e.complexity.Server.LangVersionTag == nil {
case "Server.langVersion":
if e.complexity.Server.LangVersion == nil {
break
}
return e.complexity.Server.LangVersionTag(childComplexity), true
return e.complexity.Server.LangVersion(childComplexity), true
case "Server.status":
if e.complexity.Server.Status == nil {
@ -964,7 +968,7 @@ type Server {
id: Int!
key: String!
status: ServerStatus!
langVersionTag: LanguageTag!
langVersion: LangVersion @goField(forceResolver: true)
}
type ServersList {
@ -2923,7 +2927,7 @@ func (ec *executionContext) _Server_status(ctx context.Context, field graphql.Co
return ec.marshalNServerStatus2githubᚗcomᚋtribalwarshelpᚋsharedᚋmodelsᚐServerStatus(ctx, field.Selections, res)
}
func (ec *executionContext) _Server_langVersionTag(ctx context.Context, field graphql.CollectedField, obj *models.Server) (ret graphql.Marshaler) {
func (ec *executionContext) _Server_langVersion(ctx context.Context, field graphql.CollectedField, obj *models.Server) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
@ -2934,27 +2938,24 @@ func (ec *executionContext) _Server_langVersionTag(ctx context.Context, field gr
Object: "Server",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.LangVersionTag, nil
return ec.resolvers.Server().LangVersion(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(models.LanguageTag)
res := resTmp.(*models.LangVersion)
fc.Result = res
return ec.marshalNLanguageTag2githubᚗcomᚋtribalwarshelpᚋsharedᚋmodelsᚐLanguageTag(ctx, field.Selections, res)
return ec.marshalOLangVersion2ᚖgithubᚗcomᚋtribalwarshelpᚋsharedᚋmodelsᚐLangVersion(ctx, field.Selections, res)
}
func (ec *executionContext) _ServersList_items(ctx context.Context, field graphql.CollectedField, obj *ServersList) (ret graphql.Marshaler) {
@ -6525,23 +6526,29 @@ func (ec *executionContext) _Server(ctx context.Context, sel ast.SelectionSet, o
case "id":
out.Values[i] = ec._Server_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
atomic.AddUint32(&invalids, 1)
}
case "key":
out.Values[i] = ec._Server_key(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
atomic.AddUint32(&invalids, 1)
}
case "status":
out.Values[i] = ec._Server_status(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "langVersionTag":
out.Values[i] = ec._Server_langVersionTag(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
atomic.AddUint32(&invalids, 1)
}
case "langVersion":
field := field
out.Concurrently(i, func() (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Server_langVersion(ctx, field, obj)
return res
})
default:
panic("unknown field " + strconv.Quote(field.Name))
}

View File

@ -14,7 +14,7 @@ func (r *ennoblementResolver) NewOwner(ctx context.Context, obj *models.Ennoblem
}
if server, ok := getServer(graphql.GetFieldContext(ctx)); ok {
dataloaders := middleware.DataLoadersFromContext(ctx)
dataloaders := middleware.ServerDataLoadersFromContext(ctx)
if dataloaders != nil {
if dataloader, ok := dataloaders[server]; ok {
player, _ := dataloader.PlayerByID.Load(obj.NewOwnerID)
@ -34,7 +34,7 @@ func (r *ennoblementResolver) OldOwner(ctx context.Context, obj *models.Ennoblem
}
if server, ok := getServer(graphql.GetFieldContext(ctx)); ok {
dataloaders := middleware.DataLoadersFromContext(ctx)
dataloaders := middleware.ServerDataLoadersFromContext(ctx)
if dataloaders != nil {
if dataloader, ok := dataloaders[server]; ok {
player, _ := dataloader.PlayerByID.Load(obj.OldOwnerID)
@ -54,7 +54,7 @@ func (r *ennoblementResolver) Village(ctx context.Context, obj *models.Ennobleme
}
if server, ok := getServer(graphql.GetFieldContext(ctx)); ok {
dataloaders := middleware.DataLoadersFromContext(ctx)
dataloaders := middleware.ServerDataLoadersFromContext(ctx)
if dataloaders != nil {
if dataloader, ok := dataloaders[server]; ok {
village, _ := dataloader.VillageByID.Load(obj.VillageID)

View File

@ -15,7 +15,7 @@ func (r *playerResolver) Tribe(ctx context.Context, obj *models.Player) (*models
}
if server, ok := getServer(graphql.GetFieldContext(ctx)); ok {
dataloaders := middleware.DataLoadersFromContext(ctx)
dataloaders := middleware.ServerDataLoadersFromContext(ctx)
if dataloaders != nil {
if dataloader, ok := dataloaders[server]; ok {
tribe, _ := dataloader.TribeByID.Load(obj.TribeID)

View File

@ -24,8 +24,10 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryRe
func (r *Resolver) Player() generated.PlayerResolver { return &playerResolver{r} }
func (r *Resolver) Village() generated.VillageResolver { return &villageResolver{r} }
func (r *Resolver) Ennoblement() generated.EnnoblementResolver { return &ennoblementResolver{r} }
func (r *Resolver) Server() generated.ServerResolver { return &serverResolver{r} }
type queryResolver struct{ *Resolver }
type playerResolver struct{ *Resolver }
type villageResolver struct{ *Resolver }
type ennoblementResolver struct{ *Resolver }
type serverResolver struct{ *Resolver }

View File

@ -3,10 +3,21 @@ package resolvers
import (
"context"
"github.com/tribalwarshelp/api/middleware"
"github.com/tribalwarshelp/api/graphql/generated"
"github.com/tribalwarshelp/shared/models"
)
func (r *serverResolver) LangVersion(ctx context.Context, obj *models.Server) (*models.LangVersion, error) {
loaders := middleware.DataLoadersFromContext(ctx)
if loaders != nil {
lv, _ := loaders.LangVersionByTag.Load(obj.LangVersionTag.String())
return lv, nil
}
return nil, nil
}
func (r *queryResolver) Servers(ctx context.Context, filter *models.ServerFilter) (*generated.ServersList, error) {
var err error
list := &generated.ServersList{}

View File

@ -15,7 +15,7 @@ func (r *villageResolver) Player(ctx context.Context, obj *models.Village) (*mod
}
if server, ok := getServer(graphql.GetFieldContext(ctx)); ok {
dataloaders := middleware.DataLoadersFromContext(ctx)
dataloaders := middleware.ServerDataLoadersFromContext(ctx)
if dataloaders != nil {
if dataloader, ok := dataloaders[server]; ok {
tribe, _ := dataloader.PlayerByID.Load(obj.PlayerID)

View File

@ -7,7 +7,7 @@ type Server {
id: Int!
key: String!
status: ServerStatus!
langVersionTag: LanguageTag!
langVersion: LangVersion @goField(forceResolver: true)
}
type ServersList {

View File

@ -88,9 +88,10 @@ func main() {
router := gin.Default()
v1 := router.Group("")
v1.Use(middleware.DataLoadersToContext(serverRepo, dataloaders.Config{
PlayerRepo: playerRepo,
TribeRepo: tribeRepo,
VillageRepo: villageRepo,
PlayerRepo: playerRepo,
TribeRepo: tribeRepo,
VillageRepo: villageRepo,
LangVersionRepo: langversionRepo,
}))
httpdelivery.Attach(httpdelivery.Config{
RouterGroup: v1,

View File

@ -12,12 +12,13 @@ import (
"github.com/gin-gonic/gin"
)
var serverDataLoadersContextKey ContextKey = "serverDataLoaders"
var dataloadersContextKey ContextKey = "dataloaders"
func DataLoadersToContext(serverRepo server.Repository, cfg dataloaders.Config) gin.HandlerFunc {
return func(c *gin.Context) {
ctx := c.Request.Context()
loaders := make(map[string]*dataloaders.DataLoaders)
loaders := make(map[string]*dataloaders.ServerDataLoaders)
servers, _, err := serverRepo.Fetch(c.Request.Context(), nil)
if err != nil {
c.JSON(http.StatusOK, &gqlerror.Error{
@ -27,22 +28,37 @@ func DataLoadersToContext(serverRepo server.Repository, cfg dataloaders.Config)
return
}
for _, server := range servers {
loaders[server.Key] = dataloaders.New(server.Key, cfg)
loaders[server.Key] = dataloaders.NewServerDataLoaders(server.Key, cfg)
}
c.Request = c.Request.WithContext(StoreDataLoadersInContext(ctx, loaders))
ctx = StoreServerDataLoadersInContext(ctx, loaders)
ctx = StoreDataLoadersInContext(ctx, dataloaders.New(cfg))
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
func StoreDataLoadersInContext(ctx context.Context, loaders map[string]*dataloaders.DataLoaders) context.Context {
func StoreServerDataLoadersInContext(ctx context.Context, loaders map[string]*dataloaders.ServerDataLoaders) context.Context {
return context.WithValue(ctx, serverDataLoadersContextKey, loaders)
}
func ServerDataLoadersFromContext(ctx context.Context) map[string]*dataloaders.ServerDataLoaders {
dl := ctx.Value(serverDataLoadersContextKey)
if dl == nil {
return nil
}
return dl.(map[string]*dataloaders.ServerDataLoaders)
}
func StoreDataLoadersInContext(ctx context.Context, loaders *dataloaders.DataLoaders) context.Context {
return context.WithValue(ctx, dataloadersContextKey, loaders)
}
func DataLoadersFromContext(ctx context.Context) map[string]*dataloaders.DataLoaders {
func DataLoadersFromContext(ctx context.Context) *dataloaders.DataLoaders {
dl := ctx.Value(dataloadersContextKey)
if dl == nil {
return nil
}
return dl.(map[string]*dataloaders.DataLoaders)
return dl.(*dataloaders.DataLoaders)
}