Skip to content

Commit 0185df6

Browse files
Extract duplicated list type handling logic into reusable helper (#1559)
* Initial plan * Refactor: extract duplicated list type handling into reusable helper function - Created EnsureTypedList helper in typeutils package - Replaced three instances of duplicated logic for handling untyped zero-value lists - Removed unused strings import from resource.go - All three instances (CategorizationFilters, Influencers, CustomRules) now use the centralized helper Co-authored-by: neiljbrookes <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: neiljbrookes <[email protected]>
1 parent 76d4e4b commit 0185df6

File tree

2 files changed

+26
-18
lines changed

2 files changed

+26
-18
lines changed

internal/elasticsearch/ml/anomaly_detection_job/models_tf.go

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -362,23 +362,15 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont
362362
var categorizationFiltersDiags diag.Diagnostics
363363
analysisConfigTF.CategorizationFilters, categorizationFiltersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.CategorizationFilters, types.StringType, apiConfig.CategorizationFilters)
364364
diags.Append(categorizationFiltersDiags...)
365-
// If the existing value was an untyped zero-value list (common during import), force a typed null list.
366-
if analysisConfigTF.CategorizationFilters.ElementType(ctx) == nil {
367-
analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType)
368-
} else if _, ok := analysisConfigTF.CategorizationFilters.ElementType(ctx).(basetypes.DynamicType); ok {
369-
analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType)
370-
}
365+
// Ensure the list is properly typed (handles untyped zero-value lists from import)
366+
analysisConfigTF.CategorizationFilters = typeutils.EnsureTypedList(ctx, analysisConfigTF.CategorizationFilters, types.StringType)
371367

372368
// Convert influencers
373369
var influencersDiags diag.Diagnostics
374370
analysisConfigTF.Influencers, influencersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.Influencers, types.StringType, apiConfig.Influencers)
375371
diags.Append(influencersDiags...)
376-
// If the existing value was an untyped zero-value list (common during import), force a typed null list.
377-
if analysisConfigTF.Influencers.ElementType(ctx) == nil {
378-
analysisConfigTF.Influencers = types.ListNull(types.StringType)
379-
} else if _, ok := analysisConfigTF.Influencers.ElementType(ctx).(basetypes.DynamicType); ok {
380-
analysisConfigTF.Influencers = types.ListNull(types.StringType)
381-
}
372+
// Ensure the list is properly typed (handles untyped zero-value lists from import)
373+
analysisConfigTF.Influencers = typeutils.EnsureTypedList(ctx, analysisConfigTF.Influencers, types.StringType)
382374

383375
// Convert detectors
384376
if len(apiConfig.Detectors) > 0 {
@@ -449,12 +441,8 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont
449441
var customRulesDiags diag.Diagnostics
450442
detectorsTF[i].CustomRules, customRulesDiags = typeutils.NonEmptyListOrDefault(ctx, originalDetector.CustomRules, types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}, apiConfig.Detectors[i].CustomRules)
451443
diags.Append(customRulesDiags...)
452-
// If the existing value was an untyped zero-value list (common during import), force a typed null list.
453-
if detectorsTF[i].CustomRules.ElementType(ctx) == nil {
454-
detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()})
455-
} else if _, ok := detectorsTF[i].CustomRules.ElementType(ctx).(basetypes.DynamicType); ok {
456-
detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()})
457-
}
444+
// Ensure the list is properly typed (handles untyped zero-value lists from import)
445+
detectorsTF[i].CustomRules = typeutils.EnsureTypedList(ctx, detectorsTF[i].CustomRules, types.ObjectType{AttrTypes: getCustomRuleAttrTypes()})
458446
}
459447
analysisConfigTF.Detectors = detectorsTF
460448
}

internal/utils/typeutils/list.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/hashicorp/terraform-plugin-framework/attr"
77
"github.com/hashicorp/terraform-plugin-framework/diag"
88
"github.com/hashicorp/terraform-plugin-framework/types"
9+
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
910
)
1011

1112
func NonEmptyListOrDefault[T any](ctx context.Context, original types.List, elemType attr.Type, slice []T) (types.List, diag.Diagnostics) {
@@ -15,3 +16,22 @@ func NonEmptyListOrDefault[T any](ctx context.Context, original types.List, elem
1516

1617
return types.ListValueFrom(ctx, elemType, slice)
1718
}
19+
20+
// EnsureTypedList converts untyped zero-value lists to properly typed null lists.
21+
// This is commonly needed during import operations where the framework may create
22+
// untyped lists with DynamicPseudoType elements, which causes type conversion errors.
23+
// If the list already has a proper type, it is returned unchanged.
24+
func EnsureTypedList(ctx context.Context, list types.List, elemType attr.Type) types.List {
25+
// Check if the list has no element type (nil)
26+
if list.ElementType(ctx) == nil {
27+
return types.ListNull(elemType)
28+
}
29+
30+
// Check if the list has a dynamic pseudo type
31+
if _, ok := list.ElementType(ctx).(basetypes.DynamicType); ok {
32+
return types.ListNull(elemType)
33+
}
34+
35+
// List is already properly typed, return as-is
36+
return list
37+
}

0 commit comments

Comments
 (0)