Skip to content

Commit

Permalink
Merge pull request #27 from tokopedia/idoej/improve-duplicate
Browse files Browse the repository at this point in the history
feat(exec): Duplicate only fields requested by client
  • Loading branch information
yudiharibowo authored Nov 18, 2024
2 parents a266469 + ef65986 commit 49d8e5b
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 44 deletions.
17 changes: 2 additions & 15 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -157,17 +156,6 @@ func (r *Request) execSelections(ctx context.Context, sels []selected.Selection,
// to handle JS limitation of int64, we create duplicate of this fields as string
// currently limited to these fields only as per Toko-TTS requirement
var (
targetFields = map[string]bool{
"id": true,
"product_id": true,
"productid": true,
"product_ids": true,
"productids": true,
"shop_id": true,
"shopid": true,
"shop_ids": true,
"shopids": true,
}
singularInt64Maps = map[string]bool{
"Int": true,
"Int!": true,
Expand All @@ -194,9 +182,7 @@ var (

func isNeedStrCounterpart(field *selected.SchemaField) (needStrCounterpart, isArray bool) {
defType := field.FieldDefinition.Type.String()
fieldName := strings.ToLower(field.Alias)
isTargetField, ok := targetFields[fieldName]
if ok && isTargetField {
if field.NeedStrCounterpart {
// is it single object?
isTargetTypeSingular, ok := singularInt64Maps[defType]
if ok && isTargetTypeSingular {
Expand All @@ -212,6 +198,7 @@ func isNeedStrCounterpart(field *selected.SchemaField) (needStrCounterpart, isAr
return
}
}

return
}

Expand Down
26 changes: 14 additions & 12 deletions internal/exec/selected/selected.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ type Selection interface {

type SchemaField struct {
resolvable.Field
Alias string
Args map[string]interface{}
PackedArgs reflect.Value
Sels []Selection
Async bool
FixedResult reflect.Value
Alias string
Args map[string]interface{}
PackedArgs reflect.Value
Sels []Selection
Async bool
FixedResult reflect.Value
NeedStrCounterpart bool
}

type TypeAssertion struct {
Expand Down Expand Up @@ -152,12 +153,13 @@ func applySelectionSet(r *Request, s *resolvable.Schema, e *resolvable.Object, s

fieldSels := applyField(r, s, fe.ValueExec, field.SelectionSet)
flattenedSels = append(flattenedSels, &SchemaField{
Field: *fe,
Alias: field.Alias.Name,
Args: args,
PackedArgs: packedArgs,
Sels: fieldSels,
Async: fe.HasContext || fe.ArgsPacker != nil || fe.HasError || HasAsyncSel(fieldSels),
Field: *fe,
Alias: field.Alias.Name,
Args: args,
PackedArgs: packedArgs,
Sels: fieldSels,
Async: fe.HasContext || fe.ArgsPacker != nil || fe.HasError || HasAsyncSel(fieldSels),
NeedStrCounterpart: field.NeedStrCounterpart,
})
}

Expand Down
11 changes: 11 additions & 0 deletions internal/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,30 @@ func parseFragment(l *common.Lexer) *types.FragmentDefinition {

func parseSelectionSet(l *common.Lexer) []types.Selection {
var sels []types.Selection
originalFields := make(map[string]*types.Field, 0)
needDuplicateFields := make([]string, 0)
l.ConsumeToken('{')
for l.Peek() != '}' {
f := parseSelection(l)
switch sel := f.(type) {
case *types.Field:
if !strings.HasSuffix(sel.Alias.Name, types.DUPLICATION_SUFFIX) {
sels = append(sels, f)
originalFields[sel.Alias.Name] = sel
} else {
needDuplicateFields = append(needDuplicateFields, strings.ReplaceAll(sel.Alias.Name, types.DUPLICATION_SUFFIX, ""))
}
default:
sels = append(sels, f)
}
}
l.ConsumeToken('}')
for _, fieldName := range needDuplicateFields {
f, ok := originalFields[fieldName]
if ok {
f.NeedStrCounterpart = true
}
}
return sels
}

Expand Down
23 changes: 12 additions & 11 deletions nullable_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math"
"testing"

"github.com/tokopedia/graphql-go"
"github.com/tokopedia/graphql-go/decode"
)

Expand All @@ -14,8 +15,8 @@ func TestNullInt_ImplementsUnmarshaler(t *testing.T) {
}
}()

// assert *NullInt implements decode.Unmarshaler interface
var _ decode.Unmarshaler = (*NullInt)(nil)
// assert *graphql.NullInt implements decode.Unmarshaler interface
var _ decode.Unmarshaler = (*graphql.NullInt)(nil)
}

func TestNullInt_UnmarshalGraphQL(t *testing.T) {
Expand All @@ -27,7 +28,7 @@ func TestNullInt_UnmarshalGraphQL(t *testing.T) {
b := float64(math.MinInt32 - 1)
c := 1234.6
good := int32(1234)
ref := NullInt{
ref := graphql.NullInt{
Value: &good,
Set: true,
}
Expand Down Expand Up @@ -68,7 +69,7 @@ func TestNullInt_UnmarshalGraphQL(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gt := new(NullInt)
gt := new(graphql.NullInt)
if err := gt.UnmarshalGraphQL(tt.args.input); err != nil {
if err.Error() != tt.wantErr {
t.Errorf("UnmarshalGraphQL() error = %v, want = %s", err, tt.wantErr)
Expand All @@ -85,7 +86,7 @@ func TestNullInt_UnmarshalGraphQL(t *testing.T) {
tests := []struct {
name string
args args
wantEq NullInt
wantEq graphql.NullInt
}{
{
name: "int32",
Expand All @@ -105,7 +106,7 @@ func TestNullInt_UnmarshalGraphQL(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gt := new(NullInt)
gt := new(graphql.NullInt)
if err := gt.UnmarshalGraphQL(tt.args.input); err != nil {
t.Errorf("UnmarshalGraphQL() error = %v", err)
return
Expand All @@ -126,7 +127,7 @@ func TestNullFloat_ImplementsUnmarshaler(t *testing.T) {
}()

// assert *NullFloat implements decode.Unmarshaler interface
var _ decode.Unmarshaler = (*NullFloat)(nil)
var _ decode.Unmarshaler = (*graphql.NullFloat)(nil)
}

func TestNullFloat_UnmarshalGraphQL(t *testing.T) {
Expand All @@ -135,7 +136,7 @@ func TestNullFloat_UnmarshalGraphQL(t *testing.T) {
}

good := float64(1234)
ref := NullFloat{
ref := graphql.NullFloat{
Value: &good,
Set: true,
}
Expand All @@ -155,7 +156,7 @@ func TestNullFloat_UnmarshalGraphQL(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gt := new(NullFloat)
gt := new(graphql.NullFloat)
if err := gt.UnmarshalGraphQL(tt.args.input); err != nil {
if err.Error() != tt.wantErr {
t.Errorf("UnmarshalGraphQL() error = %v, want = %s", err, tt.wantErr)
Expand All @@ -172,7 +173,7 @@ func TestNullFloat_UnmarshalGraphQL(t *testing.T) {
tests := []struct {
name string
args args
wantEq NullFloat
wantEq graphql.NullFloat
}{
{
name: "int",
Expand All @@ -199,7 +200,7 @@ func TestNullFloat_UnmarshalGraphQL(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gt := new(NullFloat)
gt := new(graphql.NullFloat)
if err := gt.UnmarshalGraphQL(tt.args.input); err != nil {
t.Errorf("UnmarshalGraphQL() error = %v", err)
return
Expand Down
13 changes: 7 additions & 6 deletions types/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ type SelectionSet []Selection

// Field represents a field used in a query.
type Field struct {
Alias Ident
Name Ident
Arguments ArgumentList
Directives DirectiveList
SelectionSet SelectionSet
SelectionSetLoc errors.Location
Alias Ident
Name Ident
Arguments ArgumentList
Directives DirectiveList
SelectionSet SelectionSet
SelectionSetLoc errors.Location
NeedStrCounterpart bool
}

func (Field) isSelection() {}
Expand Down

0 comments on commit 49d8e5b

Please sign in to comment.