Skip to content

Commit 42fb21d

Browse files
Support ReadMany operations with slices in SetResourceIdentifiers (#170)
Fixes aws-controllers-k8s/community#874 Description of changes: Automatically detects pluralised fields from the operation shape and sets the corresponding CR field. Refactor `SetResourceIdentifiers` to re-use common logic from `CheckRequiredFieldsMissingFromShape`. Now supports `primary_identifier_field_names` that reference `[]string` types. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 07d7ea7 commit 42fb21d

File tree

5 files changed

+338
-158
lines changed

5 files changed

+338
-158
lines changed

pkg/generate/code/check.go

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"strings"
1919

2020
awssdkmodel "github.com/aws/aws-sdk-go/private/model/api"
21-
"github.com/gertd/go-pluralize"
2221

2322
ackgenconfig "github.com/aws-controllers-k8s/code-generator/pkg/generate/config"
2423
"github.com/aws-controllers-k8s/code-generator/pkg/model"
@@ -184,37 +183,7 @@ func checkRequiredFieldsMissingFromShapeReadMany(
184183
indent := strings.Repeat("\t", indentLevel)
185184
result := fmt.Sprintf("%sreturn false", indent)
186185

187-
shapeIdentifiers := FindIdentifiersInShape(r, shape)
188-
crIdentifiers := FindIdentifiersInCRD(r)
189-
if len(shapeIdentifiers) == 0 || len(crIdentifiers) == 0 {
190-
return result
191-
}
192-
193-
pluralize := pluralize.NewClient()
194-
reqIdentifier := ""
195-
for _, si := range shapeIdentifiers {
196-
for _, ci := range crIdentifiers {
197-
if strings.EqualFold(pluralize.Singular(si),
198-
pluralize.Singular(ci)) {
199-
// The CRD identifiers being used for comparison reflect the
200-
// *original* field names in the API model shape.
201-
// Field renames are handled below in the call to
202-
// getSanitizedMemberPath.
203-
if reqIdentifier == "" {
204-
reqIdentifier = ci
205-
} else {
206-
// If there are multiple identifiers, then prioritize the
207-
// 'Id' identifier. Checking 'Id' to determine resource
208-
// creation should be safe as the field is usually
209-
// present in CR.Status.
210-
if !strings.HasSuffix(reqIdentifier, "Id") ||
211-
!strings.HasSuffix(reqIdentifier, "Ids") {
212-
reqIdentifier = ci
213-
}
214-
}
215-
}
216-
}
217-
}
186+
reqIdentifier, _ := FindPluralizedIdentifiersInShape(r, shape)
218187

219188
resVarPath, err := getSanitizedMemberPath(reqIdentifier, r, op, koVarName)
220189
if err != nil {

pkg/generate/code/common.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@
1414
package code
1515

1616
import (
17+
"strings"
18+
1719
awssdkmodel "github.com/aws/aws-sdk-go/private/model/api"
20+
"github.com/gertd/go-pluralize"
1821

22+
ackgenconfig "github.com/aws-controllers-k8s/code-generator/pkg/generate/config"
1923
"github.com/aws-controllers-k8s/code-generator/pkg/model"
2024
"github.com/aws-controllers-k8s/code-generator/pkg/util"
2125
)
2226

27+
var (
28+
PrimaryIdentifierARNOverride = "ARN"
29+
)
30+
2331
// FindIdentifiersInShape returns the identifier fields of a given shape which
2432
// can be singular or plural.
2533
func FindIdentifiersInShape(
@@ -49,6 +57,26 @@ func FindIdentifiersInShape(
4957
return identifiers
5058
}
5159

60+
// FindIdentifiersInShape returns the identifier fields of a given shape which
61+
// fit expect an ARN.
62+
func FindARNIdentifiersInShape(
63+
r *model.CRD,
64+
shape *awssdkmodel.Shape,
65+
) []string {
66+
var identifiers []string
67+
if r == nil || shape == nil {
68+
return identifiers
69+
}
70+
71+
for _, memberName := range shape.MemberNames() {
72+
if r.IsPrimaryARNField(memberName) {
73+
identifiers = append(identifiers, memberName)
74+
}
75+
}
76+
77+
return identifiers
78+
}
79+
5280
// FindIdentifiersInCRD returns the identifier fields of a given CRD which
5381
// can be singular or plural. Note, these fields will be the *original* field
5482
// names from the API model shape, not renamed field names.
@@ -81,3 +109,114 @@ func FindIdentifiersInCRD(
81109

82110
return identifiers
83111
}
112+
113+
// FindPluralizedIdentifiersInShape returns the name of a Spec OR Status field
114+
// that has a matching pluralized field in the given shape and the name of
115+
// the corresponding shape field name. This method will returns the original
116+
// field name - renames will need to be handled separately.
117+
// For example, DescribeVpcsInput has a `VpcIds` field which would be matched
118+
// to the `Status.VPCID` CRD field - the return value would be
119+
// "VPCID", "VpcIds".
120+
func FindPluralizedIdentifiersInShape(
121+
r *model.CRD,
122+
shape *awssdkmodel.Shape,
123+
) (crField string, shapeField string) {
124+
shapeIdentifiers := FindIdentifiersInShape(r, shape)
125+
crIdentifiers := FindIdentifiersInCRD(r)
126+
if len(shapeIdentifiers) == 0 || len(crIdentifiers) == 0 {
127+
return "", ""
128+
}
129+
130+
pluralize := pluralize.NewClient()
131+
for _, si := range shapeIdentifiers {
132+
for _, ci := range crIdentifiers {
133+
if strings.EqualFold(pluralize.Singular(si),
134+
pluralize.Singular(ci)) {
135+
// The CRD identifiers being used for comparison reflect the
136+
// *original* field names in the API model shape.
137+
if crField == "" {
138+
crField = ci
139+
shapeField = si
140+
} else {
141+
// If there are multiple identifiers, then prioritize the
142+
// 'Id' identifier. Checking 'Id' to determine resource
143+
// creation should be safe as the field is usually
144+
// present in CR.Status.
145+
if !strings.HasSuffix(crField, "Id") ||
146+
!strings.HasSuffix(crField, "Ids") {
147+
crField = ci
148+
shapeField = si
149+
}
150+
}
151+
}
152+
}
153+
}
154+
return crField, shapeField
155+
}
156+
157+
// FindPrimaryIdentifierFieldNames returns the resource identifier field name
158+
// for the primary identifier used in a given operation and its corresponding
159+
// shape field name.
160+
func FindPrimaryIdentifierFieldNames(
161+
cfg *ackgenconfig.Config,
162+
r *model.CRD,
163+
op *awssdkmodel.Operation,
164+
) (crField string, shapeField string) {
165+
shape := op.InputRef.Shape
166+
167+
// Attempt to fetch the primary identifier override from the configuration
168+
opConfig, ok := cfg.Operations[op.Name]
169+
if ok {
170+
shapeField = opConfig.PrimaryIdentifierFieldName
171+
}
172+
173+
if shapeField == "" {
174+
// For ReadOne, search for a direct identifier
175+
if op == r.Ops.ReadOne {
176+
identifiers := FindIdentifiersInShape(r, shape)
177+
identifiers = append(identifiers, FindARNIdentifiersInShape(r, shape)...)
178+
179+
switch len(identifiers) {
180+
case 0:
181+
break
182+
case 1:
183+
shapeField = identifiers[0]
184+
default:
185+
panic("Found multiple possible primary identifiers for " +
186+
r.Names.Original + ". Set " +
187+
"`primary_identifier_field_name` for the " + op.Name +
188+
" operation in the generator config.")
189+
}
190+
} else {
191+
// For ReadMany, search for pluralized identifiers
192+
crField, shapeField = FindPluralizedIdentifiersInShape(r, shape)
193+
}
194+
195+
// Require override if still can't find any identifiers
196+
if shapeField == "" {
197+
panic("Could not find primary identifier for " + r.Names.Original +
198+
". Set `primary_identifier_field_name` for the " + op.Name +
199+
" operation in the generator config.")
200+
}
201+
}
202+
203+
if r.IsPrimaryARNField(shapeField) || shapeField == PrimaryIdentifierARNOverride {
204+
return "", PrimaryIdentifierARNOverride
205+
}
206+
207+
if crField == "" {
208+
renamedName, _ := r.InputFieldRename(
209+
op.Name, shapeField,
210+
)
211+
212+
_, inSpec := r.SpecFields[renamedName]
213+
_, inStatus := r.StatusFields[renamedName]
214+
if inSpec || inStatus {
215+
crField = renamedName
216+
} else {
217+
panic("Could not find corresponding spec or status field for primary identifier " + shapeField)
218+
}
219+
}
220+
221+
return crField, shapeField
222+
}

0 commit comments

Comments
 (0)