Skip to content

Commit

Permalink
feat: Adds stored_source attribute to mongodbatlas_search_index r…
Browse files Browse the repository at this point in the history
…esource and corresponding data sources (#2388)

* fix ds schemas

* add changelog

* add storedSource to configBasic and checkBasic

* update doc about index_id

* update boolean test

* first implementation of stored_source as string

* create model file

* marshal

* don't allow update

* test for objects in stored_source

* TestAccSearchIndex_withStoredSourceUpdate

* update StoredSource

* fix merge

* tests for storedSource updates

* swap test names

* doc
  • Loading branch information
lantoli authored Jul 14, 2024
1 parent c2b384b commit 749292c
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 211 deletions.
11 changes: 11 additions & 0 deletions .changelog/2388.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
```release-note:enhancement
resource/mongodbatlas_search_index: Adds attribute `stored_source`
```

```release-note:enhancement
data-source/mongodbatlas_search_index: Adds attribute `stored_source`
```

```release-note:enhancement
data-source/mongodbatlas_search_indexes: Adds attribute `stored_source`
```
42 changes: 26 additions & 16 deletions internal/service/searchindex/data_source_search_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,35 @@ func returnSearchIndexDSSchema() map[string]*schema.Schema {
},
"analyzer": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"analyzers": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: validateSearchAnalyzersDiff,
Type: schema.TypeString,
Computed: true,
},
"collection_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"database": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"search_analyzer": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"mappings_dynamic": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"mappings_fields": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: validateSearchIndexMappingDiff,
Type: schema.TypeString,
Computed: true,
},
"synonyms": {
Type: schema.TypeSet,
Expand Down Expand Up @@ -90,12 +88,15 @@ func returnSearchIndexDSSchema() map[string]*schema.Schema {
},
"type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"fields": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: validateSearchIndexMappingDiff,
Type: schema.TypeString,
Computed: true,
},
"stored_source": {
Type: schema.TypeString,
Computed: true,
},
}
}
Expand Down Expand Up @@ -185,6 +186,15 @@ func dataSourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resour
}
}

storedSource := searchIndex.LatestDefinition.GetStoredSource()
strStoredSource, errStoredSource := MarshalStoredSource(storedSource)
if errStoredSource != nil {
return diag.FromErr(errStoredSource)
}
if err := d.Set("stored_source", strStoredSource); err != nil {
return diag.Errorf("error setting `stored_source` for search index (%s): %s", d.Id(), err)
}

d.SetId(conversion.EncodeStateID(map[string]string{
"project_id": projectID.(string),
"cluster_name": clusterName.(string),
Expand Down
10 changes: 8 additions & 2 deletions internal/service/searchindex/data_source_search_indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func PluralDataSource() *schema.Resource {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: returnSearchIndexSchema(),
Schema: returnSearchIndexDSSchema(),
},
},
"total_count": {
Expand Down Expand Up @@ -131,7 +131,13 @@ func flattenSearchIndexes(searchIndexes []admin.SearchIndexResponse, projectID,
}
searchIndexesMap[i]["fields"] = fieldsMarshaled
}
}

storedSource := searchIndexes[i].LatestDefinition.GetStoredSource()
strStoredSource, errStoredSource := MarshalStoredSource(storedSource)
if errStoredSource != nil {
return nil, errStoredSource
}
searchIndexesMap[i]["stored_source"] = strStoredSource
}
return searchIndexesMap, nil
}
151 changes: 151 additions & 0 deletions internal/service/searchindex/model_search_index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package searchindex

import (
"bytes"
"context"
"encoding/json"
"log"
"strconv"

"github.com/go-test/deep"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
"go.mongodb.org/atlas-sdk/v20240530002/admin"
)

func flattenSearchIndexSynonyms(synonyms []admin.SearchSynonymMappingDefinition) []map[string]any {
synonymsMap := make([]map[string]any, len(synonyms))
for i, s := range synonyms {
synonymsMap[i] = map[string]any{
"name": s.Name,
"analyzer": s.Analyzer,
"source_collection": s.Source.Collection,
}
}
return synonymsMap
}

func expandSearchIndexSynonyms(d *schema.ResourceData) []admin.SearchSynonymMappingDefinition {
var synonymsList []admin.SearchSynonymMappingDefinition
if vSynonyms, ok := d.GetOk("synonyms"); ok {
for _, s := range vSynonyms.(*schema.Set).List() {
synonym := s.(map[string]any)
synonymsDoc := admin.SearchSynonymMappingDefinition{
Name: synonym["name"].(string),
Analyzer: synonym["analyzer"].(string),
Source: admin.SynonymSource{
Collection: synonym["source_collection"].(string),
},
}
synonymsList = append(synonymsList, synonymsDoc)
}
}
return synonymsList
}

func marshalSearchIndex(fields any) (string, error) {
respBytes, err := json.Marshal(fields)
return string(respBytes), err
}

func unmarshalSearchIndexMappingFields(str string) (map[string]any, diag.Diagnostics) {
fields := map[string]any{}
if str == "" {
return fields, nil
}
if err := json.Unmarshal([]byte(str), &fields); err != nil {
return nil, diag.Errorf("cannot unmarshal search index attribute `mappings_fields` because it has an incorrect format")
}
return fields, nil
}

func unmarshalSearchIndexFields(str string) ([]map[string]any, diag.Diagnostics) {
fields := []map[string]any{}
if str == "" {
return fields, nil
}
if err := json.Unmarshal([]byte(str), &fields); err != nil {
return nil, diag.Errorf("cannot unmarshal search index attribute `fields` because it has an incorrect format")
}

return fields, nil
}

func unmarshalSearchIndexAnalyzersFields(str string) ([]admin.AtlasSearchAnalyzer, diag.Diagnostics) {
fields := []admin.AtlasSearchAnalyzer{}
if str == "" {
return fields, nil
}
dec := json.NewDecoder(bytes.NewReader([]byte(str)))
dec.DisallowUnknownFields()
if err := dec.Decode(&fields); err != nil {
return nil, diag.Errorf("cannot unmarshal search index attribute `analyzers` because it has an incorrect format")
}
return fields, nil
}

func MarshalStoredSource(obj any) (string, error) {
if obj == nil {
return "", nil
}
if b, ok := obj.(bool); ok {
return strconv.FormatBool(b), nil
}
respBytes, err := json.Marshal(obj)
return string(respBytes), err
}

func UnmarshalStoredSource(str string) (any, diag.Diagnostics) {
switch str {
case "":
return any(nil), nil
case "true":
return true, nil
case "false":
return false, nil
default:
var obj any
if err := json.Unmarshal([]byte(str), &obj); err != nil {
return nil, diag.Errorf("cannot unmarshal search index attribute `stored_source` because it has an incorrect format")
}
return obj, nil
}
}

func diffSuppressJSON(k, old, newStr string, d *schema.ResourceData) bool {
var j, j2 any

if old == "" {
old = "{}"
}

if newStr == "" {
newStr = "{}"
}

if err := json.Unmarshal([]byte(old), &j); err != nil {
log.Printf("[ERROR] cannot unmarshal old search index analyzer json %v", err)
}
if err := json.Unmarshal([]byte(newStr), &j2); err != nil {
log.Printf("[ERROR] cannot unmarshal new search index analyzer json %v", err)
}
if diff := deep.Equal(&j, &j2); diff != nil {
log.Printf("[DEBUG] deep equal not passed: %v", diff)
return false
}

return true
}

func resourceSearchIndexRefreshFunc(ctx context.Context, clusterName, projectID, indexID string, connV2 *admin.APIClient) retry.StateRefreshFunc {
return func() (any, string, error) {
searchIndex, _, err := connV2.AtlasSearchApi.GetAtlasSearchIndex(ctx, projectID, clusterName, indexID).Execute()
if err != nil {
return nil, "ERROR", err
}
status := conversion.SafeString(searchIndex.Status)
return searchIndex, status, nil
}
}
Loading

0 comments on commit 749292c

Please sign in to comment.