@@ -123,12 +123,25 @@ func parameterDataSource() *schema.Resource {
123123 if err != nil {
124124 return diag .Errorf ("decode parameter: %s" , err )
125125 }
126- value := parameter .Default
126+
127+ var value * string
128+ if ! rd .GetRawConfig ().AsValueMap ()["default" ].IsNull () {
129+ value = & parameter .Default
130+ }
131+
127132 envValue , ok := os .LookupEnv (ParameterEnvironmentVariable (parameter .Name ))
128133 if ok {
129- value = envValue
134+ value = & envValue
135+ }
136+
137+ if value != nil {
138+ rd .Set ("value" , value )
139+ } else {
140+ // Maintaining backwards compatibility. The previous behavior was
141+ // to write back an empty string.
142+ // TODO: Should an empty string exist if no value is set?
143+ rd .Set ("value" , "" )
130144 }
131- rd .Set ("value" , value )
132145
133146 if ! parameter .Mutable && parameter .Ephemeral {
134147 return diag .Errorf ("parameter can't be immutable and ephemeral" )
@@ -138,21 +151,6 @@ func parameterDataSource() *schema.Resource {
138151 return diag .Errorf ("ephemeral parameter requires the default property" )
139152 }
140153
141- // Do ValidateFormType up front. If there is no error, update the
142- // 'parameter.FormType' value to the new value. This is to handle default cases,
143- // since the default logic is more advanced than the sdk provider schema
144- // supports.
145- //_, newFT, err := ValidateFormType(parameter.Type, len(parameter.Option), parameter.FormType)
146- //if err == nil {
147- // // If there is an error, parameter.Valid will catch it.
148- // parameter.FormType = newFT
149- //
150- // // Set the form_type back in case the value was changed.
151- // // Eg via a default. If a user does not specify, a default value
152- // // is used and saved.
153- // rd.Set("form_type", parameter.FormType)
154- //}
155-
156154 diags := parameter .Valid (value )
157155 if diags .HasError () {
158156 return diags
@@ -399,12 +397,7 @@ func valueIsType(typ OptionType, value string) error {
399397 return nil
400398}
401399
402- func (v * Parameter ) RelaxedValidation (value string ) diag.Diagnostics {
403-
404- return nil
405- }
406-
407- func (v * Parameter ) Valid (value string ) diag.Diagnostics {
400+ func (v * Parameter ) Valid (value * string ) diag.Diagnostics {
408401 var err error
409402 var optionType OptionType
410403
@@ -422,88 +415,125 @@ func (v *Parameter) Valid(value string) diag.Diagnostics {
422415 }
423416 }
424417
425- optionNames := map [string ]any {}
426- optionValues := map [string ]any {}
427- if len (v .Option ) > 0 {
428- for _ , option := range v .Option {
429- _ , exists := optionNames [option .Name ]
430- if exists {
431- return diag.Diagnostics {{
432- Severity : diag .Error ,
433- Summary : "Option names must be unique." ,
434- Detail : fmt .Sprintf ("multiple options found with the same name %q" , option .Name ),
435- },
436- }
437- }
438- _ , exists = optionValues [option .Value ]
439- if exists {
440- return diag.Diagnostics {
441- {
442- Severity : diag .Error ,
443- Summary : "Option values must be unique." ,
444- Detail : fmt .Sprintf ("multiple options found with the same value %q" , option .Value ),
445- },
446- }
447- }
448- err = valueIsType (optionType , option .Value )
449- if err != nil {
450- return diag.Diagnostics {
451- {
452- Severity : diag .Error ,
453- Summary : fmt .Sprintf ("Option %q with value=%q is not of type %q" , option .Name , option .Value , optionType ),
454- Detail : err .Error (),
455- },
456- }
457- }
458- optionValues [option .Value ] = nil
459- optionNames [option .Name ] = nil
460-
461- // TODO: Option values should also be validated.
462- // v.validValue(option.Value, optionType, nil, cty.Path{})
463- }
418+ optionValues , diags := v .ValidOptions (optionType )
419+ if diags .HasError () {
420+ return diags
464421 }
465422
466- // Validate the default value
467- if v .Default != "" {
468- err := valueIsType (v .Type , v .Default )
423+ // TODO: The default value should also be validated
424+ //if v.Default != "" {
425+ // err := valueIsType(v.Type, v.Default)
426+ // if err != nil {
427+ // return diag.Diagnostics{
428+ // {
429+ // Severity: diag.Error,
430+ // Summary: fmt.Sprintf("Default value is not of type %q", v.Type),
431+ // Detail: err.Error(),
432+ // AttributePath: defaultValuePath,
433+ // },
434+ // }
435+ // }
436+ //
437+ // d := v.validValue(v.Default, optionType, optionValues, defaultValuePath)
438+ // if d.HasError() {
439+ // return d
440+ // }
441+ //}
442+
443+ // TODO: Move this into 'Parameter.validValue'. It exists as another check outside because
444+ // the current behavior is to always apply this validation, regardless if the param is set or not.
445+ // Other validations are only applied if the parameter is set.
446+ // This behavior should be standardized.
447+ if len (v .Validation ) == 1 {
448+ empty := ""
449+ validVal := value
450+ if value == nil {
451+ validVal = & empty
452+ }
453+ validCheck := & v .Validation [0 ]
454+ err := validCheck .Valid (v .Type , * validVal )
469455 if err != nil {
470456 return diag.Diagnostics {
471457 {
472458 Severity : diag .Error ,
473- Summary : fmt .Sprintf ("Default value is not of type %q " , v . Type ),
459+ Summary : fmt .Sprintf ("Invalid parameter %s according to 'validation' block " , strings . ToLower ( v . Name ) ),
474460 Detail : err .Error (),
475- AttributePath : defaultValuePath ,
461+ AttributePath : cty. Path {} ,
476462 },
477463 }
478464 }
465+ }
479466
480- d := v .validValue (v .Default , optionType , optionValues , defaultValuePath )
467+ // Value is only validated if it is set. If it is unset, validation
468+ // is skipped.
469+ if value != nil {
470+ d := v .validValue (* value , optionType , optionValues , cty.Path {})
481471 if d .HasError () {
482472 return d
483473 }
484- }
485474
486- // Value must always be validated
487- d := v .validValue (value , optionType , optionValues , cty.Path {})
488- if d .HasError () {
489- return d
475+ err = valueIsType (v .Type , * value )
476+ if err != nil {
477+ return diag.Diagnostics {
478+ {
479+ Severity : diag .Error ,
480+ Summary : fmt .Sprintf ("Parameter value is not of type %q" , v .Type ),
481+ Detail : err .Error (),
482+ },
483+ }
484+ }
490485 }
491486
492- err = valueIsType (v .Type , value )
493- if err != nil {
494- return diag.Diagnostics {
495- {
487+ return nil
488+ }
489+
490+ func (v * Parameter ) ValidOptions (optionType OptionType ) (map [string ]struct {}, diag.Diagnostics ) {
491+ optionNames := map [string ]struct {}{}
492+ optionValues := map [string ]struct {}{}
493+
494+ var diags diag.Diagnostics
495+ for _ , option := range v .Option {
496+ _ , exists := optionNames [option .Name ]
497+ if exists {
498+ return nil , diag.Diagnostics {{
496499 Severity : diag .Error ,
497- Summary : fmt .Sprintf ("Parameter value is not of type %q" , v .Type ),
500+ Summary : "Option names must be unique." ,
501+ Detail : fmt .Sprintf ("multiple options found with the same name %q" , option .Name ),
502+ }}
503+ }
504+
505+ _ , exists = optionValues [option .Value ]
506+ if exists {
507+ return nil , diag.Diagnostics {{
508+ Severity : diag .Error ,
509+ Summary : "Option values must be unique." ,
510+ Detail : fmt .Sprintf ("multiple options found with the same value %q" , option .Value ),
511+ }}
512+ }
513+
514+ err := valueIsType (optionType , option .Value )
515+ if err != nil {
516+ diags = append (diags , diag.Diagnostic {
517+ Severity : diag .Error ,
518+ Summary : fmt .Sprintf ("Option %q with value=%q is not of type %q" , option .Name , option .Value , optionType ),
498519 Detail : err .Error (),
499- },
520+ })
521+ continue
500522 }
523+ optionValues [option .Value ] = struct {}{}
524+ optionNames [option .Name ] = struct {}{}
525+
526+ // TODO: Option values should also be validated.
527+ // v.validValue(option.Value, optionType, nil, cty.Path{})
501528 }
502529
503- return nil
530+ if diags .HasError () {
531+ return nil , diags
532+ }
533+ return optionValues , nil
504534}
505535
506- func (v * Parameter ) validValue (value string , optionType OptionType , optionValues map [string ]any , path cty.Path ) diag.Diagnostics {
536+ func (v * Parameter ) validValue (value string , optionType OptionType , optionValues map [string ]struct {} , path cty.Path ) diag.Diagnostics {
507537 // name is used for constructing more precise error messages.
508538 name := "Value"
509539 if path .Equals (defaultValuePath ) {
@@ -568,21 +598,6 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
568598 }
569599 }
570600
571- if len (v .Validation ) == 1 {
572- validCheck := & v .Validation [0 ]
573- err := validCheck .Valid (v .Type , value )
574- if err != nil {
575- return diag.Diagnostics {
576- {
577- Severity : diag .Error ,
578- Summary : fmt .Sprintf ("Invalid parameter %s according to 'validation' block" , strings .ToLower (name )),
579- Detail : err .Error (),
580- AttributePath : path ,
581- },
582- }
583- }
584- }
585-
586601 return nil
587602}
588603
0 commit comments