Skip to content

feat(router): add router support for field resolvers without arguments#2645

Merged
Noroth merged 5 commits intomainfrom
ludwig/eng-9163-integration-into-cosmo-router
Mar 13, 2026
Merged

feat(router): add router support for field resolvers without arguments#2645
Noroth merged 5 commits intomainfrom
ludwig/eng-9163-integration-into-cosmo-router

Conversation

@Noroth
Copy link
Copy Markdown
Contributor

@Noroth Noroth commented Mar 13, 2026

closes #2527

This PR adds support for field resolvers without arguments in the cosmo router. Previously we only allowed field resolvers to be defined on fields that have arguments. To achieve the same result we could provide a hacky solution to add a dummy argument to a field

# Hack
type User {
  id: ID!
  myExpensiveField(dummy: String): [String!]! @connect__fieldResolver(context:  "id")
}

We can now omit expensive fields from the type lookup explicitly without providing a dummy argument.

Summary by CodeRabbit

New Features

  • Added computed fields to the GraphQL API for aggregated data retrieval:
    • Project: taskCount and activeMilestoneCount
    • Employee: totalProjectCount
    • Product: featureMatrix
  • These new fields enable efficient querying of aggregated metrics without additional API calls

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.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 13, 2026

Walkthrough

This PR adds support for field resolvers without arguments to the projects subgraph. It introduces four computed fields (taskCount, activeMilestoneCount, totalProjectCount, featureMatrix) in the GraphQL schema with @connect__fieldResolver annotations, implements three corresponding RPC handler methods in the service with aggregation logic, updates a dependency version, and adds comprehensive test coverage for the new no-arg field resolvers.

Changes

Cohort / File(s) Summary
Schema and Service Implementation
demo/pkg/subgraphs/projects/src/schema.graphql, demo/pkg/subgraphs/projects/src/service/service_resolve.go
Added four computed fields (taskCount, activeMilestoneCount, totalProjectCount, featureMatrix) to schema with @connect__fieldResolver annotations. Implemented three corresponding RPC handlers using read locks, context iteration, and aggregation logic.
Dependency Updates
router/go.mod, router-tests/go.mod
Bumped github.com/wundergraph/graphql-go-tools/v2 from v2.0.0-rc.262 to v2.0.0-rc.263.
Test Coverage
router-tests/protocol/grpc_subgraph_test.go, router-tests/protocol/router_plugin_test.go
Added test cases validating no-argument field resolvers and mixed no-arg/with-arg resolver scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main feature being added: router support for field resolvers without arguments, which directly matches the primary objective.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #2527: new RPC Resolve methods are generated for fields without arguments (taskCount, activeMilestoneCount, totalProjectCount), comprehensive test coverage validates the functionality, and the dummy argument workaround is no longer necessary.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing field resolvers without arguments. The schema changes add the new computed fields, service resolvers implement the RPC handlers, dependency updates support the feature, and tests validate the new functionality.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
📝 Coding Plan
  • Generate coding plan for human review comments

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 13, 2026

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-2072485739d427e91ad2d31f1c1cf83ac6fd8445

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

🧹 Nitpick comments (1)
demo/pkg/subgraphs/projects/src/service/service_resolve.go (1)

637-646: Consider performance for large datasets.

The nested iteration (all projects × team members per project × employee contexts) has O(n×m×c) complexity. For each employee context, you iterate through all projects and their team members to count memberships.

For this demo service, the current approach is acceptable. However, if this pattern were to be used in production with large datasets, consider building an inverted index (employee → projects) to achieve O(1) lookups per employee.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demo/pkg/subgraphs/projects/src/service/service_resolve.go` around lines 637
- 646, The current triple-nested loops over req.Context, data.ServiceProjects
and members (using data.GetTeamMembersByProjectId and ctx.GetId()) are O(n×m×c);
instead, build a single inverted map (e.g., empToCount) by iterating once over
data.ServiceProjects and their members to increment counts per member ID, then
replace the inner scans with O(1) lookups from empToCount for each ctx to set
count—update the block around the loop that references req.Context,
data.ServiceProjects, data.GetTeamMembersByProjectId and ctx.GetId() to use this
map-based approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@router/go.mod`:
- Line 34: The go.mod currently pins a pseudo-version for
github.com/wundergraph/graphql-go-tools/v2 (v2.0.0-rc.262...2cd631249f01);
replace that pseudo-version with the appropriate stable tagged release of
github.com/wundergraph/graphql-go-tools/v2 before merging. Update the dependency
by running a go get for the chosen tag (e.g. go get
github.com/wundergraph/graphql-go-tools/v2@<stable-tag>), then run go mod tidy
to update go.mod and go.sum, and run the relevant tests/build to verify nothing
breaks; ensure the final commit contains the stable semver (not the rc
pseudo-version).

---

Nitpick comments:
In `@demo/pkg/subgraphs/projects/src/service/service_resolve.go`:
- Around line 637-646: The current triple-nested loops over req.Context,
data.ServiceProjects and members (using data.GetTeamMembersByProjectId and
ctx.GetId()) are O(n×m×c); instead, build a single inverted map (e.g.,
empToCount) by iterating once over data.ServiceProjects and their members to
increment counts per member ID, then replace the inner scans with O(1) lookups
from empToCount for each ctx to set count—update the block around the loop that
references req.Context, data.ServiceProjects, data.GetTeamMembersByProjectId and
ctx.GetId() to use this map-based approach.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0fdf1185-5921-4b92-a9be-5c69212d7665

📥 Commits

Reviewing files that changed from the base of the PR and between 56859f0 and 47d8e98.

⛔ Files ignored due to path filters (6)
  • demo/pkg/subgraphs/projects/generated/mapping.json is excluded by !**/generated/**
  • demo/pkg/subgraphs/projects/generated/service.pb.go is excluded by !**/*.pb.go, !**/generated/**
  • demo/pkg/subgraphs/projects/generated/service.proto is excluded by !**/generated/**
  • demo/pkg/subgraphs/projects/generated/service_grpc.pb.go is excluded by !**/*.pb.go, !**/generated/**
  • router-tests/go.sum is excluded by !**/*.sum
  • router/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • demo/pkg/subgraphs/projects/src/schema.graphql
  • demo/pkg/subgraphs/projects/src/service/service_resolve.go
  • router-tests/go.mod
  • router-tests/grpc_subgraph_test.go
  • router-tests/router_plugin_test.go
  • router-tests/testenv/testdata/configWithGRPC.json
  • router-tests/testenv/testdata/configWithPlugins.json
  • router/go.mod

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.85%. Comparing base (4aacdee) to head (94a7014).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2645      +/-   ##
==========================================
+ Coverage   62.65%   62.85%   +0.20%     
==========================================
  Files         244      244              
  Lines       25831    25831              
==========================================
+ Hits        16184    16237      +53     
+ Misses       8298     8259      -39     
+ Partials     1349     1335      -14     

see 13 files with indirect coverage changes

🚀 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.

@Noroth Noroth marked this pull request as ready for review March 13, 2026 11:46
@Noroth Noroth requested a review from thisisnithin March 13, 2026 11:46
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)
router-tests/protocol/router_plugin_test.go (1)

478-497: Consider centralizing duplicated no-arg resolver cases shared with gRPC protocol tests.

This block is nearly identical to the new cases in router-tests/protocol/grpc_subgraph_test.go; pulling shared cases/expected payloads into a helper would reduce drift and future update cost.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@router-tests/protocol/router_plugin_test.go` around lines 478 - 497, The test
cases for no-arg field resolvers (e.g., cases named "query project taskCount
no-arg field resolver", "query projects with no-arg field resolvers", "query
employees with totalProjectCount no-arg field resolver", and "query project
mixing no-arg and with-arg field resolvers") are duplicated between
router_plugin_test.go and grpc_subgraph_test.go; extract these shared entries
and their expected JSON payloads into a single helper (e.g., a function like
sharedNoArgResolverCases() or a package-level variable sharedNoArgCases) and
have both test files consume that helper instead of duplicating the literal
cases, updating the test harness that iterates over the cases to use the shared
slice. Ensure the helper returns the same test struct type used by the existing
tests so no signature changes are needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@router-tests/protocol/router_plugin_test.go`:
- Around line 478-497: The test cases for no-arg field resolvers (e.g., cases
named "query project taskCount no-arg field resolver", "query projects with
no-arg field resolvers", "query employees with totalProjectCount no-arg field
resolver", and "query project mixing no-arg and with-arg field resolvers") are
duplicated between router_plugin_test.go and grpc_subgraph_test.go; extract
these shared entries and their expected JSON payloads into a single helper
(e.g., a function like sharedNoArgResolverCases() or a package-level variable
sharedNoArgCases) and have both test files consume that helper instead of
duplicating the literal cases, updating the test harness that iterates over the
cases to use the shared slice. Ensure the helper returns the same test struct
type used by the existing tests so no signature changes are needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 33124b13-c9af-421a-a5d3-eae64eb552ff

📥 Commits

Reviewing files that changed from the base of the PR and between 8a13577 and 94a7014.

📒 Files selected for processing (2)
  • router-tests/protocol/grpc_subgraph_test.go
  • router-tests/protocol/router_plugin_test.go

@Noroth Noroth merged commit 0406c7a into main Mar 13, 2026
37 checks passed
@Noroth Noroth deleted the ludwig/eng-9163-integration-into-cosmo-router branch March 13, 2026 13:26
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.

(protographic) rpc Resolve method generation does not work if there are no arguments

2 participants