Some checks failed
Coverage / coverage (push) Failing after 6s
Tests / test (1.24.x, ubuntu-latest) (push) Failing after 42s
Tests / test (1.26.x, ubuntu-latest) (push) Failing after 38s
Tests / test (1.25.x, ubuntu-latest) (push) Failing after 35s
Tests / test (1.25.x, windows-latest) (push) Has been cancelled
Tests / test (1.26.x, macos-latest) (push) Has been cancelled
Tests / test (1.26.x, windows-latest) (push) Has been cancelled
Tests / test (1.24.x, macos-latest) (push) Has been cancelled
Tests / test (1.24.x, windows-latest) (push) Has been cancelled
Tests / test (1.25.x, macos-latest) (push) Has been cancelled
1217 lines
37 KiB
Go
1217 lines
37 KiB
Go
// Copyright (c) 2026 Couchbase, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bleve
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/blevesearch/bleve/v2/mapping"
|
|
"github.com/blevesearch/bleve/v2/search"
|
|
"github.com/blevesearch/bleve/v2/search/highlight/highlighter/ansi"
|
|
"github.com/blevesearch/bleve/v2/search/query"
|
|
)
|
|
|
|
func createNestedIndexMapping() mapping.IndexMapping {
|
|
/*
|
|
company
|
|
├── id
|
|
├── name
|
|
├── departments[] (nested)
|
|
│ ├── name
|
|
│ ├── budget
|
|
│ ├── employees[] (nested)
|
|
│ │ ├── name
|
|
│ │ ├── role
|
|
│ └── projects[] (nested)
|
|
│ ├── title
|
|
│ ├── status
|
|
└── locations[] (nested)
|
|
├── city
|
|
├── country
|
|
*/
|
|
|
|
// Create the index mapping
|
|
imap := mapping.NewIndexMapping()
|
|
|
|
// Create company mapping
|
|
companyMapping := mapping.NewDocumentMapping()
|
|
|
|
// Company ID field
|
|
companyIDField := mapping.NewTextFieldMapping()
|
|
companyMapping.AddFieldMappingsAt("id", companyIDField)
|
|
|
|
// Company name field
|
|
companyNameField := mapping.NewTextFieldMapping()
|
|
companyMapping.AddFieldMappingsAt("name", companyNameField)
|
|
|
|
// Departments mapping
|
|
departmentsMapping := mapping.NewNestedDocumentMapping()
|
|
|
|
// Department name field
|
|
deptNameField := mapping.NewTextFieldMapping()
|
|
departmentsMapping.AddFieldMappingsAt("name", deptNameField)
|
|
|
|
// Department budget field
|
|
deptBudgetField := mapping.NewNumericFieldMapping()
|
|
departmentsMapping.AddFieldMappingsAt("budget", deptBudgetField)
|
|
|
|
// Employees mapping
|
|
employeesMapping := mapping.NewNestedDocumentMapping()
|
|
|
|
// Employee name field
|
|
empNameField := mapping.NewTextFieldMapping()
|
|
employeesMapping.AddFieldMappingsAt("name", empNameField)
|
|
|
|
// Employee role field
|
|
empRoleField := mapping.NewTextFieldMapping()
|
|
employeesMapping.AddFieldMappingsAt("role", empRoleField)
|
|
|
|
departmentsMapping.AddSubDocumentMapping("employees", employeesMapping)
|
|
|
|
// Projects mapping
|
|
projectsMapping := mapping.NewNestedDocumentMapping()
|
|
|
|
// Project title field
|
|
projTitleField := mapping.NewTextFieldMapping()
|
|
projectsMapping.AddFieldMappingsAt("title", projTitleField)
|
|
|
|
// Project status field
|
|
projStatusField := mapping.NewTextFieldMapping()
|
|
projectsMapping.AddFieldMappingsAt("status", projStatusField)
|
|
|
|
departmentsMapping.AddSubDocumentMapping("projects", projectsMapping)
|
|
|
|
companyMapping.AddSubDocumentMapping("departments", departmentsMapping)
|
|
|
|
// Locations mapping
|
|
locationsMapping := mapping.NewNestedDocumentMapping()
|
|
|
|
// Location city field
|
|
cityField := mapping.NewTextFieldMapping()
|
|
locationsMapping.AddFieldMappingsAt("city", cityField)
|
|
|
|
// Location country field
|
|
countryField := mapping.NewTextFieldMapping()
|
|
locationsMapping.AddFieldMappingsAt("country", countryField)
|
|
|
|
companyMapping.AddSubDocumentMapping("locations", locationsMapping)
|
|
|
|
// Add company to type mapping
|
|
imap.DefaultMapping.AddSubDocumentMapping("company", companyMapping)
|
|
|
|
return imap
|
|
}
|
|
|
|
func TestNestedPrefixes(t *testing.T) {
|
|
imap := createNestedIndexMapping()
|
|
|
|
tmpIndexPath := createTmpIndexPath(t)
|
|
defer cleanupTmpIndexPath(t, tmpIndexPath)
|
|
|
|
idx, err := New(tmpIndexPath, imap)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
if err := idx.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
nmap, ok := imap.(mapping.NestedMapping)
|
|
if !ok {
|
|
t.Fatal("index mapping is not a NestedMapping")
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 1: Employee Role AND Employee Name
|
|
// ----------------------------------------------------------------------
|
|
fs := search.NewFieldSet()
|
|
fs.AddField("company.departments.employees.role")
|
|
fs.AddField("company.departments.employees.name")
|
|
|
|
expectedCommon := 2
|
|
expectedMax := 2
|
|
|
|
common, max := nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test1: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 2: Employee Role AND Employee Name AND Department Name
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.departments.employees.role")
|
|
fs.AddField("company.departments.employees.name")
|
|
fs.AddField("company.departments.name")
|
|
|
|
expectedCommon = 1
|
|
expectedMax = 2 // employees nested deeper
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test2: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 3: Employee Role AND Location City
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.departments.employees.role")
|
|
fs.AddField("company.locations.city")
|
|
|
|
expectedCommon = 0
|
|
expectedMax = 2 // employees deeper than locations (1)
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test3: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 4: Company Name AND Location Country
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.name")
|
|
fs.AddField("company.locations.country")
|
|
fs.AddField("company.locations.city")
|
|
|
|
expectedCommon = 0
|
|
expectedMax = 1 // locations.country and locations.city share depth 1
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test4: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 5: Department Budget AND Project Status AND Employee Name
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.departments.budget")
|
|
fs.AddField("company.departments.projects.status")
|
|
fs.AddField("company.departments.employees.name")
|
|
|
|
expectedCommon = 1
|
|
expectedMax = 2 // employees + projects go deeper
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test5: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 6: Single Field
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.id")
|
|
|
|
expectedCommon = 0
|
|
expectedMax = 0
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test6: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 7: No Fields
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
|
|
expectedCommon = 0
|
|
expectedMax = 0
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test7: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 8: All Fields
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.id")
|
|
fs.AddField("company.name")
|
|
fs.AddField("company.departments.name")
|
|
fs.AddField("company.departments.budget")
|
|
fs.AddField("company.departments.employees.name")
|
|
fs.AddField("company.departments.employees.role")
|
|
fs.AddField("company.departments.projects.title")
|
|
fs.AddField("company.departments.projects.status")
|
|
fs.AddField("company.locations.city")
|
|
fs.AddField("company.locations.country")
|
|
|
|
expectedCommon = 0 // spans different contexts
|
|
expectedMax = 2
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test8: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 9: Project Title AND Project Status
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.departments.projects.title")
|
|
fs.AddField("company.departments.projects.status")
|
|
|
|
expectedCommon = 2
|
|
expectedMax = 2
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test9: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Test 10: Department Name AND Location Country
|
|
// ----------------------------------------------------------------------
|
|
fs = search.NewFieldSet()
|
|
fs.AddField("company.departments.name")
|
|
fs.AddField("company.locations.country")
|
|
fs.AddField("company.locations.city")
|
|
|
|
expectedCommon = 0
|
|
expectedMax = 1 // locations share depth 1
|
|
|
|
common, max = nmap.NestedDepth(fs)
|
|
if common != expectedCommon || max != expectedMax {
|
|
t.Fatalf("Test10: expected (common=%d, max=%d), got (common=%d, max=%d)",
|
|
expectedCommon, expectedMax, common, max)
|
|
}
|
|
}
|
|
|
|
func TestNestedConjunctionQuery(t *testing.T) {
|
|
imap := createNestedIndexMapping()
|
|
err := imap.Validate()
|
|
if err != nil {
|
|
t.Fatalf("expected valid nested index mapping, got error: %v", err)
|
|
}
|
|
tmpIndexPath := createTmpIndexPath(t)
|
|
defer cleanupTmpIndexPath(t, tmpIndexPath)
|
|
idx, err := New(tmpIndexPath, imap)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
err = idx.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
// Index 3 sample documents
|
|
docs := []struct {
|
|
id string
|
|
data string
|
|
}{
|
|
{
|
|
id: "doc1",
|
|
data: `{
|
|
"company": {
|
|
"id": "c1",
|
|
"name": "TechCorp",
|
|
"departments": [
|
|
{
|
|
"name": "Engineering",
|
|
"budget": 2000000,
|
|
"employees": [
|
|
{"name": "Alice", "role": "Engineer"},
|
|
{"name": "Bob", "role": "Manager"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project X", "status": "ongoing"},
|
|
{"title": "Project Y", "status": "completed"}
|
|
]
|
|
},
|
|
{
|
|
"name": "Sales",
|
|
"budget": 300000,
|
|
"employees": [
|
|
{"name": "Eve", "role": "Salesperson"},
|
|
{"name": "Mallory", "role": "Manager"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project A", "status": "completed"},
|
|
{"title": "Project B", "status": "ongoing"}
|
|
]
|
|
}
|
|
],
|
|
"locations": [
|
|
{"city": "Athens", "country": "Greece"},
|
|
{"city": "Berlin", "country": "USA"}
|
|
]
|
|
}
|
|
}`,
|
|
},
|
|
{
|
|
id: "doc2",
|
|
data: `{
|
|
"company" : {
|
|
"id": "c2",
|
|
"name": "BizInc",
|
|
"departments": [
|
|
{
|
|
"name": "Marketing",
|
|
"budget": 800000,
|
|
"employees": [
|
|
{"name": "Eve", "role": "Marketer"},
|
|
{"name": "David", "role": "Manager"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project Z", "status": "ongoing"},
|
|
{"title": "Project W", "status": "planned"}
|
|
]
|
|
},
|
|
{
|
|
"name": "Engineering",
|
|
"budget": 800000,
|
|
"employees": [
|
|
{"name": "Frank", "role": "Manager"},
|
|
{"name": "Grace", "role": "Engineer"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project Alpha", "status": "completed"},
|
|
{"title": "Project Beta", "status": "ongoing"}
|
|
]
|
|
}
|
|
],
|
|
"locations": [
|
|
{"city": "Athens", "country": "USA"},
|
|
{"city": "London", "country": "UK"}
|
|
]
|
|
}
|
|
}`,
|
|
},
|
|
{
|
|
id: "doc3",
|
|
data: `{
|
|
"company": {
|
|
"id": "c3",
|
|
"name": "WebSolutions",
|
|
"departments": [
|
|
{
|
|
"name": "HR",
|
|
"budget": 800000,
|
|
"employees": [
|
|
{"name": "Eve", "role": "Manager"},
|
|
{"name": "Frank", "role": "HR"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project Beta", "status": "completed"},
|
|
{"title": "Project B", "status": "ongoing"}
|
|
]
|
|
},
|
|
{
|
|
"name": "Engineering",
|
|
"budget": 200000,
|
|
"employees": [
|
|
{"name": "Heidi", "role": "Support Engineer"},
|
|
{"name": "Ivan", "role": "Manager"}
|
|
],
|
|
"projects": [
|
|
{"title": "Project Helpdesk", "status": "ongoing"},
|
|
{"title": "Project FAQ", "status": "completed"}
|
|
]
|
|
}
|
|
],
|
|
"locations": [
|
|
{"city": "Edinburgh", "country": "UK"},
|
|
{"city": "London", "country": "Canada"}
|
|
]
|
|
}
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, doc := range docs {
|
|
var dataMap map[string]interface{}
|
|
err := json.Unmarshal([]byte(doc.data), &dataMap)
|
|
if err != nil {
|
|
t.Fatalf("failed to unmarshal document %s: %v", doc.id, err)
|
|
}
|
|
err = idx.Index(doc.id, dataMap)
|
|
if err != nil {
|
|
t.Fatalf("failed to index document %s: %v", doc.id, err)
|
|
}
|
|
}
|
|
|
|
var buildReq = func(subQueries []query.Query) *SearchRequest {
|
|
rv := NewSearchRequest(query.NewConjunctionQuery(subQueries))
|
|
rv.SortBy([]string{"_id"})
|
|
rv.Fields = []string{"*"}
|
|
rv.Highlight = NewHighlightWithStyle(ansi.Name)
|
|
return rv
|
|
}
|
|
|
|
var (
|
|
req *SearchRequest
|
|
res *SearchResult
|
|
deptNameQuery *query.MatchQuery
|
|
deptBudgetQuery *query.NumericRangeQuery
|
|
empNameQuery *query.MatchQuery
|
|
empRoleQuery *query.MatchQuery
|
|
projTitleQuery *query.MatchPhraseQuery
|
|
projStatusQuery *query.MatchQuery
|
|
countryQuery *query.MatchQuery
|
|
cityQuery *query.MatchQuery
|
|
)
|
|
|
|
// Test 1: Find companies with a department named "Engineering" AND budget over 900000
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
min := float64(800000)
|
|
deptBudgetQuery = query.NewNumericRangeQuery(&min, nil)
|
|
deptBudgetQuery.SetField("company.departments.budget")
|
|
|
|
req = buildReq([]query.Query{deptNameQuery, deptBudgetQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 2 {
|
|
t.Fatalf("expected 2 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc1" || res.Hits[1].ID != "doc2" {
|
|
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
|
|
}
|
|
|
|
// Test 2: Find companies with an employee named "Eve" AND project status "completed"
|
|
empNameQuery = query.NewMatchQuery("Eve")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
projStatusQuery = query.NewMatchQuery("completed")
|
|
projStatusQuery.SetField("company.departments.projects.status")
|
|
|
|
req = buildReq([]query.Query{empNameQuery, projStatusQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 2 {
|
|
t.Fatalf("expected 2 hits, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc1" || res.Hits[1].ID != "doc3" {
|
|
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
|
|
}
|
|
|
|
// Test 3: Find companies located in "Athens, USA" AND with an Engineering department
|
|
countryQuery = query.NewMatchQuery("USA")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("Athens")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery := query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
req = buildReq([]query.Query{locQuery, deptNameQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc2" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 4a: Find companies located in "Athens, USA" AND with an Engineering department with a budget over 1M
|
|
countryQuery = query.NewMatchQuery("USA")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("Athens")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
min = float64(1000000)
|
|
deptBudgetQuery = query.NewNumericRangeQuery(&min, nil)
|
|
deptBudgetQuery.SetField("company.departments.budget")
|
|
|
|
deptQuery := query.NewConjunctionQuery([]query.Query{deptNameQuery, deptBudgetQuery})
|
|
|
|
req = buildReq([]query.Query{locQuery, deptQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 4b: Find companies located in "Athens, Greece" AND with an Engineering department with a budget over 1M
|
|
countryQuery = query.NewMatchQuery("Greece")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("Athens")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
min = float64(1000000)
|
|
deptBudgetQuery = query.NewNumericRangeQuery(&min, nil)
|
|
deptBudgetQuery.SetField("company.departments.budget")
|
|
|
|
deptQuery = query.NewConjunctionQuery([]query.Query{deptNameQuery, deptBudgetQuery})
|
|
|
|
req = buildReq([]query.Query{locQuery, deptQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hits, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc1" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 5a: Find companies with an employee named "Frank" AND role "Manager" whose department is
|
|
// handling a project titled "Project Beta" which is marked as "completed"
|
|
empNameQuery = query.NewMatchQuery("Frank")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery := query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
projTitleQuery = query.NewMatchPhraseQuery("Project Beta")
|
|
projTitleQuery.SetField("company.departments.projects.title")
|
|
|
|
projStatusQuery = query.NewMatchQuery("completed")
|
|
projStatusQuery.SetField("company.departments.projects.status")
|
|
|
|
projQuery := query.NewConjunctionQuery([]query.Query{projTitleQuery, projStatusQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, projQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hit, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 5b: Find companies with an employee named "Frank" AND role "Manager" whose department is
|
|
// handling a project titled "Project Beta" which is marked as "ongoing"
|
|
empNameQuery = query.NewMatchQuery("Frank")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
projTitleQuery = query.NewMatchPhraseQuery("Project Beta")
|
|
projTitleQuery.SetField("company.departments.projects.title")
|
|
|
|
projStatusQuery = query.NewMatchQuery("ongoing")
|
|
projStatusQuery.SetField("company.departments.projects.status")
|
|
|
|
projQuery = query.NewConjunctionQuery([]query.Query{projTitleQuery, projStatusQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, projQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc2" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 6a: Find companies with an employee named "Eve" AND role "Manager"
|
|
// who is working in a department located in "London, UK"
|
|
empNameQuery = query.NewMatchQuery("Eve")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("UK")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, locQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hit, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 6b: Find companies with an employee named "Eve" AND role "Manager"
|
|
// who is working in a department located in "London, Canada"
|
|
empNameQuery = query.NewMatchQuery("Eve")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("Canada")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, locQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc3" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 7a: Find companies where Ivan the Manager works London, UK
|
|
|
|
empNameQuery = query.NewMatchQuery("Ivan")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("UK")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, locQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hit, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 7b: Find companies where Ivan the Manager works London, Canada
|
|
|
|
empNameQuery = query.NewMatchQuery("Ivan")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("Canada")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
req = buildReq([]query.Query{empQuery, locQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc3" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 8: Find companies where Frank the Manager works in Engineering department located in London, UK
|
|
empNameQuery = query.NewMatchQuery("Frank")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
deptQuery = query.NewConjunctionQuery([]query.Query{empQuery, deptNameQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("UK")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
req = buildReq([]query.Query{deptQuery, locQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc2" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 9: Match_All query must return only top-level documents
|
|
matchAllQuery := query.NewMatchAllQuery()
|
|
req = buildReq([]query.Query{matchAllQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 3 {
|
|
t.Fatalf("expected 3 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 10: DocID query must return only top-level documents
|
|
docIDQuery := query.NewDocIDQuery([]string{"doc1", "doc2", "doc3", "doc2_$company.locations_$0", "doc3_$company.departments_$0_$company.departments.employees_$0"})
|
|
req = buildReq([]query.Query{docIDQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 3 {
|
|
t.Fatalf("expected 3 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Test 11: Boolean query in Filter-only mode must return correct top-level documents
|
|
empNameQuery = query.NewMatchQuery("Frank")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
boolQuery := query.NewBooleanQuery(nil, nil, nil)
|
|
boolQuery.AddFilter(empNameQuery)
|
|
|
|
req = buildReq([]query.Query{boolQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 2 {
|
|
t.Fatalf("expected 2 hits, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc2" || res.Hits[1].ID != "doc3" {
|
|
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
|
|
}
|
|
|
|
// Test 12: Boolean query Must clause should work in nested context
|
|
empNameQuery = query.NewMatchQuery("Ivan")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("Canada")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
boolQuery = query.NewBooleanQuery([]query.Query{empQuery, locQuery}, nil, nil)
|
|
req = buildReq([]query.Query{boolQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc3" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
// Test 13: Queries targetting _all field should:
|
|
// - match only top-level fields when no specific field is set
|
|
// - not match nested fields when no specific field is set
|
|
// - work correctly when combined with nested field queries,
|
|
// returning only top-level documents where both conditions are met
|
|
allRootFieldQuery := query.NewMatchQuery("TechCorp")
|
|
|
|
req = buildReq([]query.Query{allRootFieldQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc1" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
allNestedFieldQuery := query.NewMatchQuery("Alice")
|
|
req = buildReq([]query.Query{allNestedFieldQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
allMixedQuery := buildReq([]query.Query{allRootFieldQuery, allNestedFieldQuery})
|
|
res, err = idx.Search(allMixedQuery)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
nestedFieldQuery := query.NewMatchQuery("Alice")
|
|
nestedFieldQuery.SetField("company.departments.employees.name")
|
|
|
|
allMixedQueryWithNested := buildReq([]query.Query{allRootFieldQuery, nestedFieldQuery})
|
|
res, err = idx.Search(allMixedQueryWithNested)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc1" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
empNameQuery = query.NewMatchQuery("Frank")
|
|
empNameQuery.SetField("company.departments.employees.name")
|
|
|
|
empRoleQuery = query.NewMatchQuery("Manager")
|
|
empRoleQuery.SetField("company.departments.employees.role")
|
|
|
|
empQuery = query.NewConjunctionQuery([]query.Query{empNameQuery, empRoleQuery})
|
|
|
|
deptNameQuery = query.NewMatchQuery("Engineering")
|
|
deptNameQuery.SetField("company.departments.name")
|
|
|
|
deptQuery = query.NewConjunctionQuery([]query.Query{empQuery, deptNameQuery})
|
|
|
|
countryQuery = query.NewMatchQuery("UK")
|
|
countryQuery.SetField("company.locations.country")
|
|
|
|
cityQuery = query.NewMatchQuery("London")
|
|
cityQuery.SetField("company.locations.city")
|
|
|
|
locQuery = query.NewConjunctionQuery([]query.Query{countryQuery, cityQuery})
|
|
|
|
// mixed queries with _all field and _id field should match at root level always
|
|
companyNameAllQuery := query.NewMatchQuery("BizInc")
|
|
matchAllQuery = query.NewMatchAllQuery()
|
|
req = buildReq([]query.Query{deptQuery, locQuery, companyNameAllQuery, matchAllQuery})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", len(res.Hits))
|
|
}
|
|
if res.Hits[0].ID != "doc2" {
|
|
t.Fatalf("unexpected hit ID: %v", res.Hits[0].ID)
|
|
}
|
|
|
|
companyNameAllQueryNoMatch := query.NewMatchQuery("WebSolutions")
|
|
req = buildReq([]query.Query{deptQuery, locQuery, companyNameAllQueryNoMatch})
|
|
res, err = idx.Search(req)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
}
|
|
|
|
func TestNestedArrayConjunctionQuery(t *testing.T) {
|
|
imap := NewIndexMapping()
|
|
groupsMapping := mapping.NewNestedDocumentMapping()
|
|
|
|
nameField := mapping.NewTextFieldMapping()
|
|
groupsMapping.AddFieldMappingsAt("first_name", nameField)
|
|
groupsMapping.AddFieldMappingsAt("last_name", nameField)
|
|
|
|
imap.DefaultMapping.AddSubDocumentMapping("groups", groupsMapping)
|
|
|
|
tmpIndexPath := createTmpIndexPath(t)
|
|
defer cleanupTmpIndexPath(t, tmpIndexPath)
|
|
idx, err := New(tmpIndexPath, imap)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
err = idx.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
docs := []string{
|
|
`{
|
|
"groups": [
|
|
[
|
|
{
|
|
"first_name": "Alice",
|
|
"last_name": "Smith"
|
|
},
|
|
{
|
|
"first_name": "Bob",
|
|
"last_name": "Johnson"
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"first_name": "Charlie",
|
|
"last_name": "Williams"
|
|
},
|
|
{
|
|
"first_name": "Diana",
|
|
"last_name": "Brown"
|
|
}
|
|
]
|
|
]
|
|
}`,
|
|
`{
|
|
"groups": [
|
|
{
|
|
"first_name": "Alice",
|
|
"last_name": "Smith"
|
|
},
|
|
{
|
|
"first_name": "Bob",
|
|
"last_name": "Johnson"
|
|
},
|
|
{
|
|
"first_name": "Charlie",
|
|
"last_name": "Williams"
|
|
},
|
|
{
|
|
"first_name": "Diana",
|
|
"last_name": "Brown"
|
|
}
|
|
]
|
|
}`,
|
|
}
|
|
|
|
for i, doc := range docs {
|
|
var dataMap map[string]interface{}
|
|
err := json.Unmarshal([]byte(doc), &dataMap)
|
|
if err != nil {
|
|
t.Fatalf("failed to unmarshal document %d: %v", i, err)
|
|
}
|
|
err = idx.Index(fmt.Sprintf("%d", i+1), dataMap)
|
|
if err != nil {
|
|
t.Fatalf("failed to index document %d: %v", i, err)
|
|
}
|
|
}
|
|
|
|
var (
|
|
firstNameQuery *query.MatchQuery
|
|
lastNameQuery *query.MatchQuery
|
|
conjQuery *query.ConjunctionQuery
|
|
searchReq *SearchRequest
|
|
res *SearchResult
|
|
)
|
|
|
|
// Search for documents where first_name is "Alice" AND last_name is "Johnson"
|
|
firstNameQuery = query.NewMatchQuery("Alice")
|
|
firstNameQuery.SetField("groups.first_name")
|
|
|
|
lastNameQuery = query.NewMatchQuery("Johnson")
|
|
lastNameQuery.SetField("groups.last_name")
|
|
|
|
conjQuery = query.NewConjunctionQuery([]query.Query{firstNameQuery, lastNameQuery})
|
|
|
|
searchReq = NewSearchRequest(conjQuery)
|
|
searchReq.SortBy([]string{"_id"})
|
|
|
|
res, err = idx.Search(searchReq)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Search for documents where first_name is "Bob" AND last_name is "Johnson"
|
|
firstNameQuery = query.NewMatchQuery("Bob")
|
|
firstNameQuery.SetField("groups.first_name")
|
|
|
|
lastNameQuery = query.NewMatchQuery("Johnson")
|
|
lastNameQuery.SetField("groups.last_name")
|
|
|
|
conjQuery = query.NewConjunctionQuery([]query.Query{firstNameQuery, lastNameQuery})
|
|
|
|
searchReq = NewSearchRequest(conjQuery)
|
|
searchReq.SortBy([]string{"_id"})
|
|
|
|
res, err = idx.Search(searchReq)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
|
|
if len(res.Hits) != 2 {
|
|
t.Fatalf("expected 2 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
if res.Hits[0].ID != "1" || res.Hits[1].ID != "2" {
|
|
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
|
|
}
|
|
|
|
// Search for documents where first_name is "Alice" AND last_name is "Williams"
|
|
firstNameQuery = query.NewMatchQuery("Alice")
|
|
firstNameQuery.SetField("groups.first_name")
|
|
|
|
lastNameQuery = query.NewMatchQuery("Williams")
|
|
lastNameQuery.SetField("groups.last_name")
|
|
|
|
conjQuery = query.NewConjunctionQuery([]query.Query{firstNameQuery, lastNameQuery})
|
|
|
|
searchReq = NewSearchRequest(conjQuery)
|
|
searchReq.SortBy([]string{"_id"})
|
|
|
|
res, err = idx.Search(searchReq)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
|
|
if len(res.Hits) != 0 {
|
|
t.Fatalf("expected 0 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
// Search for documents where first_name is "Diana" AND last_name is "Brown"
|
|
firstNameQuery = query.NewMatchQuery("Diana")
|
|
firstNameQuery.SetField("groups.first_name")
|
|
|
|
lastNameQuery = query.NewMatchQuery("Brown")
|
|
lastNameQuery.SetField("groups.last_name")
|
|
|
|
conjQuery = query.NewConjunctionQuery([]query.Query{firstNameQuery, lastNameQuery})
|
|
|
|
searchReq = NewSearchRequest(conjQuery)
|
|
searchReq.SortBy([]string{"_id"})
|
|
|
|
res, err = idx.Search(searchReq)
|
|
if err != nil {
|
|
t.Fatalf("search failed: %v", err)
|
|
}
|
|
|
|
if len(res.Hits) != 2 {
|
|
t.Fatalf("expected 2 hits, got %d", len(res.Hits))
|
|
}
|
|
|
|
if res.Hits[0].ID != "1" || res.Hits[1].ID != "2" {
|
|
t.Fatalf("unexpected hit IDs: %v, %v", res.Hits[0].ID, res.Hits[1].ID)
|
|
}
|
|
}
|
|
|
|
func TestValidNestedMapping(t *testing.T) {
|
|
// ensure that top-level mappings - DefaultMapping and any type mappings - cannot be nested mappings
|
|
imap := mapping.NewIndexMapping()
|
|
nestedMapping := mapping.NewNestedDocumentMapping()
|
|
imap.DefaultMapping = nestedMapping
|
|
err := imap.Validate()
|
|
if err == nil {
|
|
t.Fatalf("expected error for nested DefaultMapping, got nil")
|
|
}
|
|
// invalid nested type mapping
|
|
imap = mapping.NewIndexMapping()
|
|
imap.AddDocumentMapping("type1", nestedMapping)
|
|
err = imap.Validate()
|
|
if err == nil {
|
|
t.Fatalf("expected error for nested type mapping, got nil")
|
|
}
|
|
// valid nested mappings within DefaultMapping
|
|
imap = mapping.NewIndexMapping()
|
|
docMapping := mapping.NewDocumentMapping()
|
|
nestedMapping = mapping.NewNestedDocumentMapping()
|
|
fieldMapping := mapping.NewTextFieldMapping()
|
|
nestedMapping.AddFieldMappingsAt("field1", fieldMapping)
|
|
docMapping.AddSubDocumentMapping("nestedField", nestedMapping)
|
|
imap.DefaultMapping = docMapping
|
|
err = imap.Validate()
|
|
if err != nil {
|
|
t.Fatalf("expected valid nested mapping, got error: %v", err)
|
|
}
|
|
// valid nested mappings within type mapping
|
|
imap = mapping.NewIndexMapping()
|
|
docMapping = mapping.NewDocumentMapping()
|
|
nestedMapping = mapping.NewNestedDocumentMapping()
|
|
fieldMapping = mapping.NewTextFieldMapping()
|
|
nestedMapping.AddFieldMappingsAt("field1", fieldMapping)
|
|
docMapping.AddSubDocumentMapping("nestedField", nestedMapping)
|
|
imap.AddDocumentMapping("type1", docMapping)
|
|
err = imap.Validate()
|
|
if err != nil {
|
|
t.Fatalf("expected valid nested mapping, got error: %v", err)
|
|
}
|
|
// some nested type mappings
|
|
imap = mapping.NewIndexMapping()
|
|
nestedMapping = mapping.NewNestedDocumentMapping()
|
|
regularMapping := mapping.NewDocumentMapping()
|
|
imap.AddDocumentMapping("non_nested1", regularMapping)
|
|
imap.AddDocumentMapping("non_nested2", regularMapping)
|
|
imap.AddDocumentMapping("nested1", nestedMapping)
|
|
imap.AddDocumentMapping("nested2", nestedMapping)
|
|
err = imap.Validate()
|
|
if err == nil {
|
|
t.Fatalf("expected error for nested type mappings, got nil")
|
|
}
|
|
}
|