Skip to content

feat: add support for fields with arguments and requires directive#1452

Merged
dkorittki merged 10 commits intomasterfrom
dominik/eng-9218-implement-requires-with-field-resolvers-in-go-tools
Apr 7, 2026
Merged

feat: add support for fields with arguments and requires directive#1452
dkorittki merged 10 commits intomasterfrom
dominik/eng-9218-implement-requires-with-field-resolvers-in-go-tools

Conversation

@dkorittki
Copy link
Copy Markdown
Contributor

@dkorittki dkorittki commented Mar 18, 2026

Context

A change in protographic allows to treat fields with arguments to be treated as a required fields alongside needed protobuf rpc's and message to retrieve field_arguments. A necessary change to allow field arguments on @requires fields.

When giving this new proto spec and mapping to the engine such fields were silently ignoring the arguments — the gRPC call received the context (key + required fields) but no field_args, so the service always saw zero-value arguments.

Implementation

Wire field arguments through the @requires execution path (grpc datasource, federation visitor, compiler), doing it similar to how field resolvers already handle them.

Tests

Three new integration + execution-plan test scenarios covering:

Scenario Args
Single required string arg prefix: String!
Two args, one repeated (list) prefixes: [String!]!, maxResults: Int!
Nullable arg (maps to google.protobuf.StringValue) prefix: String

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 18, 2026

📝 Walkthrough

Walkthrough

Propagates GraphQL field arguments from federation @requires into gRPC required-fields RPCs: the planner captures arguments, the execution plan includes an optional field_args request section when present, and the gRPC compiler conditionally builds/sets the protobuf field_args payload.

Changes

Cohort / File(s) Summary
Planning & Visitor
v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor_federation.go
Parse GraphQL field arguments for required fields and attach parsed fieldArguments to the requiredField; abort planning on parse errors.
Execution Plan Construction
v2/pkg/engine/datasource/grpc_datasource/execution_plan.go
createRequiredFieldsRPCCall conditionally appends a field_args nested request message populated from requiredField.fieldArguments when non-empty.
gRPC Compiler
v2/pkg/engine/datasource/grpc_datasource/compiler.go
buildRequiredFieldsMessage checks for a field_args field in the RPC message schema; if present, builds the protobuf message for args and sets it on the root request, propagating errors.
Unit Tests (planner/exec plan)
v2/pkg/engine/datasource/grpc_datasource/execution_plan_requires_test.go
Added table-driven tests asserting execution plans include field_args for filtered-tag argument shapes (single, repeated, nullable, multi-arg).
Integration Tests
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_federation_test.go
Added end-to-end tests for filtered-tag @requires fields driven by arguments, covering matching, no-match, truncation, and nullable-arg behaviors.
Test Mappings
v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go, v2/pkg/grpctest/mapping/mapping.go
Added Storage required-field and GraphQL field mappings for filteredTagSummary, multiFilteredTagSummary, nullableFilteredTagSummary with argument→protobuf field mappings.
Mock gRPC Service
v2/pkg/grpctest/mockservice_requires.go
Added three mock RPC handlers implementing filtered-tag logic (single prefix, multiple prefixes + maxResults, nullable prefix) that read field_args and return nullable StringValue results.
Proto & Schema
v2/pkg/grpctest/product.proto, v2/pkg/grpctest/testdata/products.graphqls
Added three new RequireStorage... RPCs with corresponding request/response/args messages and added the three Storage GraphQL fields annotated with @requires(fields: "tags").

Sequence Diagram(s)

sequenceDiagram
    participant Client as GraphQL Client
    participant Planner as Federation Planner
    participant Visitor as Visitor
    participant Executor as Execution Plan Executor
    participant Compiler as gRPC Compiler
    participant gRPCService as gRPC Service

    Client->>Planner: Request `@requires` field with arguments
    Planner->>Visitor: process required field
    Visitor->>Visitor: parseFieldArguments() -> attach to requiredField
    Visitor->>Executor: emit execution plan (includes fieldArguments)
    Executor->>Executor: createRequiredFieldsRPCCall() (include field_args if present)
    Executor->>Compiler: buildRequiredFieldsMessage(request with field_args)
    Compiler->>Compiler: locate `field_args` in RPC schema
    Compiler->>Compiler: buildProtoMessage() & setMessageValue()
    Executor->>gRPCService: call RPC with context + field_args
    gRPCService->>gRPCService: read field_args, compute filtered summary
    gRPCService-->>Executor: return response results
    Executor-->>Client: resolve `@requires` field
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main feature addition: support for fields with arguments in the @requires directive.
Description check ✅ Passed The PR description accurately describes the changeset: adding support for field arguments in @requires fields, with implementation details across grpc datasource/federation and three test scenarios covering different argument patterns.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dominik/eng-9218-implement-requires-with-field-resolvers-in-go-tools

Comment @coderabbitai help to get the list of available commands and usage tips.

@dkorittki dkorittki marked this pull request as ready for review March 20, 2026 12:28
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
v2/pkg/grpctest/mockservice_requires.go (1)

303-321: Handle non-positive maxResults explicitly in multi-prefix filtering.

At Line 319, the cap check uses equality only. For negative values, the cap is effectively disabled, which is surprising for a “max results” contract.

♻️ Suggested refinement
 func (s *MockService) RequireStorageMultiFilteredTagSummaryById(_ context.Context, req *productv1.RequireStorageMultiFilteredTagSummaryByIdRequest) (*productv1.RequireStorageMultiFilteredTagSummaryByIdResponse, error) {
 	prefixes := req.GetFieldArgs().GetPrefixes()
 	maxResults := int(req.GetFieldArgs().GetMaxResults())
 	results := make([]*productv1.RequireStorageMultiFilteredTagSummaryByIdResult, 0, len(req.GetContext()))

 	for _, ctx := range req.GetContext() {
+		if maxResults <= 0 {
+			results = append(results, &productv1.RequireStorageMultiFilteredTagSummaryByIdResult{})
+			continue
+		}
 		tags := ctx.GetFields().GetTags()

 		filteredTags := make([]string, 0, len(tags))
 		for _, tag := range tags {
 			for _, p := range prefixes {
 				if strings.HasPrefix(tag, p) {
 					filteredTags = append(filteredTags, tag)
 					break
 				}
 			}
-			if len(filteredTags) == maxResults {
+			if len(filteredTags) >= maxResults {
 				break
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v2/pkg/grpctest/mockservice_requires.go` around lines 303 - 321, In
RequireStorageMultiFilteredTagSummaryById, normalize the requested maxResults
and make the cap check robust: read maxResults :=
int(req.GetFieldArgs().GetMaxResults()), if maxResults <= 0 set maxResults = 0
(treat non-positive as zero) and replace the equality cap check with a >= guard
that only applies when maxResults > 0 (e.g. if maxResults > 0 &&
len(filteredTags) >= maxResults { break }), so negative values no longer disable
the cap and the loop behaves predictably; update references to prefixes,
filteredTags and maxResults in the filtering loop accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@v2/pkg/grpctest/mockservice_requires.go`:
- Around line 303-321: In RequireStorageMultiFilteredTagSummaryById, normalize
the requested maxResults and make the cap check robust: read maxResults :=
int(req.GetFieldArgs().GetMaxResults()), if maxResults <= 0 set maxResults = 0
(treat non-positive as zero) and replace the equality cap check with a >= guard
that only applies when maxResults > 0 (e.g. if maxResults > 0 &&
len(filteredTags) >= maxResults { break }), so negative values no longer disable
the cap and the loop behaves predictably; update references to prefixes,
filteredTags and maxResults in the filtering loop accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f71adf9-0545-407a-82bc-66cff6012a5a

📥 Commits

Reviewing files that changed from the base of the PR and between 18b292e and a7267a5.

⛔ Files ignored due to path filters (2)
  • v2/pkg/grpctest/productv1/product.pb.go is excluded by !**/*.pb.go
  • v2/pkg/grpctest/productv1/product_grpc.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (10)
  • v2/pkg/engine/datasource/grpc_datasource/compiler.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_requires_test.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor_federation.go
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_federation_test.go
  • v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go
  • v2/pkg/grpctest/mapping/mapping.go
  • v2/pkg/grpctest/mockservice_requires.go
  • v2/pkg/grpctest/product.proto
  • v2/pkg/grpctest/testdata/products.graphqls

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@v2/pkg/grpctest/mockservice_requires.go`:
- Around line 495-496: The loop that appends into filteredTags only breaks when
len(filteredTags) == maxResults, which allows results when maxResults <= 0;
update the logic in the function that builds filteredTags to first treat
non-positive maxResults as returning no matches (e.g., if maxResults <= 0 return
empty slice), and change the break condition to use >= (if len(filteredTags) >=
maxResults) to ensure we never exceed the cap; adjust the code paths that
reference filteredTags and maxResults accordingly (look for the loop appending
to filteredTags and the variables filteredTags and maxResults).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7fd88360-f35e-486d-b1a7-bc1ba2812c07

📥 Commits

Reviewing files that changed from the base of the PR and between 5036bd6 and fc1c2d3.

⛔ Files ignored due to path filters (2)
  • v2/pkg/grpctest/productv1/product.pb.go is excluded by !**/*.pb.go
  • v2/pkg/grpctest/productv1/product_grpc.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (10)
  • v2/pkg/engine/datasource/grpc_datasource/compiler.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_requires_test.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor_federation.go
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_federation_test.go
  • v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go
  • v2/pkg/grpctest/mapping/mapping.go
  • v2/pkg/grpctest/mockservice_requires.go
  • v2/pkg/grpctest/product.proto
  • v2/pkg/grpctest/testdata/products.graphqls
✅ Files skipped from review due to trivial changes (2)
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan.go
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_federation_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • v2/pkg/grpctest/mapping/mapping.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor_federation.go
  • v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_requires_test.go
  • v2/pkg/grpctest/product.proto
  • v2/pkg/engine/datasource/grpc_datasource/compiler.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
v2/pkg/grpctest/mockservice_requires.go (1)

484-497: ⚠️ Potential issue | 🟡 Minor

Handle non-positive maxResults before filtering.

At Line 495, the cap check runs after append, so maxResults <= 0 can still emit one match when the first tag passes the prefix filter.

Proposed fix
 for _, ctx := range req.GetContext() {
+		if maxResults <= 0 {
+			results = append(results, &productv1.RequireStorageMultiFilteredTagSummaryByIdResult{
+				MultiFilteredTagSummary: nil,
+			})
+			continue
+		}
+
 		tags := ctx.GetFields().GetTags()
 
 		filteredTags := make([]string, 0, len(tags))
 		for _, tag := range tags {
 			for _, p := range prefixes {
 				if strings.HasPrefix(tag, p) {
 					filteredTags = append(filteredTags, tag)
 					break
 				}
 			}
 			if len(filteredTags) >= maxResults {
 				break
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v2/pkg/grpctest/mockservice_requires.go` around lines 484 - 497, The loop
that builds filteredTags incorrectly allows a match when maxResults <= 0 because
the cap is checked only after appending; before iterating tags (inside the
context loop where req.GetContext() is handled), add an early guard that if
maxResults <= 0 then skip filtering (e.g., continue) or set filteredTags to
empty and skip further work for that context so no tags are appended; ensure the
check on maxResults happens before any append to filteredTags in the code that
uses tags, prefixes, and filteredTags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@v2/pkg/grpctest/mockservice_requires.go`:
- Around line 484-497: The loop that builds filteredTags incorrectly allows a
match when maxResults <= 0 because the cap is checked only after appending;
before iterating tags (inside the context loop where req.GetContext() is
handled), add an early guard that if maxResults <= 0 then skip filtering (e.g.,
continue) or set filteredTags to empty and skip further work for that context so
no tags are appended; ensure the check on maxResults happens before any append
to filteredTags in the code that uses tags, prefixes, and filteredTags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cb179f90-b3e1-4879-ac5f-5d2e3722a36b

📥 Commits

Reviewing files that changed from the base of the PR and between fc1c2d3 and 7e41f24.

📒 Files selected for processing (1)
  • v2/pkg/grpctest/mockservice_requires.go

Copy link
Copy Markdown
Contributor

@Noroth Noroth left a comment

Choose a reason for hiding this comment

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

LGTM

@dkorittki dkorittki merged commit 58469c3 into master Apr 7, 2026
11 checks passed
@dkorittki dkorittki deleted the dominik/eng-9218-implement-requires-with-field-resolvers-in-go-tools branch April 7, 2026 12:48
dkorittki pushed a commit that referenced this pull request Apr 7, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.0.0-rc.268](v2.0.0-rc.267...v2.0.0-rc.268)
(2026-04-07)


### Features

* add support for fields with arguments and requires directive
([#1452](#1452))
([58469c3](58469c3))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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