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

AP-682 Strip FragmentDefinitions in client:check when only included in @client fields #1454

Merged
merged 12 commits into from
Aug 12, 2019

Conversation

justinanastos
Copy link
Contributor

@justinanastos justinanastos commented Jul 31, 2019

We're getting client:check failures when using a Fragment in a @client field because while the fields with @client are stripped, Fragments that are nested below them are not. We now check that Fragments can be removed if they are only used in @client fields.

I added tests to the existing functionality on one commit, added a failing test for how I expected the method to behave, and then fixed the test. Please look at the last new test to see a reproduction.


TODO:

  • Update CHANGELOG.md* with your change (include reference to issue & this PR)
  • Make sure all of the significant new logic is covered by tests
  • Rebase your changes on master so that they can be merged easily
  • Make sure all tests and linter rules pass

*Make sure changelog entries note which project(s) has been affected. See older entries for examples on what this looks like.

@justinanastos justinanastos marked this pull request as ready for review July 31, 2019 21:42
These will make sure we don't break the original functionality
…nitions

If we remove a client field that includes fragment definitions, we should
remove the fragment definition as well if that fragment isn't reused
…tatedFields

This ensures that the type passed in extends from ASTNode and then returns
the same type that is passed in, which may be a more specific version of
ASTNode (like DocumentNode).
…d in @client field

If we spread a fragment inside of a `@client` field, we remove that
fragment spread. If we don't use that fragment anywhere else then we should
remove the fragment definition.

It _is_ possible that a fragment is used on a @client field and non-client
field if they are fragments on an interface and not and object.
@justinanastos justinanastos force-pushed the justin/AP-682/client-check-fragments branch from 83bb034 to f04abf4 Compare July 31, 2019 21:46
Copy link
Contributor

@jbaxleyiii jbaxleyiii left a comment

Choose a reason for hiding this comment

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

@justinanastos this is a good start, but fragments can be really tricky especially as the recurse. Happy to pair on this if you have questions about my comments!

@justinanastos
Copy link
Contributor Author

@jbaxleyiii Great suggestions for new test cases and awesome explanations of what my first pass was missing.

I've added the suggested test cases and another one to make sure we don't remove fragments that we didn't remove because of @client directives. I made the removal recursive as well.

@justinanastos justinanastos force-pushed the justin/AP-682/client-check-fragments branch from fc4b4c9 to 32601c1 Compare August 2, 2019 16:26
Copy link
Contributor

@jbaxleyiii jbaxleyiii left a comment

Choose a reason for hiding this comment

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

This is getting closer! I left a few more questions where a couple more complex test cases with nested behaviors may be helpful to make sure all of the work is being done the way you want it to

packages/apollo-language-server/src/utilities/graphql.ts Outdated Show resolved Hide resolved
packages/apollo-language-server/src/utilities/graphql.ts Outdated Show resolved Hide resolved
}

// All nested fragment spreads inside of this definition are now eligible to be removed
visit(ast, {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should nest visitors here. This implementation doesn't do what I think you want it to anyway. By revisiting the root ast, instead of the specific node that you are in currently, you aren't "filtering" fragment spreads inside of this definition.

Since the visitor works depth first, you should be able to visit on FragmentDefinition to create your list, then visit the FragmentSpread next as long as you sort the document prior to doing the work so that fragment definitions always come first

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Absolutely right.

Copy link
Contributor

Choose a reason for hiding this comment

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

This appears to still be nested? Why was this resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm sorry about that; I have no idea. I'll figure this last piece out on Monday! Thanks again @jbaxleyiii !

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My original logic was to visit all the descendents of node to find all fragment spreads being removed because this field was being removed as well. I wrote this to visit ast by accident; great catch @jbaxleyiii .

I think that I do, however, want to use a nested visitor here to flag all the fragment spreads under this node as eligible for deletion. I've added a comment to hopefully explain this. Please let me know if this is the correct way to handle this problem.

We're getting a list of all the fragment spreads and then removing all
fragment spreads that aren't in the list we just created. This will never
happen.
Copy link
Contributor

@jbaxleyiii jbaxleyiii left a comment

Choose a reason for hiding this comment

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

@justinanastos this looks great except for the nesting of the visitors still?

/**
* Remove nodes that have zero-length selection sets
*
* The `ast` param must extend ASTNode. We use a genetic to indicate that this function returns the same type
Copy link
Contributor

Choose a reason for hiding this comment

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

Generic*

}

// All nested fragment spreads inside of this definition are now eligible to be removed
visit(ast, {
Copy link
Contributor

Choose a reason for hiding this comment

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

This appears to still be nested? Why was this resolved?

Copy link
Contributor

@jbaxleyiii jbaxleyiii left a comment

Choose a reason for hiding this comment

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

@justinanastos thanks for sticking with me for the review cycles. I really appreciate the time and effort you put into this PR! I think it is good to go as is!

For future readers looking back, another approach that we could have taken here would be to look at the overall DocumentNode and collect 1) all fragments (inline and defined) 2) determine the relationships between them and the conditionality of that related to trimmable directives (i.e. @client) then re-walk over the AST using the visitor to selectively remove the listed fragments and trim their selection sets. This would be more kin to an "ahead of time" style versus a "just in time" style which this PR implements. If performance ever becomes a big concern, we may need to try the AOT but I'm happy with where this solution has landed

@justinanastos justinanastos merged commit 724eb1c into master Aug 12, 2019
@justinanastos justinanastos deleted the justin/AP-682/client-check-fragments branch August 12, 2019 21:11
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.

2 participants