@@ -77,7 +77,7 @@ func CheckRequiredFieldsMissingFromShape(
7777 case model .OpTypeList :
7878 op = r .Ops .ReadMany
7979 return checkRequiredFieldsMissingFromShapeReadMany (
80- r , koVarName , indentLevel , op , op .InputRef .Shape ), nil
80+ r , koVarName , indentLevel , op , op .InputRef .Shape )
8181 case model .OpTypeGetAttributes :
8282 op = r .Ops .GetAttributes
8383 case model .OpTypeSetAttributes :
@@ -96,6 +96,42 @@ func CheckRequiredFieldsMissingFromShape(
9696 )
9797}
9898
99+ // mutuallyExclusiveIdentifierNilConditions returns, for each of the resource's
100+ // configured mutually-exclusive identifier fields, a "<path> == nil" condition
101+ // string, along with the set of CR paths so callers can exclude them from
102+ // per-field required checks. The resource is uniquely identified by exactly one
103+ // of these fields, so it is considered incomplete only when all of them are
104+ // nil. Returns nil slices when the resource has no mutually-exclusive
105+ // identifiers.
106+ func mutuallyExclusiveIdentifierNilConditions (
107+ r * model.CRD ,
108+ koVarName string ,
109+ ) ([]string , map [string ]bool , error ) {
110+ if ! r .HasMutuallyExclusiveIdentifiers () {
111+ return nil , nil , nil
112+ }
113+ identifierFields , err := r .GetMutuallyExclusiveIdentifierFields ()
114+ if err != nil {
115+ return nil , nil , err
116+ }
117+ cfg := r .Config ()
118+ conditions := make ([]string , 0 , len (identifierFields ))
119+ paths := make (map [string ]bool , len (identifierFields ))
120+ for _ , identifierField := range identifierFields {
121+ memberPath , targetField := findFieldInCR (cfg , r , identifierField .Names .Original )
122+ if targetField == nil {
123+ return nil , nil , fmt .Errorf (
124+ "resource %q: mutually_exclusive_identifiers field %q is not in the CR's Spec or Status" ,
125+ r .Names .Original , identifierField .Names .Original ,
126+ )
127+ }
128+ path := fmt .Sprintf ("%s%s.%s" , koVarName , memberPath , targetField .Path )
129+ conditions = append (conditions , fmt .Sprintf ("%s == nil" , path ))
130+ paths [path ] = true
131+ }
132+ return conditions , paths , nil
133+ }
134+
99135func checkRequiredFieldsMissingFromShape (
100136 r * model.CRD ,
101137 koVarName string ,
@@ -104,7 +140,26 @@ func checkRequiredFieldsMissingFromShape(
104140 shape * awssdkmodel.Shape ,
105141) (string , error ) {
106142 indent := strings .Repeat ("\t " , indentLevel )
143+
144+ // When the resource declares mutually-exclusive identifiers, the resource is
145+ // uniquely identified by exactly one of the declared fields. Build a single
146+ // grouped condition that is true only when none of them are set, and collect
147+ // their CR paths so they are not required individually below. This makes the
148+ // generated check treat the input as incomplete unless at least one
149+ // identifier is present, mirroring the ReadMany handling.
150+ exclusiveConditions , exclusivePaths , err := mutuallyExclusiveIdentifierNilConditions (r , koVarName )
151+ if err != nil {
152+ return "" , err
153+ }
154+ exclusiveGroupCondition := ""
155+ if len (exclusiveConditions ) > 0 {
156+ exclusiveGroupCondition = fmt .Sprintf ("(%s)" , strings .Join (exclusiveConditions , " && " ))
157+ }
158+
107159 if shape == nil || len (shape .Required ) == 0 {
160+ if exclusiveGroupCondition != "" {
161+ return fmt .Sprintf ("%sreturn %s\n " , indent , exclusiveGroupCondition ), nil
162+ }
108163 return fmt .Sprintf ("%sreturn false" , indent ), nil
109164 }
110165
@@ -144,8 +199,16 @@ func checkRequiredFieldsMissingFromShape(
144199 r .Names .Original , memberName , shape .ShapeName ,
145200 )
146201 }
202+ // Mutually-exclusive identifiers are not required individually; they are
203+ // covered by the grouped condition appended below.
204+ if exclusivePaths [resVarPath ] {
205+ continue
206+ }
147207 missing = append (missing , fmt .Sprintf ("%s == nil" , resVarPath ))
148208 }
209+ if exclusiveGroupCondition != "" {
210+ missing = append (missing , exclusiveGroupCondition )
211+ }
149212 // Use '||' because if any of the required fields are missing the object
150213 // is not created yet
151214 missingCondition := strings .Join (missing , " || " )
@@ -174,18 +237,34 @@ func checkRequiredFieldsMissingFromShapeReadMany(
174237 indentLevel int ,
175238 op * awssdkmodel.Operation ,
176239 shape * awssdkmodel.Shape ,
177- ) string {
240+ ) ( string , error ) {
178241 indent := strings .Repeat ("\t " , indentLevel )
179242 result := fmt .Sprintf ("%sreturn false" , indent )
180243
244+ // When the resource declares mutually-exclusive identifiers, the ReadMany
245+ // input typically has no required members, so the default `return false`
246+ // would let sdkFind list every resource and match an arbitrary one. Instead,
247+ // treat the read input as incomplete (returning true so sdkFind bails out
248+ // with NotFound) unless at least one of the declared identifiers is set on
249+ // the resource.
250+ if r .HasMutuallyExclusiveIdentifiers () {
251+ exclusiveConditions , _ , err := mutuallyExclusiveIdentifierNilConditions (r , koVarName )
252+ if err != nil {
253+ return "" , err
254+ }
255+ // Parenthesize the grouped condition to mirror the ReadOne handling and
256+ // stay correct if a future term is ever joined here with `||`.
257+ return fmt .Sprintf ("%sreturn (%s)\n " , indent , strings .Join (exclusiveConditions , " && " )), nil
258+ }
259+
181260 reqIdentifier , _ := FindPluralizedIdentifiersInShape (r , shape , op )
182261 resVarPath , err := r .GetSanitizedMemberPath (reqIdentifier , op , koVarName )
183262 if err != nil {
184- return result
263+ return result , nil
185264 }
186265
187266 result = fmt .Sprintf ("%s == nil" , resVarPath )
188- return fmt .Sprintf ("%sreturn %s\n " , indent , result )
267+ return fmt .Sprintf ("%sreturn %s\n " , indent , result ), nil
189268}
190269
191270// CheckNilFieldPath returns the condition statement for Nil check
0 commit comments