Skip to content

Conversation

@Ckk3
Copy link
Collaborator

@Ckk3 Ckk3 commented Nov 15, 2025

This PR fixes a bug in the codegen where Relay Node's id field was incorrectly generated as _id in the output code.

Description

The Relay Node class defines its id field like this:

@field(name="id", ...)  # GraphQL name
def _id(cls, ...):  # Python method name

The codegen was using field.name (the Python name _id) instead of respecting the explicit graphql_name (id) set via the decorator.

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

Summary by Sourcery

Tests:

  • Add test verifying codegen output for Relay NodeID field name mapping from NodeID to id: str using a sample query and schema

Summary by Sourcery

Ensure code generation respects GraphQL field names (e.g. Relay Node id) instead of Python attribute names.

Bug Fixes:

  • Fix Relay Node fields being generated with the Python method name _id instead of the GraphQL field name id in codegen outputs.

Enhancements:

  • Introduce a helper to consistently derive the correct GraphQL field name for generated fields based on graphql_name when present.

Documentation:

  • Add release notes describing the fix for Relay Node id field name generation in codegen.

Tests:

  • Add Relay-focused codegen tests and snapshots for Python and TypeScript to verify correct handling of NodeID id fields, aliases, fragments, lists, nested nodes, and variables.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 15, 2025

Reviewer's Guide

Fixes query codegen to use each Strawberry field’s GraphQL name (e.g. Relay Node id) instead of the Python attribute name, and adds relay-focused codegen tests and snapshots for Python and TypeScript plugins to validate the behavior across various query patterns.

File-Level Changes

Change Details Files
Ensure code generation uses the field’s GraphQL name (including Relay Node id) instead of the Python attribute name.
  • Import StrawberryField into the query codegen module to access field metadata.
  • Introduce a helper function that returns field.graphql_name when present, otherwise falls back to field.name.
  • Update type-collection logic to construct GraphQLField instances using the helper-derived field name.
  • Update selection-based field construction paths to use the helper-derived field name so selections and aliases resolve using GraphQL names.
strawberry/codegen/query_codegen.py
Add relay-focused codegen tests and snapshots for Python and TypeScript plugins to exercise NodeID/id handling across multiple query patterns.
  • Define Relay-style schema types (User, Post, Query) using Node and NodeID to drive code generation.
  • Parametrize a new test to run both Python and TypeScript query codegen plugins against a set of relay_* GraphQL queries and snapshot their outputs.
  • Add relay-related GraphQL query fixtures (single node, lists, fragments, aliases, and variableized queries).
  • Add corresponding Python and TypeScript snapshot files asserting that generated result types expose id: str for node IDs and correct alias handling.
tests/codegen/test_relay_node_id_codegen.py
tests/codegen/relay_queries/relay_fragment.graphql
tests/codegen/relay_queries/relay_nested_nodes.graphql
tests/codegen/relay_queries/relay_node_id.graphql
tests/codegen/relay_queries/relay_alias.graphql
tests/codegen/relay_queries/relay_list.graphql
tests/codegen/relay_queries/relay_variables.graphql
tests/codegen/snapshots/relay/python/relay_alias.py
tests/codegen/snapshots/relay/python/relay_fragment.py
tests/codegen/snapshots/relay/python/relay_list.py
tests/codegen/snapshots/relay/python/relay_nested_nodes.py
tests/codegen/snapshots/relay/python/relay_node_id.py
tests/codegen/snapshots/relay/python/relay_variables.py
tests/codegen/snapshots/relay/typescript/relay_alias.ts
tests/codegen/snapshots/relay/typescript/relay_fragment.ts
tests/codegen/snapshots/relay/typescript/relay_list.ts
tests/codegen/snapshots/relay/typescript/relay_nested_nodes.ts
tests/codegen/snapshots/relay/typescript/relay_node_id.ts
tests/codegen/snapshots/relay/typescript/relay_variables.ts
Document the change as a patch release entry.
  • Add a release note describing the fix for Relay Node id codegen to respect the explicit GraphQL name instead of the Python method name.
RELEASE.md

Assessment against linked issues

Issue Objective Addressed Explanation
#4005 Update code generation so that Relay NodeID fields are emitted as id: str (using the GraphQL field name) instead of _id: str (the Python attribute name).

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov
Copy link

codecov bot commented Nov 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.41%. Comparing base (71b7182) to head (7a2955c).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4053   +/-   ##
=======================================
  Coverage   94.41%   94.41%           
=======================================
  Files         536      537    +1     
  Lines       35036    35077   +41     
  Branches     1842     1842           
=======================================
+ Hits        33079    33118   +39     
- Misses       1659     1661    +2     
  Partials      298      298           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 15, 2025

CodSpeed Performance Report

Merging #4053 will not alter performance

Comparing Ckk3:issue-4005 (7a2955c) with main (71b7182)

Summary

✅ 28 untouched

@Ckk3 Ckk3 self-assigned this Nov 30, 2025
@Ckk3 Ckk3 changed the title Codegen outputs relay.NodeID fields as _id: str instead of id: str. fix(codegen): Relay Node id field generated as _id instead of id Dec 1, 2025
@Ckk3 Ckk3 changed the title fix(codegen): Relay Node id field generated as _id instead of id fix(codegen): Relay Node id field generated as _id instead of id Dec 1, 2025
@Ckk3 Ckk3 marked this pull request as ready for review December 1, 2025 03:14
@botberry
Copy link
Member

botberry commented Dec 1, 2025

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Fixed a bug in the codegen where Relay Node's id field was incorrectly generated as _id in the output code.

The codegen now correctly respects the explicit graphql_name set via the @field(name="id") decorator, ensuring that the generated code uses id instead of the Python method name _id.

Here's the tweet text:

🆕 Release (next) is out! Thanks to Luis Gustavo for the PR 👏

Get it here 👉 https://strawberry.rocks/release/(next)

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 1, 2025

Greptile Overview

Greptile Summary

This PR fixes a bug where Relay Node's id field was incorrectly generated as _id in codegen output. The root cause was that the codegen used the Python method name (_id) instead of respecting the explicit GraphQL field name (id) set via the @field(name="id") decorator.

Key Changes:

  • Added _get_field_name() helper function in query_codegen.py:126-132 that prioritizes field.graphql_name over field.name
  • Applied the helper in three locations where field names are used for codegen (lines 591, 640, 724)
  • Comprehensive test coverage with 7 GraphQL query variations (basic node, aliases, lists, nested nodes, fragments, variables)
  • All snapshot tests updated to show correct id field naming

Impact:
The fix ensures that any Strawberry field with an explicit graphql_name will be correctly reflected in generated code, not just for Relay Node but for any field using the name parameter in the @field decorator.

Confidence Score: 5/5

  • This PR is safe to merge with no risks
  • The fix is minimal, well-targeted, and correctly addresses the root cause. The new _get_field_name() helper has clear logic with proper fallback behavior. Comprehensive test coverage across 7 different Relay query scenarios (basic, aliases, lists, nested, fragments, variables) with both Python and TypeScript snapshot validation ensures the fix works correctly and doesn't introduce regressions. The change is backwards-compatible since it only affects fields with explicit graphql_name set, which were previously buggy anyway.
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
strawberry/codegen/query_codegen.py 5/5 Adds _get_field_name() helper to use graphql_name when set, fixing Relay Node id field codegen
tests/codegen/test_relay_node_id_codegen.py 5/5 Comprehensive test for Relay Node codegen covering single nodes, lists, nested nodes, aliases, fragments, and variables
tests/codegen/snapshots/relay/python/relay_node_id.py 5/5 Expected Python output showing id: str instead of incorrect _id: str
tests/codegen/snapshots/relay/typescript/relay_node_id.ts 5/5 Expected TypeScript output showing id: string field name

Sequence Diagram

sequenceDiagram
    participant User as User Query
    participant QC as QueryCodegen
    participant Helper as _get_field_name()
    participant Schema as Strawberry Schema
    participant Field as StrawberryField
    
    User->>QC: Generate code for Relay query
    QC->>Schema: Get Relay Node type definition
    Schema-->>QC: Node with _id method (@field(name="id"))
    
    QC->>QC: Process field for codegen
    QC->>Helper: _get_field_name(field)
    Helper->>Field: Check field.graphql_name
    
    alt graphql_name is set (e.g., "id")
        Field-->>Helper: "id" (explicit GraphQL name)
        Helper-->>QC: Return "id"
    else graphql_name is None
        Field-->>Helper: None
        Helper->>Field: Get field.name (Python name)
        Field-->>Helper: Python method name
        Helper-->>QC: Return Python name
    end
    
    QC->>QC: Create GraphQLField with correct name
    QC-->>User: Generated code with "id: str"
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

20 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@Ckk3
Copy link
Collaborator Author

Ckk3 commented Dec 1, 2025

@sourcery-ai review

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Member

@bellini666 bellini666 left a comment

Choose a reason for hiding this comment

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

Image

return strawberry.Schema(query=Query)


HERE = Path(__file__).parent
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: move this to the top of the file, after imports

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree, fixed!

Comment on lines 54 to 65
RELAY_QUERIES = list((HERE / "relay_queries").glob("*.graphql"))


@pytest.mark.parametrize(
("plugin_class", "plugin_name", "extension"),
[
(PythonPlugin, "python", "py"),
(TypeScriptPlugin, "typescript", "ts"),
],
ids=["python", "typescript"],
)
@pytest.mark.parametrize("query", RELAY_QUERIES, ids=[x.name for x in RELAY_QUERIES])
Copy link
Member

Choose a reason for hiding this comment

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

nitpick:

Suggested change
RELAY_QUERIES = list((HERE / "relay_queries").glob("*.graphql"))
@pytest.mark.parametrize(
("plugin_class", "plugin_name", "extension"),
[
(PythonPlugin, "python", "py"),
(TypeScriptPlugin, "typescript", "ts"),
],
ids=["python", "typescript"],
)
@pytest.mark.parametrize("query", RELAY_QUERIES, ids=[x.name for x in RELAY_QUERIES])
@pytest.mark.parametrize(
("plugin_class", "plugin_name", "extension"),
[
(PythonPlugin, "python", "py"),
(TypeScriptPlugin, "typescript", "ts"),
],
ids=["python", "typescript"],
)
@pytest.mark.parametrize("query", RELAY_QUERIES, ids=[x.name for x in (HERE / "relay_queries").glob("*.graphql")])

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, @bellini666 , I've updated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codegen for relay.NodeID

3 participants