@@ -5,6 +5,7 @@ package resource
55import (
66 "context"
77 "fmt"
8+ "math/big"
89 "strings"
910
1011 "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/api"
@@ -656,6 +657,10 @@ func (c *ClickPipeResource) Schema(_ context.Context, _ resource.SchemaRequest,
656657 },
657658 },
658659 },
660+ "settings" : schema.DynamicAttribute {
661+ Description : "Advanced settings for the ClickPipe. These settings are pipe-specific configurations." ,
662+ Optional : true ,
663+ },
659664 },
660665 }
661666}
@@ -764,6 +769,59 @@ func (c *ClickPipeResource) Create(ctx context.Context, request resource.CreateR
764769 }
765770 }
766771
772+ // Handle settings
773+ if ! plan .Settings .IsNull () && ! plan .Settings .IsUnknown () {
774+ settingsMap := make (map [string ]interface {})
775+ underlyingValue := plan .Settings .UnderlyingValue ()
776+
777+ // Settings should be an object/map at the top level
778+ if objValue , ok := underlyingValue .(types.Object ); ok {
779+ for key , value := range objValue .Attributes () {
780+ if dynamicValue , ok := value .(types.Dynamic ); ok {
781+ innerValue := dynamicValue .UnderlyingValue ()
782+ switch v := innerValue .(type ) {
783+ case types.String :
784+ settingsMap [key ] = v .ValueString ()
785+ case types.Bool :
786+ settingsMap [key ] = v .ValueBool ()
787+ case types.Number :
788+ if intVal , accuracy := v .ValueBigFloat ().Int64 (); accuracy == big .Exact {
789+ settingsMap [key ] = intVal
790+ } else if floatVal , accuracy := v .ValueBigFloat ().Float64 (); accuracy == big .Exact {
791+ settingsMap [key ] = floatVal
792+ } else {
793+ settingsMap [key ] = v .ValueBigFloat ().String ()
794+ }
795+ default :
796+ settingsMap [key ] = fmt .Sprintf ("%v" , v )
797+ }
798+ } else {
799+ // Handle direct values
800+ switch v := value .(type ) {
801+ case types.String :
802+ settingsMap [key ] = v .ValueString ()
803+ case types.Bool :
804+ settingsMap [key ] = v .ValueBool ()
805+ case types.Number :
806+ if intVal , accuracy := v .ValueBigFloat ().Int64 (); accuracy == big .Exact {
807+ settingsMap [key ] = intVal
808+ } else if floatVal , accuracy := v .ValueBigFloat ().Float64 (); accuracy == big .Exact {
809+ settingsMap [key ] = floatVal
810+ } else {
811+ settingsMap [key ] = v .ValueBigFloat ().String ()
812+ }
813+ default :
814+ settingsMap [key ] = fmt .Sprintf ("%v" , v )
815+ }
816+ }
817+ }
818+ }
819+
820+ if len (settingsMap ) > 0 {
821+ clickPipe .Settings = settingsMap
822+ }
823+ }
824+
767825 createdClickPipe , err := c .client .CreateClickPipe (ctx , serviceID , clickPipe )
768826 if err != nil {
769827 response .Diagnostics .AddError (
@@ -1115,10 +1173,36 @@ func (c *ClickPipeResource) syncClickPipeState(ctx context.Context, state *model
11151173 state .State = types .StringValue (clickPipe .State )
11161174
11171175 if clickPipe .Scaling != nil {
1176+ cpuMillicores := clickPipe .Scaling .GetCpuMillicores ()
1177+ memoryGb := clickPipe .Scaling .GetMemoryGb ()
1178+
1179+ // Create scaling model with proper null handling
1180+ var replicasValue types.Int64
1181+ var cpuValue types.Int64
1182+ var memoryValue types.Float64
1183+
1184+ if clickPipe .Scaling .Replicas != nil {
1185+ replicasValue = types .Int64Value (* clickPipe .Scaling .Replicas )
1186+ } else {
1187+ replicasValue = types .Int64Null ()
1188+ }
1189+
1190+ if cpuMillicores != nil {
1191+ cpuValue = types .Int64Value (* cpuMillicores )
1192+ } else {
1193+ cpuValue = types .Int64Null ()
1194+ }
1195+
1196+ if memoryGb != nil {
1197+ memoryValue = types .Float64Value (* memoryGb )
1198+ } else {
1199+ memoryValue = types .Float64Null ()
1200+ }
1201+
11181202 scalingModel := models.ClickPipeScalingModel {
1119- Replicas : types . Int64PointerValue ( clickPipe . Scaling . Replicas ) ,
1120- ReplicaCpuMillicores : types . Int64PointerValue ( clickPipe . Scaling . GetCpuMillicores ()) ,
1121- ReplicaMemoryGb : types . Float64PointerValue ( clickPipe . Scaling . GetMemoryGb ()) ,
1203+ Replicas : replicasValue ,
1204+ ReplicaCpuMillicores : cpuValue ,
1205+ ReplicaMemoryGb : memoryValue ,
11221206 }
11231207
11241208 state .Scaling = scalingModel .ObjectValue ()
@@ -1373,6 +1457,45 @@ func (c *ClickPipeResource) syncClickPipeState(ctx context.Context, state *model
13731457 state .FieldMappings , _ = types .ListValue (models.ClickPipeFieldMappingModel {}.ObjectType (), fieldMappingList )
13741458 }
13751459
1460+ // Handle settings
1461+ if clickPipe .Settings != nil && len (clickPipe .Settings ) > 0 {
1462+ settingsElements := make (map [string ]attr.Value )
1463+ for key , value := range clickPipe .Settings {
1464+ switch v := value .(type ) {
1465+ case string :
1466+ settingsElements [key ] = types .StringValue (v )
1467+ case bool :
1468+ settingsElements [key ] = types .BoolValue (v )
1469+ case int64 :
1470+ settingsElements [key ] = types .NumberValue (big .NewFloat (float64 (v )))
1471+ case float64 :
1472+ settingsElements [key ] = types .NumberValue (big .NewFloat (v ))
1473+ case int :
1474+ settingsElements [key ] = types .NumberValue (big .NewFloat (float64 (v )))
1475+ case float32 :
1476+ settingsElements [key ] = types .NumberValue (big .NewFloat (float64 (v )))
1477+ default :
1478+ // Fallback to string representation
1479+ settingsElements [key ] = types .StringValue (fmt .Sprintf ("%v" , v ))
1480+ }
1481+ }
1482+ settingsObj , _ := types .ObjectValue (
1483+ map [string ]attr.Type {},
1484+ make (map [string ]attr.Value ),
1485+ )
1486+
1487+ // Create object type dynamically based on actual values
1488+ attrTypes := make (map [string ]attr.Type )
1489+ for key := range settingsElements {
1490+ attrTypes [key ] = settingsElements [key ].Type (ctx )
1491+ }
1492+
1493+ settingsObj , _ = types .ObjectValue (attrTypes , settingsElements )
1494+ state .Settings = types .DynamicValue (settingsObj )
1495+ } else {
1496+ state .Settings = types .DynamicNull ()
1497+ }
1498+
13761499 return nil
13771500}
13781501
@@ -1477,6 +1600,62 @@ func (c *ClickPipeResource) Update(ctx context.Context, req resource.UpdateReque
14771600 }
14781601 }
14791602
1603+ // Handle settings separately using dedicated endpoint
1604+ var settingsChanged bool
1605+ var newSettingsMap map [string ]interface {}
1606+
1607+ if ! plan .Settings .Equal (state .Settings ) {
1608+ settingsChanged = true
1609+ newSettingsMap = make (map [string ]interface {})
1610+ if ! plan .Settings .IsNull () && ! plan .Settings .IsUnknown () {
1611+ underlyingValue := plan .Settings .UnderlyingValue ()
1612+
1613+ // Settings should be an object/map at the top level
1614+ if objValue , ok := underlyingValue .(types.Object ); ok {
1615+ for key , value := range objValue .Attributes () {
1616+ if dynamicValue , ok := value .(types.Dynamic ); ok {
1617+ innerValue := dynamicValue .UnderlyingValue ()
1618+ switch v := innerValue .(type ) {
1619+ case types.String :
1620+ newSettingsMap [key ] = v .ValueString ()
1621+ case types.Bool :
1622+ newSettingsMap [key ] = v .ValueBool ()
1623+ case types.Number :
1624+ if intVal , accuracy := v .ValueBigFloat ().Int64 (); accuracy == big .Exact {
1625+ newSettingsMap [key ] = intVal
1626+ } else if floatVal , accuracy := v .ValueBigFloat ().Float64 (); accuracy == big .Exact {
1627+ newSettingsMap [key ] = floatVal
1628+ } else {
1629+ newSettingsMap [key ] = v .ValueBigFloat ().String ()
1630+ }
1631+ default :
1632+ newSettingsMap [key ] = fmt .Sprintf ("%v" , v )
1633+ }
1634+ } else {
1635+ // Handle direct values
1636+ switch v := value .(type ) {
1637+ case types.String :
1638+ newSettingsMap [key ] = v .ValueString ()
1639+ case types.Bool :
1640+ newSettingsMap [key ] = v .ValueBool ()
1641+ case types.Number :
1642+ if intVal , accuracy := v .ValueBigFloat ().Int64 (); accuracy == big .Exact {
1643+ newSettingsMap [key ] = intVal
1644+ } else if floatVal , accuracy := v .ValueBigFloat ().Float64 (); accuracy == big .Exact {
1645+ newSettingsMap [key ] = floatVal
1646+ } else {
1647+ newSettingsMap [key ] = v .ValueBigFloat ().String ()
1648+ }
1649+ default :
1650+ newSettingsMap [key ] = fmt .Sprintf ("%v" , v )
1651+ }
1652+ }
1653+ }
1654+ }
1655+ }
1656+ }
1657+
1658+ // Update the main ClickPipe if non-settings fields changed
14801659 if pipeChanged {
14811660 if _ , err := c .client .UpdateClickPipe (ctx , state .ServiceID .ValueString (), state .ID .ValueString (), clickPipeUpdate ); err != nil {
14821661 response .Diagnostics .AddError (
@@ -1487,6 +1666,17 @@ func (c *ClickPipeResource) Update(ctx context.Context, req resource.UpdateReque
14871666 }
14881667 }
14891668
1669+ // Update settings separately if they changed
1670+ if settingsChanged {
1671+ if _ , err := c .client .UpdateClickPipeSettings (ctx , state .ServiceID .ValueString (), state .ID .ValueString (), newSettingsMap ); err != nil {
1672+ response .Diagnostics .AddError (
1673+ "Error Updating ClickPipe Settings" ,
1674+ "Could not update ClickPipe settings, unexpected error: " + err .Error (),
1675+ )
1676+ return
1677+ }
1678+ }
1679+
14901680 if ! plan .State .Equal (state .State ) {
14911681 var command string
14921682
0 commit comments