Skip to content

Commit 921c7b2

Browse files
lantoliZuhairahmed
andauthored
feat: Adds type and fields attributes in resource and data sources for search_index (#1605) INTMDB-1260
* add type field * add fields field * log when using existing cluster * remove skip * change random prefixes * fix tests * const collectionName * const searchAnalyzer * const resourceName and datasourceName * reduce cluster name size * don't check dangling indices for existing clusters as it takes some time for them to be deleted * failing test for vector search index * create vector index in test * change data source * continue if it can't unmarshal * add fields to search-indexes data source * initial doc * small fix in doc * fix example * Update search_index.html.markdown formatting * Update search_index.html.markdown formatting * adapt doc and example for Fields * detect format errors in fields and mappings_fields * detect format errors in analyzers * test stringified JSON attributes for fields * generic json diff check * test with explicit search type --------- Co-authored-by: Zuhair Ahmed <[email protected]>
1 parent 47469dd commit 921c7b2

5 files changed

+467
-153
lines changed

mongodbatlas/data_source_mongodbatlas_search_index.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ func returnSearchIndexDSSchema() map[string]*schema.Schema {
8787
Optional: true,
8888
Computed: true,
8989
},
90+
"type": {
91+
Type: schema.TypeString,
92+
Optional: true,
93+
},
94+
"fields": {
95+
Type: schema.TypeString,
96+
Optional: true,
97+
DiffSuppressFunc: validateSearchIndexMappingDiff,
98+
},
9099
}
91100
}
92101

@@ -105,6 +114,10 @@ func dataSourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resour
105114
return diag.Errorf("error getting search index information: %s", err)
106115
}
107116

117+
if err := d.Set("type", searchIndex.Type); err != nil {
118+
return diag.Errorf("error setting `type` for search index (%s): %s", d.Id(), err)
119+
}
120+
108121
if err := d.Set("index_id", indexID); err != nil {
109122
return diag.Errorf("error setting `index_id` for search index (%s): %s", d.Id(), err)
110123
}
@@ -140,21 +153,34 @@ func dataSourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resour
140153
return diag.Errorf("error setting `searchAnalyzer` for search index (%s): %s", d.Id(), err)
141154
}
142155

143-
if err := d.Set("mappings_dynamic", searchIndex.Mappings.Dynamic); err != nil {
144-
return diag.Errorf("error setting `mappings_dynamic` for search index (%s): %s", d.Id(), err)
145-
}
146-
147156
if err := d.Set("synonyms", flattenSearchIndexSynonyms(searchIndex.Synonyms)); err != nil {
148157
return diag.Errorf("error setting `synonyms` for search index (%s): %s", d.Id(), err)
149158
}
150159

151-
if len(searchIndex.Mappings.Fields) > 0 {
152-
searchIndexMappingFields, err := marshalSearchIndex(searchIndex.Mappings.Fields)
160+
if searchIndex.Mappings != nil {
161+
if err := d.Set("mappings_dynamic", searchIndex.Mappings.Dynamic); err != nil {
162+
return diag.Errorf("error setting `mappings_dynamic` for search index (%s): %s", d.Id(), err)
163+
}
164+
165+
if len(searchIndex.Mappings.Fields) > 0 {
166+
searchIndexMappingFields, err := marshalSearchIndex(searchIndex.Mappings.Fields)
167+
if err != nil {
168+
return diag.FromErr(err)
169+
}
170+
if err := d.Set("mappings_fields", searchIndexMappingFields); err != nil {
171+
return diag.Errorf("error setting `mappings_fields` for for search index (%s): %s", d.Id(), err)
172+
}
173+
}
174+
}
175+
176+
if len(searchIndex.Fields) > 0 {
177+
fields, err := marshalSearchIndex(searchIndex.Fields)
153178
if err != nil {
154179
return diag.FromErr(err)
155180
}
156-
if err := d.Set("mappings_fields", searchIndexMappingFields); err != nil {
157-
return diag.Errorf("error setting `mappings_fields` for for search index (%s): %s", d.Id(), err)
181+
182+
if err := d.Set("fields", fields); err != nil {
183+
return diag.Errorf("error setting `fields` for for search index (%s): %s", d.Id(), err)
158184
}
159185
}
160186

mongodbatlas/data_source_mongodbatlas_search_indexes.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,25 +100,29 @@ func flattenSearchIndexes(searchIndexes []admin.ClusterSearchIndex, projectID, c
100100

101101
for i := range searchIndexes {
102102
searchIndexesMap[i] = map[string]any{
103-
"project_id": projectID,
104-
"cluster_name": clusterName,
105-
"analyzer": searchIndexes[i].Analyzer,
106-
"collection_name": searchIndexes[i].CollectionName,
107-
"database": searchIndexes[i].Database,
108-
"index_id": searchIndexes[i].IndexID,
109-
"mappings_dynamic": searchIndexes[i].Mappings.Dynamic,
110-
"name": searchIndexes[i].Name,
111-
"search_analyzer": searchIndexes[i].SearchAnalyzer,
112-
"status": searchIndexes[i].Status,
113-
"synonyms": flattenSearchIndexSynonyms(searchIndexes[i].Synonyms),
103+
"project_id": projectID,
104+
"cluster_name": clusterName,
105+
"analyzer": searchIndexes[i].Analyzer,
106+
"collection_name": searchIndexes[i].CollectionName,
107+
"database": searchIndexes[i].Database,
108+
"index_id": searchIndexes[i].IndexID,
109+
"name": searchIndexes[i].Name,
110+
"search_analyzer": searchIndexes[i].SearchAnalyzer,
111+
"status": searchIndexes[i].Status,
112+
"synonyms": flattenSearchIndexSynonyms(searchIndexes[i].Synonyms),
113+
"type": searchIndexes[i].Type,
114114
}
115115

116-
if len(searchIndexes[i].Mappings.Fields) > 0 {
117-
searchIndexMappingFields, err := marshalSearchIndex(searchIndexes[i].Mappings.Fields)
118-
if err != nil {
119-
return nil, err
116+
if searchIndexes[i].Mappings != nil {
117+
searchIndexesMap[i]["mappings_dynamic"] = searchIndexes[i].Mappings.Dynamic
118+
119+
if len(searchIndexes[i].Mappings.Fields) > 0 {
120+
searchIndexMappingFields, err := marshalSearchIndex(searchIndexes[i].Mappings.Fields)
121+
if err != nil {
122+
return nil, err
123+
}
124+
searchIndexesMap[i]["mappings_fields"] = searchIndexMappingFields
120125
}
121-
searchIndexesMap[i]["mappings_fields"] = searchIndexMappingFields
122126
}
123127

124128
if len(searchIndexes[i].Analyzers) > 0 {
@@ -128,6 +132,14 @@ func flattenSearchIndexes(searchIndexes []admin.ClusterSearchIndex, projectID, c
128132
}
129133
searchIndexesMap[i]["analyzers"] = searchIndexAnalyzers
130134
}
135+
136+
if len(searchIndexes[i].Fields) > 0 {
137+
fields, err := marshalSearchIndex(searchIndexes[i].Fields)
138+
if err != nil {
139+
return nil, err
140+
}
141+
searchIndexesMap[i]["fields"] = fields
142+
}
131143
}
132144

133145
return searchIndexesMap, nil

mongodbatlas/resource_mongodbatlas_search_index.go

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import (
1717
"go.mongodb.org/atlas-sdk/v20231115001/admin"
1818
)
1919

20+
const (
21+
vectorSearch = "vectorSearch"
22+
)
23+
2024
func resourceMongoDBAtlasSearchIndex() *schema.Resource {
2125
return &schema.Resource{
2226
CreateWithoutTimeout: resourceMongoDBAtlasSearchIndexCreate,
@@ -115,6 +119,15 @@ func returnSearchIndexSchema() map[string]*schema.Schema {
115119
Type: schema.TypeBool,
116120
Optional: true,
117121
},
122+
"type": {
123+
Type: schema.TypeString,
124+
Optional: true,
125+
},
126+
"fields": {
127+
Type: schema.TypeString,
128+
Optional: true,
129+
DiffSuppressFunc: validateSearchIndexMappingDiff,
130+
},
118131
}
119132
}
120133

@@ -181,12 +194,12 @@ func resourceMongoDBAtlasSearchIndexUpdate(ctx context.Context, d *schema.Resour
181194
return diag.Errorf("error getting search index information: %s", err)
182195
}
183196

184-
if d.HasChange("analyzer") {
185-
searchIndex.Analyzer = stringPtr(d.Get("analyzer").(string))
197+
if d.HasChange("type") {
198+
searchIndex.Type = stringPtr(d.Get("type").(string))
186199
}
187200

188-
if d.HasChange("analyzers") {
189-
searchIndex.Analyzers = unmarshalSearchIndexAnalyzersFields(d.Get("analyzers").(string))
201+
if d.HasChange("analyzer") {
202+
searchIndex.Analyzer = stringPtr(d.Get("analyzer").(string))
190203
}
191204

192205
if d.HasChange("collection_name") {
@@ -210,8 +223,28 @@ func resourceMongoDBAtlasSearchIndexUpdate(ctx context.Context, d *schema.Resour
210223
searchIndex.Mappings.Dynamic = &dynamic
211224
}
212225

226+
if d.HasChange("analyzers") {
227+
analyzers, err := unmarshalSearchIndexAnalyzersFields(d.Get("analyzers").(string))
228+
if err != nil {
229+
return err
230+
}
231+
searchIndex.Analyzers = analyzers
232+
}
233+
213234
if d.HasChange("mappings_fields") {
214-
searchIndex.Mappings.Fields = unmarshalSearchIndexMappingFields(d.Get("mappings_fields").(string))
235+
mappingsFields, err := unmarshalSearchIndexMappingFields(d.Get("mappings_fields").(string))
236+
if err != nil {
237+
return err
238+
}
239+
searchIndex.Mappings.Fields = mappingsFields
240+
}
241+
242+
if d.HasChange("fields") {
243+
fields, err := unmarshalSearchIndexFields(d.Get("fields").(string))
244+
if err != nil {
245+
return err
246+
}
247+
searchIndex.Fields = fields
215248
}
216249

217250
if d.HasChange("synonyms") {
@@ -272,6 +305,10 @@ func resourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resource
272305
return diag.Errorf("error setting `index_id` for search index (%s): %s", d.Id(), err)
273306
}
274307

308+
if err := d.Set("type", searchIndex.Type); err != nil {
309+
return diag.Errorf("error setting `type` for search index (%s): %s", d.Id(), err)
310+
}
311+
275312
if err := d.Set("analyzer", searchIndex.Analyzer); err != nil {
276313
return diag.Errorf("error setting `analyzer` for search index (%s): %s", d.Id(), err)
277314
}
@@ -283,7 +320,7 @@ func resourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resource
283320
}
284321

285322
if err := d.Set("analyzers", searchIndexMappingFields); err != nil {
286-
return diag.Errorf("error setting `analyzer` for search index (%s): %s", d.Id(), err)
323+
return diag.Errorf("error setting `analyzers` for search index (%s): %s", d.Id(), err)
287324
}
288325
}
289326

@@ -303,22 +340,35 @@ func resourceMongoDBAtlasSearchIndexRead(ctx context.Context, d *schema.Resource
303340
return diag.Errorf("error setting `searchAnalyzer` for search index (%s): %s", d.Id(), err)
304341
}
305342

306-
if err := d.Set("mappings_dynamic", searchIndex.Mappings.Dynamic); err != nil {
307-
return diag.Errorf("error setting `mappings_dynamic` for search index (%s): %s", d.Id(), err)
308-
}
309-
310343
if err := d.Set("synonyms", flattenSearchIndexSynonyms(searchIndex.Synonyms)); err != nil {
311344
return diag.Errorf("error setting `synonyms` for search index (%s): %s", d.Id(), err)
312345
}
313346

314-
if len(searchIndex.Mappings.Fields) > 0 {
315-
searchIndexMappingFields, err := marshalSearchIndex(searchIndex.Mappings.Fields)
347+
if searchIndex.Mappings != nil {
348+
if err := d.Set("mappings_dynamic", searchIndex.Mappings.Dynamic); err != nil {
349+
return diag.Errorf("error setting `mappings_dynamic` for search index (%s): %s", d.Id(), err)
350+
}
351+
352+
if len(searchIndex.Mappings.Fields) > 0 {
353+
searchIndexMappingFields, err := marshalSearchIndex(searchIndex.Mappings.Fields)
354+
if err != nil {
355+
return diag.FromErr(err)
356+
}
357+
358+
if err := d.Set("mappings_fields", searchIndexMappingFields); err != nil {
359+
return diag.Errorf("error setting `mappings_fields` for for search index (%s): %s", d.Id(), err)
360+
}
361+
}
362+
}
363+
364+
if len(searchIndex.Fields) > 0 {
365+
fields, err := marshalSearchIndex(searchIndex.Fields)
316366
if err != nil {
317367
return diag.FromErr(err)
318368
}
319369

320-
if err := d.Set("mappings_fields", searchIndexMappingFields); err != nil {
321-
return diag.Errorf("error setting `mappings_fields` for for search index (%s): %s", d.Id(), err)
370+
if err := d.Set("fields", fields); err != nil {
371+
return diag.Errorf("error setting `fields` for for search index (%s): %s", d.Id(), err)
322372
}
323373
}
324374

@@ -346,21 +396,42 @@ func resourceMongoDBAtlasSearchIndexCreate(ctx context.Context, d *schema.Resour
346396
connV2 := meta.(*MongoDBClient).AtlasV2
347397
projectID := d.Get("project_id").(string)
348398
clusterName := d.Get("cluster_name").(string)
349-
dynamic := d.Get("mappings_dynamic").(bool)
399+
indexType := d.Get("type").(string)
400+
350401
searchIndexRequest := &admin.ClusterSearchIndex{
402+
Type: stringPtr(indexType),
351403
Analyzer: stringPtr(d.Get("analyzer").(string)),
352-
Analyzers: unmarshalSearchIndexAnalyzersFields(d.Get("analyzers").(string)),
353404
CollectionName: d.Get("collection_name").(string),
354405
Database: d.Get("database").(string),
355-
Mappings: &admin.ApiAtlasFTSMappings{
356-
Dynamic: &dynamic,
357-
Fields: unmarshalSearchIndexMappingFields(d.Get("mappings_fields").(string)),
358-
},
359406
Name: d.Get("name").(string),
360407
SearchAnalyzer: stringPtr(d.Get("search_analyzer").(string)),
361408
Status: stringPtr(d.Get("status").(string)),
362409
Synonyms: expandSearchIndexSynonyms(d),
363410
}
411+
412+
if indexType == vectorSearch {
413+
fields, err := unmarshalSearchIndexFields(d.Get("fields").(string))
414+
if err != nil {
415+
return err
416+
}
417+
searchIndexRequest.Fields = fields
418+
} else {
419+
analyzers, err := unmarshalSearchIndexAnalyzersFields(d.Get("analyzers").(string))
420+
if err != nil {
421+
return err
422+
}
423+
searchIndexRequest.Analyzers = analyzers
424+
mappingsFields, err := unmarshalSearchIndexMappingFields(d.Get("mappings_fields").(string))
425+
if err != nil {
426+
return err
427+
}
428+
dynamic := d.Get("mappings_dynamic").(bool)
429+
searchIndexRequest.Mappings = &admin.ApiAtlasFTSMappings{
430+
Dynamic: &dynamic,
431+
Fields: mappingsFields,
432+
}
433+
}
434+
364435
dbSearchIndexRes, _, err := connV2.AtlasSearchApi.CreateAtlasSearchIndex(ctx, projectID, clusterName, searchIndexRequest).Execute()
365436
if err != nil {
366437
return diag.Errorf("error creating index: %s", err)
@@ -467,28 +538,38 @@ func validateSearchAnalyzersDiff(k, old, newStr string, d *schema.ResourceData)
467538
return true
468539
}
469540

470-
func unmarshalSearchIndexMappingFields(mappingString string) map[string]any {
541+
func unmarshalSearchIndexMappingFields(mappingString string) (map[string]any, diag.Diagnostics) {
471542
if mappingString == "" {
472-
return nil
543+
return nil, nil
473544
}
474545
var fields map[string]any
475546
if err := json.Unmarshal([]byte(mappingString), &fields); err != nil {
476-
log.Printf("[ERROR] cannot unmarshal search index mapping fields: %v", err)
477-
return nil
547+
return nil, diag.Errorf("cannot unmarshal search index attribute `mappings_fields` because it has an incorrect format")
478548
}
479-
return fields
549+
return fields, nil
550+
}
551+
552+
func unmarshalSearchIndexFields(fieldsStr string) ([]map[string]any, diag.Diagnostics) {
553+
if fieldsStr == "" {
554+
return nil, nil
555+
}
556+
var fields []map[string]any
557+
if err := json.Unmarshal([]byte(fieldsStr), &fields); err != nil {
558+
return nil, diag.Errorf("cannot unmarshal search index attribute `fields` because it has an incorrect format")
559+
}
560+
561+
return fields, nil
480562
}
481563

482-
func unmarshalSearchIndexAnalyzersFields(mappingString string) []admin.ApiAtlasFTSAnalyzers {
564+
func unmarshalSearchIndexAnalyzersFields(mappingString string) ([]admin.ApiAtlasFTSAnalyzers, diag.Diagnostics) {
483565
if mappingString == "" {
484-
return nil
566+
return nil, nil
485567
}
486568
var fields []admin.ApiAtlasFTSAnalyzers
487569
if err := json.Unmarshal([]byte(mappingString), &fields); err != nil {
488-
log.Printf("[ERROR] cannot unmarshal search index mapping fields: %v", err)
489-
return nil
570+
return nil, diag.Errorf("cannot unmarshal search index attribute `analyzers` because it has an incorrect format")
490571
}
491-
return fields
572+
return fields, nil
492573
}
493574

494575
func resourceSearchIndexRefreshFunc(ctx context.Context, clusterName, projectID, indexID string, connV2 *admin.APIClient) retry.StateRefreshFunc {

0 commit comments

Comments
 (0)