Skip to content

Commit

Permalink
Implement dataloader base
Browse files Browse the repository at this point in the history
  • Loading branch information
yasuflatland-lf committed Jul 31, 2024
1 parent c4de89a commit 1b24209
Show file tree
Hide file tree
Showing 15 changed files with 939 additions and 1,017 deletions.
3 changes: 2 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ require (
github.com/caarlos0/env/v11 v11.1.0
github.com/go-playground/validator/v10 v10.22.0
github.com/gorilla/websocket v1.5.0
github.com/graph-gophers/dataloader/v7 v7.1.0
github.com/labstack/echo/v4 v4.12.0
github.com/labstack/gommon v0.4.2
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.31.0
github.com/vektah/gqlparser/v2 v2.5.16
golang.org/x/net v0.26.0
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f
gorm.io/driver/postgres v1.5.9
gorm.io/gorm v1.25.10
)
Expand Down
5 changes: 4 additions & 1 deletion backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/dataloader/v7 v7.1.0 h1:Wn8HGF/q7MNXcvfaBnLEPEFJttVHR8zuEqP1obys/oc=
github.com/graph-gophers/dataloader/v7 v7.1.0/go.mod h1:1bKE0Dm6OUcTB/OAuYVOZctgIz7Q3d0XrYtlIzTgg6Q=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
Expand Down Expand Up @@ -247,8 +249,9 @@ golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
Expand Down
21 changes: 21 additions & 0 deletions backend/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ models:
Time:
model:
- github.com/99designs/gqlgen/graphql.Time
Card:
fields:
cardGroup:
resolver: true
CardGroup:
fields:
cards:
resolver: true
users:
resolver: true
User:
fields:
cardGroups:
resolver: true
roles:
resolver: true
Role:
fields:
users:
resolver: true

directives:
validation:
skip_runtime: true
184 changes: 184 additions & 0 deletions backend/graph/dataloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package graph

import (
"backend/graph/model"
"backend/graph/services"
"context"
"errors"
"strconv"

"github.com/graph-gophers/dataloader/v7"
)

type Loaders struct {
CardLoader dataloader.Interface[string, *model.Card]
UserLoader dataloader.Interface[string, *model.User]
RoleLoader dataloader.Interface[string, *model.Role]
CardGroupLoader dataloader.Interface[string, *model.CardGroup]
}

func NewLoaders(srv services.Services) *Loaders {
cardBatcher := &cardBatcher{Srv: srv}
userBatcher := &userBatcher{Srv: srv}
roleBatcher := &roleBatcher{Srv: srv}
cardGroupBatcher := &cardGroupBatcher{Srv: srv}

return &Loaders{
CardLoader: dataloader.NewBatchedLoader[string, *model.Card](cardBatcher.BatchGetCards),
UserLoader: dataloader.NewBatchedLoader[string, *model.User](userBatcher.BatchGetUsers),
RoleLoader: dataloader.NewBatchedLoader[string, *model.Role](roleBatcher.BatchGetRoles),
CardGroupLoader: dataloader.NewBatchedLoader[string, *model.CardGroup](cardGroupBatcher.BatchGetCardGroups),
}
}

type cardBatcher struct {
Srv services.Services
}

func (c *cardBatcher) BatchGetCards(ctx context.Context, keys []string) []*dataloader.Result[*model.Card] {
ids := make([]int64, len(keys))
for i, key := range keys {
id, err := strconv.ParseInt(key, 10, 64)
if err != nil {
return []*dataloader.Result[*model.Card]{{
Error: err,
}}
}
ids[i] = id
}

cards, err := c.Srv.GetCardsByIDs(ctx, ids)
if err != nil {
return make([]*dataloader.Result[*model.Card], len(keys))
}

cardMap := make(map[int64]*model.Card)
for _, card := range cards {
cardMap[card.ID] = card
}

results := make([]*dataloader.Result[*model.Card], len(keys))
for i, key := range keys {
id, _ := strconv.ParseInt(key, 10, 64)
if card, ok := cardMap[id]; ok {
results[i] = &dataloader.Result[*model.Card]{Data: card}
} else {
results[i] = &dataloader.Result[*model.Card]{Error: errors.New("card not found")}
}
}
return results
}

type userBatcher struct {
Srv services.Services
}

func (u *userBatcher) BatchGetUsers(ctx context.Context, keys []string) []*dataloader.Result[*model.User] {
ids := make([]int64, len(keys))
for i, key := range keys {
id, err := strconv.ParseInt(key, 10, 64)
if err != nil {
return []*dataloader.Result[*model.User]{{
Error: err,
}}
}
ids[i] = id
}

users, err := u.Srv.GetUsersByIDs(ctx, ids)
if err != nil {
return make([]*dataloader.Result[*model.User], len(keys))
}

userMap := make(map[int64]*model.User)
for _, user := range users {
userMap[user.ID] = user
}

results := make([]*dataloader.Result[*model.User], len(keys))
for i, key := range keys {
id, _ := strconv.ParseInt(key, 10, 64)
if user, ok := userMap[id]; ok {
results[i] = &dataloader.Result[*model.User]{Data: user}
} else {
results[i] = &dataloader.Result[*model.User]{Error: errors.New("user not found")}
}
}
return results
}

type roleBatcher struct {
Srv services.Services
}

func (r *roleBatcher) BatchGetRoles(ctx context.Context, keys []string) []*dataloader.Result[*model.Role] {
ids := make([]int64, len(keys))
for i, key := range keys {
id, err := strconv.ParseInt(key, 10, 64)
if err != nil {
return []*dataloader.Result[*model.Role]{{
Error: err,
}}
}
ids[i] = id
}

roles, err := r.Srv.GetRolesByIDs(ctx, ids)
if err != nil {
return make([]*dataloader.Result[*model.Role], len(keys))
}

roleMap := make(map[int64]*model.Role)
for _, role := range roles {
roleMap[role.ID] = role
}

results := make([]*dataloader.Result[*model.Role], len(keys))
for i, key := range keys {
id, _ := strconv.ParseInt(key, 10, 64)
if role, ok := roleMap[id]; ok {
results[i] = &dataloader.Result[*model.Role]{Data: role}
} else {
results[i] = &dataloader.Result[*model.Role]{Error: errors.New("role not found")}
}
}
return results
}

type cardGroupBatcher struct {
Srv services.Services
}

func (c *cardGroupBatcher) BatchGetCardGroups(ctx context.Context, keys []string) []*dataloader.Result[*model.CardGroup] {
ids := make([]int64, len(keys))
for i, key := range keys {
id, err := strconv.ParseInt(key, 10, 64)
if err != nil {
return []*dataloader.Result[*model.CardGroup]{{
Error: err,
}}
}
ids[i] = id
}

cardGroups, err := c.Srv.GetCardGroupsByIDs(ctx, ids)
if err != nil {
return make([]*dataloader.Result[*model.CardGroup], len(keys))
}

cardGroupMap := make(map[int64]*model.CardGroup)
for _, cardGroup := range cardGroups {
cardGroupMap[cardGroup.ID] = cardGroup
}

results := make([]*dataloader.Result[*model.CardGroup], len(keys))
for i, key := range keys {
id, _ := strconv.ParseInt(key, 10, 64)
if cardGroup, ok := cardGroupMap[id]; ok {
results[i] = &dataloader.Result[*model.CardGroup]{Data: cardGroup}
} else {
results[i] = &dataloader.Result[*model.CardGroup]{Error: errors.New("card group not found")}
}
}
return results
}
Loading

0 comments on commit 1b24209

Please sign in to comment.