Skip to content

Instantly share code, notes, and snippets.

@Horusiath
Created April 15, 2016 17:09
Show Gist options
  • Save Horusiath/0770c470fd9fb8dd5c2119c33bdbdf9f to your computer and use it in GitHub Desktop.
Save Horusiath/0770c470fd9fb8dd5c2119c33bdbdf9f to your computer and use it in GitHub Desktop.
New API example
/// These are all of the possible kinds of types
type GraphQLType =
interface
end
/// These types may be used as input types for arguments and directives
and InputType<'Inner> =
interface
end
/// These types may be used as output types as the result of fields
and OutputType<'Inner> =
interface
end
/// These types may describe types which may be leaf values
and LeafType =
interface
end
/// These types may describe the parent context of a selection set
and CompositeType =
interface
end
/// These types may describe the parent context of a selection set
and AbstractType<'Inner> =
interface
abstract ResolveType : obj -> ResolveInfo -> ObjectType<'Inner> option
end
/// These types can all accept null as a value
and NullableType =
interface
end
/// These named types do not include modifiers like List or NonNull
and NamedType =
interface
abstract Name : string
end
and ScalarType<'Inner> =
interface
inherit GraphQLType
inherit InputType<'Inner>
inherit OutputType<'Inner>
inherit LeafType
inherit NullableType
inherit NamedType
abstract Serialize : obj -> 'Inner option
abstract ParseLiteral : Value -> 'Inner option
end
and EnumType =
interface
inherit GraphQLType
inherit InputType<string>
inherit OutputType<string>
inherit LeafType
inherit NullableType
inherit NamedType
abstract Values : Map<string, EnumValueDefinition>
abstract Serialize : obj -> 'Inner option
abstract ParseLiteral : Value -> 'Inner option
end
and EnumValueDefinition =
{ Name : string
Description : string option
Value : obj }
and ObjectType<'Inner> =
interface
inherit GraphQLType
inherit OutputType<'Inner>
inherit CompositeType
inherit NullableType
inherit NamedType
abstract IsTypeOf : obj -> ResolveInfo -> bool
abstract Fields : Map<string, FieldDefinition<'Inner>>
abstract Interfaces : InterfaceType<obj> list
end
and InterfaceType<'Inner> =
interface
inherit GraphQLType
inherit OutputType<'Inner>
inherit CompositeType
inherit AbstractType<'Inner>
inherit NullableType
inherit NamedType
abstract Fields : Map<string, FieldDefinition<'Inner>>
end
and UnionType<'Inner> =
interface
inherit GraphQLType
inherit OutputType<'Inner>
inherit CompositeType
inherit AbstractType<'Inner>
inherit NullableType
inherit NamedType
abstract Types : ObjectType<'Inner> list
end
and InputObjectType<'Inner> =
interface
inherit GraphQLType
inherit InputType<'Inner>
inherit OutputType<'Inner>
inherit NullableType
inherit NamedType
abstract Fields : Map<string, FieldDefinition<'Inner>>
end
and ListType<'Inner when 'Inner :> GraphQLType> =
interface
inherit GraphQLType
inherit InputType<'Inner>
inherit OutputType<'Inner>
inherit NullableType
end
and NonNullType<'Inner when 'Inner :> NullableType> =
interface
inherit GraphQLType
inherit InputType<'Inner>
end
and FieldDefinition<'Inner> =
interface
abstract Name : string
abstract Args : ArgumentDefinition array
end
and ArgumentDefinition =
{ Name : string
Type : InputType
DefaultType : obj option
Description : string option }
and FieldDefinition<'Inner, 'Val> =
interface
abstract Type : OutputType<'Val>
end
and FieldDefinitionConfig<'Inner, 'Val, 'Args> =
{ Name : string
Description : string option
Type : OutputType<'Val>
Args : ArgumentDefinition array
DeprecationReason : string option
Resolve : 'Inner -> 'Args -> ResolveInfo -> 'Val }
interface FieldDefinition<'Inner> with
member x.Name = x.Name
member x.Args = x.Args
interface FieldDefinition<'Inner, 'Val> with
member x.Type = x.Type
and ResolveInfo =
{ FieldName : string
Fields : Field list
ParentType : CompositeType
Schema : obj
Fragments : Map<string, FragmentDefinition>
RootValue : obj
Operation : OperationDefinition
Variables : Map<string, obj> }
type ScalarTypeConfig<'Inner> =
{ Name : string
Description : string option
Serialize : obj -> 'Inner option
ParseLiteral : Value -> 'Inner option }
interface ScalarType<'Inner> with
member x.Name = x.Name
member x.ParseLiteral(ast) = x.ParseLiteral ast
member x.Serialize(o) = x.Serialize o
type EnumTypeConfig =
{ Name : string
Description : string option
Values : EnumValueDefinition list }
interface EnumType with
member x.Name = x.Name
member x.ParseLiteral(ast) = failwith "Not implemented yet"
member x.Serialize(arg1) = failwith "Not implemented yet"
member x.Values =
x.Values
|> List.map (fun x -> (x.Name, x))
|> Map.ofList
type ObjectTypeConfig<'Inner> =
{ Name : string
Description : string option
IsTypeOf : (obj -> ResolveInfo -> bool) option
Interfaces : InterfaceType<obj> list
Fields : FieldDefinition<'Inner> list }
interface ObjectType<'Inner> with
member x.Fields =
x.Fields
|> List.map (fun x -> (x.Name, x))
|> Map.ofList
member x.Interfaces = x.Interfaces
member x.IsTypeOf value info =
match x.IsTypeOf with
| Some resolver -> resolver value info
| None -> value :? 'Inner
member x.Name = x.Name
type InterfaceTypeConfig<'Inner> =
{ Name : string
Description : string option
ResolveType : (obj -> ResolveInfo -> ObjectType<'Inner> option) option
Fields : FieldDefinition<'Inner> list }
interface InterfaceType<'Inner> with
member x.Fields =
x.Fields
|> List.map (fun x -> (x.Name, x))
|> Map.ofList
member x.ResolveType value info =
match x.ResolveType with
| Some resolver -> resolver value info
| None -> None
member x.Name = x.Name
type UnionTypeConfig<'Inner> =
{ Name : string
Description : string option
ResolveType : (obj -> ResolveInfo -> ObjectType<'Inner> option) option
Types : ObjectType<'Inner> list }
interface UnionType<'Inner> with
member x.Types = x.Types
member x.ResolveType value info =
match x.ResolveType with
| Some resolver -> resolver value info
| None -> None
member x.Name = x.Name
module Mod =
// helper func for object type definitions
let objdef<'t> (name : string) (fields : FieldDefinition<'t> list) : ObjectType<'t> =
let o =
{ Name = name
Description = None
Interfaces = []
IsTypeOf = Some(fun o info -> o :? 't)
Fields = fields }
o :> ObjectType<'t>
// helper func for field definitions
let field (name : string) (typedef : #OutputType<'v>) (resolve : 't -> 'a -> ResolveInfo -> 'v) =
let f =
{ Name = name
Description = None
Type = typedef
Args = [||]
DeprecationReason = None
Resolve = resolve }
f
// helper func for scalar types definitions
let scalar name serialize parse =
let s =
{ Name = name
Description = None
Serialize = serialize
ParseLiteral = parse }
s :> ScalarType<'t>
// let's start with defining two scalar types for int and string
// second func is not implemented
let Int = scalar "Int" (fun o -> Some(o :?> int)) (fun v -> Some 0)
let String = scalar "String" (fun o -> Some(o :?> string)) (fun v -> Some "")
// define custom types - this example shows how nested types can be defined
// using GraphQL object types
type Deeper =
{ z : int }
type Record =
{ x : int
y : string
deep : Deeper }
// first we define object type for nested record...
let DeeperDef = objdef<Deeper> "Deeper" [ field "z" Int (fun deeper _ _ -> deeper.z) ]
// ...then for the top-level record
// everything is type safe - i.e. unlike previous API,
// you cannot define field x with graphQL type String, cause String is Scalar type constrained to .NET string type
// also 3rd param (resolve function) can infer all input and output types, which was not checked previously
let RecordDef =
objdef<Record> "Record" [ field "x" Int (fun record _ _ -> record.x)
field "y" String (fun record _ _ -> record.y)
field "deeper" DeeperDef (fun record _ _ -> record.deep) ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment