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

Clarify to which nodes genqlient directives apply #151

Open
benjaminjkraft opened this issue Nov 2, 2021 · 3 comments
Open

Clarify to which nodes genqlient directives apply #151

benjaminjkraft opened this issue Nov 2, 2021 · 3 comments
Labels
needs design Issues where we don't know exactly what we need yet; discuss on the issue before implementing
Milestone

Comments

@benjaminjkraft
Copy link
Collaborator

benjaminjkraft commented Nov 2, 2021

If you do

# @genqlient(...)
query Q(arg: T!) { field { subfield } }

then the directive applies -- and must be legal for -- not only query Q but also arg: T!, field, and subfield. This is documented but in a somewhat obscure place and has caused quite a bit of confusion (see e.g. #148/#149). It's also not clear how useful it is either.

Instead we could:

  1. Warn more clearly if a directive applies multiple places, or at least add text to the error in the case where one of those places is invalid.
  2. Only apply @genqlient directives to the first following node (so the above directive would apply to query Q only).
  3. Don't allow @genqlient directives which would apply to multiple nodes.
  4. Figure out how to make @genqlient directives real directives instead of comments -- this may be more possible now that we're rewriting queries (edit: and now that the new GraphQL spec adds repeatable directives and directives on variable definitions) although it has costs if it means other tools no longer consider the query in source valid (or require a schema addition to do so) -- and then ordinary GraphQL syntax applies.
  5. Do (1), (2), or (3), but only for when one of the nodes is the entire query (the others are typically arguments), which has empirically been the most common source of confusion and seems the least useful. (Namely, one can imagine wanting the same directive to apply to several sibling fields, but applying it to both query and a particular argument seems nonsensical.)

I lean towards option 5.3, i.e. forbid this with a clear error if one of the nodes is the entire query; it seems to me that's unlikely to break anyone who wasn't already seeing confusing behavior and it's simple enough to avoid. But I'm open to other options depending on what others think or what's easy to implement!

@benjaminjkraft benjaminjkraft added help wanted Issues that anyone could pick up and implement if useful to them needs design Issues where we don't know exactly what we need yet; discuss on the issue before implementing labels Nov 2, 2021
@nathanstitt
Copy link
Contributor

@csilvers and @benjaminjkraft thanks for both of your help with debugging #148, I've managed to debug the the root cause of the strange errors I was receiving. This discussion likely belongs on this issue since it relates to how comment directives are applied.

While these two statements appear identical, the comment will be applied differently:

This statement works fine.

# @genqlient(for: message_insert_input.created_by_id", omitempty: true)
mutation insertComment(
    $comment: message_insert_input!
) {
  insert_task_comment_one( object: $comment ) { id }
}

But this one fails with either: for is only applicable to operations and arguments or omitempty may only be used on optional arguments

# @genqlient(for: message_insert_input.created_by_id", omitempty: true)
mutation insertComment($comment: message_insert_input!) {
  insert_task_comment_one( object: $comment ) { id }
}

Note that the above statement lacks the newline before the variable declaration. The comment is parsed for both the *ast.OperationDefinition. and *ast.VariableDefinition: blocks in https://github.com/Khan/genqlient/blob/main/generate/genqlient_directive.go#L241

I'm not sure if this is really a bug, maybe the newline behavior just needs to be documented?

@benjaminjkraft
Copy link
Collaborator Author

benjaminjkraft commented Nov 10, 2021

Yeah, that's the maybe-bug I mean! It is documented but the documentation is very hidden and also clearly not explained well enough. I think what you say makes it clear that what we need to do is change the behavior, not just try to document it.

I'm liking option 3 above, personally, I think that leaves the least room for confusion. If I have time this week I can take a stab at doing that. (Note to self: it may be best to do it as a separate pass so that we can also look for directives that would apply to no nodes, which are also probably an error.)

@nathanstitt
Copy link
Contributor

yes, option 3 would be great from my perspective.

if it had a clear error that the directive was applying to multiple nodes that would make it clear what would need to change in the graphql statement.

@benjaminjkraft benjaminjkraft removed the help wanted Issues that anyone could pick up and implement if useful to them label Aug 15, 2022
@benjaminjkraft benjaminjkraft added this to the v1.0 milestone Aug 15, 2022
StevenACoffman pushed a commit that referenced this issue Nov 17, 2022
This PR is addressing the behavior described in #151.
The former version of `for` directive example usage ended in:
```
genqlient.graphql:<line>: for is only applicable to operations and arguments
```


I have:
- [x] Written a clear PR title and description (above)
- [x] Signed the [Khan Academy CLA](https://www.khanacademy.org/r/cla)
- [x] Added tests covering my changes, if applicable
- [x] Included a link to the issue fixed, if applicable
- [x] Included documentation, for new features
- [x] Added an entry to the changelog

Signed-off-by: Matúš Bafrnec <matus.bafrnec@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs design Issues where we don't know exactly what we need yet; discuss on the issue before implementing
Projects
None yet
Development

No branches or pull requests

2 participants