Skip to content

Conversation

@AgustinBettati
Copy link
Member

@AgustinBettati AgustinBettati commented Nov 7, 2025

Description

Link to any related issue(s): CLOUDP-352319

Before

  • Code generation didn’t handle OpenAPI object maps with dynamic json as values, resulting in a panic during code generation.
objectOfDynamicValues:
  description: Object of dynamic values.
  type: object
  additionalProperties:
    type: object
  • search_index_api couldn’t express definition.mappings.fields as a map of schemaless JSON values.

After

  • Codegen recognizes this pattern and generates a MapValue[jsontypes.Normalized] on the terraform side.
  • search_index_api now exposes definition.mappings.fields enabling jsonencode(...) per field.
  • Add unit testing to ensure Marshal/Unmarshal support dynamic JSON (jsontypes.Normalized) across map/list/set.

Type of change:

  • Bug fix (non-breaking change which fixes an issue). Please, add the "bug" label to the PR.
  • New feature (non-breaking change which adds functionality). Please, add the "enhancement" label to the PR. A migration guide must be created or updated if the new feature will go in a major version.
  • Breaking change (fix or feature that would cause existing functionality to not work as expected). Please, add the "breaking change" label to the PR. A migration guide must be created or updated.
  • This change requires a documentation update
  • Documentation fix/enhancement

Required Checklist:

  • I have signed the MongoDB CLA
  • I have read the contributing guides
  • I have checked that this change does not generate any credentials and that they are NOT accidentally logged anywhere.
  • I have added tests that prove my fix is effective or that my feature works per HashiCorp requirements
  • I have added any necessary documentation (if appropriate)
  • I have run make fmt and formatted my code
  • If changes include deprecations or removals I have added appropriate changelog entries.
  • If changes include removal or addition of 3rd party GitHub actions, I updated our internal document. Reach out to the APIx Integration slack channel to get access to the internal document.

Further comments

AttrDynamicJSONString jsontypes.Normalized `tfsdk:"attr_dynamic_json_string"`
AttrDynamicJSONNumber jsontypes.Normalized `tfsdk:"attr_dynamic_json_number"`
AttrDynamicJSONArray jsontypes.Normalized `tfsdk:"attr_dynamic_json_array"`
AttrDynamicJSONObject jsontypes.Normalized `tfsdk:"attr_dynamic_json_object"`
Copy link
Member Author

Choose a reason for hiding this comment

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

no changes to marshal/unmarshal logic needed, adding testing to ensure coverage

Comment on lines +225 to +233
nestedObject := NestedAttributeObject{Attributes: objectAttributes}
if len(nestedObject.Attributes) == 0 {
// objects without attributes use JSON custom type as element
result := s.buildRegularCollectionAttribute(name, tfModelName, computability, isSet, CustomTypeJSON)
return result, nil
}

result := s.buildNestedCollectionAttribute(name, tfModelName, fullName, computability, isSet, nestedObject)
return result, nil
Copy link
Member Author

Choose a reason for hiding this comment

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

change to list creation was purely refactoring, want to make clear when nested vs regular collection types are created, and when CustomTypeJSON is used (only within regular collection type).

@AgustinBettati AgustinBettati marked this pull request as ready for review November 7, 2025 16:18
@AgustinBettati AgustinBettati requested a review from a team as a code owner November 7, 2025 16:18
Copilot AI review requested due to automatic review settings November 7, 2025 16:18
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances the code generation tool to support OpenAPI object maps with dynamic JSON values, addressing a previous limitation that caused panics during code generation. The key change enables search_index_api to express definition.mappings.fields as a map of schemaless JSON values using MapValue[jsontypes.Normalized].

Key Changes:

  • Code generation now recognizes OpenAPI objects without defined properties and generates appropriate MapValue[jsontypes.Normalized] types
  • Error handling improved by replacing panics with proper error returns in code generation functions
  • Added comprehensive test coverage for marshaling/unmarshaling dynamic JSON across map/list/set types

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tools/codegen/models/search_index_api.yaml Adds fields map attribute to definition.mappings for search index API
tools/codegen/main.go Updates to handle errors from code generation functions instead of ignoring them
tools/codegen/gofilegen/schema/schema_file.go Changes GenerateGoCode to return errors instead of panicking
tools/codegen/gofilegen/resource/resource_file.go Changes GenerateGoCode to return errors instead of panicking
tools/codegen/gofilegen/schema/schema_file_test.go Updates tests to handle error returns from GenerateGoCode
tools/codegen/gofilegen/resource/resource_file_test.go Updates tests to handle error returns from GenerateGoCode
tools/codegen/config.yml Removes TODO comment and ignores for fields that are now supported
tools/codegen/codespec/testdata/config.yml Adds test resource configuration for dynamic JSON properties
tools/codegen/codespec/testdata/api-spec.yml Adds OpenAPI spec for testing dynamic JSON properties
tools/codegen/codespec/attribute.go Refactors array/map attribute building to handle empty objects as dynamic JSON
tools/codegen/codespec/api_to_provider_spec_mapper_test.go Adds test case for dynamic JSON properties conversion
internal/serviceapi/searchindexapi/resource_test.go Adds acceptance test for mappings.fields functionality
internal/serviceapi/searchindexapi/resource_schema.go Adds generated fields map attribute to mappings schema
internal/common/autogen/unmarshal_test.go Expands tests to cover dynamic JSON in map/list/set types
internal/common/autogen/marshal_test.go Expands tests to cover dynamic JSON in map/list/set types

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}},
},
}
runTestCase(t, tc)
Copy link
Member

Choose a reason for hiding this comment

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

nit: i know it's not only from this PR but don't see the need to extract runTestCase logic instead of having it in each test.

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah agree runTestCase is very lightweight, don't see harm in having it unified

Comment on lines +194 to +200
if isSet {
attr.CustomType = NewCustomNestedSetType(nestedObjectName)
attr.SetNested = &SetNestedAttribute{NestedObject: nestedObject}
} else {
attr.CustomType = NewCustomNestedListType(nestedObjectName)
attr.ListNested = &ListNestedAttribute{NestedObject: nestedObject}
}
Copy link
Member

@lantoli lantoli Nov 11, 2025

Choose a reason for hiding this comment

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

Suggested change
if isSet {
attr.CustomType = NewCustomNestedSetType(nestedObjectName)
attr.SetNested = &SetNestedAttribute{NestedObject: nestedObject}
} else {
attr.CustomType = NewCustomNestedListType(nestedObjectName)
attr.ListNested = &ListNestedAttribute{NestedObject: nestedObject}
}
attr.CustomType = NewCustomNestedListType(nestedObjectName)
attr.ListNested = &ListNestedAttribute{NestedObject: nestedObject}
if isSet {
attr.CustomType = NewCustomNestedSetType(nestedObjectName)
attr.SetNested = &SetNestedAttribute{NestedObject: nestedObject}
}

nit: don't know if it have side effect to update the values and then set again if set

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would go for the current implementation which does not allocate more than necessary (even if the compiler does optimize this, which I don't think it does).

)

func GenerateGoCode(input *codespec.Resource) []byte {
func GenerateGoCode(input *codespec.Resource) ([]byte, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice

@AgustinBettati AgustinBettati merged commit 603f19d into master Nov 11, 2025
63 checks passed
@AgustinBettati AgustinBettati deleted the CLOUDP-352319-rebased branch November 11, 2025 11:23
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.

5 participants