-
-
Notifications
You must be signed in to change notification settings - Fork 15
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
RFC: Mark certain queries as used even no attributes are accessed #269
Comments
Transferred to However, I think we may want to first consider expanding bail-out patterns, e.g. when a given field is passed into a function, we should, under some circumstances mark it as used automatically. |
Thanks for you quick answer and transferring it to this repo, I was not aware that there is a different repo for the LSP. I'm not sure how much forward through the call tree one could track the usage of the attributes. But in some circumstances one need to save all the attributes, where I think it makes sense to intentionally say that from now on a query should be marked as "all fields used". If following through the call tree to identify used/unused attributes would work, this would conflict with always marking as used if passed to a function, that's why I suggested to intentionally mark it. |
I'm trying gql.tada for e2e testing a graphQL API along with supertest, const query = graphql(`
query login($email: String!, $password: String!) {
login(email: $email, password: $password) {
token
}
}
`)
const variables: VariablesOf<typeof query> = { email, password }
const { body } = await request(app.getHttpServer())
.post(GQL_ENDPOINT)
.send({
query: print(query),
variables,
})
.expect(200)
return body.data.login.token |
@gterras For a field to be marked as used the result type has to flow through to a type in your code. The type checker here can't infer the type of An easy way to fix that is to wrap this You can adapt this example though from the docs to type your |
Indeed although I posted this e2e example as a somewhat legitimate use case for needing an escape hatch to that warning, in the sense that adding a wrapper to an 2e2 suite makes it instantly harder to understand, use and maintain. Like this wrapper would also need a way to inject a token or return errors when needed, and would then need to be tested on its own. I like my tests (especially e2e) to be self-contained and to have zero abstraction (like in the posted example) so that a modified test cannot in any way impact another test. Also this wrapper requires quite some typing work, and while I don't doubt this is very useful in front-end code, in a testing context it feels like it could be advantageously replaced with a type assertion (since the result will be used only once). For the record I solved the warning issue by moving the query and its variables to a dedicated file, which makes me think people doing this in the first place would not ever see the warning. |
I'm also having this issue when passing the data to a component with a spread operator: const [{ data }] = useQuery({
query: FooQuery,
});
if (!data?.foo) {
return;
}
return <Foo {...data.foo} />; This should just mark all the fields as used here. |
@musjj well, we could go that way but imho it's an anti-pattern in GraphQL compared to https://gql-tada.0no.co/guides/fragment-colocation |
Thanks for the link, but I'm still very confused. Are there any end-to-end examples showing how this can be put together (still new to GraphQL)? I tried to use fragments like this: "use client";
import { FragmentOf, graphql } from "@/graphql";
import { useQuery } from "@urql/next";
const UserFragment = graphql(`
fragment UserFragment on User @_unmask {
name
age
}
`);
export const UserQuery = graphql(
`
query UserQuery {
user {
...UserFragment
}
}
`,
[UserFragment]
);
export function User({ data }: { data: FragmentOf<typeof UserFragment> }) {
return (
<article>
<h1>Name: {data.name}</h1>
<p>Age: {data.age}</p>
</article>
);
}
export function Page() {
const [{ data }] = useQuery({
query: UserQuery,
});
if (!data?.user) {
return;
}
return (
<main>
<User data={data.user} />
</main>
);
} But it still warns that the fields are unused. EDIT: Alright, it looks like you need to use an unmasked fragment: - fragment UserFragment on User @_unmask {
+ fragment UserFragment on User { Then later unmask it inside the const user = readFragment(UserFragment, data) Only then the warning stops. |
Summary
Checking for unused fields is a really powerful feature which definitely makes sense, but sometimes we don't want that, but instead want to pass the complete return type to an other function which e.g. stores this in local storage, but then we end up with an error that not all properties are accessed. E.g.:
Proposed Solution
Add some type of
@gql-tada-mark-used
comment, which could be used like this:This should then mark everything from the me query as used and there shouldn't be an error
Alternatively a simple
@gql-tada-ignore-unused
comment to the query definition may be sufficient too.Requirements
Have the ability to mark certain queries as fully used and ignore checking if all fields are actually accessed, because that will fail if the complete object is passed to any function.
The text was updated successfully, but these errors were encountered: