Skip to content

Conversation

@Noroth
Copy link
Contributor

@Noroth Noroth commented Jul 7, 2025

Summary by CodeRabbit

  • New Features

    • Added comprehensive support for nullable fields in GraphQL queries and mutations, including new types, inputs, queries, and mutations for handling optional and required scalar fields.
    • Enhanced gRPC and protobuf integration to support explicit nullability in scalar fields, enabling accurate representation of optional values.
    • Expanded mock services and test coverage to validate correct handling of nullable fields in various scenarios.
  • Bug Fixes

    • Improved response handling to correctly process and return null values for optional fields.
  • Tests

    • Introduced extensive test cases for queries, mutations, filters, and execution plans involving nullable fields, ensuring robust validation of new functionality.
  • Documentation

    • Updated schema and mapping definitions to reflect new nullable field capabilities and expanded API surface.

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.

@Noroth Noroth requested review from a team, StarpTech and devsergiy as code owners July 7, 2025 12:31
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 7, 2025

Walkthrough

This change introduces comprehensive support for nullable scalar fields in GraphQL-to-gRPC execution. It expands the protobuf schema, GraphQL schema, mapping configurations, and mock service to handle nullable fields using protobuf wrapper types. Compiler, execution plan, and marshalling logic are updated to recognize and process optional fields. Extensive new tests validate correct handling of nullable fields in queries and mutations.

Changes

File(s) Change Summary
v2/pkg/grpctest/product.proto Added new RPCs and message types for handling nullable fields, using protobuf wrapper types for optional scalars.
v2/pkg/grpctest/testdata/products.graphqls Extended GraphQL schema with NullableFieldsType, corresponding inputs, filters, queries, and mutations for nullable fields.
v2/pkg/grpctest/mapping/mapping.go
v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go
Added new RPC and field mappings for nullable fields queries and mutations, including entity field mappings for NullableFieldsType, NullableFieldsInput, and NullableFieldsFilter.
v2/pkg/grpctest/mockservice.go Implemented mock service methods for create, update, query (by ID, filter, all) operations on NullableFieldsType, handling nullable fields with wrapper types.
v2/pkg/grpctest/schema.go Added field configurations and data source metadata for new nullable fields queries/mutations and related types.
v2/pkg/engine/datasource/grpc_datasource/compiler.go Enhanced compiler to track and process imported protobuf files, support optional wrapper fields, and handle optional nested messages for nullable fields.
v2/pkg/engine/datasource/grpc_datasource/execution_plan.go Extended RPCMessage and RPCField structs with Optional and Message fields; added logic to wrap optional scalars as messages for nullability semantics.
v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor.go Added method to detect nullable scalar fields and mark corresponding RPCField as optional in request/response message construction.
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource.go Updated response marshalling to handle optional message fields by extracting inner "value" and setting it in JSON output.
v2/pkg/engine/datasource/grpc_datasource/execution_plan_test.go Added tests for execution plan generation covering queries/mutations with nullable fields, including optional input/output scenarios.
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go Added integration tests for gRPC datasource execution with nullable fields, verifying correct handling of nulls and types in responses.
execution/engine/execution_engine_grpc_test.go Extended gRPC execution engine tests with subtests for queries and mutations involving nullable fields, checking correct null handling and response content.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37321d7 and e50b1e4.

📒 Files selected for processing (1)
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (1)
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.23 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
  • GitHub Check: Linters
  • GitHub Check: Build and test (go 1.23 / windows-latest)
🔇 Additional comments (1)
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (1)

1541-1877: Excellent comprehensive test coverage for nullable fields feature!

This test function provides thorough coverage of the nullable fields functionality with well-structured test cases covering:

  • Query scenarios: All fields, partial fields, by ID with various data states
  • Mutation scenarios: Create and update operations with full/minimal inputs
  • Edge cases: Not-found scenarios, null value handling
  • Field selection: Proper testing of partial field selections

The implementation follows established patterns in the codebase and includes:

  • Proper type assertions with meaningful error messages
  • Correct JSON number handling (expecting float64)
  • Comprehensive null value validation
  • Consistent error handling approach

The test validates both the presence/absence of fields and their correct types, ensuring robust coverage of the nullable fields feature.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Noroth Noroth changed the title Ludwig/eng 7465 add support for nullable base types feat: support nullable base types Jul 7, 2025
Copy link
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: 0

🧹 Nitpick comments (7)
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource.go (1)

253-261: Document the protobuf wrapper type convention

The method correctly handles protobuf wrapper types by extracting the "value" field. Consider adding a comment documenting this convention for clarity.

+// resolveOptionalField extracts the inner value from protobuf wrapper types
+// (e.g., google.protobuf.StringValue, Int32Value) which contain a single "value" field
 func (d *DataSource) resolveOptionalField(arena *astjson.Arena, root *astjson.Value, name string, data protoref.Message) error {
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (2)

1670-1670: Consider using approximate equality for float comparisons

Using math.Round for float comparisons works but could be more idiomatic. Consider using a tolerance-based comparison or the testify InDelta assertion.

-require.Equal(t, float64(3.14), math.Round(firstEntry["optionalFloat"].(float64)*100)/100) // round to 2 decimal places
+require.InDelta(t, 3.14, firstEntry["optionalFloat"].(float64), 0.001, "optionalFloat should be approximately 3.14")

Also applies to: 1730-1730


1542-1878: Comprehensive test coverage for nullable fields

The test thoroughly covers all nullable field scenarios with well-structured table-driven tests. Consider extracting the common setup code (schema parsing, datasource creation) into a helper function to reduce duplication across test cases.

v2/pkg/engine/datasource/grpc_datasource/compiler.go (2)

93-93: Enhance comment clarity for the Imports field.

Consider making the comment more descriptive to clarify these are protobuf file import paths.

-	Imports  []string  // The imports of the protobuf document
+	Imports  []string  // Import paths of other protobuf files referenced by this document

492-492: Remove or update misleading TODO comment.

The TODO comment about handling optional fields appears outdated since optional scalar fields are already handled in the nested message section above (lines 448-464).

-		// TODO handle optional fields
v2/pkg/engine/datasource/grpc_datasource/execution_plan.go (1)

176-196: Consider adding validation for scalar field types.

The ToOptionalTypeMessage method correctly wraps fields in a message, but it could benefit from validation to ensure it's only called on scalar fields.

Consider adding a check to ensure this method is only used with scalar types:

// ToOptionalTypeMessage returns a message that wraps the scalar value in a message
// as protobuf scalar types are not nullable.
func (r *RPCField) ToOptionalTypeMessage(protoName string) *RPCMessage {
	if r == nil {
		return nil
	}

	// Ensure this is only used for scalar types
	if r.Message != nil {
		// Field already has a message type, shouldn't wrap again
		return r.Message
	}

	return &RPCMessage{
		Name: protoName,
		Fields: RPCFields{
			RPCField{
				Name:     knownTypeOptionalFieldValueName,
				JSONPath: r.JSONPath,
				TypeName: r.TypeName,
				Repeated: r.Repeated,
				EnumName: r.EnumName,
			},
		},
	}
}
v2/pkg/grpctest/mockservice.go (1)

21-50: Consider more robust ID generation for production use.

The implementation correctly handles nullable fields. However, the ID generation using rand.Intn(1000) could lead to collisions. While acceptable for a mock service, consider using UUID or a monotonic counter for production implementations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9223351 and 37321d7.

⛔ 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 (13)
  • execution/engine/execution_engine_grpc_test.go (1 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/compiler.go (4 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan.go (3 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_test.go (4 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor.go (4 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource.go (2 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (2 hunks)
  • v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go (5 hunks)
  • v2/pkg/grpctest/mapping/mapping.go (7 hunks)
  • v2/pkg/grpctest/mockservice.go (2 hunks)
  • v2/pkg/grpctest/product.proto (4 hunks)
  • v2/pkg/grpctest/schema.go (3 hunks)
  • v2/pkg/grpctest/testdata/products.graphqls (3 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_test.go (1)
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
execution/engine/execution_engine_grpc_test.go (1)
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
v2/pkg/grpctest/mockservice.go (1)
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
v2/pkg/engine/datasource/grpc_datasource/execution_plan_test.go (1)
Learnt from: SkArchon
PR: wundergraph/graphql-go-tools#1203
File: v2/pkg/engine/resolve/loader.go:63-67
Timestamp: 2025-07-02T15:28:02.073Z
Learning: In the graphql-go-tools codebase, result structs are consistently initialized with non-nil bytes.Buffer instances, making additional nil checks for res.out unnecessary defensive programming.
🧬 Code Graph Analysis (2)
execution/engine/execution_engine_grpc_test.go (1)
v2/pkg/grpctest/mapping/mapping.go (1)
  • DefaultGRPCMapping (10-619)
v2/pkg/engine/datasource/grpc_datasource/execution_plan.go (1)
v2/pkg/engine/datasource/grpc_datasource/compiler.go (1)
  • Message (117-121)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Linters
  • GitHub Check: Build and test (go 1.23 / windows-latest)
  • GitHub Check: Build and test (go 1.23 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
🔇 Additional comments (26)
v2/pkg/engine/datasource/grpc_datasource/execution_plan_visitor.go (1)

821-823: LGTM!

The helper method cleanly encapsulates the nullable scalar check logic and is consistently used across the visitor methods.

v2/pkg/grpctest/mapping/mapping.go (1)

74-616: Mapping additions are well-structured and consistent

The new RPC and field mappings for nullable fields follow the established patterns and naming conventions. All required mapping fields are properly configured.

execution/engine/execution_engine_grpc_test.go (1)

502-811: Comprehensive test coverage for nullable fields functionality.

The test suite thoroughly covers various scenarios for nullable fields including queries with default values, by ID with varying data completeness, filters, and mutations. The test structure is consistent and assertions are appropriate.

v2/pkg/engine/datasource/grpc_datasource/compiler.go (2)

275-316: Well-structured refactoring for multi-file protobuf support.

The refactoring properly handles imported protobuf files by processing them before the main schema file, ensuring correct dependency resolution. The new processFile method effectively encapsulates the parsing logic.


446-467: Correct implementation of optional field handling.

The logic properly handles optional scalar fields by wrapping them in protobuf wrapper types, correctly skipping fields without values to represent null.

v2/pkg/engine/datasource/grpc_datasource/execution_plan.go (1)

14-17: Well-documented additions for nullable field support.

The constant and struct field additions are properly documented and provide the necessary infrastructure for handling optional scalar fields wrapped in protobuf messages.

Also applies to: 86-88, 169-173

v2/pkg/grpctest/testdata/products.graphqls (1)

167-194: Well-designed GraphQL schema additions for nullable fields.

The schema additions follow GraphQL best practices with clear type definitions, appropriate use of nullable vs non-nullable fields, and comprehensive query/mutation operations for testing nullable field scenarios.

Also applies to: 223-227, 240-242

v2/pkg/engine/datasource/grpc_datasource/execution_plan_test.go (4)

17-22: Good test structure improvement!

The introduction of the testCase struct standardizes test case definitions and improves test maintainability.


23-53: Excellent refactoring to reduce test duplication!

The runTest helper function effectively consolidates common test logic, making tests more maintainable and consistent.


1745-1746: Correct implementation of optional field marking.

The addition of Optional: true to the limit field in SearchInput properly indicates nullable field support in the execution plan.

Also applies to: 1937-1938


3161-3797: Comprehensive test coverage for nullable fields!

The TestNullableFieldsExecutionPlan function provides excellent coverage of nullable field scenarios including queries, mutations, filters, and various field selection patterns. The tests properly validate that optional fields are marked with Optional: true in the execution plan.

v2/pkg/grpctest/schema.go (3)

199-262: Well-structured field configuration additions.

The new field configurations for nullable fields queries and mutations follow the established pattern and properly define argument sources.


297-308: Consistent metadata updates for new schema fields.

The root node metadata properly includes all new nullable fields queries and mutations.

Also applies to: 314-316


448-583: Comprehensive type definitions for nullable fields support.

The child node metadata additions include all necessary types and their fields for the nullable fields functionality, maintaining consistency with the existing schema structure.

v2/pkg/engine/datasource/grpc_datasource/mapping_test_helper.go (3)

87-106: Proper RPC configuration for nullable fields operations.

The new RPC configurations correctly map GraphQL operations to their corresponding gRPC methods with appropriate request/response types.

Also applies to: 119-128


232-249: Consistent field mappings for nullable operations.

The Query and Mutation field mappings properly define target names and argument mappings following the snake_case convention.

Also applies to: 264-276


537-596: Complete field mappings for nullable types.

The field mappings for NullableFieldsType, NullableFieldsInput, and NullableFieldsFilter correctly map all fields with proper snake_case naming for protobuf compatibility.

v2/pkg/grpctest/mockservice.go (6)

12-12: LGTM! Correct import for protobuf wrapper types.

The addition of the wrapperspb import is necessary for handling nullable scalar fields using protobuf wrapper types.


52-89: Well-implemented update method with proper error case handling.

The method correctly handles nullable fields and includes test case support for non-existent IDs, which is valuable for testing error scenarios.


91-136: Excellent test data coverage for nullable fields!

The method provides comprehensive test scenarios:

  • Full data with all optional fields populated
  • Partial data with mixed null/non-null optional fields
  • Minimal data with all optional fields null

The clear comments make the test cases easy to understand.


138-155: Good default test case implementation.

The method provides a useful default test case with mixed null/non-null optional fields, which is helpful for testing nullable field handling.


157-222: Comprehensive test scenarios with clever dynamic data generation!

The implementation provides excellent test coverage:

  • Special cases for null responses ("not-found", "null-test")
  • Named test cases for different nullable field combinations
  • Dynamic data generation based on ID characteristics in the default case

The use of ID length for generating consistent test data is particularly clever.


224-300: Well-designed filtering implementation with nullable field support.

The method handles filtering comprehensively:

  • Graceful handling of nil filters
  • Proper extraction of filter values with nil checks
  • Sophisticated logic for varying nullable fields based on includeNulls flag
  • Good test data diversity using index-based variations
v2/pkg/grpctest/product.proto (3)

4-4: Proper protobuf wrapper import and well-structured RPC definitions.

The import of google/protobuf/wrappers.proto is correctly placed, and the new RPCs follow the established naming conventions with clear documentation.

Also applies to: 32-38


248-294: Well-structured request/response messages following protobuf conventions.

All message definitions are properly structured with:

  • Consistent naming patterns
  • Appropriate field types and numbering
  • Clear comments for each operation

473-499: Correct implementation of nullable fields using protobuf wrapper types.

The message definitions properly distinguish between:

  • Optional fields using wrapper types (google.protobuf.StringValue, etc.)
  • Required fields using regular scalar types

This follows protobuf best practices for representing nullable scalar fields in proto3.

alepane21
alepane21 previously approved these changes Jul 9, 2025
@alepane21 alepane21 dismissed their stale review July 9, 2025 07:40

just a test

@Noroth Noroth merged commit b45b92c into master Jul 10, 2025
10 checks passed
@Noroth Noroth deleted the ludwig/eng-7465-add-support-for-nullable-base-types branch July 10, 2025 14:13
Noroth pushed a commit that referenced this pull request Jul 11, 2025
🤖 I have created a release *beep* *boop*
---


##
[2.0.0-rc.204](v2.0.0-rc.203...v2.0.0-rc.204)
(2025-07-10)


### Features

* support nullable base types
([#1212](#1212))
([b45b92c](b45b92c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Added support for nullable base types.

* **Documentation**
* Updated the changelog with details for version 2.0.0-rc.204, including
the new feature.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

4 participants