Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/iopr 4234 Add datasource autonomi_access_product #24

Merged
merged 3 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions docs/data-sources/access_product.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "autonomi_access_product Data Source - autonomi"
subcategory: ""
description: |-

---

# autonomi_access_product (Data Source)

```terraform
data "autonomi_access_product" "one_product" {
cheapest = true
filters = [
{
name = "location"
operator = "="
values = ["EQUINIX FR5"]
},
{
name = "bandwidth"
operator = "="
values = ["100"]
},
]
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `cheapest` (Boolean) To ensure only one hit is returned we advise to set at true
- `filters` (Attributes List) List of filters: [location, bandwidth]. (see [below for nested schema](#nestedatt--filters))

### Read-Only

- `facet_distribution` (Attributes) The **facet_distribution** attribute provides an overview of the distribution of various facets
within the access products returned by the Meilisearch query. This attribute allows you to analyze the frequency of
different categories or attributes in the search results. (see [below for nested schema](#nestedatt--facet_distribution))
- `hit` (Attributes) The **hit** attribute contains the access products returned by the Meilisearch query.
Each hit represents an access product that matches the specified search criteria.
If no hit is returned, an error will be returned (see [below for nested schema](#nestedatt--hit))

<a id="nestedatt--filters"></a>
### Nested Schema for `filters`

Optional:

- `name` (String)
- `operator` (String)
- `values` (List of String)

<a id="nestedatt--facet_distribution"></a>
### Nested Schema for `facet_distribution`

Read-Only:

- `bandwidth` (Map of Number)
- `location` (Map of Number)
- `provider` (Map of Number)
- `type` (Map of Number)

<a id="nestedatt--hit"></a>
### Nested Schema for `hit`

Read-Only:

- `bandwidth` (Number)
- `cost_mrc` (Number)
- `cost_nrc` (Number)
- `date` (String)
- `duration` (Number)
- `id` (Number)
- `location` (String)
- `price_mrc` (Number)
- `price_nrc` (Number)
- `provider` (String)
- `sku` (String)
- `type` (String)
20 changes: 18 additions & 2 deletions examples/data-sources/autonomi_data_source/data-source.tf
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ data "autonomi_transport_products" "transports" {
]
}

data "autonomi_access_products" "access" {
data "autonomi_access_products" "list_access_products" {
filters = [
{
name = "location"
Expand All @@ -59,4 +59,20 @@ data "autonomi_access_products" "access" {
values = ["100", "500"]
},
]
}
}

data "autonomi_access_product" "one_product" {
cheapest = true
filters = [
{
name = "location"
operator = "="
values = ["EQUINIX FR5"]
},
{
name = "bandwidth"
operator = "="
values = ["100"]
},
]
}
139 changes: 60 additions & 79 deletions internal/data_sources/access_product_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"sort"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
Expand All @@ -16,32 +17,10 @@ type accessProductDataSource struct {
client *meilisearch.Client
}

type accessHits struct {
ID types.Int64 `tfsdk:"id"`
Provider types.String `tfsdk:"provider"`
Duration types.Int64 `tfsdk:"duration"`
Location types.String `tfsdk:"location"`
Bandwidth types.Int64 `tfsdk:"bandwidth"`
Date types.String `tfsdk:"date"`
PriceNRC types.Float64 `tfsdk:"price_nrc"`
PriceMRC types.Float64 `tfsdk:"price_mrc"`
CostNRC types.Float64 `tfsdk:"cost_nrc"`
CostMRC types.Float64 `tfsdk:"cost_mrc"`
SKU types.String `tfsdk:"sku"`
Type types.String `tfsdk:"type"`
}

type accessFacetDistributionDataSourceModel struct {
Bandwidth map[string]int `tfsdk:"bandwidth"`
Location map[string]int `tfsdk:"location"`
Provider map[string]int `tfsdk:"provider"`
Type map[string]int `tfsdk:"type"`
}

type accessProductDataSourceModel struct {
Cheapest bool `tfsdk:"cheapest"`
Filters []filter `tfsdk:"filters"`
Sort []sort `tfsdk:"sort"`
Hits []accessHits `tfsdk:"hits"`
Hit *accessHits `tfsdk:"hit"`
FacetDistribution *accessFacetDistributionDataSourceModel `tfsdk:"facet_distribution"`
}

Expand All @@ -57,15 +36,19 @@ func NewAccessProductDataSource() datasource.DataSource {

// Metadata returns the data source type name.
func (d *accessProductDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_access_products"
resp.TypeName = req.ProviderTypeName + "_access_product"
}

// Schema defines the schema for the data source.
func (d *accessProductDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"cheapest": schema.BoolAttribute{
MarkdownDescription: "To ensure only one hit is returned we advise to set at true",
Optional: true,
},
"filters": schema.ListNestedAttribute{
MarkdownDescription: "List of filters: [location, bandwidth]",
MarkdownDescription: "List of filters: [location, bandwidth].",
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
Expand All @@ -82,39 +65,24 @@ func (d *accessProductDataSource) Schema(_ context.Context, _ datasource.SchemaR
},
},
},
"sort": schema.ListNestedAttribute{
MarkdownDescription: "List of sort: [location, bandwidth, priceNrc, priceMrc, costNrc, costMrc]",
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Optional: true,
},
"value": schema.StringAttribute{
Optional: true,
},
},
},
},
"hits": schema.ListNestedAttribute{
MarkdownDescription: `The **hits** attribute contains the list of cloud products returned by the Meilisearch query.
Each hit represents an access product that matches the specified search criteria.`,
"hit": schema.SingleNestedAttribute{
MarkdownDescription: `The **hit** attribute contains the access products returned by the Meilisearch query.
Each hit represents an access product that matches the specified search criteria.
If no hit is returned, an error will be returned`,
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{Computed: true},
"provider": schema.StringAttribute{Computed: true},
"duration": schema.Int64Attribute{Computed: true},
"location": schema.StringAttribute{Computed: true},
"bandwidth": schema.Int64Attribute{Computed: true},
"date": schema.StringAttribute{Computed: true},
"price_nrc": schema.Int64Attribute{Computed: true},
"price_mrc": schema.Int64Attribute{Computed: true},
"cost_nrc": schema.Int64Attribute{Computed: true},
"cost_mrc": schema.Int64Attribute{Computed: true},
"sku": schema.StringAttribute{Computed: true},
"type": schema.StringAttribute{Computed: true},
},
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{Computed: true},
"provider": schema.StringAttribute{Computed: true},
"duration": schema.Int64Attribute{Computed: true},
"location": schema.StringAttribute{Computed: true},
"bandwidth": schema.Int64Attribute{Computed: true},
"date": schema.StringAttribute{Computed: true},
"price_nrc": schema.Int64Attribute{Computed: true},
"price_mrc": schema.Int64Attribute{Computed: true},
"cost_nrc": schema.Int64Attribute{Computed: true},
"cost_mrc": schema.Int64Attribute{Computed: true},
"sku": schema.StringAttribute{Computed: true},
"type": schema.StringAttribute{Computed: true},
},
},
"facet_distribution": schema.SingleNestedAttribute{
Expand Down Expand Up @@ -205,8 +173,7 @@ func (d *accessProductDataSource) Read(ctx context.Context, req datasource.ReadR
return
}

err = json.Unmarshal(productsJSON, &accessProducts) // Unmarshal JSON into the CloudProduct slice
if err != nil {
if err := json.Unmarshal(productsJSON, &accessProducts); err != nil { // Unmarshal JSON into the AccessProduct slice
resp.Diagnostics.AddError(
"Unable to Read Autonomi Access Products",
err.Error(),
Expand All @@ -216,26 +183,40 @@ func (d *accessProductDataSource) Read(ctx context.Context, req datasource.ReadR

state := accessProductDataSourceModel{
Filters: data.Filters,
Sort: data.Sort,
}

// Map response body to model
for _, ap := range accessProducts.Hits {
accessProductState := accessHits{
ID: types.Int64Value(int64(ap.ID)),
Provider: types.StringValue(ap.Provider),
Duration: types.Int64Value(int64(ap.Duration)),
Location: types.StringValue(ap.Location),
Bandwidth: types.Int64Value(int64(ap.Bandwidth)),
Date: types.StringValue(ap.Date),
PriceNRC: types.Float64Value(float64(ap.PriceNRC)),
PriceMRC: types.Float64Value(float64(ap.PriceMRC)),
CostNRC: types.Float64Value(float64(ap.CostNRC)),
CostMRC: types.Float64Value(float64(ap.CostMRC)),
SKU: types.StringValue(ap.SKU),
Type: types.StringValue(ap.Type),
}

if accessProducts.Hits == nil {
resp.Diagnostics.AddError("Not hit found", "")
return
}

// If Meiliesearch return more than one hit, check if `cheapest` filter has been set.
// If not, an error is returned, otherwise a sort will be done to order the list by price mrc. The first entry will be returned
if len(accessProducts.Hits) > 1 {
if !data.Cheapest {
resp.Diagnostics.AddError("Request got more than one hit, please add filters [location, bandwidth, cheapest]", "")
return
}
state.Hits = append(state.Hits, accessProductState)
// sort slice by price mrc if cheapest=true is set
sort.Slice(accessProducts.Hits, func(i, j int) bool {
return accessProducts.Hits[i].PriceMRC < accessProducts.Hits[j].PriceMRC
})
}

ap := accessProducts.Hits[0]
state.Hit = &accessHits{
ID: types.Int64Value(int64(ap.ID)),
Provider: types.StringValue(ap.Provider),
Duration: types.Int64Value(int64(ap.Duration)),
Location: types.StringValue(ap.Location),
Bandwidth: types.Int64Value(int64(ap.Bandwidth)),
Date: types.StringValue(ap.Date),
PriceNRC: types.Float64Value(float64(ap.PriceNRC)),
PriceMRC: types.Float64Value(float64(ap.PriceMRC)),
CostNRC: types.Float64Value(float64(ap.CostNRC)),
CostMRC: types.Float64Value(float64(ap.CostMRC)),
SKU: types.StringValue(ap.SKU),
Type: types.StringValue(ap.Type),
}

// Set the bandwidth map in the state
Expand Down
Loading
Loading