KevinStephenson
Adding in weaviate code
b110593
raw
history blame
14.5 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package refcache
import (
"context"
"fmt"
"testing"
"time"
"github.com/go-openapi/strfmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/weaviate/weaviate/entities/additional"
"github.com/weaviate/weaviate/entities/models"
"github.com/weaviate/weaviate/entities/multi"
"github.com/weaviate/weaviate/entities/search"
)
func TestResolver(t *testing.T) {
id1 := "df5d4e49-0c56-4b87-ade1-3d46cc9b425f"
id2 := "3a08d808-8eb5-49ee-86b2-68b6035e8b69"
t.Run("with nil input", func(t *testing.T) {
r := NewResolver(newFakeCacher())
res, err := r.Do(context.Background(), nil, nil, additional.Properties{})
require.Nil(t, err)
assert.Nil(t, res)
})
t.Run("with nil-schemas", func(t *testing.T) {
r := NewResolver(newFakeCacher())
input := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
},
}
expected := input
res, err := r.Do(context.Background(), input, nil, additional.Properties{})
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with single ref but no select props", func(t *testing.T) {
r := NewResolver(newFakeCacher())
input := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: "weaviate://localhost/123",
},
},
},
},
}
expected := input
res, err := r.Do(context.Background(), input, nil, additional.Properties{})
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with single ref with vector and matching select prop", func(t *testing.T) {
getInput := func() []search.Result {
return []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id1)),
},
},
},
},
}
}
getResolver := func() *Resolver {
cacher := newFakeCacher()
r := NewResolver(cacher)
cacher.lookup[multi.Identifier{ID: id1, ClassName: "SomeClass"}] = search.Result{
ClassName: "SomeClass",
ID: strfmt.UUID(id1),
Schema: map[string]interface{}{
"bar": "some string",
},
Vector: []float32{0.1, 0.2},
}
return r
}
getSelectProps := func(withVector bool) search.SelectProperties {
return search.SelectProperties{
search.SelectProperty{
Name: "refProp",
Refs: []search.SelectClass{
{
ClassName: "SomeClass",
RefProperties: search.SelectProperties{
search.SelectProperty{
Name: "bar",
IsPrimitive: true,
},
},
AdditionalProperties: additional.Properties{
Vector: withVector,
},
},
},
},
}
}
getExpectedResult := func(withVector bool) []search.Result {
fields := map[string]interface{}{
"bar": "some string",
}
if withVector {
fields["vector"] = []float32{0.1, 0.2}
}
return []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": []interface{}{
search.LocalRef{
Class: "SomeClass",
Fields: fields,
},
},
},
},
}
}
// ask for vector in ref property
res, err := getResolver().Do(context.Background(), getInput(), getSelectProps(true), additional.Properties{})
require.Nil(t, err)
assert.Equal(t, getExpectedResult(true), res)
// don't ask for vector in ref property
res, err = getResolver().Do(context.Background(), getInput(), getSelectProps(false), additional.Properties{})
require.Nil(t, err)
assert.Equal(t, getExpectedResult(false), res)
})
t.Run("with single ref with creation/update timestamps and matching select prop", func(t *testing.T) {
now := time.Now().UnixMilli()
getInput := func() []search.Result {
return []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id1)),
},
},
},
},
}
}
getResolver := func() *Resolver {
cacher := newFakeCacher()
r := NewResolver(cacher)
cacher.lookup[multi.Identifier{ID: id1, ClassName: "SomeClass"}] = search.Result{
ClassName: "SomeClass",
ID: strfmt.UUID(id1),
Schema: map[string]interface{}{
"bar": "some string",
},
Created: now,
Updated: now,
}
return r
}
selectProps := search.SelectProperties{
search.SelectProperty{
Name: "refProp",
Refs: []search.SelectClass{
{
ClassName: "SomeClass",
RefProperties: search.SelectProperties{
search.SelectProperty{
Name: "bar",
IsPrimitive: true,
},
},
AdditionalProperties: additional.Properties{
CreationTimeUnix: true,
LastUpdateTimeUnix: true,
},
},
},
},
}
expected := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": []interface{}{
search.LocalRef{
Class: "SomeClass",
Fields: map[string]interface{}{
"bar": "some string",
"creationTimeUnix": now,
"lastUpdateTimeUnix": now,
},
},
},
},
},
}
res, err := getResolver().Do(context.Background(), getInput(), selectProps, additional.Properties{})
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with single ref and matching select prop", func(t *testing.T) {
cacher := newFakeCacher()
r := NewResolver(cacher)
cacher.lookup[multi.Identifier{ID: id1, ClassName: "SomeClass"}] = search.Result{
ClassName: "SomeClass",
ID: strfmt.UUID(id1),
Schema: map[string]interface{}{
"bar": "some string",
},
}
input := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id1)),
},
},
},
},
}
selectProps := search.SelectProperties{
search.SelectProperty{
Name: "refProp",
Refs: []search.SelectClass{
{
ClassName: "SomeClass",
RefProperties: search.SelectProperties{
search.SelectProperty{
Name: "bar",
IsPrimitive: true,
},
},
},
},
},
}
expected := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": []interface{}{
search.LocalRef{
Class: "SomeClass",
Fields: map[string]interface{}{
"bar": "some string",
},
},
},
},
},
}
res, err := r.Do(context.Background(), input, selectProps, additional.Properties{})
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with a nested lookup", func(t *testing.T) {
cacher := newFakeCacher()
r := NewResolver(cacher)
cacher.lookup[multi.Identifier{ID: id1, ClassName: "SomeClass"}] = search.Result{
ClassName: "SomeClass",
ID: strfmt.UUID(id1),
Schema: map[string]interface{}{
"primitive": "foobar",
"ignoredRef": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI("weaviate://localhost/ignoreMe"),
},
},
"nestedRef": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id2)),
},
},
},
}
cacher.lookup[multi.Identifier{ID: id2, ClassName: "SomeNestedClass"}] = search.Result{
ClassName: "SomeNestedClass",
ID: strfmt.UUID(id2),
Schema: map[string]interface{}{
"name": "John Doe",
},
}
input := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id1)),
},
},
},
},
}
selectProps := search.SelectProperties{
search.SelectProperty{
Name: "refProp",
Refs: []search.SelectClass{
{
ClassName: "SomeClass",
RefProperties: search.SelectProperties{
search.SelectProperty{
Name: "primitive",
IsPrimitive: true,
},
search.SelectProperty{
Name: "nestedRef",
Refs: []search.SelectClass{
{
ClassName: "SomeNestedClass",
RefProperties: []search.SelectProperty{
{
Name: "name",
IsPrimitive: true,
},
},
},
},
},
},
},
},
},
}
expected := []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": []interface{}{
search.LocalRef{
Class: "SomeClass",
Fields: map[string]interface{}{
"primitive": "foobar",
"ignoredRef": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI("weaviate://localhost/ignoreMe"),
},
},
"nestedRef": []interface{}{
search.LocalRef{
Class: "SomeNestedClass",
Fields: map[string]interface{}{
"name": "John Doe",
},
},
},
},
},
},
},
},
}
res, err := r.Do(context.Background(), input, selectProps, additional.Properties{})
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with single ref with vector and matching select prop and group", func(t *testing.T) {
getInput := func() []search.Result {
return []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id1)),
},
},
},
AdditionalProperties: models.AdditionalProperties{
"group": &additional.Group{
Hits: []map[string]interface{}{
{
"nestedRef": models.MultipleRef{
&models.SingleRef{
Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/SomeNestedClass/%s", id2)),
},
},
},
},
},
},
},
}
}
getResolver := func() *Resolver {
cacher := newFakeCacher()
r := NewResolverWithGroup(cacher)
cacher.lookup[multi.Identifier{ID: id1, ClassName: "SomeClass"}] = search.Result{
ClassName: "SomeClass",
ID: strfmt.UUID(id1),
Schema: map[string]interface{}{
"bar": "some string",
},
Vector: []float32{0.1, 0.2},
}
cacher.lookup[multi.Identifier{ID: id2, ClassName: "SomeNestedClass"}] = search.Result{
ClassName: "SomeNestedClass",
ID: strfmt.UUID(id2),
Schema: map[string]interface{}{
"name": "John Doe",
},
}
return r
}
getSelectProps := func(withVector bool) search.SelectProperties {
return search.SelectProperties{
search.SelectProperty{
Name: "refProp",
Refs: []search.SelectClass{
{
ClassName: "SomeClass",
RefProperties: search.SelectProperties{
search.SelectProperty{
Name: "bar",
IsPrimitive: true,
},
},
AdditionalProperties: additional.Properties{
Vector: withVector,
},
},
},
},
search.SelectProperty{
Name: "_additional:group:hits:nestedRef",
Refs: []search.SelectClass{
{
ClassName: "SomeNestedClass",
RefProperties: []search.SelectProperty{
{
Name: "name",
IsPrimitive: true,
},
},
},
},
},
}
}
getExpectedResult := func(withVector bool) []search.Result {
fields := map[string]interface{}{
"bar": "some string",
}
if withVector {
fields["vector"] = []float32{0.1, 0.2}
}
return []search.Result{
{
ID: "foo",
ClassName: "BestClass",
Schema: map[string]interface{}{
"refProp": []interface{}{
search.LocalRef{
Class: "SomeClass",
Fields: fields,
},
},
},
AdditionalProperties: models.AdditionalProperties{
"group": &additional.Group{
Hits: []map[string]interface{}{
{
"nestedRef": []interface{}{
search.LocalRef{
Class: "SomeNestedClass",
Fields: map[string]interface{}{
"name": "John Doe",
},
},
},
},
},
},
},
},
}
}
// ask for vector in ref property
res, err := getResolver().Do(context.Background(), getInput(), getSelectProps(true), additional.Properties{})
require.Nil(t, err)
assert.Equal(t, getExpectedResult(true), res)
// don't ask for vector in ref property
res, err = getResolver().Do(context.Background(), getInput(), getSelectProps(false), additional.Properties{})
require.Nil(t, err)
assert.Equal(t, getExpectedResult(false), res)
})
}
func newFakeCacher() *fakeCacher {
return &fakeCacher{
lookup: map[multi.Identifier]search.Result{},
}
}
type fakeCacher struct {
lookup map[multi.Identifier]search.Result
}
func (f *fakeCacher) Build(ctx context.Context, objects []search.Result, properties search.SelectProperties,
additional additional.Properties,
) error {
return nil
}
func (f *fakeCacher) Get(si multi.Identifier) (search.Result, bool) {
res, ok := f.lookup[si]
return res, ok
}