Skip to content

Commit a30a7a2

Browse files
bug fixes and UTs
1 parent 1b11cd6 commit a30a7a2

4 files changed

Lines changed: 202 additions & 1 deletion

File tree

index_update.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ func checkUpdatedMapping(ori, upd *mapping.DocumentMapping) error {
180180
return nil
181181
}
182182

183+
if ori.Nested != upd.Nested {
184+
return fmt.Errorf("nested property cannot be changed")
185+
}
186+
183187
var err error
184188
// Recursively go through the child mappings
185189
for name, updDMapping := range upd.Properties {

index_update_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,3 +3082,133 @@ func BenchmarkIndexUpdateText(b *testing.B) {
30823082
}
30833083
}
30843084
}
3085+
3086+
func TestIndexUpdateNestedMapping(t *testing.T) {
3087+
// Helper: create a mapping with optional nested structure
3088+
createCompanyMapping := func(nestedEmployees, nestedDepartments, nestedProjects, nestedLocations bool) *mapping.IndexMappingImpl {
3089+
rv := mapping.NewIndexMapping()
3090+
companyMapping := mapping.NewDocumentMapping()
3091+
3092+
// Basic fields
3093+
companyMapping.AddFieldMappingsAt("id", mapping.NewTextFieldMapping())
3094+
companyMapping.AddFieldMappingsAt("name", mapping.NewTextFieldMapping())
3095+
3096+
var deptMapping *mapping.DocumentMapping
3097+
// Departments nested conditionally
3098+
if !nestedDepartments {
3099+
deptMapping = mapping.NewDocumentMapping()
3100+
} else {
3101+
deptMapping = mapping.NewNestedDocumentMapping()
3102+
}
3103+
deptMapping.AddFieldMappingsAt("name", mapping.NewTextFieldMapping())
3104+
deptMapping.AddFieldMappingsAt("budget", mapping.NewNumericFieldMapping())
3105+
3106+
// Employees nested conditionally
3107+
var empMapping *mapping.DocumentMapping
3108+
if !nestedEmployees {
3109+
empMapping = mapping.NewNestedDocumentMapping()
3110+
} else {
3111+
empMapping = mapping.NewDocumentMapping()
3112+
}
3113+
empMapping.AddFieldMappingsAt("name", mapping.NewTextFieldMapping())
3114+
empMapping.AddFieldMappingsAt("role", mapping.NewTextFieldMapping())
3115+
deptMapping.AddSubDocumentMapping("employees", empMapping)
3116+
3117+
// Projects nested conditionally
3118+
var projMapping *mapping.DocumentMapping
3119+
if !nestedProjects {
3120+
projMapping = mapping.NewNestedDocumentMapping()
3121+
} else {
3122+
projMapping = mapping.NewDocumentMapping()
3123+
}
3124+
projMapping.AddFieldMappingsAt("title", mapping.NewTextFieldMapping())
3125+
projMapping.AddFieldMappingsAt("status", mapping.NewTextFieldMapping())
3126+
deptMapping.AddSubDocumentMapping("projects", projMapping)
3127+
3128+
companyMapping.AddSubDocumentMapping("departments", deptMapping)
3129+
3130+
// Locations nested conditionally
3131+
var locMapping *mapping.DocumentMapping
3132+
if nestedLocations {
3133+
locMapping = mapping.NewNestedDocumentMapping()
3134+
} else {
3135+
locMapping = mapping.NewDocumentMapping()
3136+
}
3137+
locMapping.AddFieldMappingsAt("address", mapping.NewTextFieldMapping())
3138+
locMapping.AddFieldMappingsAt("city", mapping.NewTextFieldMapping())
3139+
3140+
companyMapping.AddSubDocumentMapping("locations", locMapping)
3141+
3142+
rv.DefaultMapping.AddSubDocumentMapping("company", companyMapping)
3143+
return rv
3144+
}
3145+
3146+
tests := []struct {
3147+
name string
3148+
original *mapping.IndexMappingImpl
3149+
updated *mapping.IndexMappingImpl
3150+
expectErr bool
3151+
}{
3152+
{
3153+
name: "No nested to all nested",
3154+
original: createCompanyMapping(false, false, false, false),
3155+
updated: createCompanyMapping(true, true, true, true),
3156+
expectErr: true,
3157+
},
3158+
{
3159+
name: "No nested to mixed nested",
3160+
original: createCompanyMapping(false, false, false, false),
3161+
updated: createCompanyMapping(true, false, true, false),
3162+
expectErr: true,
3163+
},
3164+
{
3165+
name: "No nested to mixed nested",
3166+
original: createCompanyMapping(false, false, false, false),
3167+
updated: createCompanyMapping(true, true, true, false),
3168+
expectErr: true,
3169+
},
3170+
{
3171+
name: "Mixed nested to no nested",
3172+
original: createCompanyMapping(false, true, false, true),
3173+
updated: createCompanyMapping(false, false, true, true),
3174+
expectErr: true,
3175+
},
3176+
{
3177+
name: "All nested to no nested",
3178+
original: createCompanyMapping(true, true, true, true),
3179+
updated: createCompanyMapping(false, false, false, false),
3180+
expectErr: true,
3181+
},
3182+
{
3183+
name: "Mixed nested to all nested",
3184+
original: createCompanyMapping(true, false, true, false),
3185+
updated: createCompanyMapping(true, true, true, true),
3186+
expectErr: true,
3187+
},
3188+
{
3189+
name: "All nested to mixed nested",
3190+
original: createCompanyMapping(true, true, true, true),
3191+
updated: createCompanyMapping(true, false, true, false),
3192+
expectErr: true,
3193+
},
3194+
{
3195+
name: "No nested to no nested",
3196+
original: createCompanyMapping(false, false, false, false),
3197+
updated: createCompanyMapping(false, false, false, false),
3198+
expectErr: false,
3199+
},
3200+
{
3201+
name: "All nested to all nested",
3202+
original: createCompanyMapping(true, true, true, true),
3203+
updated: createCompanyMapping(true, true, true, true),
3204+
expectErr: false,
3205+
},
3206+
}
3207+
3208+
for _, test := range tests {
3209+
_, err := DeletedFields(test.original, test.updated)
3210+
if (err != nil) != test.expectErr {
3211+
t.Errorf("Test '%s' unexpected error state: got %v, expectErr %t", test.name, err, test.expectErr)
3212+
}
3213+
}
3214+
}

mapping/index.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,19 @@ func (im *IndexMappingImpl) Validate() error {
194194
}
195195
}
196196
fieldAliasCtx := make(map[string]*FieldMapping)
197+
// ensure that the nested property is not set for top-level default mapping
198+
if im.DefaultMapping.Nested {
199+
return fmt.Errorf("default mapping cannot be nested")
200+
}
197201
err = im.DefaultMapping.Validate(im.cache, "", fieldAliasCtx)
198202
if err != nil {
199203
return err
200204
}
201-
for _, docMapping := range im.TypeMapping {
205+
for name, docMapping := range im.TypeMapping {
206+
// ensure that the nested property is not set for top-level mappings
207+
if docMapping.Nested {
208+
return fmt.Errorf("type mapping named: %s cannot be nested", name)
209+
}
202210
err = docMapping.Validate(im.cache, "", fieldAliasCtx)
203211
if err != nil {
204212
return err

search_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5298,6 +5298,7 @@ func createNestedIndexMapping() mapping.IndexMapping {
52985298

52995299
return imap
53005300
}
5301+
53015302
func TestNestedPrefixes(t *testing.T) {
53025303
imap := createNestedIndexMapping()
53035304

@@ -5448,6 +5449,10 @@ func TestNestedPrefixes(t *testing.T) {
54485449

54495450
func TestNestedConjunctionQuery(t *testing.T) {
54505451
imap := createNestedIndexMapping()
5452+
err := imap.Validate()
5453+
if err != nil {
5454+
t.Fatalf("expected valid nested index mapping, got error: %v", err)
5455+
}
54515456
tmpIndexPath := createTmpIndexPath(t)
54525457
defer cleanupTmpIndexPath(t, tmpIndexPath)
54535458
idx, err := New(tmpIndexPath, imap)
@@ -6123,3 +6128,57 @@ func TestNestedArrayConjunctionQuery(t *testing.T) {
61236128
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
61246129
}
61256130
}
6131+
6132+
func TestValidNestedMapping(t *testing.T) {
6133+
// ensure that top-level mappings - DefaultMapping and any type mappings - cannot be nested mappings
6134+
imap := mapping.NewIndexMapping()
6135+
nestedMapping := mapping.NewNestedDocumentMapping()
6136+
imap.DefaultMapping = nestedMapping
6137+
err := imap.Validate()
6138+
if err == nil {
6139+
t.Fatalf("expected error for nested DefaultMapping, got nil")
6140+
}
6141+
// invalid nested type mapping
6142+
imap = mapping.NewIndexMapping()
6143+
imap.AddDocumentMapping("type1", nestedMapping)
6144+
err = imap.Validate()
6145+
if err == nil {
6146+
t.Fatalf("expected error for nested type mapping, got nil")
6147+
}
6148+
// valid nested mappings within DefaultMapping
6149+
imap = mapping.NewIndexMapping()
6150+
docMapping := mapping.NewDocumentMapping()
6151+
nestedMapping = mapping.NewNestedDocumentMapping()
6152+
fieldMapping := mapping.NewTextFieldMapping()
6153+
nestedMapping.AddFieldMappingsAt("field1", fieldMapping)
6154+
docMapping.AddSubDocumentMapping("nestedField", nestedMapping)
6155+
imap.DefaultMapping = docMapping
6156+
err = imap.Validate()
6157+
if err != nil {
6158+
t.Fatalf("expected valid nested mapping, got error: %v", err)
6159+
}
6160+
// valid nested mappings within type mapping
6161+
imap = mapping.NewIndexMapping()
6162+
docMapping = mapping.NewDocumentMapping()
6163+
nestedMapping = mapping.NewNestedDocumentMapping()
6164+
fieldMapping = mapping.NewTextFieldMapping()
6165+
nestedMapping.AddFieldMappingsAt("field1", fieldMapping)
6166+
docMapping.AddSubDocumentMapping("nestedField", nestedMapping)
6167+
imap.AddDocumentMapping("type1", docMapping)
6168+
err = imap.Validate()
6169+
if err != nil {
6170+
t.Fatalf("expected valid nested mapping, got error: %v", err)
6171+
}
6172+
// some nested type mappings
6173+
imap = mapping.NewIndexMapping()
6174+
nestedMapping = mapping.NewNestedDocumentMapping()
6175+
regularMapping := mapping.NewDocumentMapping()
6176+
imap.AddDocumentMapping("non_nested1", regularMapping)
6177+
imap.AddDocumentMapping("non_nested2", regularMapping)
6178+
imap.AddDocumentMapping("nested1", nestedMapping)
6179+
imap.AddDocumentMapping("nested2", nestedMapping)
6180+
err = imap.Validate()
6181+
if err == nil {
6182+
t.Fatalf("expected error for nested type mappings, got nil")
6183+
}
6184+
}

0 commit comments

Comments
 (0)