Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Union and interface support #70

Merged
merged 2 commits into from
Jul 20, 2018
Merged

Union and interface support #70

merged 2 commits into from
Jul 20, 2018

Conversation

andreas
Copy link
Owner

@andreas andreas commented Nov 30, 2017

This PR adds support for GraphQL union and interface types.

The examples below assume the following types and values:

type dog
val fido : dog
val dog : ('ctx, dog option) Schema.typ

type cat
val meow : cat
val cat : ('ctx, cat option) Schema.typ

Union

Unions are constructed with Schema.union and requires a type annotation to distinguish between other unions and interfaces (this is similar to ctypes). Adding a object type ('ctx, 'src option) typ to a union type ('ctx, ('ctx, 'a) abstract_value) typ returns a function to embed into the union type: 'src -> ('ctx, 'a) abstract_value.

let pet : ('ctx, [`Pet]) Schema.abstract_typ = Schema.union "Pet"
let cat_as_pet = Schema.add_typ pet cat
let dog_as_pet = Schema.add_typ pet dog

Schema.(schema [
  field "pets"
    ~typ:(list (non_null pet))
    ~args:Arg.[]
    ~resolve:(fun ctx () -> Some [cat_as_pet meow; dog_as_pet fido])
])

Interface

Interfaces work very similar to unions. Interfaces are constructed with Schema.interface and requires a type annotation to distinguish between unions and interfaces. Adding a object type ('ctx, 'src option) typ to an interface type ('ctx, ('ctx, 'a) abstract_value) typ returns a function to embed into the union type: 'src -> ('ctx, 'a) abstract_value.

let nameable : ('ctx, [`Nameable]) Schema.abstract_typ = Schema.interface "Nameable"
  ~fields:(fun _ -> [
    abstract_field "name"
      ~typ:(non_null string)
      ~args:Arg.[]
  ])

(* raises if cat does not implement Nameable *)
let cat_as_nameable = Schema.add_typ nameable cat

(* raises if dog does not implement Nameable *)
let dog_as_nameable = Schema.add_typ nameable dog 

Schema.(schema [
  field "nameable"
    ~typ:(list (non_null nameable))
    ~args:Arg.[]
    ~resolve:(fun ctx () -> Some [cat_as_nameable meow; dog_as_nameable fido])
])

Future

  • Currently a subtyping check is missing when adding a type to an interface. This will yield a runtime exception when calling Schema.add_type. Although inconvenient, I think it's a reasonable trade-off to have an exception at schema-construction time to be exception-free at query-execution time.
  • It may be possible to get rid of the manual type ascription using generative functors, similarly to what is described for ctypes.

Closes #6, #7

@andreas andreas force-pushed the abstract-types branch 3 times, most recently from 9d1808a to 021aa3e Compare December 1, 2017 12:06
@andreas andreas force-pushed the abstract-types branch 2 times, most recently from 0aa1f95 to f436f14 Compare April 24, 2018 20:11
@shinzui
Copy link

shinzui commented Jul 9, 2018

Why isn't this merged?

@andreas andreas force-pushed the abstract-types branch 3 times, most recently from 3687e96 to 026ebea Compare July 19, 2018 08:58
@andreas
Copy link
Owner Author

andreas commented Jul 20, 2018

@shinzui I wanted to get rid of the required type annotation as described in the PR. I did make some progress with this, but the result was not substantially better. Essentially it ended up looking like this:

module Pet = (val Schema.union "Pet" : Schema.Abstract with type ctx = unit)
let cat_as_pet = Pet.add_type cat
let dog_as_pet = Pet.add_type dog

I haven't found a way to avoid the type annotation for Pet, unfortunately.

Finally, there was a remaining bug regarding nested fragment spreads and abstract types (test case). That should have been resolved now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Interface support
2 participants