GraphQL master FF for review (#18445)
* Initial work on a graphql API * Added receipts, and more transaction fields. * Finish receipts, add logs * Add transactionCount to block * Add types and . * Update Block type to be compatible with ethql * Rename nonce to transactionCount in Account, to be compatible with ethql * Update transaction, receipt and log to match ethql * Add query operator, for a range of blocks * Added ommerCount to Block * Add transactionAt and ommerAt to Block * Added sendRawTransaction mutation * Add Call and EstimateGas to graphQL API * Refactored to use hexutil.Bytes instead of HexBytes * Replace BigNum with hexutil.Big * Refactor call and estimateGas to use ethapi struct type * Replace ethgraphql.Address with common.Address * Replace ethgraphql.Hash with common.Hash * Converted most quantities to Long instead of Int * Add support for logs * Fix bug in runFilter * Restructured Transaction to work primarily with headers, so uncle data is reported properly * Add gasPrice API * Add protocolVersion API * Add syncing API * Moved schema into its own source file * Move some single use args types into anonymous structs * Add doc-comments * Fixed backend fetching to use context * Added (very) basic tests * Add documentation to the graphql schema * Fix reversion for formatting of big numbers * Correct spelling error * s/BigInt/Long/ * Update common/types.go * Fixes in response to review * Fix lint error * Updated calls on private functions * Fix typo in graphql.go * Rollback ethapi breaking changes for graphql support Co-Authored-By: Arachnid <arachnid@notdot.net>
This commit is contained in:
committed by
Guillaume Ballet
parent
105008b6a1
commit
f91312dbdb
190
vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go
generated
vendored
Normal file
190
vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
package schema
|
||||
|
||||
var Meta *Schema
|
||||
|
||||
func init() {
|
||||
Meta = &Schema{} // bootstrap
|
||||
Meta = New()
|
||||
if err := Meta.Parse(metaSrc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var metaSrc = `
|
||||
# The ` + "`" + `Int` + "`" + ` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
|
||||
scalar Int
|
||||
|
||||
# The ` + "`" + `Float` + "`" + ` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
|
||||
scalar Float
|
||||
|
||||
# The ` + "`" + `String` + "`" + ` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
|
||||
scalar String
|
||||
|
||||
# The ` + "`" + `Boolean` + "`" + ` scalar type represents ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `.
|
||||
scalar Boolean
|
||||
|
||||
# The ` + "`" + `ID` + "`" + ` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as ` + "`" + `"4"` + "`" + `) or integer (such as ` + "`" + `4` + "`" + `) input value will be accepted as an ID.
|
||||
scalar ID
|
||||
|
||||
# Directs the executor to include this field or fragment only when the ` + "`" + `if` + "`" + ` argument is true.
|
||||
directive @include(
|
||||
# Included when true.
|
||||
if: Boolean!
|
||||
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
||||
|
||||
# Directs the executor to skip this field or fragment when the ` + "`" + `if` + "`" + ` argument is true.
|
||||
directive @skip(
|
||||
# Skipped when true.
|
||||
if: Boolean!
|
||||
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
||||
|
||||
# Marks an element of a GraphQL schema as no longer supported.
|
||||
directive @deprecated(
|
||||
# Explains why this element was deprecated, usually also including a suggestion
|
||||
# for how to access supported similar data. Formatted in
|
||||
# [Markdown](https://daringfireball.net/projects/markdown/).
|
||||
reason: String = "No longer supported"
|
||||
) on FIELD_DEFINITION | ENUM_VALUE
|
||||
|
||||
# A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
|
||||
#
|
||||
# In some cases, you need to provide options to alter GraphQL's execution behavior
|
||||
# in ways field arguments will not suffice, such as conditionally including or
|
||||
# skipping a field. Directives provide this by describing additional information
|
||||
# to the executor.
|
||||
type __Directive {
|
||||
name: String!
|
||||
description: String
|
||||
locations: [__DirectiveLocation!]!
|
||||
args: [__InputValue!]!
|
||||
}
|
||||
|
||||
# A Directive can be adjacent to many parts of the GraphQL language, a
|
||||
# __DirectiveLocation describes one such possible adjacencies.
|
||||
enum __DirectiveLocation {
|
||||
# Location adjacent to a query operation.
|
||||
QUERY
|
||||
# Location adjacent to a mutation operation.
|
||||
MUTATION
|
||||
# Location adjacent to a subscription operation.
|
||||
SUBSCRIPTION
|
||||
# Location adjacent to a field.
|
||||
FIELD
|
||||
# Location adjacent to a fragment definition.
|
||||
FRAGMENT_DEFINITION
|
||||
# Location adjacent to a fragment spread.
|
||||
FRAGMENT_SPREAD
|
||||
# Location adjacent to an inline fragment.
|
||||
INLINE_FRAGMENT
|
||||
# Location adjacent to a schema definition.
|
||||
SCHEMA
|
||||
# Location adjacent to a scalar definition.
|
||||
SCALAR
|
||||
# Location adjacent to an object type definition.
|
||||
OBJECT
|
||||
# Location adjacent to a field definition.
|
||||
FIELD_DEFINITION
|
||||
# Location adjacent to an argument definition.
|
||||
ARGUMENT_DEFINITION
|
||||
# Location adjacent to an interface definition.
|
||||
INTERFACE
|
||||
# Location adjacent to a union definition.
|
||||
UNION
|
||||
# Location adjacent to an enum definition.
|
||||
ENUM
|
||||
# Location adjacent to an enum value definition.
|
||||
ENUM_VALUE
|
||||
# Location adjacent to an input object type definition.
|
||||
INPUT_OBJECT
|
||||
# Location adjacent to an input object field definition.
|
||||
INPUT_FIELD_DEFINITION
|
||||
}
|
||||
|
||||
# One possible value for a given Enum. Enum values are unique values, not a
|
||||
# placeholder for a string or numeric value. However an Enum value is returned in
|
||||
# a JSON response as a string.
|
||||
type __EnumValue {
|
||||
name: String!
|
||||
description: String
|
||||
isDeprecated: Boolean!
|
||||
deprecationReason: String
|
||||
}
|
||||
|
||||
# Object and Interface types are described by a list of Fields, each of which has
|
||||
# a name, potentially a list of arguments, and a return type.
|
||||
type __Field {
|
||||
name: String!
|
||||
description: String
|
||||
args: [__InputValue!]!
|
||||
type: __Type!
|
||||
isDeprecated: Boolean!
|
||||
deprecationReason: String
|
||||
}
|
||||
|
||||
# Arguments provided to Fields or Directives and the input fields of an
|
||||
# InputObject are represented as Input Values which describe their type and
|
||||
# optionally a default value.
|
||||
type __InputValue {
|
||||
name: String!
|
||||
description: String
|
||||
type: __Type!
|
||||
# A GraphQL-formatted string representing the default value for this input value.
|
||||
defaultValue: String
|
||||
}
|
||||
|
||||
# A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
|
||||
# available types and directives on the server, as well as the entry points for
|
||||
# query, mutation, and subscription operations.
|
||||
type __Schema {
|
||||
# A list of all types supported by this server.
|
||||
types: [__Type!]!
|
||||
# The type that query operations will be rooted at.
|
||||
queryType: __Type!
|
||||
# If this server supports mutation, the type that mutation operations will be rooted at.
|
||||
mutationType: __Type
|
||||
# If this server support subscription, the type that subscription operations will be rooted at.
|
||||
subscriptionType: __Type
|
||||
# A list of all directives supported by this server.
|
||||
directives: [__Directive!]!
|
||||
}
|
||||
|
||||
# The fundamental unit of any GraphQL Schema is the type. There are many kinds of
|
||||
# types in GraphQL as represented by the ` + "`" + `__TypeKind` + "`" + ` enum.
|
||||
#
|
||||
# Depending on the kind of a type, certain fields describe information about that
|
||||
# type. Scalar types provide no information beyond a name and description, while
|
||||
# Enum types provide their values. Object and Interface types provide the fields
|
||||
# they describe. Abstract types, Union and Interface, provide the Object types
|
||||
# possible at runtime. List and NonNull types compose other types.
|
||||
type __Type {
|
||||
kind: __TypeKind!
|
||||
name: String
|
||||
description: String
|
||||
fields(includeDeprecated: Boolean = false): [__Field!]
|
||||
interfaces: [__Type!]
|
||||
possibleTypes: [__Type!]
|
||||
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
|
||||
inputFields: [__InputValue!]
|
||||
ofType: __Type
|
||||
}
|
||||
|
||||
# An enum describing what kind of type a given ` + "`" + `__Type` + "`" + ` is.
|
||||
enum __TypeKind {
|
||||
# Indicates this type is a scalar.
|
||||
SCALAR
|
||||
# Indicates this type is an object. ` + "`" + `fields` + "`" + ` and ` + "`" + `interfaces` + "`" + ` are valid fields.
|
||||
OBJECT
|
||||
# Indicates this type is an interface. ` + "`" + `fields` + "`" + ` and ` + "`" + `possibleTypes` + "`" + ` are valid fields.
|
||||
INTERFACE
|
||||
# Indicates this type is a union. ` + "`" + `possibleTypes` + "`" + ` is a valid field.
|
||||
UNION
|
||||
# Indicates this type is an enum. ` + "`" + `enumValues` + "`" + ` is a valid field.
|
||||
ENUM
|
||||
# Indicates this type is an input object. ` + "`" + `inputFields` + "`" + ` is a valid field.
|
||||
INPUT_OBJECT
|
||||
# Indicates this type is a list. ` + "`" + `ofType` + "`" + ` is a valid field.
|
||||
LIST
|
||||
# Indicates this type is a non-null. ` + "`" + `ofType` + "`" + ` is a valid field.
|
||||
NON_NULL
|
||||
}
|
||||
`
|
570
vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go
generated
vendored
Normal file
570
vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go
generated
vendored
Normal file
@@ -0,0 +1,570 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/scanner"
|
||||
|
||||
"github.com/graph-gophers/graphql-go/errors"
|
||||
"github.com/graph-gophers/graphql-go/internal/common"
|
||||
)
|
||||
|
||||
// Schema represents a GraphQL service's collective type system capabilities.
|
||||
// A schema is defined in terms of the types and directives it supports as well as the root
|
||||
// operation types for each kind of operation: `query`, `mutation`, and `subscription`.
|
||||
//
|
||||
// For a more formal definition, read the relevant section in the specification:
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Schema
|
||||
type Schema struct {
|
||||
// EntryPoints determines the place in the type system where `query`, `mutation`, and
|
||||
// `subscription` operations begin.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Root-Operation-Types
|
||||
//
|
||||
// NOTE: The specification refers to this concept as "Root Operation Types".
|
||||
// TODO: Rename the `EntryPoints` field to `RootOperationTypes` to align with spec terminology.
|
||||
EntryPoints map[string]NamedType
|
||||
|
||||
// Types are the fundamental unit of any GraphQL schema.
|
||||
// There are six kinds of named types, and two wrapping types.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Types
|
||||
Types map[string]NamedType
|
||||
|
||||
// TODO: Type extensions?
|
||||
// http://facebook.github.io/graphql/draft/#sec-Type-Extensions
|
||||
|
||||
// Directives are used to annotate various parts of a GraphQL document as an indicator that they
|
||||
// should be evaluated differently by a validator, executor, or client tool such as a code
|
||||
// generator.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Type-System.Directives
|
||||
Directives map[string]*DirectiveDecl
|
||||
|
||||
entryPointNames map[string]string
|
||||
objects []*Object
|
||||
unions []*Union
|
||||
enums []*Enum
|
||||
}
|
||||
|
||||
// Resolve a named type in the schema by its name.
|
||||
func (s *Schema) Resolve(name string) common.Type {
|
||||
return s.Types[name]
|
||||
}
|
||||
|
||||
// NamedType represents a type with a name.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#NamedType
|
||||
type NamedType interface {
|
||||
common.Type
|
||||
TypeName() string
|
||||
Description() string
|
||||
}
|
||||
|
||||
// Scalar types represent primitive leaf values (e.g. a string or an integer) in a GraphQL type
|
||||
// system.
|
||||
//
|
||||
// GraphQL responses take the form of a hierarchical tree; the leaves on these trees are GraphQL
|
||||
// scalars.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Scalars
|
||||
type Scalar struct {
|
||||
Name string
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
}
|
||||
|
||||
// Object types represent a list of named fields, each of which yield a value of a specific type.
|
||||
//
|
||||
// GraphQL queries are hierarchical and composed, describing a tree of information.
|
||||
// While Scalar types describe the leaf values of these hierarchical types, Objects describe the
|
||||
// intermediate levels.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Objects
|
||||
type Object struct {
|
||||
Name string
|
||||
Interfaces []*Interface
|
||||
Fields FieldList
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
|
||||
interfaceNames []string
|
||||
}
|
||||
|
||||
// Interface types represent a list of named fields and their arguments.
|
||||
//
|
||||
// GraphQL objects can then implement these interfaces which requires that the object type will
|
||||
// define all fields defined by those interfaces.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Interfaces
|
||||
type Interface struct {
|
||||
Name string
|
||||
PossibleTypes []*Object
|
||||
Fields FieldList // NOTE: the spec refers to this as `FieldsDefinition`.
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
}
|
||||
|
||||
// Union types represent objects that could be one of a list of GraphQL object types, but provides no
|
||||
// guaranteed fields between those types.
|
||||
//
|
||||
// They also differ from interfaces in that object types declare what interfaces they implement, but
|
||||
// are not aware of what unions contain them.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Unions
|
||||
type Union struct {
|
||||
Name string
|
||||
PossibleTypes []*Object // NOTE: the spec refers to this as `UnionMemberTypes`.
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
|
||||
typeNames []string
|
||||
}
|
||||
|
||||
// Enum types describe a set of possible values.
|
||||
//
|
||||
// Like scalar types, Enum types also represent leaf values in a GraphQL type system.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Enums
|
||||
type Enum struct {
|
||||
Name string
|
||||
Values []*EnumValue // NOTE: the spec refers to this as `EnumValuesDefinition`.
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
}
|
||||
|
||||
// EnumValue types are unique values that may be serialized as a string: the name of the
|
||||
// represented value.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#EnumValueDefinition
|
||||
type EnumValue struct {
|
||||
Name string
|
||||
Directives common.DirectiveList
|
||||
Desc string
|
||||
// TODO: Add a list of directives?
|
||||
}
|
||||
|
||||
// InputObject types define a set of input fields; the input fields are either scalars, enums, or
|
||||
// other input objects.
|
||||
//
|
||||
// This allows arguments to accept arbitrarily complex structs.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#sec-Input-Objects
|
||||
type InputObject struct {
|
||||
Name string
|
||||
Desc string
|
||||
Values common.InputValueList
|
||||
// TODO: Add a list of directives?
|
||||
}
|
||||
|
||||
// FieldsList is a list of an Object's Fields.
|
||||
//
|
||||
// http://facebook.github.io/graphql/draft/#FieldsDefinition
|
||||
type FieldList []*Field
|
||||
|
||||
// Get iterates over the field list, returning a pointer-to-Field when the field name matches the
|
||||
// provided `name` argument.
|
||||
// Returns nil when no field was found by that name.
|
||||
func (l FieldList) Get(name string) *Field {
|
||||
for _, f := range l {
|
||||
if f.Name == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Names returns a string slice of the field names in the FieldList.
|
||||
func (l FieldList) Names() []string {
|
||||
names := make([]string, len(l))
|
||||
for i, f := range l {
|
||||
names[i] = f.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// http://facebook.github.io/graphql/draft/#sec-Type-System.Directives
|
||||
type DirectiveDecl struct {
|
||||
Name string
|
||||
Desc string
|
||||
Locs []string
|
||||
Args common.InputValueList
|
||||
}
|
||||
|
||||
func (*Scalar) Kind() string { return "SCALAR" }
|
||||
func (*Object) Kind() string { return "OBJECT" }
|
||||
func (*Interface) Kind() string { return "INTERFACE" }
|
||||
func (*Union) Kind() string { return "UNION" }
|
||||
func (*Enum) Kind() string { return "ENUM" }
|
||||
func (*InputObject) Kind() string { return "INPUT_OBJECT" }
|
||||
|
||||
func (t *Scalar) String() string { return t.Name }
|
||||
func (t *Object) String() string { return t.Name }
|
||||
func (t *Interface) String() string { return t.Name }
|
||||
func (t *Union) String() string { return t.Name }
|
||||
func (t *Enum) String() string { return t.Name }
|
||||
func (t *InputObject) String() string { return t.Name }
|
||||
|
||||
func (t *Scalar) TypeName() string { return t.Name }
|
||||
func (t *Object) TypeName() string { return t.Name }
|
||||
func (t *Interface) TypeName() string { return t.Name }
|
||||
func (t *Union) TypeName() string { return t.Name }
|
||||
func (t *Enum) TypeName() string { return t.Name }
|
||||
func (t *InputObject) TypeName() string { return t.Name }
|
||||
|
||||
func (t *Scalar) Description() string { return t.Desc }
|
||||
func (t *Object) Description() string { return t.Desc }
|
||||
func (t *Interface) Description() string { return t.Desc }
|
||||
func (t *Union) Description() string { return t.Desc }
|
||||
func (t *Enum) Description() string { return t.Desc }
|
||||
func (t *InputObject) Description() string { return t.Desc }
|
||||
|
||||
// Field is a conceptual function which yields values.
|
||||
// http://facebook.github.io/graphql/draft/#FieldDefinition
|
||||
type Field struct {
|
||||
Name string
|
||||
Args common.InputValueList // NOTE: the spec refers to this as `ArgumentsDefinition`.
|
||||
Type common.Type
|
||||
Directives common.DirectiveList
|
||||
Desc string
|
||||
}
|
||||
|
||||
// New initializes an instance of Schema.
|
||||
func New() *Schema {
|
||||
s := &Schema{
|
||||
entryPointNames: make(map[string]string),
|
||||
Types: make(map[string]NamedType),
|
||||
Directives: make(map[string]*DirectiveDecl),
|
||||
}
|
||||
for n, t := range Meta.Types {
|
||||
s.Types[n] = t
|
||||
}
|
||||
for n, d := range Meta.Directives {
|
||||
s.Directives[n] = d
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Parse the schema string.
|
||||
func (s *Schema) Parse(schemaString string) error {
|
||||
l := common.NewLexer(schemaString)
|
||||
|
||||
err := l.CatchSyntaxError(func() { parseSchema(s, l) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, t := range s.Types {
|
||||
if err := resolveNamedType(s, t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, d := range s.Directives {
|
||||
for _, arg := range d.Args {
|
||||
t, err := common.ResolveType(arg.Type, s.Resolve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
arg.Type = t
|
||||
}
|
||||
}
|
||||
|
||||
s.EntryPoints = make(map[string]NamedType)
|
||||
for key, name := range s.entryPointNames {
|
||||
t, ok := s.Types[name]
|
||||
if !ok {
|
||||
if !ok {
|
||||
return errors.Errorf("type %q not found", name)
|
||||
}
|
||||
}
|
||||
s.EntryPoints[key] = t
|
||||
}
|
||||
|
||||
for _, obj := range s.objects {
|
||||
obj.Interfaces = make([]*Interface, len(obj.interfaceNames))
|
||||
for i, intfName := range obj.interfaceNames {
|
||||
t, ok := s.Types[intfName]
|
||||
if !ok {
|
||||
return errors.Errorf("interface %q not found", intfName)
|
||||
}
|
||||
intf, ok := t.(*Interface)
|
||||
if !ok {
|
||||
return errors.Errorf("type %q is not an interface", intfName)
|
||||
}
|
||||
obj.Interfaces[i] = intf
|
||||
intf.PossibleTypes = append(intf.PossibleTypes, obj)
|
||||
}
|
||||
}
|
||||
|
||||
for _, union := range s.unions {
|
||||
union.PossibleTypes = make([]*Object, len(union.typeNames))
|
||||
for i, name := range union.typeNames {
|
||||
t, ok := s.Types[name]
|
||||
if !ok {
|
||||
return errors.Errorf("object type %q not found", name)
|
||||
}
|
||||
obj, ok := t.(*Object)
|
||||
if !ok {
|
||||
return errors.Errorf("type %q is not an object", name)
|
||||
}
|
||||
union.PossibleTypes[i] = obj
|
||||
}
|
||||
}
|
||||
|
||||
for _, enum := range s.enums {
|
||||
for _, value := range enum.Values {
|
||||
if err := resolveDirectives(s, value.Directives); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveNamedType(s *Schema, t NamedType) error {
|
||||
switch t := t.(type) {
|
||||
case *Object:
|
||||
for _, f := range t.Fields {
|
||||
if err := resolveField(s, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *Interface:
|
||||
for _, f := range t.Fields {
|
||||
if err := resolveField(s, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *InputObject:
|
||||
if err := resolveInputObject(s, t.Values); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveField(s *Schema, f *Field) error {
|
||||
t, err := common.ResolveType(f.Type, s.Resolve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Type = t
|
||||
if err := resolveDirectives(s, f.Directives); err != nil {
|
||||
return err
|
||||
}
|
||||
return resolveInputObject(s, f.Args)
|
||||
}
|
||||
|
||||
func resolveDirectives(s *Schema, directives common.DirectiveList) error {
|
||||
for _, d := range directives {
|
||||
dirName := d.Name.Name
|
||||
dd, ok := s.Directives[dirName]
|
||||
if !ok {
|
||||
return errors.Errorf("directive %q not found", dirName)
|
||||
}
|
||||
for _, arg := range d.Args {
|
||||
if dd.Args.Get(arg.Name.Name) == nil {
|
||||
return errors.Errorf("invalid argument %q for directive %q", arg.Name.Name, dirName)
|
||||
}
|
||||
}
|
||||
for _, arg := range dd.Args {
|
||||
if _, ok := d.Args.Get(arg.Name.Name); !ok {
|
||||
d.Args = append(d.Args, common.Argument{Name: arg.Name, Value: arg.Default})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveInputObject(s *Schema, values common.InputValueList) error {
|
||||
for _, v := range values {
|
||||
t, err := common.ResolveType(v.Type, s.Resolve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Type = t
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseSchema(s *Schema, l *common.Lexer) {
|
||||
l.Consume()
|
||||
|
||||
for l.Peek() != scanner.EOF {
|
||||
desc := l.DescComment()
|
||||
switch x := l.ConsumeIdent(); x {
|
||||
|
||||
case "schema":
|
||||
l.ConsumeToken('{')
|
||||
for l.Peek() != '}' {
|
||||
name := l.ConsumeIdent()
|
||||
l.ConsumeToken(':')
|
||||
typ := l.ConsumeIdent()
|
||||
s.entryPointNames[name] = typ
|
||||
}
|
||||
l.ConsumeToken('}')
|
||||
|
||||
case "type":
|
||||
obj := parseObjectDef(l)
|
||||
obj.Desc = desc
|
||||
s.Types[obj.Name] = obj
|
||||
s.objects = append(s.objects, obj)
|
||||
|
||||
case "interface":
|
||||
iface := parseInterfaceDef(l)
|
||||
iface.Desc = desc
|
||||
s.Types[iface.Name] = iface
|
||||
|
||||
case "union":
|
||||
union := parseUnionDef(l)
|
||||
union.Desc = desc
|
||||
s.Types[union.Name] = union
|
||||
s.unions = append(s.unions, union)
|
||||
|
||||
case "enum":
|
||||
enum := parseEnumDef(l)
|
||||
enum.Desc = desc
|
||||
s.Types[enum.Name] = enum
|
||||
s.enums = append(s.enums, enum)
|
||||
|
||||
case "input":
|
||||
input := parseInputDef(l)
|
||||
input.Desc = desc
|
||||
s.Types[input.Name] = input
|
||||
|
||||
case "scalar":
|
||||
name := l.ConsumeIdent()
|
||||
s.Types[name] = &Scalar{Name: name, Desc: desc}
|
||||
|
||||
case "directive":
|
||||
directive := parseDirectiveDef(l)
|
||||
directive.Desc = desc
|
||||
s.Directives[directive.Name] = directive
|
||||
|
||||
default:
|
||||
// TODO: Add support for type extensions.
|
||||
l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union", "input", "scalar" or "directive"`, x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseObjectDef(l *common.Lexer) *Object {
|
||||
object := &Object{Name: l.ConsumeIdent()}
|
||||
|
||||
if l.Peek() == scanner.Ident {
|
||||
l.ConsumeKeyword("implements")
|
||||
|
||||
for l.Peek() != '{' {
|
||||
if l.Peek() == '&' {
|
||||
l.ConsumeToken('&')
|
||||
}
|
||||
|
||||
object.interfaceNames = append(object.interfaceNames, l.ConsumeIdent())
|
||||
}
|
||||
}
|
||||
|
||||
l.ConsumeToken('{')
|
||||
object.Fields = parseFieldsDef(l)
|
||||
l.ConsumeToken('}')
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func parseInterfaceDef(l *common.Lexer) *Interface {
|
||||
i := &Interface{Name: l.ConsumeIdent()}
|
||||
|
||||
l.ConsumeToken('{')
|
||||
i.Fields = parseFieldsDef(l)
|
||||
l.ConsumeToken('}')
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func parseUnionDef(l *common.Lexer) *Union {
|
||||
union := &Union{Name: l.ConsumeIdent()}
|
||||
|
||||
l.ConsumeToken('=')
|
||||
union.typeNames = []string{l.ConsumeIdent()}
|
||||
for l.Peek() == '|' {
|
||||
l.ConsumeToken('|')
|
||||
union.typeNames = append(union.typeNames, l.ConsumeIdent())
|
||||
}
|
||||
|
||||
return union
|
||||
}
|
||||
|
||||
func parseInputDef(l *common.Lexer) *InputObject {
|
||||
i := &InputObject{}
|
||||
i.Name = l.ConsumeIdent()
|
||||
l.ConsumeToken('{')
|
||||
for l.Peek() != '}' {
|
||||
i.Values = append(i.Values, common.ParseInputValue(l))
|
||||
}
|
||||
l.ConsumeToken('}')
|
||||
return i
|
||||
}
|
||||
|
||||
func parseEnumDef(l *common.Lexer) *Enum {
|
||||
enum := &Enum{Name: l.ConsumeIdent()}
|
||||
|
||||
l.ConsumeToken('{')
|
||||
for l.Peek() != '}' {
|
||||
v := &EnumValue{
|
||||
Desc: l.DescComment(),
|
||||
Name: l.ConsumeIdent(),
|
||||
Directives: common.ParseDirectives(l),
|
||||
}
|
||||
|
||||
enum.Values = append(enum.Values, v)
|
||||
}
|
||||
l.ConsumeToken('}')
|
||||
return enum
|
||||
}
|
||||
|
||||
func parseDirectiveDef(l *common.Lexer) *DirectiveDecl {
|
||||
l.ConsumeToken('@')
|
||||
d := &DirectiveDecl{Name: l.ConsumeIdent()}
|
||||
|
||||
if l.Peek() == '(' {
|
||||
l.ConsumeToken('(')
|
||||
for l.Peek() != ')' {
|
||||
v := common.ParseInputValue(l)
|
||||
d.Args = append(d.Args, v)
|
||||
}
|
||||
l.ConsumeToken(')')
|
||||
}
|
||||
|
||||
l.ConsumeKeyword("on")
|
||||
|
||||
for {
|
||||
loc := l.ConsumeIdent()
|
||||
d.Locs = append(d.Locs, loc)
|
||||
if l.Peek() != '|' {
|
||||
break
|
||||
}
|
||||
l.ConsumeToken('|')
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func parseFieldsDef(l *common.Lexer) FieldList {
|
||||
var fields FieldList
|
||||
for l.Peek() != '}' {
|
||||
f := &Field{}
|
||||
f.Desc = l.DescComment()
|
||||
f.Name = l.ConsumeIdent()
|
||||
if l.Peek() == '(' {
|
||||
l.ConsumeToken('(')
|
||||
for l.Peek() != ')' {
|
||||
f.Args = append(f.Args, common.ParseInputValue(l))
|
||||
}
|
||||
l.ConsumeToken(')')
|
||||
}
|
||||
l.ConsumeToken(':')
|
||||
f.Type = common.ParseType(l)
|
||||
f.Directives = common.ParseDirectives(l)
|
||||
fields = append(fields, f)
|
||||
}
|
||||
return fields
|
||||
}
|
Reference in New Issue
Block a user