diff options
Diffstat (limited to 'vendor/github.com/graphql-go/graphql/definition.go')
-rw-r--r-- | vendor/github.com/graphql-go/graphql/definition.go | 1340 |
1 files changed, 1340 insertions, 0 deletions
diff --git a/vendor/github.com/graphql-go/graphql/definition.go b/vendor/github.com/graphql-go/graphql/definition.go new file mode 100644 index 00000000..dffea080 --- /dev/null +++ b/vendor/github.com/graphql-go/graphql/definition.go @@ -0,0 +1,1340 @@ +package graphql + +import ( + "context" + "fmt" + "reflect" + "regexp" + + "github.com/graphql-go/graphql/language/ast" +) + +// Type interface for all of the possible kinds of GraphQL types +type Type interface { + Name() string + Description() string + String() string + Error() error +} + +var _ Type = (*Scalar)(nil) +var _ Type = (*Object)(nil) +var _ Type = (*Interface)(nil) +var _ Type = (*Union)(nil) +var _ Type = (*Enum)(nil) +var _ Type = (*InputObject)(nil) +var _ Type = (*List)(nil) +var _ Type = (*NonNull)(nil) +var _ Type = (*Argument)(nil) + +// Input interface for types that may be used as input types for arguments and directives. +type Input interface { + Name() string + Description() string + String() string + Error() error +} + +var _ Input = (*Scalar)(nil) +var _ Input = (*Enum)(nil) +var _ Input = (*InputObject)(nil) +var _ Input = (*List)(nil) +var _ Input = (*NonNull)(nil) + +// IsInputType determines if given type is a GraphQLInputType +func IsInputType(ttype Type) bool { + named := GetNamed(ttype) + if _, ok := named.(*Scalar); ok { + return true + } + if _, ok := named.(*Enum); ok { + return true + } + if _, ok := named.(*InputObject); ok { + return true + } + return false +} + +// IsOutputType determines if given type is a GraphQLOutputType +func IsOutputType(ttype Type) bool { + name := GetNamed(ttype) + if _, ok := name.(*Scalar); ok { + return true + } + if _, ok := name.(*Object); ok { + return true + } + if _, ok := name.(*Interface); ok { + return true + } + if _, ok := name.(*Union); ok { + return true + } + if _, ok := name.(*Enum); ok { + return true + } + return false +} + +// Leaf interface for types that may be leaf values +type Leaf interface { + Name() string + Description() string + String() string + Error() error + Serialize(value interface{}) interface{} +} + +var _ Leaf = (*Scalar)(nil) +var _ Leaf = (*Enum)(nil) + +// IsLeafType determines if given type is a leaf value +func IsLeafType(ttype Type) bool { + named := GetNamed(ttype) + if _, ok := named.(*Scalar); ok { + return true + } + if _, ok := named.(*Enum); ok { + return true + } + return false +} + +// Output interface for types that may be used as output types as the result of fields. +type Output interface { + Name() string + Description() string + String() string + Error() error +} + +var _ Output = (*Scalar)(nil) +var _ Output = (*Object)(nil) +var _ Output = (*Interface)(nil) +var _ Output = (*Union)(nil) +var _ Output = (*Enum)(nil) +var _ Output = (*List)(nil) +var _ Output = (*NonNull)(nil) + +// Composite interface for types that may describe the parent context of a selection set. +type Composite interface { + Name() string + Description() string + String() string + Error() error +} + +var _ Composite = (*Object)(nil) +var _ Composite = (*Interface)(nil) +var _ Composite = (*Union)(nil) + +// IsCompositeType determines if given type is a GraphQLComposite type +func IsCompositeType(ttype interface{}) bool { + if _, ok := ttype.(*Object); ok { + return true + } + if _, ok := ttype.(*Interface); ok { + return true + } + if _, ok := ttype.(*Union); ok { + return true + } + return false +} + +// Abstract interface for types that may describe the parent context of a selection set. +type Abstract interface { + Name() string +} + +var _ Abstract = (*Interface)(nil) +var _ Abstract = (*Union)(nil) + +func IsAbstractType(ttype interface{}) bool { + if _, ok := ttype.(*Interface); ok { + return true + } + if _, ok := ttype.(*Union); ok { + return true + } + return false +} + +// Nullable interface for types that can accept null as a value. +type Nullable interface { +} + +var _ Nullable = (*Scalar)(nil) +var _ Nullable = (*Object)(nil) +var _ Nullable = (*Interface)(nil) +var _ Nullable = (*Union)(nil) +var _ Nullable = (*Enum)(nil) +var _ Nullable = (*InputObject)(nil) +var _ Nullable = (*List)(nil) + +// GetNullable returns the Nullable type of the given GraphQL type +func GetNullable(ttype Type) Nullable { + if ttype, ok := ttype.(*NonNull); ok { + return ttype.OfType + } + return ttype +} + +// Named interface for types that do not include modifiers like List or NonNull. +type Named interface { + String() string +} + +var _ Named = (*Scalar)(nil) +var _ Named = (*Object)(nil) +var _ Named = (*Interface)(nil) +var _ Named = (*Union)(nil) +var _ Named = (*Enum)(nil) +var _ Named = (*InputObject)(nil) + +// GetNamed returns the Named type of the given GraphQL type +func GetNamed(ttype Type) Named { + unmodifiedType := ttype + for { + if ttype, ok := unmodifiedType.(*List); ok { + unmodifiedType = ttype.OfType + continue + } + if ttype, ok := unmodifiedType.(*NonNull); ok { + unmodifiedType = ttype.OfType + continue + } + break + } + return unmodifiedType +} + +// Scalar Type Definition +// +// The leaf values of any request and input values to arguments are +// Scalars (or Enums) and are defined with a name and a series of functions +// used to parse input from ast or variables and to ensure validity. +// +// Example: +// +// var OddType = new Scalar({ +// name: 'Odd', +// serialize(value) { +// return value % 2 === 1 ? value : null; +// } +// }); +// +type Scalar struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + + scalarConfig ScalarConfig + err error +} + +// SerializeFn is a function type for serializing a GraphQLScalar type value +type SerializeFn func(value interface{}) interface{} + +// ParseValueFn is a function type for parsing the value of a GraphQLScalar type +type ParseValueFn func(value interface{}) interface{} + +// ParseLiteralFn is a function type for parsing the literal value of a GraphQLScalar type +type ParseLiteralFn func(valueAST ast.Value) interface{} + +// ScalarConfig options for creating a new GraphQLScalar +type ScalarConfig struct { + Name string `json:"name"` + Description string `json:"description"` + Serialize SerializeFn + ParseValue ParseValueFn + ParseLiteral ParseLiteralFn +} + +// NewScalar creates a new GraphQLScalar +func NewScalar(config ScalarConfig) *Scalar { + st := &Scalar{} + err := invariant(config.Name != "", "Type must be named.") + if err != nil { + st.err = err + return st + } + + err = assertValidName(config.Name) + if err != nil { + st.err = err + return st + } + + st.PrivateName = config.Name + st.PrivateDescription = config.Description + + err = invariantf( + config.Serialize != nil, + `%v must provide "serialize" function. If this custom Scalar is `+ + `also used as an input type, ensure "parseValue" and "parseLiteral" `+ + `functions are also provided.`, st, + ) + if err != nil { + st.err = err + return st + } + if config.ParseValue != nil || config.ParseLiteral != nil { + err = invariantf( + config.ParseValue != nil && config.ParseLiteral != nil, + `%v must provide both "parseValue" and "parseLiteral" functions.`, st, + ) + if err != nil { + st.err = err + return st + } + } + + st.scalarConfig = config + return st +} +func (st *Scalar) Serialize(value interface{}) interface{} { + if st.scalarConfig.Serialize == nil { + return value + } + return st.scalarConfig.Serialize(value) +} +func (st *Scalar) ParseValue(value interface{}) interface{} { + if st.scalarConfig.ParseValue == nil { + return value + } + return st.scalarConfig.ParseValue(value) +} +func (st *Scalar) ParseLiteral(valueAST ast.Value) interface{} { + if st.scalarConfig.ParseLiteral == nil { + return nil + } + return st.scalarConfig.ParseLiteral(valueAST) +} +func (st *Scalar) Name() string { + return st.PrivateName +} +func (st *Scalar) Description() string { + return st.PrivateDescription + +} +func (st *Scalar) String() string { + return st.PrivateName +} +func (st *Scalar) Error() error { + return st.err +} + +// Object Type Definition +// +// Almost all of the GraphQL types you define will be object Object types +// have a name, but most importantly describe their fields. +// Example: +// +// var AddressType = new Object({ +// name: 'Address', +// fields: { +// street: { type: String }, +// number: { type: Int }, +// formatted: { +// type: String, +// resolve(obj) { +// return obj.number + ' ' + obj.street +// } +// } +// } +// }); +// +// When two types need to refer to each other, or a type needs to refer to +// itself in a field, you can use a function expression (aka a closure or a +// thunk) to supply the fields lazily. +// +// Example: +// +// var PersonType = new Object({ +// name: 'Person', +// fields: () => ({ +// name: { type: String }, +// bestFriend: { type: PersonType }, +// }) +// }); +// +// / +type Object struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + IsTypeOf IsTypeOfFn + + typeConfig ObjectConfig + initialisedFields bool + fields FieldDefinitionMap + initialisedInterfaces bool + interfaces []*Interface + // Interim alternative to throwing an error during schema definition at run-time + err error +} + +// IsTypeOfParams Params for IsTypeOfFn() +type IsTypeOfParams struct { + // Value that needs to be resolve. + // Use this to decide which GraphQLObject this value maps to. + Value interface{} + + // Info is a collection of information about the current execution state. + Info ResolveInfo + + // Context argument is a context value that is provided to every resolve function within an execution. + // It is commonly + // used to represent an authenticated user, or request-specific caches. + Context context.Context +} + +type IsTypeOfFn func(p IsTypeOfParams) bool + +type InterfacesThunk func() []*Interface + +type ObjectConfig struct { + Name string `json:"name"` + Interfaces interface{} `json:"interfaces"` + Fields interface{} `json:"fields"` + IsTypeOf IsTypeOfFn `json:"isTypeOf"` + Description string `json:"description"` +} + +type FieldsThunk func() Fields + +func NewObject(config ObjectConfig) *Object { + objectType := &Object{} + + err := invariant(config.Name != "", "Type must be named.") + if err != nil { + objectType.err = err + return objectType + } + err = assertValidName(config.Name) + if err != nil { + objectType.err = err + return objectType + } + + objectType.PrivateName = config.Name + objectType.PrivateDescription = config.Description + objectType.IsTypeOf = config.IsTypeOf + objectType.typeConfig = config + + return objectType +} +func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *Field) { + if fieldName == "" || fieldConfig == nil { + return + } + switch gt.typeConfig.Fields.(type) { + case Fields: + gt.typeConfig.Fields.(Fields)[fieldName] = fieldConfig + gt.initialisedFields = false + } +} +func (gt *Object) Name() string { + return gt.PrivateName +} +func (gt *Object) Description() string { + return "" +} +func (gt *Object) String() string { + return gt.PrivateName +} +func (gt *Object) Fields() FieldDefinitionMap { + if gt.initialisedFields { + return gt.fields + } + + var configureFields Fields + switch gt.typeConfig.Fields.(type) { + case Fields: + configureFields = gt.typeConfig.Fields.(Fields) + case FieldsThunk: + configureFields = gt.typeConfig.Fields.(FieldsThunk)() + } + + fields, err := defineFieldMap(gt, configureFields) + gt.err = err + gt.fields = fields + gt.initialisedFields = true + return gt.fields +} + +func (gt *Object) Interfaces() []*Interface { + if gt.initialisedInterfaces { + return gt.interfaces + } + + var configInterfaces []*Interface + switch gt.typeConfig.Interfaces.(type) { + case InterfacesThunk: + configInterfaces = gt.typeConfig.Interfaces.(InterfacesThunk)() + case []*Interface: + configInterfaces = gt.typeConfig.Interfaces.([]*Interface) + case nil: + default: + gt.err = fmt.Errorf("Unknown Object.Interfaces type: %T", gt.typeConfig.Interfaces) + gt.initialisedInterfaces = true + return nil + } + + interfaces, err := defineInterfaces(gt, configInterfaces) + gt.err = err + gt.interfaces = interfaces + gt.initialisedInterfaces = true + return gt.interfaces +} + +func (gt *Object) Error() error { + return gt.err +} + +func defineInterfaces(ttype *Object, interfaces []*Interface) ([]*Interface, error) { + ifaces := []*Interface{} + + if len(interfaces) == 0 { + return ifaces, nil + } + for _, iface := range interfaces { + err := invariantf( + iface != nil, + `%v may only implement Interface types, it cannot implement: %v.`, ttype, iface, + ) + if err != nil { + return ifaces, err + } + if iface.ResolveType != nil { + err = invariantf( + iface.ResolveType != nil, + `Interface Type %v does not provide a "resolveType" function `+ + `and implementing Type %v does not provide a "isTypeOf" `+ + `function. There is no way to resolve this implementing type `+ + `during execution.`, iface, ttype, + ) + if err != nil { + return ifaces, err + } + } + ifaces = append(ifaces, iface) + } + + return ifaces, nil +} + +func defineFieldMap(ttype Named, fieldMap Fields) (FieldDefinitionMap, error) { + resultFieldMap := FieldDefinitionMap{} + + err := invariantf( + len(fieldMap) > 0, + `%v fields must be an object with field names as keys or a function which return such an object.`, ttype, + ) + if err != nil { + return resultFieldMap, err + } + + for fieldName, field := range fieldMap { + if field == nil { + continue + } + err = invariantf( + field.Type != nil, + `%v.%v field type must be Output Type but got: %v.`, ttype, fieldName, field.Type, + ) + if err != nil { + return resultFieldMap, err + } + if field.Type.Error() != nil { + return resultFieldMap, field.Type.Error() + } + err = assertValidName(fieldName) + if err != nil { + return resultFieldMap, err + } + fieldDef := &FieldDefinition{ + Name: fieldName, + Description: field.Description, + Type: field.Type, + Resolve: field.Resolve, + DeprecationReason: field.DeprecationReason, + } + + fieldDef.Args = []*Argument{} + for argName, arg := range field.Args { + err := assertValidName(argName) + if err != nil { + return resultFieldMap, err + } + err = invariantf( + arg != nil, + `%v.%v args must be an object with argument names as keys.`, ttype, fieldName, + ) + if err != nil { + return resultFieldMap, err + } + err = invariantf( + arg.Type != nil, + `%v.%v(%v:) argument type must be Input Type but got: %v.`, ttype, fieldName, argName, arg.Type, + ) + if err != nil { + return resultFieldMap, err + } + fieldArg := &Argument{ + PrivateName: argName, + PrivateDescription: arg.Description, + Type: arg.Type, + DefaultValue: arg.DefaultValue, + } + fieldDef.Args = append(fieldDef.Args, fieldArg) + } + resultFieldMap[fieldName] = fieldDef + } + return resultFieldMap, nil +} + +// ResolveParams Params for FieldResolveFn() +type ResolveParams struct { + // Source is the source value + Source interface{} + + // Args is a map of arguments for current GraphQL request + Args map[string]interface{} + + // Info is a collection of information about the current execution state. + Info ResolveInfo + + // Context argument is a context value that is provided to every resolve function within an execution. + // It is commonly + // used to represent an authenticated user, or request-specific caches. + Context context.Context +} + +type FieldResolveFn func(p ResolveParams) (interface{}, error) + +type ResolveInfo struct { + FieldName string + FieldASTs []*ast.Field + ReturnType Output + ParentType Composite + Schema Schema + Fragments map[string]ast.Definition + RootValue interface{} + Operation ast.Definition + VariableValues map[string]interface{} +} + +type Fields map[string]*Field + +type Field struct { + Name string `json:"name"` // used by graphlql-relay + Type Output `json:"type"` + Args FieldConfigArgument `json:"args"` + Resolve FieldResolveFn `json:"-"` + DeprecationReason string `json:"deprecationReason"` + Description string `json:"description"` +} + +type FieldConfigArgument map[string]*ArgumentConfig + +type ArgumentConfig struct { + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + Description string `json:"description"` +} + +type FieldDefinitionMap map[string]*FieldDefinition +type FieldDefinition struct { + Name string `json:"name"` + Description string `json:"description"` + Type Output `json:"type"` + Args []*Argument `json:"args"` + Resolve FieldResolveFn `json:"-"` + DeprecationReason string `json:"deprecationReason"` +} + +type FieldArgument struct { + Name string `json:"name"` + Type Type `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + Description string `json:"description"` +} + +type Argument struct { + PrivateName string `json:"name"` + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + PrivateDescription string `json:"description"` +} + +func (st *Argument) Name() string { + return st.PrivateName +} +func (st *Argument) Description() string { + return st.PrivateDescription + +} +func (st *Argument) String() string { + return st.PrivateName +} +func (st *Argument) Error() error { + return nil +} + +// Interface Type Definition +// +// When a field can return one of a heterogeneous set of types, a Interface type +// is used to describe what types are possible, what fields are in common across +// all types, as well as a function to determine which type is actually used +// when the field is resolved. +// +// Example: +// +// var EntityType = new Interface({ +// name: 'Entity', +// fields: { +// name: { type: String } +// } +// }); +// +// +type Interface struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + ResolveType ResolveTypeFn + + typeConfig InterfaceConfig + initialisedFields bool + fields FieldDefinitionMap + err error +} +type InterfaceConfig struct { + Name string `json:"name"` + Fields interface{} `json:"fields"` + ResolveType ResolveTypeFn + Description string `json:"description"` +} + +// ResolveTypeParams Params for ResolveTypeFn() +type ResolveTypeParams struct { + // Value that needs to be resolve. + // Use this to decide which GraphQLObject this value maps to. + Value interface{} + + // Info is a collection of information about the current execution state. + Info ResolveInfo + + // Context argument is a context value that is provided to every resolve function within an execution. + // It is commonly + // used to represent an authenticated user, or request-specific caches. + Context context.Context +} + +type ResolveTypeFn func(p ResolveTypeParams) *Object + +func NewInterface(config InterfaceConfig) *Interface { + it := &Interface{} + + err := invariant(config.Name != "", "Type must be named.") + if err != nil { + it.err = err + return it + } + err = assertValidName(config.Name) + if err != nil { + it.err = err + return it + } + it.PrivateName = config.Name + it.PrivateDescription = config.Description + it.ResolveType = config.ResolveType + it.typeConfig = config + + return it +} + +func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *Field) { + if fieldName == "" || fieldConfig == nil { + return + } + switch it.typeConfig.Fields.(type) { + case Fields: + it.typeConfig.Fields.(Fields)[fieldName] = fieldConfig + it.initialisedFields = false + } +} + +func (it *Interface) Name() string { + return it.PrivateName +} + +func (it *Interface) Description() string { + return it.PrivateDescription +} + +func (it *Interface) Fields() (fields FieldDefinitionMap) { + if it.initialisedFields { + return it.fields + } + + var configureFields Fields + switch it.typeConfig.Fields.(type) { + case Fields: + configureFields = it.typeConfig.Fields.(Fields) + case FieldsThunk: + configureFields = it.typeConfig.Fields.(FieldsThunk)() + } + + fields, err := defineFieldMap(it, configureFields) + it.err = err + it.fields = fields + it.initialisedFields = true + return it.fields +} + +func (it *Interface) String() string { + return it.PrivateName +} + +func (it *Interface) Error() error { + return it.err +} + +// Union Type Definition +// +// When a field can return one of a heterogeneous set of types, a Union type +// is used to describe what types are possible as well as providing a function +// to determine which type is actually used when the field is resolved. +// +// Example: +// +// var PetType = new Union({ +// name: 'Pet', +// types: [ DogType, CatType ], +// resolveType(value) { +// if (value instanceof Dog) { +// return DogType; +// } +// if (value instanceof Cat) { +// return CatType; +// } +// } +// }); +type Union struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + ResolveType ResolveTypeFn + + typeConfig UnionConfig + types []*Object + possibleTypes map[string]bool + + err error +} +type UnionConfig struct { + Name string `json:"name"` + Types []*Object `json:"types"` + ResolveType ResolveTypeFn + Description string `json:"description"` +} + +func NewUnion(config UnionConfig) *Union { + objectType := &Union{} + + err := invariant(config.Name != "", "Type must be named.") + if err != nil { + objectType.err = err + return objectType + } + err = assertValidName(config.Name) + if err != nil { + objectType.err = err + return objectType + } + objectType.PrivateName = config.Name + objectType.PrivateDescription = config.Description + objectType.ResolveType = config.ResolveType + + err = invariantf( + len(config.Types) > 0, + `Must provide Array of types for Union %v.`, config.Name, + ) + if err != nil { + objectType.err = err + return objectType + } + for _, ttype := range config.Types { + err := invariantf( + ttype != nil, + `%v may only contain Object types, it cannot contain: %v.`, objectType, ttype, + ) + if err != nil { + objectType.err = err + return objectType + } + if objectType.ResolveType == nil { + err = invariantf( + ttype.IsTypeOf != nil, + `Union Type %v does not provide a "resolveType" function `+ + `and possible Type %v does not provide a "isTypeOf" `+ + `function. There is no way to resolve this possible type `+ + `during execution.`, objectType, ttype, + ) + if err != nil { + objectType.err = err + return objectType + } + } + } + objectType.types = config.Types + objectType.typeConfig = config + + return objectType +} +func (ut *Union) Types() []*Object { + return ut.types +} +func (ut *Union) String() string { + return ut.PrivateName +} +func (ut *Union) Name() string { + return ut.PrivateName +} +func (ut *Union) Description() string { + return ut.PrivateDescription +} +func (ut *Union) Error() error { + return ut.err +} + +// Enum Type Definition +// +// Some leaf values of requests and input values are Enums. GraphQL serializes +// Enum values as strings, however internally Enums can be represented by any +// kind of type, often integers. +// +// Example: +// +// var RGBType = new Enum({ +// name: 'RGB', +// values: { +// RED: { value: 0 }, +// GREEN: { value: 1 }, +// BLUE: { value: 2 } +// } +// }); +// +// Note: If a value is not provided in a definition, the name of the enum value +// will be used as its internal value. + +type Enum struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + + enumConfig EnumConfig + values []*EnumValueDefinition + valuesLookup map[interface{}]*EnumValueDefinition + nameLookup map[string]*EnumValueDefinition + + err error +} +type EnumValueConfigMap map[string]*EnumValueConfig +type EnumValueConfig struct { + Value interface{} `json:"value"` + DeprecationReason string `json:"deprecationReason"` + Description string `json:"description"` +} +type EnumConfig struct { + Name string `json:"name"` + Values EnumValueConfigMap `json:"values"` + Description string `json:"description"` +} +type EnumValueDefinition struct { + Name string `json:"name"` + Value interface{} `json:"value"` + DeprecationReason string `json:"deprecationReason"` + Description string `json:"description"` +} + +func NewEnum(config EnumConfig) *Enum { + gt := &Enum{} + gt.enumConfig = config + + err := assertValidName(config.Name) + if err != nil { + gt.err = err + return gt + } + + gt.PrivateName = config.Name + gt.PrivateDescription = config.Description + gt.values, err = gt.defineEnumValues(config.Values) + if err != nil { + gt.err = err + return gt + } + + return gt +} +func (gt *Enum) defineEnumValues(valueMap EnumValueConfigMap) ([]*EnumValueDefinition, error) { + values := []*EnumValueDefinition{} + + err := invariantf( + len(valueMap) > 0, + `%v values must be an object with value names as keys.`, gt, + ) + if err != nil { + return values, err + } + + for valueName, valueConfig := range valueMap { + err := invariantf( + valueConfig != nil, + `%v.%v must refer to an object with a "value" key `+ + `representing an internal value but got: %v.`, gt, valueName, valueConfig, + ) + if err != nil { + return values, err + } + err = assertValidName(valueName) + if err != nil { + return values, err + } + value := &EnumValueDefinition{ + Name: valueName, + Value: valueConfig.Value, + DeprecationReason: valueConfig.DeprecationReason, + Description: valueConfig.Description, + } + if value.Value == nil { + value.Value = valueName + } + values = append(values, value) + } + return values, nil +} +func (gt *Enum) Values() []*EnumValueDefinition { + return gt.values +} +func (gt *Enum) Serialize(value interface{}) interface{} { + v := value + if reflect.ValueOf(v).Kind() == reflect.Ptr { + v = reflect.Indirect(reflect.ValueOf(v)).Interface() + } + if enumValue, ok := gt.getValueLookup()[v]; ok { + return enumValue.Name + } + return nil +} +func (gt *Enum) ParseValue(value interface{}) interface{} { + var v string + + switch value := value.(type) { + case string: + v = value + case *string: + v = *value + default: + return nil + } + if enumValue, ok := gt.getNameLookup()[v]; ok { + return enumValue.Value + } + return nil +} +func (gt *Enum) ParseLiteral(valueAST ast.Value) interface{} { + if valueAST, ok := valueAST.(*ast.EnumValue); ok { + if enumValue, ok := gt.getNameLookup()[valueAST.Value]; ok { + return enumValue.Value + } + } + return nil +} +func (gt *Enum) Name() string { + return gt.PrivateName +} +func (gt *Enum) Description() string { + return gt.PrivateDescription +} +func (gt *Enum) String() string { + return gt.PrivateName +} +func (gt *Enum) Error() error { + return gt.err +} +func (gt *Enum) getValueLookup() map[interface{}]*EnumValueDefinition { + if len(gt.valuesLookup) > 0 { + return gt.valuesLookup + } + valuesLookup := map[interface{}]*EnumValueDefinition{} + for _, value := range gt.Values() { + valuesLookup[value.Value] = value + } + gt.valuesLookup = valuesLookup + return gt.valuesLookup +} + +func (gt *Enum) getNameLookup() map[string]*EnumValueDefinition { + if len(gt.nameLookup) > 0 { + return gt.nameLookup + } + nameLookup := map[string]*EnumValueDefinition{} + for _, value := range gt.Values() { + nameLookup[value.Name] = value + } + gt.nameLookup = nameLookup + return gt.nameLookup +} + +// InputObject Type Definition +// +// An input object defines a structured collection of fields which may be +// supplied to a field argument. +// +// Using `NonNull` will ensure that a value must be provided by the query +// +// Example: +// +// var GeoPoint = new InputObject({ +// name: 'GeoPoint', +// fields: { +// lat: { type: new NonNull(Float) }, +// lon: { type: new NonNull(Float) }, +// alt: { type: Float, defaultValue: 0 }, +// } +// }); +type InputObject struct { + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + + typeConfig InputObjectConfig + fields InputObjectFieldMap + init bool + err error +} +type InputObjectFieldConfig struct { + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + Description string `json:"description"` +} +type InputObjectField struct { + PrivateName string `json:"name"` + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + PrivateDescription string `json:"description"` +} + +func (st *InputObjectField) Name() string { + return st.PrivateName +} +func (st *InputObjectField) Description() string { + return st.PrivateDescription + +} +func (st *InputObjectField) String() string { + return st.PrivateName +} +func (st *InputObjectField) Error() error { + return nil +} + +type InputObjectConfigFieldMap map[string]*InputObjectFieldConfig +type InputObjectFieldMap map[string]*InputObjectField +type InputObjectConfigFieldMapThunk func() InputObjectConfigFieldMap +type InputObjectConfig struct { + Name string `json:"name"` + Fields interface{} `json:"fields"` + Description string `json:"description"` +} + +func NewInputObject(config InputObjectConfig) *InputObject { + gt := &InputObject{} + err := invariant(config.Name != "", "Type must be named.") + if err != nil { + gt.err = err + return gt + } + + gt.PrivateName = config.Name + gt.PrivateDescription = config.Description + gt.typeConfig = config + //gt.fields = gt.defineFieldMap() + return gt +} + +func (gt *InputObject) defineFieldMap() InputObjectFieldMap { + var fieldMap InputObjectConfigFieldMap + switch gt.typeConfig.Fields.(type) { + case InputObjectConfigFieldMap: + fieldMap = gt.typeConfig.Fields.(InputObjectConfigFieldMap) + case InputObjectConfigFieldMapThunk: + fieldMap = gt.typeConfig.Fields.(InputObjectConfigFieldMapThunk)() + } + resultFieldMap := InputObjectFieldMap{} + + err := invariantf( + len(fieldMap) > 0, + `%v fields must be an object with field names as keys or a function which return such an object.`, gt, + ) + if err != nil { + gt.err = err + return resultFieldMap + } + + for fieldName, fieldConfig := range fieldMap { + if fieldConfig == nil { + continue + } + err := assertValidName(fieldName) + if err != nil { + continue + } + err = invariantf( + fieldConfig.Type != nil, + `%v.%v field type must be Input Type but got: %v.`, gt, fieldName, fieldConfig.Type, + ) + if err != nil { + gt.err = err + return resultFieldMap + } + field := &InputObjectField{} + field.PrivateName = fieldName + field.Type = fieldConfig.Type + field.PrivateDescription = fieldConfig.Description + field.DefaultValue = fieldConfig.DefaultValue + resultFieldMap[fieldName] = field + } + gt.init = true + return resultFieldMap +} + +func (gt *InputObject) Fields() InputObjectFieldMap { + if !gt.init { + gt.fields = gt.defineFieldMap() + } + return gt.fields +} +func (gt *InputObject) Name() string { + return gt.PrivateName +} +func (gt *InputObject) Description() string { + return gt.PrivateDescription +} +func (gt *InputObject) String() string { + return gt.PrivateName +} +func (gt *InputObject) Error() error { + return gt.err +} + +// List Modifier +// +// A list is a kind of type marker, a wrapping type which points to another +// type. Lists are often created within the context of defining the fields of +// an object type. +// +// Example: +// +// var PersonType = new Object({ +// name: 'Person', +// fields: () => ({ +// parents: { type: new List(Person) }, +// children: { type: new List(Person) }, +// }) +// }) +// +type List struct { + OfType Type `json:"ofType"` + + err error +} + +func NewList(ofType Type) *List { + gl := &List{} + + err := invariantf(ofType != nil, `Can only create List of a Type but got: %v.`, ofType) + if err != nil { + gl.err = err + return gl + } + + gl.OfType = ofType + return gl +} +func (gl *List) Name() string { + return fmt.Sprintf("%v", gl.OfType) +} +func (gl *List) Description() string { + return "" +} +func (gl *List) String() string { + if gl.OfType != nil { + return fmt.Sprintf("[%v]", gl.OfType) + } + return "" +} +func (gl *List) Error() error { + return gl.err +} + +// NonNull Modifier +// +// A non-null is a kind of type marker, a wrapping type which points to another +// type. Non-null types enforce that their values are never null and can ensure +// an error is raised if this ever occurs during a request. It is useful for +// fields which you can make a strong guarantee on non-nullability, for example +// usually the id field of a database row will never be null. +// +// Example: +// +// var RowType = new Object({ +// name: 'Row', +// fields: () => ({ +// id: { type: new NonNull(String) }, +// }) +// }) +// +// Note: the enforcement of non-nullability occurs within the executor. +type NonNull struct { + OfType Type `json:"ofType"` + + err error +} + +func NewNonNull(ofType Type) *NonNull { + gl := &NonNull{} + + _, isOfTypeNonNull := ofType.(*NonNull) + err := invariantf(ofType != nil && !isOfTypeNonNull, `Can only create NonNull of a Nullable Type but got: %v.`, ofType) + if err != nil { + gl.err = err + return gl + } + gl.OfType = ofType + return gl +} +func (gl *NonNull) Name() string { + return fmt.Sprintf("%v!", gl.OfType) +} +func (gl *NonNull) Description() string { + return "" +} +func (gl *NonNull) String() string { + if gl.OfType != nil { + return gl.Name() + } + return "" +} +func (gl *NonNull) Error() error { + return gl.err +} + +var NameRegExp, _ = regexp.Compile("^[_a-zA-Z][_a-zA-Z0-9]*$") + +func assertValidName(name string) error { + return invariantf( + NameRegExp.MatchString(name), + `Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "%v" does not.`, name) + +} |