Skip to content

Add key fields to selections even when they're already selected with an alias #6503

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 2 commits into
base: main
Choose a base branch
from

Conversation

BoD
Copy link
Contributor

@BoD BoD commented Apr 30, 2025

No description provided.

@BoD BoD requested a review from martinbonnin as a code owner April 30, 2025 15:07
@svc-apollo-docs
Copy link
Collaborator

svc-apollo-docs commented Apr 30, 2025

⚠️ Docs preview not attached to branch

The preview was not built because the PR's base branch main is not in the list of sources.

An Apollo team member can comment one of the following commands to dictate which branch to attach the preview to:

  • !docs set-base-branch release-2.x
  • !docs set-base-branch release-3.x
  • !docs set-base-branch release-4.x

Build ID: 20c26efb3a364a0cd31e0bfe

Copy link
Contributor

@martinbonnin martinbonnin left a comment

Choose a reason for hiding this comment

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

Could we avoid duplicating the field? I think we have everything for that in CacheKeyGeneratorContext.field.selections?

Fragments make it a bit more complicated (because we don't have the full schema at runtime so a given field may be key in one fragment but not in the other and we probaby wouldn't know which one...).

@@ -94,7 +94,7 @@ private fun List<GQLSelection>.addRequiredFields(
requiredFieldNames.add("__typename")
}

val fieldNames = parentFields + selectionSet.filterIsInstance<GQLField>().map { it.name }.toSet()
val fieldNames = parentFields + selectionSet.filterIsInstance<GQLField>().map { it.alias ?: it.name }.toSet()
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
val fieldNames = parentFields + selectionSet.filterIsInstance<GQLField>().map { it.alias ?: it.name }.toSet()
val fieldNames = parentFields + selectionSet.filterIsInstance<GQLField>().map { it.responseName() }.toSet()

@martinbonnin
Copy link
Contributor

martinbonnin commented Apr 30, 2025

Another option is to codegen the key responseNames in CompiledField... We could make it so that we only codegen them if there are aliases but it's still one extra pointer for every field.

Note: just realized that the keyfields are added after validation so we're potentially sending invalid queries to the server 😬

@BoD
Copy link
Contributor Author

BoD commented Apr 30, 2025

Could we avoid duplicating the field? I think we have everything for that in CacheKeyGeneratorContext.field.selections?

Ah yes we could look for the field's name, and fallback to its alias(es).

But I actually don't follow your caveat about fragments, do you have an example?

@martinbonnin
Copy link
Contributor

union Stuff = Book | Banana

interface Product {
  # ...
}
type Book @typePolicy(keyFields: "isbn") implements Product {
  isbn: String!
  # ...
}

query GetStuff {
  stuff {
    ... on Product {
      ... on Book {
        identifier: isbn
      }
    }
  }
}

Walking compiledField.selections bumps into Product. In order to know if we need to collect the fragment, we need to know whether Book is an instance of Product. Might be doable but it's not trivial logic.

Ultimately, it probably requires that we implement collectFields() inside the CacheKeyResolver just like we're doing in the Normalizer

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.

3 participants