Skip to content

Commit 687d3ab

Browse files
author
Edward Ma
committed
Merge remote-tracking branch 'upstream/master' into coerce-null-int
2 parents 422bda0 + 7aec311 commit 687d3ab

File tree

15 files changed

+397
-39
lines changed

15 files changed

+397
-39
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
CHANGELOG
22

3+
[v1.1.0](https://github.com/graph-gophers/graphql-go/releases/tag/v1.1.0) Release v1.1.0
4+
* [FEATURE] Add types package #437
5+
* [FEATURE] Expose `packer.Unmarshaler` as `decode.Unmarshaler` to the public #450
6+
* [FEATURE] Add location fields to type definitions #454
7+
* [FEATURE] `errors.Errorf` preserves original error similar to `fmt.Errorf` #456
8+
* [BUGFIX] Fix duplicated __typename in response (fixes #369) #443
9+
310
[v1.0.0](https://github.com/graph-gophers/graphql-go/releases/tag/v1.0.0) Initial release

errors/errors.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
)
66

77
type QueryError struct {
8+
Err error `json:"-"` // Err holds underlying if available
89
Message string `json:"message"`
910
Locations []Location `json:"locations,omitempty"`
1011
Path []interface{} `json:"path,omitempty"`
@@ -23,7 +24,16 @@ func (a Location) Before(b Location) bool {
2324
}
2425

2526
func Errorf(format string, a ...interface{}) *QueryError {
27+
// similar to fmt.Errorf, Errorf will wrap the last argument if it is an instance of error
28+
var err error
29+
if n := len(a); n > 0 {
30+
if v, ok := a[n-1].(error); ok {
31+
err = v
32+
}
33+
}
34+
2635
return &QueryError{
36+
Err: err,
2737
Message: fmt.Sprintf(format, a...),
2838
}
2939
}
@@ -39,4 +49,11 @@ func (err *QueryError) Error() string {
3949
return str
4050
}
4151

52+
func (err *QueryError) Unwrap() error {
53+
if err == nil {
54+
return nil
55+
}
56+
return err.Err
57+
}
58+
4259
var _ error = &QueryError{}

errors/errors_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package errors
2+
3+
import (
4+
"io"
5+
"testing"
6+
)
7+
8+
// Is is simplified facsimile of the go 1.13 errors.Is to ensure QueryError is compatible
9+
func Is(err, target error) bool {
10+
for err != nil {
11+
if target == err {
12+
return true
13+
}
14+
15+
switch e := err.(type) {
16+
case interface{ Unwrap() error }:
17+
err = e.Unwrap()
18+
default:
19+
break
20+
}
21+
}
22+
return false
23+
}
24+
25+
func TestErrorf(t *testing.T) {
26+
cause := io.EOF
27+
28+
t.Run("wrap error", func(t *testing.T) {
29+
err := Errorf("boom: %v", cause)
30+
if !Is(err, cause) {
31+
t.Fatalf("expected errors.Is to return true")
32+
}
33+
})
34+
35+
t.Run("handles nil", func(t *testing.T) {
36+
var err *QueryError
37+
if Is(err, cause) {
38+
t.Fatalf("expected errors.Is to return false")
39+
}
40+
})
41+
42+
t.Run("handle no arguments", func(t *testing.T) {
43+
err := Errorf("boom")
44+
if Is(err, cause) {
45+
t.Fatalf("expected errors.Is to return false")
46+
}
47+
})
48+
49+
t.Run("handle non-error argument arguments", func(t *testing.T) {
50+
err := Errorf("boom: %v", "shaka")
51+
if Is(err, cause) {
52+
t.Fatalf("expected errors.Is to return false")
53+
}
54+
})
55+
}

gqltesting/testing.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func checkErrors(t *testing.T, want, got []*errors.QueryError) {
102102
sortErrors(want)
103103
sortErrors(got)
104104

105+
// Clear the underlying error before the DeepEqual check. It's too
106+
// much to ask the tester to include the raw failing error.
107+
for _, err := range got {
108+
err.Err = nil
109+
}
110+
105111
if !reflect.DeepEqual(got, want) {
106112
t.Fatalf("unexpected error: got %+v, want %+v", got, want)
107113
}

internal/schema/schema.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,10 @@ func parseSchema(s *types.Schema, l *common.Lexer) {
348348
s.Types[input.Name] = input
349349

350350
case "scalar":
351+
loc := l.Location()
351352
name := l.ConsumeIdent()
352353
directives := common.ParseDirectives(l)
353-
s.Types[name] = &types.ScalarTypeDefinition{Name: name, Desc: desc, Directives: directives}
354+
s.Types[name] = &types.ScalarTypeDefinition{Name: name, Desc: desc, Directives: directives, Loc: loc}
354355

355356
case "directive":
356357
directive := parseDirectiveDef(l)
@@ -368,7 +369,7 @@ func parseSchema(s *types.Schema, l *common.Lexer) {
368369
}
369370

370371
func parseObjectDef(l *common.Lexer) *types.ObjectTypeDefinition {
371-
object := &types.ObjectTypeDefinition{Name: l.ConsumeIdent()}
372+
object := &types.ObjectTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()}
372373

373374
for {
374375
if l.Peek() == '{' {
@@ -403,7 +404,7 @@ func parseObjectDef(l *common.Lexer) *types.ObjectTypeDefinition {
403404
}
404405

405406
func parseInterfaceDef(l *common.Lexer) *types.InterfaceTypeDefinition {
406-
i := &types.InterfaceTypeDefinition{Name: l.ConsumeIdent()}
407+
i := &types.InterfaceTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()}
407408

408409
i.Directives = common.ParseDirectives(l)
409410

@@ -415,7 +416,7 @@ func parseInterfaceDef(l *common.Lexer) *types.InterfaceTypeDefinition {
415416
}
416417

417418
func parseUnionDef(l *common.Lexer) *types.Union {
418-
union := &types.Union{Name: l.ConsumeIdent()}
419+
union := &types.Union{Loc: l.Location(), Name: l.ConsumeIdent()}
419420

420421
union.Directives = common.ParseDirectives(l)
421422
l.ConsumeToken('=')
@@ -430,6 +431,7 @@ func parseUnionDef(l *common.Lexer) *types.Union {
430431

431432
func parseInputDef(l *common.Lexer) *types.InputObject {
432433
i := &types.InputObject{}
434+
i.Loc = l.Location()
433435
i.Name = l.ConsumeIdent()
434436
i.Directives = common.ParseDirectives(l)
435437
l.ConsumeToken('{')
@@ -441,13 +443,14 @@ func parseInputDef(l *common.Lexer) *types.InputObject {
441443
}
442444

443445
func parseEnumDef(l *common.Lexer) *types.EnumTypeDefinition {
444-
enum := &types.EnumTypeDefinition{Name: l.ConsumeIdent()}
446+
enum := &types.EnumTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()}
445447

446448
enum.Directives = common.ParseDirectives(l)
447449
l.ConsumeToken('{')
448450
for l.Peek() != '}' {
449451
v := &types.EnumValueDefinition{
450452
Desc: l.DescComment(),
453+
Loc: l.Location(),
451454
EnumValue: l.ConsumeIdent(),
452455
Directives: common.ParseDirectives(l),
453456
}
@@ -459,7 +462,8 @@ func parseEnumDef(l *common.Lexer) *types.EnumTypeDefinition {
459462
}
460463
func parseDirectiveDef(l *common.Lexer) *types.DirectiveDefinition {
461464
l.ConsumeToken('@')
462-
d := &types.DirectiveDefinition{Name: l.ConsumeIdent()}
465+
loc := l.Location()
466+
d := &types.DirectiveDefinition{Name: l.ConsumeIdent(), Loc: loc}
463467

464468
if l.Peek() == '(' {
465469
l.ConsumeToken('(')
@@ -484,6 +488,7 @@ func parseDirectiveDef(l *common.Lexer) *types.DirectiveDefinition {
484488
}
485489

486490
func parseExtension(s *types.Schema, l *common.Lexer) {
491+
loc := l.Location()
487492
switch x := l.ConsumeIdent(); x {
488493
case "schema":
489494
l.ConsumeToken('{')
@@ -497,23 +502,23 @@ func parseExtension(s *types.Schema, l *common.Lexer) {
497502

498503
case "type":
499504
obj := parseObjectDef(l)
500-
s.Extensions = append(s.Extensions, &types.Extension{Type: obj})
505+
s.Extensions = append(s.Extensions, &types.Extension{Type: obj, Loc: loc})
501506

502507
case "interface":
503508
iface := parseInterfaceDef(l)
504-
s.Extensions = append(s.Extensions, &types.Extension{Type: iface})
509+
s.Extensions = append(s.Extensions, &types.Extension{Type: iface, Loc: loc})
505510

506511
case "union":
507512
union := parseUnionDef(l)
508-
s.Extensions = append(s.Extensions, &types.Extension{Type: union})
513+
s.Extensions = append(s.Extensions, &types.Extension{Type: union, Loc: loc})
509514

510515
case "enum":
511516
enum := parseEnumDef(l)
512-
s.Extensions = append(s.Extensions, &types.Extension{Type: enum})
517+
s.Extensions = append(s.Extensions, &types.Extension{Type: enum, Loc: loc})
513518

514519
case "input":
515520
input := parseInputDef(l)
516-
s.Extensions = append(s.Extensions, &types.Extension{Type: input})
521+
s.Extensions = append(s.Extensions, &types.Extension{Type: input, Loc: loc})
517522

518523
default:
519524
// TODO: Add ScalarTypeDefinition when adding directives
@@ -526,6 +531,7 @@ func parseFieldsDef(l *common.Lexer) types.FieldsDefinition {
526531
for l.Peek() != '}' {
527532
f := &types.FieldDefinition{}
528533
f.Desc = l.DescComment()
534+
f.Loc = l.Location()
529535
f.Name = l.ConsumeIdent()
530536
if l.Peek() == '(' {
531537
l.ConsumeToken('(')

0 commit comments

Comments
 (0)