github.com/dgraph-io/dgraph@v1.2.8/graphql/schema/wrappers.go (about)

     1  /*
     2   * Copyright 2019 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package schema
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/dgraph-io/dgraph/x"
    25  	"github.com/pkg/errors"
    26  	"github.com/vektah/gqlparser/ast"
    27  )
    28  
    29  // Wrap the github.com/vektah/gqlparser/ast defintions so that the bulk of the GraphQL
    30  // algorithm and interface is dependent on behaviours we expect from a GraphQL schema
    31  // and validation, but not dependent the exact structure in the gqlparser.
    32  //
    33  // This also auto hooks up some bookkeeping that's otherwise no fun.  E.g. getting values for
    34  // field arguments requires the variable map from the operation - so we'd need to carry vars
    35  // through all the resolver functions.  Much nicer if they are resolved by magic here.
    36  
    37  // QueryType is currently supported queries
    38  type QueryType string
    39  
    40  // MutationType is currently supported mutations
    41  type MutationType string
    42  
    43  // Query/Mutation types and arg names
    44  const (
    45  	GetQuery             QueryType    = "get"
    46  	FilterQuery          QueryType    = "query"
    47  	SchemaQuery          QueryType    = "schema"
    48  	NotSupportedQuery    QueryType    = "notsupported"
    49  	AddMutation          MutationType = "add"
    50  	UpdateMutation       MutationType = "update"
    51  	DeleteMutation       MutationType = "delete"
    52  	NotSupportedMutation MutationType = "notsupported"
    53  	IDType                            = "ID"
    54  	IDArgName                         = "id"
    55  	InputArgName                      = "input"
    56  	FilterArgName                     = "filter"
    57  )
    58  
    59  // Schema represents a valid GraphQL schema
    60  type Schema interface {
    61  	Operation(r *Request) (Operation, error)
    62  	Queries(t QueryType) []string
    63  	Mutations(t MutationType) []string
    64  }
    65  
    66  // An Operation is a single valid GraphQL operation.  It contains either
    67  // Queries or Mutations, but not both.  Subscriptions are not yet supported.
    68  type Operation interface {
    69  	Queries() []Query
    70  	Mutations() []Mutation
    71  	Schema() Schema
    72  	IsQuery() bool
    73  	IsMutation() bool
    74  	IsSubscription() bool
    75  }
    76  
    77  // A Field is one field from an Operation.
    78  type Field interface {
    79  	Name() string
    80  	Alias() string
    81  	ResponseName() string
    82  	ArgValue(name string) interface{}
    83  	IsArgListType(name string) bool
    84  	IDArgValue() (*string, uint64, error)
    85  	XIDArg() string
    86  	SetArgTo(arg string, val interface{})
    87  	Skip() bool
    88  	Include() bool
    89  	Type() Type
    90  	SelectionSet() []Field
    91  	Location() x.Location
    92  	DgraphPredicate() string
    93  	Operation() Operation
    94  	// InterfaceType tells us whether this field represents a GraphQL Interface.
    95  	InterfaceType() bool
    96  	IncludeInterfaceField(types []interface{}) bool
    97  	TypeName(dgraphTypes []interface{}) string
    98  	GetObjectName() string
    99  }
   100  
   101  // A Mutation is a field (from the schema's Mutation type) from an Operation
   102  type Mutation interface {
   103  	Field
   104  	MutationType() MutationType
   105  	MutatedType() Type
   106  	QueryField() Field
   107  }
   108  
   109  // A Query is a field (from the schema's Query type) from an Operation
   110  type Query interface {
   111  	Field
   112  	QueryType() QueryType
   113  	Rename(newName string)
   114  }
   115  
   116  // A Type is a GraphQL type like: Float, T, T! and [T!]!.  If it's not a list, then
   117  // ListType is nil.  If it's an object type then Field gets field definitions by
   118  // name from the definition of the type; IDField gets the ID field of the type.
   119  type Type interface {
   120  	Field(name string) FieldDefinition
   121  	IDField() FieldDefinition
   122  	XIDField() FieldDefinition
   123  	Name() string
   124  	DgraphName() string
   125  	DgraphPredicate(fld string) string
   126  	Nullable() bool
   127  	ListType() Type
   128  	Interfaces() []string
   129  	EnsureNonNulls(map[string]interface{}, string) error
   130  	fmt.Stringer
   131  }
   132  
   133  // A FieldDefinition is a field as defined in some Type in the schema.  As opposed
   134  // to a Field, which is an instance of a query or mutation asking for a field
   135  // (which in turn must have a FieldDefinition of the right type in the schema.)
   136  type FieldDefinition interface {
   137  	Name() string
   138  	Type() Type
   139  	IsID() bool
   140  	Inverse() (Type, FieldDefinition)
   141  }
   142  
   143  type astType struct {
   144  	typ             *ast.Type
   145  	inSchema        *ast.Schema
   146  	dgraphPredicate map[string]map[string]string
   147  }
   148  
   149  type schema struct {
   150  	schema *ast.Schema
   151  	// dgraphPredicate gives us the dgraph predicate corresponding to a typeName + fieldName.
   152  	// It is pre-computed so that runtime queries and mutations can look it
   153  	// up quickly.
   154  	// The key for the first map are the type names. The second map has a mapping of the
   155  	// fieldName => dgraphPredicate.
   156  	dgraphPredicate map[string]map[string]string
   157  	// Map of mutation field name to mutated type.
   158  	mutatedType map[string]*astType
   159  	// Map from typename to ast.Definition
   160  	typeNameAst map[string][]*ast.Definition
   161  }
   162  
   163  type operation struct {
   164  	op   *ast.OperationDefinition
   165  	vars map[string]interface{}
   166  
   167  	// The fields below are used by schema introspection queries.
   168  	query    string
   169  	doc      *ast.QueryDocument
   170  	inSchema *schema
   171  }
   172  
   173  type field struct {
   174  	field *ast.Field
   175  	op    *operation
   176  	sel   ast.Selection
   177  	// arguments contains the computed values for arguments taking into account the values
   178  	// for the GraphQL variables supplied in the query.
   179  	arguments map[string]interface{}
   180  }
   181  
   182  type fieldDefinition struct {
   183  	fieldDef        *ast.FieldDefinition
   184  	inSchema        *ast.Schema
   185  	dgraphPredicate map[string]map[string]string
   186  }
   187  
   188  type mutation field
   189  type query field
   190  
   191  func (s *schema) Queries(t QueryType) []string {
   192  	var result []string
   193  	for _, q := range s.schema.Query.Fields {
   194  		if queryType(q.Name) == t {
   195  			result = append(result, q.Name)
   196  		}
   197  	}
   198  	return result
   199  }
   200  
   201  func (s *schema) Mutations(t MutationType) []string {
   202  	var result []string
   203  	for _, m := range s.schema.Mutation.Fields {
   204  		if mutationType(m.Name) == t {
   205  			result = append(result, m.Name)
   206  		}
   207  	}
   208  	return result
   209  }
   210  
   211  func (o *operation) IsQuery() bool {
   212  	return o.op.Operation == ast.Query
   213  }
   214  
   215  func (o *operation) IsMutation() bool {
   216  	return o.op.Operation == ast.Mutation
   217  }
   218  
   219  func (o *operation) IsSubscription() bool {
   220  	return o.op.Operation == ast.Subscription
   221  }
   222  
   223  func (o *operation) Schema() Schema {
   224  	return o.inSchema
   225  }
   226  
   227  func (o *operation) Queries() (qs []Query) {
   228  	if !o.IsQuery() {
   229  		return
   230  	}
   231  
   232  	for _, s := range o.op.SelectionSet {
   233  		if f, ok := s.(*ast.Field); ok {
   234  			qs = append(qs, &query{field: f, op: o, sel: s})
   235  		}
   236  	}
   237  
   238  	return
   239  }
   240  
   241  func (o *operation) Mutations() (ms []Mutation) {
   242  	if !o.IsMutation() {
   243  		return
   244  	}
   245  
   246  	for _, s := range o.op.SelectionSet {
   247  		if f, ok := s.(*ast.Field); ok {
   248  			ms = append(ms, &mutation{field: f, op: o})
   249  		}
   250  	}
   251  
   252  	return
   253  }
   254  
   255  // parentInterface returns the name of an interface that a field belonging to a type definition
   256  // typDef inherited from. If there is no such interface, then it returns an empty string.
   257  //
   258  // Given the following schema
   259  // interface A {
   260  //   name: String
   261  // }
   262  //
   263  // type B implements A {
   264  //	 name: String
   265  //   age: Int
   266  // }
   267  //
   268  // calling parentInterface on the fieldName name with type definition for B, would return A.
   269  func parentInterface(sch *ast.Schema, typDef *ast.Definition, fieldName string) *ast.Definition {
   270  	if len(typDef.Interfaces) == 0 {
   271  		return nil
   272  	}
   273  
   274  	for _, iface := range typDef.Interfaces {
   275  		interfaceDef := sch.Types[iface]
   276  		for _, interfaceField := range interfaceDef.Fields {
   277  			if fieldName == interfaceField.Name {
   278  				return interfaceDef
   279  			}
   280  		}
   281  	}
   282  	return nil
   283  }
   284  
   285  func dgraphMapping(sch *ast.Schema) map[string]map[string]string {
   286  	const (
   287  		add     = "Add"
   288  		update  = "Update"
   289  		del     = "Delete"
   290  		payload = "Payload"
   291  	)
   292  
   293  	dgraphPredicate := make(map[string]map[string]string)
   294  	for _, inputTyp := range sch.Types {
   295  		// We only want to consider input types (object and interface) defined by the user as part
   296  		// of the schema hence we ignore BuiltIn, query and mutation types.
   297  		if inputTyp.BuiltIn || inputTyp.Name == "Query" || inputTyp.Name == "Mutation" ||
   298  			(inputTyp.Kind != ast.Object && inputTyp.Kind != ast.Interface) {
   299  			continue
   300  		}
   301  
   302  		originalTyp := inputTyp
   303  		inputTypeName := inputTyp.Name
   304  		if strings.HasPrefix(inputTypeName, add) && strings.HasSuffix(inputTypeName, payload) {
   305  			continue
   306  		}
   307  
   308  		dgraphPredicate[originalTyp.Name] = make(map[string]string)
   309  
   310  		if (strings.HasPrefix(inputTypeName, update) || strings.HasPrefix(inputTypeName, del)) &&
   311  			strings.HasSuffix(inputTypeName, payload) {
   312  			// For UpdateTypePayload and DeleteTypePayload, inputTyp should be Type.
   313  			if strings.HasPrefix(inputTypeName, update) {
   314  				inputTypeName = strings.TrimSuffix(strings.TrimPrefix(inputTypeName, update),
   315  					payload)
   316  			} else if strings.HasPrefix(inputTypeName, del) {
   317  				inputTypeName = strings.TrimSuffix(strings.TrimPrefix(inputTypeName, del), payload)
   318  			}
   319  			inputTyp = sch.Types[inputTypeName]
   320  		}
   321  
   322  		for _, fld := range inputTyp.Fields {
   323  			if isID(fld) {
   324  				// We don't need a mapping for the field, as we the dgraph predicate for them is
   325  				// fixed i.e. uid.
   326  				continue
   327  			}
   328  			typName := typeName(inputTyp)
   329  			parentInt := parentInterface(sch, inputTyp, fld.Name)
   330  			if parentInt != nil {
   331  				typName = typeName(parentInt)
   332  			}
   333  			// 1. For fields that have @dgraph(pred: xxxName) directive, field name would be
   334  			//    xxxName.
   335  			// 2. For fields where the type (or underlying interface) has a @dgraph(type: xxxName)
   336  			//    directive, field name would be xxxName.fldName.
   337  			//
   338  			// The cases below cover the cases where neither the type or field have @dgraph
   339  			// directive.
   340  			// 3. For types which don't inherit from an interface the keys, value would be.
   341  			//    typName,fldName => typName.fldName
   342  			// 4. For types which inherit fields from an interface
   343  			//    typName,fldName => interfaceName.fldName
   344  			// 5. For DeleteTypePayload type
   345  			//    DeleteTypePayload,fldName => typName.fldName
   346  
   347  			fname := fieldName(fld, typName)
   348  			dgraphPredicate[originalTyp.Name][fld.Name] = fname
   349  		}
   350  	}
   351  	return dgraphPredicate
   352  }
   353  
   354  func mutatedTypeMapping(s *ast.Schema,
   355  	dgraphPredicate map[string]map[string]string) map[string]*astType {
   356  	if s.Mutation == nil {
   357  		return nil
   358  	}
   359  
   360  	m := make(map[string]*astType, len(s.Mutation.Fields))
   361  	for _, field := range s.Mutation.Fields {
   362  		mutatedTypeName := ""
   363  		switch {
   364  		case strings.HasPrefix(field.Name, "add"):
   365  			mutatedTypeName = strings.TrimPrefix(field.Name, "add")
   366  		case strings.HasPrefix(field.Name, "update"):
   367  			mutatedTypeName = strings.TrimPrefix(field.Name, "update")
   368  		case strings.HasPrefix(field.Name, "delete"):
   369  			mutatedTypeName = strings.TrimPrefix(field.Name, "delete")
   370  		default:
   371  		}
   372  		// This is a convoluted way of getting the type for mutatedTypeName. We get the definition
   373  		// for UpdateTPayload and get the type from the first field. There is no direct way to get
   374  		// the type from the definition of an object. We use Update and not Add here because
   375  		// Interfaces only have Update.
   376  		var def *ast.Definition
   377  		if def = s.Types["Update"+mutatedTypeName+"Payload"]; def == nil {
   378  			def = s.Types["Add"+mutatedTypeName+"Payload"]
   379  		}
   380  
   381  		if def == nil {
   382  			continue
   383  		}
   384  
   385  		// Accessing 0th element should be safe to do as according to the spec an object must define
   386  		// one or more fields.
   387  		typ := def.Fields[0].Type
   388  		// This would contain mapping of mutation field name to the Type()
   389  		// for e.g. addPost => astType for Post
   390  		m[field.Name] = &astType{typ, s, dgraphPredicate}
   391  	}
   392  	return m
   393  }
   394  
   395  func typeMappings(s *ast.Schema) map[string][]*ast.Definition {
   396  	typeNameAst := make(map[string][]*ast.Definition)
   397  
   398  	for _, typ := range s.Types {
   399  		name := typeName(typ)
   400  		typeNameAst[name] = append(typeNameAst[name], typ)
   401  	}
   402  
   403  	return typeNameAst
   404  }
   405  
   406  // AsSchema wraps a github.com/vektah/gqlparser/ast.Schema.
   407  func AsSchema(s *ast.Schema) Schema {
   408  	dgraphPredicate := dgraphMapping(s)
   409  	return &schema{
   410  		schema:          s,
   411  		dgraphPredicate: dgraphPredicate,
   412  		mutatedType:     mutatedTypeMapping(s, dgraphPredicate),
   413  		typeNameAst:     typeMappings(s),
   414  	}
   415  }
   416  
   417  func responseName(f *ast.Field) string {
   418  	if f.Alias == "" {
   419  		return f.Name
   420  	}
   421  	return f.Alias
   422  }
   423  
   424  func (f *field) Name() string {
   425  	return f.field.Name
   426  }
   427  
   428  func (f *field) Alias() string {
   429  	return f.field.Alias
   430  }
   431  
   432  func (f *field) ResponseName() string {
   433  	return responseName(f.field)
   434  }
   435  
   436  func (f *field) SetArgTo(arg string, val interface{}) {
   437  	if f.arguments == nil {
   438  		f.arguments = make(map[string]interface{})
   439  	}
   440  	f.arguments[arg] = val
   441  }
   442  
   443  func (f *field) ArgValue(name string) interface{} {
   444  	if f.arguments == nil {
   445  		// Compute and cache the map first time this function is called for a field.
   446  		f.arguments = f.field.ArgumentMap(f.op.vars)
   447  	}
   448  	return f.arguments[name]
   449  }
   450  
   451  func (f *field) IsArgListType(name string) bool {
   452  	arg := f.field.Arguments.ForName(name)
   453  	if arg == nil {
   454  		return false
   455  	}
   456  
   457  	return arg.Value.ExpectedType.Elem != nil
   458  }
   459  
   460  func (f *field) Skip() bool {
   461  	dir := f.field.Directives.ForName("skip")
   462  	if dir == nil {
   463  		return false
   464  	}
   465  	return dir.ArgumentMap(f.op.vars)["if"].(bool)
   466  }
   467  
   468  func (f *field) Include() bool {
   469  	dir := f.field.Directives.ForName("include")
   470  	if dir == nil {
   471  		return true
   472  	}
   473  	return dir.ArgumentMap(f.op.vars)["if"].(bool)
   474  }
   475  
   476  func (f *field) XIDArg() string {
   477  	xidArgName := ""
   478  	for _, arg := range f.field.Arguments {
   479  		if arg.Name != IDArgName {
   480  			xidArgName = arg.Name
   481  		}
   482  	}
   483  	return f.Type().DgraphPredicate(xidArgName)
   484  }
   485  
   486  func (f *field) IDArgValue() (xid *string, uid uint64, err error) {
   487  	idField := f.Type().IDField()
   488  	xidArgName := ""
   489  	// This method is only called for Get queries. These queries can accept one of the
   490  	// combinations as input.
   491  	// 1. ID only
   492  	// 2. XID only
   493  	// 3. ID and XID fields
   494  	// Therefore, the non ID field is an XID field.
   495  	for _, arg := range f.field.Arguments {
   496  		if arg.Name != idField.Name() {
   497  			xidArgName = arg.Name
   498  		}
   499  	}
   500  	if xidArgName != "" {
   501  		xidArgVal, ok := f.ArgValue(xidArgName).(string)
   502  		pos := f.field.GetPosition()
   503  		if !ok {
   504  			err = x.GqlErrorf("Argument (%s) of %s was not able to be parsed as a string",
   505  				xidArgName, f.Name()).WithLocations(x.Location{Line: pos.Line, Column: pos.Column})
   506  			return
   507  		}
   508  		xid = &xidArgVal
   509  	}
   510  
   511  	if idField == nil && xid == nil {
   512  		// This means that both were optional and were not supplied, lets return here.
   513  		return
   514  	}
   515  
   516  	idArg := f.ArgValue(idField.Name())
   517  	if idArg != nil {
   518  		id, ok := idArg.(string)
   519  		var ierr error
   520  		uid, ierr = strconv.ParseUint(id, 0, 64)
   521  
   522  		if !ok || ierr != nil {
   523  			pos := f.field.GetPosition()
   524  			err = x.GqlErrorf("ID argument (%s) of %s was not able to be parsed", id, f.Name()).
   525  				WithLocations(x.Location{Line: pos.Line, Column: pos.Column})
   526  			return
   527  		}
   528  	}
   529  
   530  	return
   531  }
   532  
   533  func (f *field) Type() Type {
   534  	return &astType{
   535  		typ:             f.field.Definition.Type,
   536  		inSchema:        f.op.inSchema.schema,
   537  		dgraphPredicate: f.op.inSchema.dgraphPredicate,
   538  	}
   539  }
   540  
   541  func (f *field) InterfaceType() bool {
   542  	return f.op.inSchema.schema.Types[f.field.Definition.Type.Name()].Kind == ast.Interface
   543  }
   544  
   545  func (f *field) GetObjectName() string {
   546  	return f.field.ObjectDefinition.Name
   547  }
   548  
   549  func (f *field) SelectionSet() (flds []Field) {
   550  	for _, s := range f.field.SelectionSet {
   551  		if fld, ok := s.(*ast.Field); ok {
   552  			flds = append(flds, &field{
   553  				field: fld,
   554  				op:    f.op,
   555  			})
   556  		}
   557  		if fragment, ok := s.(*ast.InlineFragment); ok {
   558  			// This is the case where an inline fragment is defined within a query
   559  			// block. Usually this is for requesting some fields for a concrete type
   560  			// within a query for an interface.
   561  			for _, s := range fragment.SelectionSet {
   562  				if fld, ok := s.(*ast.Field); ok {
   563  					flds = append(flds, &field{
   564  						field: fld,
   565  						op:    f.op,
   566  					})
   567  				}
   568  			}
   569  		}
   570  	}
   571  
   572  	return
   573  }
   574  
   575  func (f *field) Location() x.Location {
   576  	return x.Location{
   577  		Line:   f.field.Position.Line,
   578  		Column: f.field.Position.Column}
   579  }
   580  
   581  func (f *field) Operation() Operation {
   582  	return f.op
   583  }
   584  
   585  func (f *field) DgraphPredicate() string {
   586  	return f.op.inSchema.dgraphPredicate[f.field.ObjectDefinition.Name][f.Name()]
   587  }
   588  
   589  func (f *field) TypeName(dgraphTypes []interface{}) string {
   590  	for _, typ := range dgraphTypes {
   591  		styp, ok := typ.(string)
   592  		if !ok {
   593  			continue
   594  		}
   595  
   596  		for _, origTyp := range f.op.inSchema.typeNameAst[styp] {
   597  			if origTyp.Kind != ast.Object {
   598  				continue
   599  			}
   600  			return origTyp.Name
   601  		}
   602  
   603  	}
   604  	return ""
   605  }
   606  
   607  func (f *field) IncludeInterfaceField(dgraphTypes []interface{}) bool {
   608  	// Given a list of dgraph types, we query the schema and find the one which is an ast.Object
   609  	// and not an Interface object.
   610  	for _, typ := range dgraphTypes {
   611  		styp, ok := typ.(string)
   612  		if !ok {
   613  			continue
   614  		}
   615  		for _, origTyp := range f.op.inSchema.typeNameAst[styp] {
   616  			if origTyp.Kind == ast.Object {
   617  				// If the field doesn't exist in the map corresponding to the object type, then we
   618  				// don't need to include it.
   619  				_, ok := f.op.inSchema.dgraphPredicate[origTyp.Name][f.Name()]
   620  				return ok || f.Name() == Typename
   621  			}
   622  		}
   623  
   624  	}
   625  	return false
   626  }
   627  
   628  func (q *query) Rename(newName string) {
   629  	q.field.Name = newName
   630  }
   631  
   632  func (q *query) Name() string {
   633  	return (*field)(q).Name()
   634  }
   635  
   636  func (q *query) Alias() string {
   637  	return (*field)(q).Alias()
   638  }
   639  
   640  func (q *query) SetArgTo(arg string, val interface{}) {
   641  	(*field)(q).SetArgTo(arg, val)
   642  }
   643  
   644  func (q *query) ArgValue(name string) interface{} {
   645  	return (*field)(q).ArgValue(name)
   646  }
   647  
   648  func (q *query) IsArgListType(name string) bool {
   649  	return (*field)(q).IsArgListType(name)
   650  }
   651  
   652  func (q *query) Skip() bool {
   653  	return false
   654  }
   655  
   656  func (q *query) Include() bool {
   657  	return true
   658  }
   659  
   660  func (q *query) IDArgValue() (*string, uint64, error) {
   661  	return (*field)(q).IDArgValue()
   662  }
   663  
   664  func (q *query) XIDArg() string {
   665  	return (*field)(q).XIDArg()
   666  }
   667  
   668  func (q *query) Type() Type {
   669  	return (*field)(q).Type()
   670  }
   671  
   672  func (q *query) SelectionSet() []Field {
   673  	return (*field)(q).SelectionSet()
   674  }
   675  
   676  func (q *query) Location() x.Location {
   677  	return (*field)(q).Location()
   678  }
   679  
   680  func (q *query) ResponseName() string {
   681  	return (*field)(q).ResponseName()
   682  }
   683  
   684  func (q *query) GetObjectName() string {
   685  	return q.field.ObjectDefinition.Name
   686  }
   687  
   688  func (q *query) QueryType() QueryType {
   689  	return queryType(q.Name())
   690  }
   691  
   692  func queryType(name string) QueryType {
   693  	switch {
   694  	case strings.HasPrefix(name, "get"):
   695  		return GetQuery
   696  	case name == "__schema" || name == "__type":
   697  		return SchemaQuery
   698  	case strings.HasPrefix(name, "query"):
   699  		return FilterQuery
   700  	default:
   701  		return NotSupportedQuery
   702  	}
   703  }
   704  
   705  func (q *query) Operation() Operation {
   706  	return (*field)(q).Operation()
   707  }
   708  
   709  func (q *query) DgraphPredicate() string {
   710  	return (*field)(q).DgraphPredicate()
   711  }
   712  
   713  func (q *query) InterfaceType() bool {
   714  	return (*field)(q).InterfaceType()
   715  }
   716  
   717  func (q *query) TypeName(dgraphTypes []interface{}) string {
   718  	return (*field)(q).TypeName(dgraphTypes)
   719  }
   720  
   721  func (q *query) IncludeInterfaceField(dgraphTypes []interface{}) bool {
   722  	return (*field)(q).IncludeInterfaceField(dgraphTypes)
   723  }
   724  
   725  func (m *mutation) Name() string {
   726  	return (*field)(m).Name()
   727  }
   728  
   729  func (m *mutation) Alias() string {
   730  	return (*field)(m).Alias()
   731  }
   732  
   733  func (m *mutation) SetArgTo(arg string, val interface{}) {
   734  	(*field)(m).SetArgTo(arg, val)
   735  }
   736  
   737  func (m *mutation) IsArgListType(name string) bool {
   738  	return (*field)(m).IsArgListType(name)
   739  }
   740  
   741  func (m *mutation) ArgValue(name string) interface{} {
   742  	return (*field)(m).ArgValue(name)
   743  }
   744  
   745  func (m *mutation) Skip() bool {
   746  	return false
   747  }
   748  
   749  func (m *mutation) Include() bool {
   750  	return true
   751  }
   752  
   753  func (m *mutation) Type() Type {
   754  	return (*field)(m).Type()
   755  }
   756  
   757  func (m *mutation) InterfaceType() bool {
   758  	return (*field)(m).InterfaceType()
   759  }
   760  
   761  func (m *mutation) XIDArg() string {
   762  	return (*field)(m).XIDArg()
   763  }
   764  
   765  func (m *mutation) IDArgValue() (*string, uint64, error) {
   766  	return (*field)(m).IDArgValue()
   767  }
   768  
   769  func (m *mutation) SelectionSet() []Field {
   770  	return (*field)(m).SelectionSet()
   771  }
   772  
   773  func (m *mutation) QueryField() Field {
   774  	// TODO: All our mutations currently have exactly 1 field, but that will change
   775  	// - need a better way to get the right field by convention.
   776  	return m.SelectionSet()[0]
   777  }
   778  
   779  func (m *mutation) Location() x.Location {
   780  	return (*field)(m).Location()
   781  }
   782  
   783  func (m *mutation) ResponseName() string {
   784  	return (*field)(m).ResponseName()
   785  }
   786  
   787  // MutatedType returns the underlying type that gets mutated by m.
   788  //
   789  // It's not the same as the response type of m because mutations don't directly
   790  // return what they mutate.  Mutations return a payload package that includes
   791  // the actual node mutated as a field.
   792  func (m *mutation) MutatedType() Type {
   793  	// ATM there's a single field in the mutation payload.
   794  	return m.op.inSchema.mutatedType[m.Name()]
   795  }
   796  
   797  func (m *mutation) GetObjectName() string {
   798  	return m.field.ObjectDefinition.Name
   799  }
   800  
   801  func (m *mutation) MutationType() MutationType {
   802  	return mutationType(m.Name())
   803  }
   804  
   805  func mutationType(name string) MutationType {
   806  	switch {
   807  	case strings.HasPrefix(name, "add"):
   808  		return AddMutation
   809  	case strings.HasPrefix(name, "update"):
   810  		return UpdateMutation
   811  	case strings.HasPrefix(name, "delete"):
   812  		return DeleteMutation
   813  	default:
   814  		return NotSupportedMutation
   815  	}
   816  }
   817  
   818  func (m *mutation) Operation() Operation {
   819  	return (*field)(m).Operation()
   820  }
   821  
   822  func (m *mutation) DgraphPredicate() string {
   823  	return (*field)(m).DgraphPredicate()
   824  }
   825  
   826  func (m *mutation) TypeName(dgraphTypes []interface{}) string {
   827  	return (*field)(m).TypeName(dgraphTypes)
   828  }
   829  
   830  func (m *mutation) IncludeInterfaceField(dgraphTypes []interface{}) bool {
   831  	return (*field)(m).IncludeInterfaceField(dgraphTypes)
   832  }
   833  
   834  func (t *astType) Field(name string) FieldDefinition {
   835  	typName := t.Name()
   836  	parentInt := parentInterface(t.inSchema, t.inSchema.Types[typName], name)
   837  	if parentInt != nil {
   838  		typName = parentInt.Name
   839  	}
   840  
   841  	return &fieldDefinition{
   842  		// this ForName lookup is a loop in the underlying schema :-(
   843  		fieldDef:        t.inSchema.Types[typName].Fields.ForName(name),
   844  		inSchema:        t.inSchema,
   845  		dgraphPredicate: t.dgraphPredicate,
   846  	}
   847  }
   848  
   849  func (fd *fieldDefinition) Name() string {
   850  	return fd.fieldDef.Name
   851  }
   852  
   853  func (fd *fieldDefinition) IsID() bool {
   854  	return isID(fd.fieldDef)
   855  }
   856  
   857  func hasIDDirective(fd *ast.FieldDefinition) bool {
   858  	id := fd.Directives.ForName("id")
   859  	return id != nil
   860  }
   861  
   862  func isID(fd *ast.FieldDefinition) bool {
   863  	return fd.Type.Name() == "ID"
   864  }
   865  
   866  func (fd *fieldDefinition) Type() Type {
   867  	return &astType{
   868  		typ:             fd.fieldDef.Type,
   869  		inSchema:        fd.inSchema,
   870  		dgraphPredicate: fd.dgraphPredicate,
   871  	}
   872  }
   873  
   874  func (fd *fieldDefinition) Inverse() (Type, FieldDefinition) {
   875  
   876  	invDirective := fd.fieldDef.Directives.ForName(inverseDirective)
   877  	if invDirective == nil {
   878  		return nil, nil
   879  	}
   880  
   881  	invFieldArg := invDirective.Arguments.ForName(inverseArg)
   882  	if invFieldArg == nil {
   883  		return nil, nil // really not possible
   884  	}
   885  
   886  	// typ must exist if the schema passed GQL validation
   887  	typ := fd.inSchema.Types[fd.Type().Name()]
   888  
   889  	// fld must exist if the schema passed our validation
   890  	fld := typ.Fields.ForName(invFieldArg.Value.Raw)
   891  
   892  	return fd.Type(), &fieldDefinition{fieldDef: fld, inSchema: fd.inSchema}
   893  }
   894  
   895  func (t *astType) Name() string {
   896  	if t.typ.NamedType == "" {
   897  		return t.typ.Elem.NamedType
   898  	}
   899  	return t.typ.NamedType
   900  }
   901  
   902  func (t *astType) DgraphName() string {
   903  	typeDef := t.inSchema.Types[t.typ.Name()]
   904  	name := typeName(typeDef)
   905  	if name != "" {
   906  		return name
   907  	}
   908  	return t.Name()
   909  }
   910  
   911  func (t *astType) Nullable() bool {
   912  	return !t.typ.NonNull
   913  }
   914  
   915  func (t *astType) ListType() Type {
   916  	if t.typ.Elem == nil {
   917  		return nil
   918  	}
   919  	return &astType{typ: t.typ.Elem}
   920  }
   921  
   922  // DgraphPredicate returns the name of the predicate in Dgraph that represents this
   923  // type's field fld.  Mostly this will be type_name.field_name,.
   924  func (t *astType) DgraphPredicate(fld string) string {
   925  	return t.dgraphPredicate[t.Name()][fld]
   926  }
   927  
   928  func (t *astType) String() string {
   929  	if t == nil {
   930  		return ""
   931  	}
   932  
   933  	var sb strings.Builder
   934  	// give it enough space in case it happens to be `[t.Name()!]!`
   935  	sb.Grow(len(t.Name()) + 4)
   936  
   937  	if t.ListType() == nil {
   938  		x.Check2(sb.WriteString(t.Name()))
   939  	} else {
   940  		// There's no lists of lists, so this needn't be recursive
   941  		x.Check2(sb.WriteRune('['))
   942  		x.Check2(sb.WriteString(t.Name()))
   943  		if !t.ListType().Nullable() {
   944  			x.Check2(sb.WriteRune('!'))
   945  		}
   946  		x.Check2(sb.WriteRune(']'))
   947  	}
   948  
   949  	if !t.Nullable() {
   950  		x.Check2(sb.WriteRune('!'))
   951  	}
   952  
   953  	return sb.String()
   954  }
   955  
   956  func (t *astType) IDField() FieldDefinition {
   957  	def := t.inSchema.Types[t.Name()]
   958  	if def.Kind != ast.Object && def.Kind != ast.Interface {
   959  		return nil
   960  	}
   961  
   962  	for _, fd := range def.Fields {
   963  		if isID(fd) {
   964  			return &fieldDefinition{
   965  				fieldDef: fd,
   966  				inSchema: t.inSchema,
   967  			}
   968  		}
   969  	}
   970  
   971  	return nil
   972  }
   973  
   974  func (t *astType) XIDField() FieldDefinition {
   975  	def := t.inSchema.Types[t.Name()]
   976  	if def.Kind != ast.Object && def.Kind != ast.Interface {
   977  		return nil
   978  	}
   979  
   980  	for _, fd := range def.Fields {
   981  		if hasIDDirective(fd) {
   982  			return &fieldDefinition{
   983  				fieldDef: fd,
   984  				inSchema: t.inSchema,
   985  			}
   986  		}
   987  	}
   988  
   989  	return nil
   990  }
   991  
   992  func (t *astType) Interfaces() []string {
   993  	interfaces := t.inSchema.Types[t.typ.Name()].Interfaces
   994  	if len(interfaces) == 0 {
   995  		return nil
   996  	}
   997  
   998  	// Look up the interface types in the schema and find their typeName which could have been
   999  	// overwritten using @dgraph(type: ...)
  1000  	names := make([]string, 0, len(interfaces))
  1001  	for _, intr := range interfaces {
  1002  		i := t.inSchema.Types[intr]
  1003  		name := intr
  1004  		if n := typeName(i); n != "" {
  1005  			name = n
  1006  		}
  1007  		names = append(names, name)
  1008  	}
  1009  	return names
  1010  }
  1011  
  1012  // CheckNonNulls checks that any non nullables in t are present in obj.
  1013  // Fields of type ID are not checked, nor is any exclusion.
  1014  //
  1015  // For our reference types for adding/linking objects, we'd like to have something like
  1016  //
  1017  // input PostRef {
  1018  // 	id: ID!
  1019  // }
  1020  //
  1021  // input PostNew {
  1022  // 	title: String!
  1023  // 	text: String
  1024  // 	author: AuthorRef!
  1025  // }
  1026  //
  1027  // and then have something like this
  1028  //
  1029  // input PostNewOrReference = PostRef | PostNew
  1030  //
  1031  // input AuthorNew {
  1032  //   ...
  1033  //   posts: [PostNewOrReference]
  1034  // }
  1035  //
  1036  // but GraphQL doesn't allow union types in input, so best we can do is
  1037  //
  1038  // input PostRef {
  1039  // 	id: ID
  1040  // 	title: String
  1041  // 	text: String
  1042  // 	author: AuthorRef
  1043  // }
  1044  //
  1045  // and then check ourselves that either there's an ID, or there's all the bits to
  1046  // satisfy a valid post.
  1047  func (t *astType) EnsureNonNulls(obj map[string]interface{}, exclusion string) error {
  1048  	for _, fld := range t.inSchema.Types[t.Name()].Fields {
  1049  		if fld.Type.NonNull && !isID(fld) && !(fld.Name == exclusion) {
  1050  			if val, ok := obj[fld.Name]; !ok || val == nil {
  1051  				return errors.Errorf(
  1052  					"type %s requires a value for field %s, but no value present",
  1053  					t.Name(), fld.Name)
  1054  			}
  1055  		}
  1056  	}
  1057  	return nil
  1058  }