Skip to content

Commit 384b016

Browse files
committed
aws_appconfig_application: cleanup datasource implementation
1 parent 0d01cab commit 384b016

File tree

1 file changed

+65
-31
lines changed

1 file changed

+65
-31
lines changed

internal/service/appconfig/application_data_source.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,48 @@ package appconfig
66
import (
77
"context"
88
"fmt"
9+
"iter"
910

1011
"github.com/YakDriver/regexache"
1112
"github.com/aws/aws-sdk-go-v2/aws"
1213
"github.com/aws/aws-sdk-go-v2/service/appconfig"
1314
awstypes "github.com/aws/aws-sdk-go-v2/service/appconfig/types"
15+
"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
1416
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
1517
"github.com/hashicorp/terraform-plugin-framework/datasource"
1618
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
19+
"github.com/hashicorp/terraform-plugin-framework/path"
1720
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1821
"github.com/hashicorp/terraform-plugin-framework/types"
19-
"github.com/hashicorp/terraform-provider-aws/internal/errs"
2022
"github.com/hashicorp/terraform-provider-aws/internal/framework"
2123
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
22-
"github.com/hashicorp/terraform-provider-aws/internal/retry"
24+
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
2325
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
26+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
2427
"github.com/hashicorp/terraform-provider-aws/names"
2528
)
2629

27-
// Function annotations are used for datasource registration to the Provider. DO NOT EDIT.
2830
// @FrameworkDataSource("aws_appconfig_application", name="Application")
2931
func newDataSourceApplication(context.Context) (datasource.DataSourceWithConfigure, error) {
3032
return &dataSourceApplication{}, nil
3133
}
3234

33-
const (
34-
DSNameApplication = "Application Data Source"
35-
)
36-
3735
type dataSourceApplication struct {
3836
framework.DataSourceWithModel[dataSourceApplicationModel]
3937
}
4038

4139
func (d *dataSourceApplication) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
4240
resp.Schema = schema.Schema{
4341
Attributes: map[string]schema.Attribute{
42+
names.AttrARN: framework.ARNAttributeComputedOnly(),
4443
names.AttrDescription: schema.StringAttribute{
4544
Computed: true,
4645
Validators: []validator.String{
4746
stringvalidator.LengthBetween(0, 1024),
4847
},
4948
},
5049
names.AttrID: schema.StringAttribute{
50+
Optional: true,
5151
Computed: true,
5252
Validators: []validator.String{
5353
stringvalidator.RegexMatches(
@@ -56,9 +56,9 @@ func (d *dataSourceApplication) Schema(ctx context.Context, req datasource.Schem
5656
),
5757
},
5858
},
59-
//names.AttrARN: framework.ARNAttributeComputedOnly(),
6059
names.AttrName: schema.StringAttribute{
61-
Required: true,
60+
Optional: true,
61+
Computed: true,
6262
Validators: []validator.String{
6363
stringvalidator.LengthBetween(1, 64),
6464
},
@@ -76,53 +76,87 @@ func (d *dataSourceApplication) Read(ctx context.Context, req datasource.ReadReq
7676
return
7777
}
7878

79-
out, err := findApplicationByName(ctx, conn, data.Name.ValueString())
79+
var out *awstypes.Application
80+
var err error
81+
var input appconfig.ListApplicationsInput
82+
if !data.ID.IsNull() {
83+
out, err = findApplicationWithFilter(ctx, conn, &input, func(v *awstypes.Application) bool {
84+
return aws.ToString(v.Id) == data.ID.ValueString()
85+
}, tfslices.WithReturnFirstMatch)
86+
}
87+
88+
if !data.Name.IsNull() {
89+
out, err = findApplicationWithFilter(ctx, conn, &input, func(v *awstypes.Application) bool {
90+
return aws.ToString(v.Name) == data.Name.ValueString()
91+
}, tfslices.WithReturnFirstMatch)
92+
}
93+
8094
if err != nil {
8195
smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, data.Name.String())
8296
return
8397
}
8498

85-
smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &data, flex.WithFieldNamePrefix("Application")), smerr.ID, data.Name.String())
99+
smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &data), smerr.ID, data.Name.String())
86100
if resp.Diagnostics.HasError() {
87101
return
88102
}
89103

104+
data.ARN = flex.StringValueToFramework(ctx, d.Meta().RegionalARN(ctx, "appconfig", "application/"+data.ID.ValueString()))
105+
90106
smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID, data.Name.String())
91107
}
92108

109+
func (d *dataSourceApplication) ConfigValidators(_ context.Context) []datasource.ConfigValidator {
110+
return []datasource.ConfigValidator{
111+
datasourcevalidator.ExactlyOneOf(
112+
path.MatchRoot(names.AttrID),
113+
path.MatchRoot(names.AttrName),
114+
),
115+
}
116+
}
117+
93118
type dataSourceApplicationModel struct {
94119
framework.WithRegionModel
120+
ARN types.String `tfsdk:"arn"`
95121
Description types.String `tfsdk:"description"`
96122
ID types.String `tfsdk:"id"`
97123
Name types.String `tfsdk:"name"`
98124
}
99125

100-
func findApplicationByName(ctx context.Context, conn *appconfig.Client, name string) (*appconfig.GetApplicationOutput, error) {
101-
input := &appconfig.ListApplicationsInput{}
102-
103-
pages := appconfig.NewListApplicationsPaginator(conn, input)
104-
for pages.HasMorePages() {
105-
page, err := pages.NextPage(ctx)
106-
107-
if errs.IsA[*awstypes.ResourceNotFoundException](err) {
108-
return nil, &retry.NotFoundError{
109-
LastError: err,
110-
}
111-
}
112-
126+
func findApplicationWithFilter(ctx context.Context, conn *appconfig.Client, input *appconfig.ListApplicationsInput, filter tfslices.Predicate[*awstypes.Application], optFns ...tfslices.FinderOptionsFunc) (*awstypes.Application, error) {
127+
opts := tfslices.NewFinderOptions(optFns)
128+
var output []awstypes.Application
129+
for value, err := range listApplications(ctx, conn, input, filter) {
113130
if err != nil {
114131
return nil, err
115132
}
116133

117-
for _, app := range page.Items {
118-
if aws.ToString(app.Name) == name {
119-
// AppConfig does not support duplicate names, so we can return the first match
120-
return findApplicationByID(ctx, conn, aws.ToString(app.Id))
121-
}
134+
output = append(output, value)
135+
if opts.ReturnFirstMatch() {
136+
break
122137
}
123138
}
124139

125-
return nil, &retry.NotFoundError{
126-
LastError: fmt.Errorf("AppConfig Application (%s) not found", name),
140+
return tfresource.AssertSingleValueResult(output)
141+
}
142+
143+
func listApplications(ctx context.Context, conn *appconfig.Client, input *appconfig.ListApplicationsInput, filter tfslices.Predicate[*awstypes.Application]) iter.Seq2[awstypes.Application, error] {
144+
return func(yield func(awstypes.Application, error) bool) {
145+
pages := appconfig.NewListApplicationsPaginator(conn, input)
146+
for pages.HasMorePages() {
147+
page, err := pages.NextPage(ctx)
148+
if err != nil {
149+
yield(awstypes.Application{}, fmt.Errorf("listing AppConfig Applications: %w", err))
150+
return
151+
}
152+
153+
for _, v := range page.Items {
154+
if filter(&v) {
155+
if !yield(v, nil) {
156+
return
157+
}
158+
}
159+
}
160+
}
127161
}
128162
}

0 commit comments

Comments
 (0)