Skip to content

Directive chooser middleware #192

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

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
Open

Directive chooser middleware #192

wants to merge 11 commits into from

Conversation

ivelten
Copy link
Collaborator

@ivelten ivelten commented Nov 27, 2018

With this Pull Request, I'm proposing an operation planning middleware that changes the current operation based on directives present in the query. The user can choose directives with a chooser function(Directive -> Directive option) by placing it in the Metadata object of executor.AsyncExecute method. If the middleware is present in the pipeline, it will look for this chooser function and apply it to the operation.

  • Create middleware initial version
  • Unit tests
  • Documentation

Sorry, something went wrong.

[ DirectiveChooser.fallbackDefer; DirectiveChooser.fallbackStream; DirectiveChooser.fallbackLive ]
|> DirectiveChooser.fromSeq
|> DirectiveChooser.merge (DirectiveChooser.fallbackWhen (fun _ -> fallbackDirectives))
Metadata.WithDirectiveChooser(chooser)
Copy link
Collaborator Author

@ivelten ivelten Nov 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we can use DirectiveChooser module to quickly build and compose choosers. In this example, I'm fallbacking defer, stream and live directives when fallbackDirectives is true - in other words, they will be returned directly.


/// A function that checks if a directive should be used in the exection of a query, or changed to a new directive.
type DirectiveChooser = Directive -> Directive option
Copy link
Collaborator Author

@ivelten ivelten Nov 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function will be used to choose Directives. We can opt to transform them into a new Directive, or remove them from the operation. For example, if we remove a defer directive by returning None, all deferred fields will be returned directly. This is also implemented in helper functions of DirectiveChooser module, like fallbackByName, fallbackDefer, etc.

type DirectiveChooser = Directive -> Directive option

/// Basic operations on DirectiveChoosers.
module DirectiveChooser =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DirectiveChooser has a module to help composing choosers. We can easily build choosers based on other choosers, or diverse conditions.

@@ -126,7 +126,7 @@ let private directiveIncluder (directive: Directive) : Includer =
| None -> raise (GraphQLException (sprintf "Expected 'if' argument of directive '@%s' to have boolean value but got %A" directive.Name other))

let private incl: Includer = fun _ -> true
let private excl: Includer = fun _ -> false
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just removed this function as it is not referenced anywhere in the code.

@ivelten ivelten changed the title Directive fallback middleware Directive chooser middleware Nov 27, 2018
match query, variables with
| Some query, Some variables ->
printfn "Received query: %s" query
printfn "Received variables: %A" variables
let query = query |> removeSpacesAndNewLines
let result = Schema.executor.AsyncExecute(query, variables = variables, data = Schema.root) |> Async.RunSynchronously
let result = Schema.executor.AsyncExecute(query, variables = variables, data = Schema.root, meta = buildMetadata true) |> Async.RunSynchronously
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can define our choosers on a per request basis, as they are sent into the Metadata object of the AsyncExecute last param.


/// Builds a chooser that, given a Directive x, if x.Name is 'defer', returns None.
/// Otherwise, returns Some x.
let fallbackDefer = fallbackByName "defer"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, I'm not sure if we need all of those helpers on the DirectiveChooser module. Can be useful to make readable code, but things can be much simpler if we just apply the chooser function directly.

@xperiandri
Copy link
Collaborator

And this

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.

None yet

2 participants