diff --git a/docs/data-sources/audience.md b/docs/data-sources/audience.md new file mode 100644 index 0000000..4ff26aa --- /dev/null +++ b/docs/data-sources/audience.md @@ -0,0 +1,97 @@ +# segment_audience Data Source + +Fetches a Segment Audience by space and ID. + +## Example Usage + +```hcl +resource "segment_audience" "example" { + space_id = "your_space_id" + name = "Test Audience" + description = "Created by Terraform" + definition = { + query = "event('Shoes Bought').count() >= 1" + } +} + +data "segment_audience" "example" { + space_id = segment_audience.example.space_id + id = segment_audience.example.id +} +``` + +## Argument Reference + +- `space_id` (Required) — The Segment Space ID. +- `id` (Required) — The Audience ID. + +## Attributes Reference + +The following attributes are exported: + +- `name` — The name of the Audience. +- `description` — The description of the Audience. +- `key` — The key of the Audience. +- `enabled` — Whether the Audience is enabled. +- `definition` — The definition of the Audience (map). +- `status` — The status of the Audience. +- `options` — Additional options for the Audience (map). + +## Advanced Usage & Test Scenarios + +### Error Scenario: Not Found + +If you attempt to look up an Audience that does not exist, the data source will return an error. This is useful for negative testing and validation. + +**Example:** + +```hcl +# This will fail if the audience does not exist + +data "segment_audience" "not_found" { + space_id = "your_space_id" + id = "audience_does_not_exist" +} +``` + +**Expected error:** + +``` +Error: Unable to read Audience: ... +``` + +--- + +### Complex Attribute Validation + +The data source supports complex/nested attributes, such as advanced queries and boolean options. You can validate these in your tests or usage. + +**Example:** + +```hcl +resource "segment_audience" "complex" { + space_id = "your_space_id" + name = "Complex Audience" + description = "Testing complex attributes" + definition = { + query = "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2" + } + options = { + includeHistoricalData = true + } +} + +data "segment_audience" "complex" { + space_id = segment_audience.complex.space_id + id = segment_audience.complex.id +} +``` + +You can then assert on these attributes in your tests or outputs: + +- `definition.query` should match the complex query string. +- `options.includeHistoricalData` should be `true`. + +--- + +For more test examples, see the provider's `internal/provider/audience_data_source_test.go` file. \ No newline at end of file diff --git a/internal/provider/audience_data_source.go b/internal/provider/audience_data_source.go new file mode 100644 index 0000000..c90eb70 --- /dev/null +++ b/internal/provider/audience_data_source.go @@ -0,0 +1,112 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/segmentio/public-api-sdk-go/api" + "github.com/segmentio/terraform-provider-segment/internal/provider/models" +) + +var _ datasource.DataSource = &audienceDataSource{} +var _ datasource.DataSourceWithConfigure = &audienceDataSource{} + +func NewAudienceDataSource() datasource.DataSource { + return &audienceDataSource{} +} + +type audienceDataSource struct { + client *api.APIClient + authContext context.Context +} + +func (d *audienceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_audience" +} + +func (d *audienceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "space_id": schema.StringAttribute{ + Required: true, + Description: "The Space ID.", + }, + "id": schema.StringAttribute{ + Required: true, + Description: "The Audience ID.", + }, + "name": schema.StringAttribute{ + Computed: true, + Description: "The name of the Audience.", + }, + "description": schema.StringAttribute{ + Computed: true, + Description: "The description of the Audience.", + }, + "key": schema.StringAttribute{ + Computed: true, + Description: "The key of the Audience.", + }, + "enabled": schema.BoolAttribute{ + Computed: true, + Description: "Whether the Audience is enabled.", + }, + "definition": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + Description: "The definition of the Audience.", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "The status of the Audience.", + }, + "options": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + Description: "Additional options for the Audience.", + }, + }, + } +} + +func (d *audienceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data models.AudienceState + diags := req.Config.Get(ctx, &data) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + out, _, err := d.client.GetAudience(d.authContext, data.SpaceID.ValueString(), data.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Unable to read Audience", err.Error()) + return + } + audience := out.Data.Audience + data.Name = types.StringValue(audience.Name) + data.Description = types.StringValue(audience.Description) + data.Key = types.StringValue(audience.Key) + data.Enabled = types.BoolValue(audience.Enabled) + data.Status = types.StringValue(audience.Status) + // TODO: convert audience.Definition and audience.Options to types.Map + diags = resp.State.Set(ctx, &data) + resp.Diagnostics.Append(diags...) +} + +func (d *audienceDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + config, ok := req.ProviderData.(*ClientInfo) + if !ok { + resp.Diagnostics.AddError( + "Unexpected DataSource Configure Type", + fmt.Sprintf("Expected ClientInfo, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + d.client = config.client + d.authContext = config.authContext +} diff --git a/internal/provider/audience_data_source_test.go b/internal/provider/audience_data_source_test.go new file mode 100644 index 0000000..86ffc82 --- /dev/null +++ b/internal/provider/audience_data_source_test.go @@ -0,0 +1,108 @@ +package provider + +import ( + "os" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccAudienceDataSource_basic(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceDataSourceConfig(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.segment_audience.test", "id"), + resource.TestCheckResourceAttr("data.segment_audience.test", "name", "Test Audience"), + ), + }, + }, + }) +} + +func TestAccAudienceDataSource_notFound(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceDataSourceConfigNotFound(spaceID), + ExpectError: regexp.MustCompile(`(?i)Unable to read Audience`), + }, + }, + }) +} + +func TestAccAudienceDataSource_complexAttributes(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceDataSourceConfigComplex(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.segment_audience.test", "definition.query", "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2"), + resource.TestCheckResourceAttr("data.segment_audience.test", "options.includeHistoricalData", "true"), + ), + }, + }, + }) +} + +func testAccAudienceDataSourceConfig(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Test Audience" + description = "Created by Terraform acceptance test" + definition = { + query = "event('Shoes Bought').count() >= 1" + } +} + +data "segment_audience" "test" { + space_id = segment_audience.test.space_id + id = segment_audience.test.id +} +` +} + +func testAccAudienceDataSourceConfigNotFound(spaceID string) string { + return ` +data "segment_audience" "test" { + space_id = "` + spaceID + `" + id = "audience_does_not_exist" +} +` +} + +func testAccAudienceDataSourceConfigComplex(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Complex Audience" + description = "Testing complex attributes" + definition = { + query = "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2" + } + options = { + includeHistoricalData = true + } +} + +data "segment_audience" "test" { + space_id = segment_audience.test.space_id + id = segment_audience.test.id +} +` +} diff --git a/internal/provider/audience_resource.go b/internal/provider/audience_resource.go new file mode 100644 index 0000000..1ad9423 --- /dev/null +++ b/internal/provider/audience_resource.go @@ -0,0 +1,246 @@ +package provider + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/segmentio/public-api-sdk-go/api" + "github.com/segmentio/terraform-provider-segment/internal/provider/models" +) + +var ( + _ resource.Resource = &audienceResource{} + _ resource.ResourceWithConfigure = &audienceResource{} + _ resource.ResourceWithImportState = &audienceResource{} +) + +func NewAudienceResource() resource.Resource { + return &audienceResource{} +} + +type audienceResource struct { + client *api.APIClient + authContext context.Context +} + +func (r *audienceResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_audience" +} + +func (r *audienceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The Audience ID.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "space_id": schema.StringAttribute{ + Required: true, + Description: "The Space ID.", + }, + "name": schema.StringAttribute{ + Required: true, + Description: "The name of the Audience.", + }, + "description": schema.StringAttribute{ + Optional: true, + Description: "The description of the Audience.", + }, + "key": schema.StringAttribute{ + Optional: true, + Description: "The key of the Audience.", + }, + "enabled": schema.BoolAttribute{ + Optional: true, + Description: "Whether the Audience is enabled.", + }, + "definition": schema.MapAttribute{ + ElementType: types.StringType, + Required: true, + Description: "The definition of the Audience.", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "The status of the Audience.", + }, + "options": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Additional options for the Audience.", + }, + }, + } +} + +// TODO: Implement Create, Read, Update, Delete, ImportState, Configure methods using the SDK + +func (r *audienceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan models.AudienceState + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + input := api.CreateAudienceInput{ + Name: plan.Name.ValueString(), + Description: plan.Description.ValueString(), + Key: plan.Key.ValueString(), + Enabled: plan.Enabled.ValueBool(), + Options: nil, // TODO: convert plan.Options to map[string]interface{} + Definition: nil, // TODO: convert plan.Definition to map[string]interface{} + } + // Convert plan.Definition and plan.Options from types.Map to map[string]interface{} + if !plan.Definition.IsNull() && !plan.Definition.IsUnknown() { + var def map[string]interface{} + diags := plan.Definition.ElementsAs(ctx, &def, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + input.Definition = def + } + if !plan.Options.IsNull() && !plan.Options.IsUnknown() { + var opts map[string]interface{} + diags := plan.Options.ElementsAs(ctx, &opts, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + input.Options = opts + } + + out, _, err := r.client.CreateAudience(r.authContext, plan.SpaceID.ValueString(), input) + if err != nil { + resp.Diagnostics.AddError("Unable to create Audience", err.Error()) + return + } + audience := out.Data.Audience + plan.ID = types.StringValue(audience.Id) + plan.Status = types.StringValue(audience.Status) + // Set other fields as needed + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *audienceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state models.AudienceState + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + out, _, err := r.client.GetAudience(r.authContext, state.SpaceID.ValueString(), state.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Unable to read Audience", err.Error()) + return + } + audience := out.Data.Audience + state.Name = types.StringValue(audience.Name) + state.Description = types.StringValue(audience.Description) + state.Key = types.StringValue(audience.Key) + state.Enabled = types.BoolValue(audience.Enabled) + state.Status = types.StringValue(audience.Status) + // TODO: convert audience.Definition and audience.Options to types.Map + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) +} + +func (r *audienceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan models.AudienceState + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + input := api.UpdateAudienceInput{ + Name: plan.Name.ValueString(), + Description: plan.Description.ValueString(), + Key: plan.Key.ValueString(), + Enabled: plan.Enabled.ValueBool(), + Options: nil, // TODO: convert plan.Options to map[string]interface{} + Definition: nil, // TODO: convert plan.Definition to map[string]interface{} + } + if !plan.Definition.IsNull() && !plan.Definition.IsUnknown() { + var def map[string]interface{} + diags := plan.Definition.ElementsAs(ctx, &def, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + input.Definition = def + } + if !plan.Options.IsNull() && !plan.Options.IsUnknown() { + var opts map[string]interface{} + diags := plan.Options.ElementsAs(ctx, &opts, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + input.Options = opts + } + out, _, err := r.client.UpdateAudience(r.authContext, plan.SpaceID.ValueString(), plan.ID.ValueString(), input) + if err != nil { + resp.Diagnostics.AddError("Unable to update Audience", err.Error()) + return + } + audience := out.Data.Audience + plan.Status = types.StringValue(audience.Status) + // Set other fields as needed + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *audienceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state models.AudienceState + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + _, err := r.client.DeleteAudience(r.authContext, state.SpaceID.ValueString(), state.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Unable to delete Audience", err.Error()) + return + } +} + +func (r *audienceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // Expect import ID as : + idParts := strings.Split(req.ID, ":") + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: :. Got: %q", req.ID), + ) + return + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("space_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) +} + +func (r *audienceResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + config, ok := req.ProviderData.(*ClientInfo) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected ClientInfo, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + r.client = config.client + r.authContext = config.authContext +} diff --git a/internal/provider/audience_resource_test.go b/internal/provider/audience_resource_test.go new file mode 100644 index 0000000..fb875a4 --- /dev/null +++ b/internal/provider/audience_resource_test.go @@ -0,0 +1,202 @@ +package provider + +import ( + "fmt" + "os" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + tfstate "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccAudienceResource_basic(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + // ProviderFactories: testAccProviderFactories, // Uncomment if you use provider factories + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfig(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("segment_audience.test", "id"), + resource.TestCheckResourceAttr("segment_audience.test", "name", "Test Audience"), + ), + }, + }, + }) +} + +func TestAccAudienceResource_update(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfig(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("segment_audience.test", "id"), + resource.TestCheckResourceAttr("segment_audience.test", "name", "Test Audience"), + ), + }, + { + Config: testAccAudienceResourceConfigUpdate(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("segment_audience.test", "name", "Updated Audience"), + resource.TestCheckResourceAttr("segment_audience.test", "description", "Updated by Terraform acceptance test"), + ), + }, + }, + }) +} + +func TestAccAudienceResource_import(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resourceName := "segment_audience.test" + resource.Test(t, resource.TestCase{ + // ProviderFactories: testAccProviderFactories, // Uncomment if you use provider factories + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfig(spaceID), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: func(s *tfstate.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + spaceID := rs.Primary.Attributes["space_id"] + id := rs.Primary.ID + return fmt.Sprintf("%s:%s", spaceID, id), nil + }, + }, + }, + }) +} + +func TestAccAudienceResource_delete(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resourceName := "segment_audience.test" + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfig(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resourceName, "id"), + ), + }, + { + ResourceName: resourceName, + Config: "", + Check: func(s *tfstate.State) error { + if _, ok := s.RootModule().Resources[resourceName]; ok { + return fmt.Errorf("Resource %s still exists after delete", resourceName) + } + return nil + }, + Destroy: true, + }, + }, + }) +} + +func TestAccAudienceResource_error_invalidDefinition(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfigInvalidDefinition(spaceID), + ExpectError: regexp.MustCompile(`(?i)definition`), + }, + }, + }) +} + +func TestAccAudienceResource_complexAttributes(t *testing.T) { + spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID") + if spaceID == "" { + t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.") + } + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: testAccAudienceResourceConfigComplex(spaceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("segment_audience.test", "definition.query", "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2"), + resource.TestCheckResourceAttr("segment_audience.test", "options.includeHistoricalData", "true"), + ), + }, + }, + }) +} + +func testAccAudienceResourceConfig(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Test Audience" + description = "Created by Terraform acceptance test" + definition = { + query = "event('Shoes Bought').count() >= 1" + } +} +` +} + +func testAccAudienceResourceConfigUpdate(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Updated Audience" + description = "Updated by Terraform acceptance test" + definition = { + query = "event('Shoes Bought').count() >= 2" + } +} +` +} + +func testAccAudienceResourceConfigInvalidDefinition(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Invalid Audience" + description = "Should fail" + definition = { + invalid_field = "not a valid query" + } +} +` +} + +func testAccAudienceResourceConfigComplex(spaceID string) string { + return ` +resource "segment_audience" "test" { + space_id = "` + spaceID + `" + name = "Complex Audience" + description = "Testing complex attributes" + definition = { + query = "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2" + } + options = { + includeHistoricalData = true + } +} +` +} diff --git a/internal/provider/models/audience.go b/internal/provider/models/audience.go new file mode 100644 index 0000000..0f34f08 --- /dev/null +++ b/internal/provider/models/audience.go @@ -0,0 +1,17 @@ +package models + +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type AudienceState struct { + ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Key types.String `tfsdk:"key"` + Enabled types.Bool `tfsdk:"enabled"` + Definition types.Map `tfsdk:"definition"` + Status types.String `tfsdk:"status"` + Options types.Map `tfsdk:"options"` +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 524646c..819a819 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -177,6 +177,7 @@ func (p *segmentProvider) DataSources(_ context.Context) []func() datasource.Dat NewTrackingPlanDataSource, NewRoleDataSource, NewUserDataSource, + NewAudienceDataSource, } }