Skip to content

fix: improve field resolver handling for nested resolver calls#2464

Merged
Noroth merged 12 commits intomainfrom
ludwig/eng-8789-recursive-call-with-field-resolvers-causes-issues
Jan 26, 2026
Merged

fix: improve field resolver handling for nested resolver calls#2464
Noroth merged 12 commits intomainfrom
ludwig/eng-8789-recursive-call-with-field-resolvers-causes-issues

Conversation

@Noroth
Copy link
Copy Markdown
Contributor

@Noroth Noroth commented Jan 20, 2026

Nested field resolvers are not behaving properly. This PR updates the dependencies for the related engine improvements for field resolvers and adds some more test cases

Summary by CodeRabbit

  • New Features

    • Recursive project hierarchy querying via a new subProjects field and multiple project analytics/resolvers (completion rate, estimated days remaining, top-priority item, milestone risk/status, days-until-due, task blocked/effort, employee workload/averages, filtered tasks).
  • Tests

    • Added coverage for recursive subProjects resolution, including multi-level nesting and alias scenarios.
  • Refactor

    • Projects service implementations reorganized to consolidate resolver logic.
  • Chores

    • Updated dependency versions.

✏️ Tip: You can customize this high-level summary in your review settings.

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 Jan 20, 2026

Walkthrough

Moves many resolver implementations from service.go into a new resolver file, adds a recursive subProjects field to the Project schema, introduces relationship-population helpers, updates a Makefile build flag, bumps graphql-go-tools versions, and adds tests for recursive field resolution.

Changes

Cohort / File(s) Summary
Build config
demo/Makefile
Adds --go-module-path github.com/wundergraph/cosmo/demo/pkg/subgraphs/projects to the plugin-build-ci-go-binary invocation.
Schema
demo/pkg/subgraphs/projects/src/schema.graphql
Adds subProjects(includeArchived: Boolean): [Project!]! @connect__fieldResolver(context: "id name status") to Project.
Service — removed implementations
demo/pkg/subgraphs/projects/src/service/service.go
Removes many resolver methods and helper population functions (numerous Resolve* handlers and related helpers deleted).
Service — added resolver implementations
demo/pkg/subgraphs/projects/src/service/service_resolve.go
Adds comprehensive resolver implementations (ResolveProjectCriticalDeadline, ResolveProjectTopPriorityItem, ResolveEmployeeAverageTaskCompletionDays, ResolveEmployeeCurrentWorkload, ResolveMilestoneDaysUntilDue, ResolveMilestoneIsAtRisk, ResolveProjectCompletionRate, ResolveProjectEstimatedDaysRemaining, ResolveProjectFilteredTasks, ResolveTaskIsBlocked, ResolveTaskTotalEffort, ResolveProjectSubProjects).
Service — relationship helpers
demo/pkg/subgraphs/projects/src/service/util.go
Adds helpers: populateProjectRelationships, populateMilestonesList, populateTasksList, populateProjectUpdateRelationships, getRelatedProductsByProjectId.
Dependency bumps
router/go.mod, router-tests/go.mod
Bumps github.com/wundergraph/graphql-go-tools/v2 from rc.243 → rc.245 and minor go.mod comment formatting.
Tests
router-tests/grpc_subgraph_test.go, router-tests/router_plugin_test.go
Adds tests covering recursive subProjects resolution, multi-level recursion, and aliasing scenarios.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 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 objective: improving field resolver handling for nested resolver calls. The changes include new resolver implementations, test cases for recursive subProjects resolution, and dependency updates to support better field resolver handling.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 20, 2026

❌ Internal Query Planner CI checks failed

The Internal Query Planner CI checks failed in the celestial repository, and this is going to stop the merge of this PR.
If you are part of the WunderGraph organization, you can see the PR with more details.

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.41%. Comparing base (916d3ac) to head (5582f9f).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2464      +/-   ##
==========================================
- Coverage   61.43%   61.41%   -0.03%     
==========================================
  Files         229      229              
  Lines       23855    23855              
==========================================
- Hits        14656    14650       -6     
- Misses       7967     7971       +4     
- Partials     1232     1234       +2     

see 3 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 January 26, 2026 08:34
@Noroth Noroth requested a review from JivusAyrus January 26, 2026 08:34
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: 3

🤖 Fix all issues with AI agents
In `@demo/pkg/subgraphs/projects/src/service/service_resolve.go`:
- Around line 47-75: The code currently uses
math.Abs(endDate.Sub(now).Hours()/24) which treats past deadlines as upcoming;
change both milestone and project checks to compute the raw duration
(endDate.Sub(now)) and only consider non-negative durations (i.e., duration >=
0) before converting to days and comparing to withinDays/nearestDays; update the
milestone loop (where nearestMilestone, nearestDays are set) and the project
fallback (where project.EndDate is parsed and daysUntil computed via duration)
so overdue dates are excluded while keeping the existing comparisons and the use
of data.PopulateMilestoneRelationships and data.GetProjectByID intact.

In `@router-tests/grpc_subgraph_test.go`:
- Around line 256-260: This test case duplicates the one in
router_plugin_test.go and its query doesn't match the test name (no multiple
recursion levels); either remove this duplicate test entry named "query project
with normal and recursive field resolver and aliases and multiple levels of
recursion and aliases" or update its query to actually exercise multiple levels
of recursion and aliases (e.g., expand the project selection to include nested
subProjects within subProjects and use distinct aliases like
urgent/nextDeadline/subsub/subsubsub) and then update the expected JSON to match
the deeper nested response; ensure you modify the test entry's query string and
expected string together (the test name, query field 'subProjects', and the
expected JSON are the unique symbols to change) and avoid keeping an identical
test already present in router_plugin_test.go.

In `@router-tests/router_plugin_test.go`:
- Around line 453-457: The test case in router_tests (the struct with name
"query project with normal and recursive field resolver and aliases and multiple
levels of recursion and aliases") is a duplicate of the previous case; either
remove this duplicated test entry or change its query to actually exercise
multi-level recursion and aliases (e.g., in the query string for that test add a
nested alias like `subsub: subProjects { id name status nested: subProjects { id
} }`) and update the corresponding expected JSON to include the
nested.subProjects results (IDs) so the expected output matches the new nested
alias shape; locate this test by the name field in the test table in
router_plugin_test.go and edit the query and expected fields (or delete the
entire test struct) accordingly.
🧹 Nitpick comments (2)
demo/pkg/subgraphs/projects/src/service/util.go (1)

39-54: Consider pre-allocating slice capacity for minor efficiency gain.

The loops use append without pre-allocation. For demo/test code this is acceptable, but pre-allocating would avoid repeated reallocations.

♻️ Optional: Pre-allocate slice capacity
 func (p *ProjectsService) populateMilestonesList(milestones []*service.Milestone) []*service.Milestone {
-	var populatedMilestones []*service.Milestone
+	populatedMilestones := make([]*service.Milestone, 0, len(milestones))
 	for _, milestone := range milestones {
 		populatedMilestones = append(populatedMilestones, data.PopulateMilestoneRelationships(milestone))
 	}
 	return populatedMilestones
 }

 func (p *ProjectsService) populateTasksList(tasks []*service.Task) []*service.Task {
-	var populatedTasks []*service.Task
+	populatedTasks := make([]*service.Task, 0, len(tasks))
 	for _, task := range tasks {
 		populatedTasks = append(populatedTasks, data.PopulateTaskRelationships(task))
 	}
 	return populatedTasks
 }
demo/pkg/subgraphs/projects/src/schema.graphql (1)

108-109: Trim resolver context to only required fields.

ResolveProjectSubProjects uses only the project ID; including name and status increases payload without benefit. If you don’t plan to use them, trim the context.

♻️ Proposed update
-  subProjects(includeArchived: Boolean): [Project!]! `@connect__fieldResolver`(context: "id name status")
+  subProjects(includeArchived: Boolean): [Project!]! `@connect__fieldResolver`(context: "id")

@Noroth Noroth merged commit 7fed361 into main Jan 26, 2026
55 of 58 checks passed
@Noroth Noroth deleted the ludwig/eng-8789-recursive-call-with-field-resolvers-causes-issues branch January 26, 2026 15:36
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.

3 participants