Skip to content

Conversation

randallb
Copy link

@randallb randallb commented Sep 7, 2025

Summary

  • Fixes crash when auto-generated refetch fields use field: "node.asType" but the schema lacks Query.node.
  • Treats node as rooted at the Query type and checks for existence.
  • If Query.node is absent, skips generating the refetch field instead of erroring (and returns a more specific error variant internally).

Motivation

  • On commits around 0.0.0-main-620f4c6f, any object implementing Node triggers a refetch field via @exposeField (field: "node.as<Obj>"). In schemas without Query.node, compilation fails with "Invalid field node in @exposeField directive".
  • This breaks real-world schemas that implement Node but intentionally do not expose Query.node.

Changes

  • create_additional_fields/expose_field_directive.rs:
    • Resolve top-level "node" against Query root when present.
    • Emit a PrimaryDirectiveFieldNotFound error if Query.node is absent (clearer than a generic InvalidField).
  • isograph_compiler/create_schema.rs:
    • Gracefully skip generating the refetch field when the error indicates that Query.node is missing; continue compiling the rest of the schema.
  • Dev quality-of-life: add flake.nix and .envrc for a reproducible dev shell with cargo/deno/node.

Notes

  • This preserves the refetch field behavior for projects that have Query.node, while making compilation resilient for projects that don’t.
  • Alternatively, the compiler could hard-require Query.node whenever any type implements Node; this PR aims to be permissive and avoid breakages while improving the error.

Testing

  • Verified with a minimal schema reproducer and with a larger application. In the reproducer without Query.node, the compiler proceeds without failing.

Related gist/repro: https://gist.github.com/randallb/df13780a215c74f3f9e05d81f4fe6e03

Randall Bennett added 2 commits September 7, 2025 13:48
…n when Query.node is absent; add dev shell for local builds
…e when Node is implemented (refetch generation handled gracefully)
@randallb
Copy link
Author

randallb commented Sep 7, 2025

(generated with gpt5 pro)

@randallb randallb marked this pull request as draft September 7, 2025 17:56
@randallb
Copy link
Author

randallb commented Sep 7, 2025

per patryk:


here we need to add another condition, object_implements_node && Query.node is "valid" don't know if we can do it at this step


unprocessed_items.push(SelectionType::Scalar(unprocessed_scalar_item));
match unvalidated_isograph_schema
.create_new_exposed_field(expose_as_field, parent_object_entity_name)
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's have create_new_exposed_field return a Result<Option<...>> and leave this code unchanged

if field == "node" {
let Some((query_name, _)) = self.find_query() else {
return Err(WithLocation::new(
CreateAdditionalFieldsError::PrimaryDirectiveFieldNotFound {
Copy link
Collaborator

Choose a reason for hiding this comment

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

and here, let's return None

.expect("canonicalize cwd")
.to_string_lossy()
.to_string();
db.set(CurrentWorkingDirectory(cwd_str.intern().into()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

we don't need to use the tmp folder, we can a bunch of calls to db.set(...) instead. Happy to figure out how to make that work unless you're interested in it. But not a blocker, the test lgtm

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