From 193467a42193cc3419b6f318c4d41c2e87a07eb8 Mon Sep 17 00:00:00 2001 From: Marc Daniels Date: Thu, 7 May 2026 22:39:16 -0400 Subject: [PATCH 1/2] Fix nodes returning empty when only __typename is requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a query selects only `__typename` under `nodes` or `edges { node }`, `requested_fields` ends up empty (because `__typename` is a dynamic field and is stripped before populating `requested_fields`). This left `individual_docs_needed: false`, causing `size: 0` in the datastore query and returning no documents despite `total_edge_count > 0`. Fix by additionally setting `individual_docs_needed: true` whenever `nodes` or `edges.node` is selected at all — the client selecting that part of the query is itself the signal that individual documents are needed. Fixes #1055 Generated with Claude Code --- .../graphql/query_adapter/requested_fields.rb | 2 +- .../spec/acceptance/search_spec.rb | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/elasticgraph-graphql/lib/elastic_graph/graphql/query_adapter/requested_fields.rb b/elasticgraph-graphql/lib/elastic_graph/graphql/query_adapter/requested_fields.rb index 3dc12a4d3..e17736e4f 100644 --- a/elasticgraph-graphql/lib/elastic_graph/graphql/query_adapter/requested_fields.rb +++ b/elasticgraph-graphql/lib/elastic_graph/graphql/query_adapter/requested_fields.rb @@ -55,7 +55,7 @@ def query_attributes_for(field:, lookahead:) .selection(@schema.element_names.highlights) { - individual_docs_needed: pagination_fields_need_individual_docs?(lookahead), + individual_docs_needed: pagination_fields_need_individual_docs?(lookahead) || relay_connection_node_from(lookahead).selected?, requested_fields: requested_fields_under(relay_connection_node_from(lookahead), index_field_paths), request_all_highlights: requesting_all_highlights?(lookahead), requested_highlights: requested_fields_under(highlights, index_field_paths) diff --git a/elasticgraph-graphql/spec/acceptance/search_spec.rb b/elasticgraph-graphql/spec/acceptance/search_spec.rb index 05ccc7813..910471b7b 100644 --- a/elasticgraph-graphql/spec/acceptance/search_spec.rb +++ b/elasticgraph-graphql/spec/acceptance/search_spec.rb @@ -913,6 +913,42 @@ module ElasticGraph ] end + it "returns nodes when querying only `__typename` with no other fields" do + index_records( + build(:address), + build(:address), + build(:electrical_part), + build(:mechanical_part) + ) + + # Concrete type: nodes { __typename } + address_nodes = call_graphql_query(<<~QUERY).dig("data", "addresses", "nodes") + query { addresses { nodes { __typename } } } + QUERY + expect(address_nodes).to contain_exactly( + {"__typename" => "Address"}, + {"__typename" => "Address"} + ) + + # Concrete type: edges { node { __typename } } + address_edges = call_graphql_query(<<~QUERY).dig("data", "addresses", "edges") + query { addresses { edges { node { __typename } } } } + QUERY + expect(address_edges).to contain_exactly( + {"node" => {"__typename" => "Address"}}, + {"node" => {"__typename" => "Address"}} + ) + + # Abstract type: nodes { __typename } (no type-specific fragments) + part_nodes = call_graphql_query(<<~QUERY).dig("data", "parts", "nodes") + query { parts { nodes { __typename } } } + QUERY + expect(part_nodes).to contain_exactly( + {"__typename" => "ElectricalPart"}, + {"__typename" => "MechanicalPart"} + ) + end + describe "`list` filtering behavior" do it "supports filtering on scalar lists, nested object lists, and embedded object lists", :expect_index_exclusions do index_records( From 78d8ee9fe058daaea1c7d6d150a07c00c1467fc1 Mon Sep 17 00:00:00 2001 From: Marc Daniels Date: Fri, 8 May 2026 22:10:16 -0400 Subject: [PATCH 2/2] Add unit tests for individual_docs_needed when only __typename is requested Covers the fix from the previous commit at the unit level, as requested in code review. Generated with Claude Code --- .../query_adapter/requested_fields_spec.rb | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_adapter/requested_fields_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_adapter/requested_fields_spec.rb index 3615315b7..6e8b95a62 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_adapter/requested_fields_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_adapter/requested_fields_spec.rb @@ -669,6 +669,38 @@ class QueryAdapter expect(query.individual_docs_needed).to be true end + it "sets `individual_docs_needed = true` when only `__typename` is requested under `nodes`" do + query = datastore_query_for(:Query, :widgets, <<~QUERY) + query { + widgets { + nodes { + __typename + } + } + } + QUERY + + expect(query.individual_docs_needed).to be true + expect(query.requested_fields).to be_empty + end + + it "sets `individual_docs_needed = true` when only `__typename` is requested under `edges.node`" do + query = datastore_query_for(:Query, :widgets, <<~QUERY) + query { + widgets { + edges { + node { + __typename + } + } + } + } + QUERY + + expect(query.individual_docs_needed).to be true + expect(query.requested_fields).to be_empty + end + it "sets `individual_docs_needed = true` when an edge cursor is requested" do query = datastore_query_for(:Query, :widgets, <<~QUERY) query {