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

Added possibility to explore the actual field selection tree #422

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

maoueh
Copy link

@maoueh maoueh commented Nov 13, 2020

Added possibility to explore the actual field selection tree, this is attached to the context that the resolver method receive. I'm opening this to gather feedback about this new feature.

Each resolver's context will now be able to access through the graph of elements that were selected as part of the execution of this resolve via the standard go context's value.

The returned field is an interface representing a subset of the functionality of the internal/exec/selected package, enough for the developer to know what was queried by the user.

I'm opening the PR to start a discussion about offering this feature to end user of the library. We have started using it in our own fork of the library.

Design

This introduces new API interfaces the would become part of the standard library.

The interface is currently a simple wrapper around elements of internal/exec/selected/Selection interface needed to "walk" the selected field. Hopefully, I got the structure right.

I've currently used Identifier() instead of Name() and Aliased() instead of Alias to not renamed the field's name since there would be conflict with struct fields in the internal/exec/selected/Selection package. If we agree, the internal struct could change so the interface has the best name.

A future addition that I forsee could be:

  • A "path" retrieval syntax "a la" gjson to quickly extract some nodes of the selection, for example with the star wars element ".search[]" that would return all type assertion nodes below the search field. Exact semantic to be discussed.
  • Maybe a visitor pattern to ease the walking of the selection tree.

Each resolver's context will now be able to access through the graph
of elements that were selected as part of the execution of this resolve via the standard
go context's value.

The returned field is an interface representing a subset of the functionality of the
internal/exec/selected package, enough for the developer to know what was queried by the
user.

I'm opening the PR to start a discussion about offering this feature to end user of the
library. We have started using it in our own fork of the library.

##### Design

This introduces new API interfaces the would become part of the standard library.

The interface is currently a simple wrapper around elements of
`internal/exec/selected/Selection` interface needed to "walk" the selected field.
Hopefully, I got the structure right.

I've currently used `Identifier()` instead of `Name()` and `Aliased()` instead of `Alias` to not renamed the field's name
since there would be conflict with struct fields in the `internal/exec/selected/Selection`
package. If we agree, the internal struct could change so the interface has the best name.

A future addition that I forsee could be:
- A "path" retrieval syntax "a la" gjson to quickly extract some nodes of the selection, for
  example with the star wars element ".search[]" that would return all type assertion nodes
  below the `search` field. Exact semantic to be discussed.
- Maybe a visitor pattern to ease the walking of the selection tree.
Field selected.Field
}

// GraphQLContext is used to retrieved the graphql from the context. If no graphql
Copy link
Author

Choose a reason for hiding this comment

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

Wrong comment

@@ -4,12 +4,14 @@
package starwars

import (
"context"
Copy link
Author

Choose a reason for hiding this comment

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

Changes here are just for demonstration purposes if someone wants to play with the feature a bit. To try it out, run the starwars example server and perform this curl call:

curl 'http://localhost:8080/query' -d '{"query":"query {search(text:\"C-3PO\") {... on Droid {name} ... on Starship {name}}}","variables":null}'

Copy link
Author

Choose a reason for hiding this comment

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

I do not intend to ship that if the feature is merged, it will be removed.

Aliased() string
}

func Dump(selection Selection) {
Copy link
Author

Choose a reason for hiding this comment

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

This is also present mainly for debugging/exploration purposes, another method that could be removed.

@maoueh
Copy link
Author

maoueh commented Nov 13, 2020

The use case we have right now is to explore the type assertion provided by the user, like in the starwars search query:

query {
  search(text:\"C-3PO\") {
    ... on Droid { name } 
    ... on Starship { name }
  }
}

We use the elements as a "filter" in our backend so we do not search for everything, only for what was requested by the user.

return selected.FieldKind
}

func (f *SchemaField) Identifier() string {
Copy link
Author

Choose a reason for hiding this comment

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

Couldn't use Name() method here yet since the backing internal/exec/selected/*SchemaField already has a field Name so it conflicts.

At one point, if we all agree on the feature and the interface, I suggest the internal field changes to the interface looks better.

This is the same reasoning for Aliased below.

Copy link
Member

Choose a reason for hiding this comment

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

Why can't you use its own Name field then?

Copy link
Author

Choose a reason for hiding this comment

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

Because the new public interface would exposes it, hence a field with the same name cannot exist.

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

Successfully merging this pull request may close these issues.

2 participants