@@ -19,10 +19,12 @@ import (
19
19
"strings"
20
20
21
21
awssdkmodel "github.com/aws/aws-sdk-go/private/model/api"
22
+ "github.com/gertd/go-pluralize"
22
23
23
24
ackgenconfig "github.com/aws-controllers-k8s/code-generator/pkg/generate/config"
24
25
"github.com/aws-controllers-k8s/code-generator/pkg/model"
25
26
"github.com/aws-controllers-k8s/code-generator/pkg/names"
27
+ "github.com/aws-controllers-k8s/code-generator/pkg/util"
26
28
)
27
29
28
30
// SetSDK returns the Go code that sets an SDK input shape's member fields from
@@ -98,6 +100,8 @@ func SetSDK(
98
100
op = r .Ops .ReadOne
99
101
case model .OpTypeList :
100
102
op = r .Ops .ReadMany
103
+ return setSDKReadMany (cfg , r , op ,
104
+ sourceVarName , targetVarName , indentLevel )
101
105
case model .OpTypeUpdate :
102
106
op = r .Ops .Update
103
107
case model .OpTypeDelete :
@@ -718,6 +722,151 @@ func SetSDKSetAttributes(
718
722
return out
719
723
}
720
724
725
+ // setSDKReadMany is a special-case handling of those APIs where there is no
726
+ // ReadOne operation and instead the only way to grab information for a single
727
+ // object is to call the ReadMany/List operation with one of more filtering
728
+ // fields-- specifically identifier(s). This method populates this identifier
729
+ // field with the identifier shared between the shape and the CR. Note, in the
730
+ // case of multiple matching identifiers, the identifier field containing 'Id'
731
+ // will be the only field populated.
732
+ //
733
+ // As an example, DescribeVpcs EC2 API call doesn't have a ReadOne operation or
734
+ // required fields. However, the input shape VpcIds field can be populated using
735
+ // a VpcId, a field in the VPC CR's Status. Therefore, populate VpcIds field
736
+ // with the *single* VpcId value to ensure the returned array from the API call
737
+ // consists only of the desired Vpc.
738
+ //
739
+ // Sample Output:
740
+ //
741
+ // if r.ko.Status.VPCID != nil {
742
+ // f4 := []*string{}
743
+ // f4 = append(f4, r.ko.Status.VPCID)
744
+ // res.SetVpcIds(f4)
745
+ // }
746
+ func setSDKReadMany (
747
+ cfg * ackgenconfig.Config ,
748
+ r * model.CRD ,
749
+ op * awssdkmodel.Operation ,
750
+ sourceVarName string ,
751
+ targetVarName string ,
752
+ indentLevel int ,
753
+ ) string {
754
+ inputShape := op .InputRef .Shape
755
+ if inputShape == nil {
756
+ return ""
757
+ }
758
+
759
+ out := "\n "
760
+ indent := strings .Repeat ("\t " , indentLevel )
761
+
762
+ resVarPath := ""
763
+ pluralize := pluralize .NewClient ()
764
+ opConfig , override := cfg .OverrideValues (op .Name )
765
+ shapeIdentifiers := FindIdentifiersInShape (r , inputShape )
766
+ var err error
767
+ for memberIndex , memberName := range inputShape .MemberNames () {
768
+ if override {
769
+ value , ok := opConfig [memberName ]
770
+ memberShapeRef , _ := inputShape .MemberRefs [memberName ]
771
+ memberShape := memberShapeRef .Shape
772
+ if ok {
773
+ switch memberShape .Type {
774
+ case "boolean" , "integer" :
775
+ case "string" :
776
+ value = "\" " + value + "\" "
777
+ default :
778
+ panic (fmt .Sprintf ("Unsupported shape type %s in " +
779
+ "generate.code.setSDKReadMany" , memberShape .Type ))
780
+ }
781
+
782
+ out += fmt .Sprintf ("%s%s.Set%s(%s)\n " , indent , targetVarName , memberName , value )
783
+ continue
784
+ }
785
+ }
786
+
787
+ // Field renames are handled in getSanitizedMemberPath
788
+ resVarPath , err = getSanitizedMemberPath (memberName , r , op , sourceVarName )
789
+ if err != nil {
790
+ // if it's an identifier field check for singular/plural
791
+ if util .InStrings (memberName , shapeIdentifiers ) {
792
+ var flipped string
793
+ if pluralize .IsPlural (memberName ) {
794
+ flipped = pluralize .Singular (memberName )
795
+ } else {
796
+ flipped = pluralize .Plural (memberName )
797
+ }
798
+ // If there are multiple identifiers, then prioritize the
799
+ // 'Id' identifier.
800
+ if resVarPath == "" || (! strings .HasSuffix (resVarPath , "Id" ) ||
801
+ ! strings .HasSuffix (resVarPath , "Ids" )) {
802
+ resVarPath , err = getSanitizedMemberPath (flipped , r , op , sourceVarName )
803
+ if err != nil {
804
+ panic (fmt .Sprintf (
805
+ "Unable to locate identifier field %s in " +
806
+ "%s Spec/Status in generate.code.setSDKReadMany" , flipped , r .Kind ))
807
+ }
808
+ }
809
+ } else {
810
+ // TODO(jaypipes): check generator config for exceptions?
811
+ continue
812
+ }
813
+ }
814
+
815
+ memberShapeRef , _ := inputShape .MemberRefs [memberName ]
816
+ memberShape := memberShapeRef .Shape
817
+ out += fmt .Sprintf (
818
+ "%sif %s != nil {\n " , indent , resVarPath ,
819
+ )
820
+
821
+ switch memberShape .Type {
822
+ case "list" :
823
+ // Expecting slice of identifiers
824
+ memberVarName := fmt .Sprintf ("f%d" , memberIndex )
825
+ // f0 := []*string{}
826
+ out += varEmptyConstructorSDKType (
827
+ cfg , r ,
828
+ memberVarName ,
829
+ memberShape ,
830
+ indentLevel + 1 ,
831
+ )
832
+
833
+ // f0 = append(f0, sourceVarName)
834
+ out += fmt .Sprintf ("%s\t %s = append(%s, %s)\n " , indent ,
835
+ memberVarName , memberVarName , resVarPath )
836
+
837
+ // res.SetIds(f0)
838
+ out += setSDKForScalar (
839
+ cfg , r ,
840
+ memberName ,
841
+ targetVarName ,
842
+ inputShape .Type ,
843
+ sourceVarName ,
844
+ memberVarName ,
845
+ memberShapeRef ,
846
+ indentLevel + 1 ,
847
+ )
848
+ default :
849
+ // For ReadMany that have a singular identifier field.
850
+ // ex: DescribeReplicationGroups
851
+ out += setSDKForScalar (
852
+ cfg , r ,
853
+ memberName ,
854
+ targetVarName ,
855
+ inputShape .Type ,
856
+ sourceVarName ,
857
+ resVarPath ,
858
+ memberShapeRef ,
859
+ indentLevel + 1 ,
860
+ )
861
+ }
862
+ out += fmt .Sprintf (
863
+ "%s}\n " , indent ,
864
+ )
865
+ }
866
+
867
+ return out
868
+ }
869
+
721
870
// setSDKForContainer returns a string of Go code that sets the value of a
722
871
// target variable to that of a source variable. When the source variable type
723
872
// is a map, struct or slice type, then this function is called recursively on
@@ -969,7 +1118,7 @@ func SetSDKForStruct(
969
1118
}
970
1119
971
1120
// setSDKForSlice returns a string of Go code that sets a target variable value
972
- // to a source variable when the type of the source variable is a struct .
1121
+ // to a source variable when the type of the source variable is a slice .
973
1122
func setSDKForSlice (
974
1123
cfg * ackgenconfig.Config ,
975
1124
r * model.CRD ,
@@ -1034,7 +1183,7 @@ func setSDKForSlice(
1034
1183
}
1035
1184
1036
1185
// setSDKForMap returns a string of Go code that sets a target variable value
1037
- // to a source variable when the type of the source variable is a struct .
1186
+ // to a source variable when the type of the source variable is a map .
1038
1187
func setSDKForMap (
1039
1188
cfg * ackgenconfig.Config ,
1040
1189
r * model.CRD ,
0 commit comments