Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ V V / __/ (_| |\ V /| | (_| | || __/ | |
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
// | |
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
// | |
// CONTACT: [email protected] | |
// | |
package test | |
import ( | |
"fmt" | |
"testing" | |
"github.com/go-openapi/strfmt" | |
"github.com/stretchr/testify/assert" | |
"github.com/stretchr/testify/require" | |
"github.com/weaviate/weaviate/test/helper" | |
graphqlhelper "github.com/weaviate/weaviate/test/helper/graphql" | |
"github.com/weaviate/weaviate/test/helper/sample-schema/multishard" | |
) | |
func getWithCursorSearch(t *testing.T) { | |
t.Run("listing objects using cursor api", func(t *testing.T) { | |
tests := []struct { | |
name string | |
className string | |
after string | |
limit int | |
filter string | |
expectedIDs []strfmt.UUID | |
expectedErrorMsg string | |
}{ | |
{ | |
name: `cursor with after: "" limit: 2`, | |
className: "CursorClass", | |
after: "", | |
limit: 2, | |
expectedIDs: []strfmt.UUID{ | |
cursorClassID1, | |
cursorClassID2, | |
cursorClassID3, | |
cursorClassID4, | |
cursorClassID5, | |
cursorClassID6, | |
cursorClassID7, | |
}, | |
}, | |
{ | |
name: fmt.Sprintf("cursor with after: \"%s\" limit: 1", cursorClassID4), | |
className: "CursorClass", | |
after: cursorClassID4.String(), | |
limit: 1, | |
expectedIDs: []strfmt.UUID{ | |
cursorClassID5, | |
cursorClassID6, | |
cursorClassID7, | |
}, | |
}, | |
{ | |
name: "error with offset", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" offset: 1`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: offset cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with nearObject", | |
className: "CursorClass", | |
filter: fmt.Sprintf("limit: 1 after: \"\" nearObject:{id:\"%s\"}", cursorClassID1), | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with nearVector", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" nearVector:{vector:[0.1, 0.2]}`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with hybrid", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" hybrid:{query:"cursor api"}`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with bm25", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" bm25:{query:"cursor api"}`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with sort", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" sort:{path:"name"}`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: sort cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with where", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" where:{path:"id" operator:Like valueText:"*"}`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: where cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with bm25, hybrid and offset", | |
className: "CursorClass", | |
filter: `limit: 1 after: "" bm25:{query:"cursor api"} hybrid:{query:"cursor api"} offset:1`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", | |
}, | |
{ | |
name: "error with no limit set", | |
className: "CursorClass", | |
filter: `after:"00000000-0000-0000-0000-000000000000"`, | |
expectedErrorMsg: "cursor api: invalid 'after' parameter: limit parameter must be set", | |
}, | |
// multi shard | |
{ | |
name: `multi shard cursor with after: "" limit: 1`, | |
className: "MultiShard", | |
after: "", | |
limit: 1, | |
expectedIDs: []strfmt.UUID{ | |
multishard.MultiShardID1, | |
multishard.MultiShardID2, | |
multishard.MultiShardID3, | |
}, | |
}, | |
} | |
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
query := "{ Get { " + tt.className + " %s { _additional { id } } } }" | |
if len(tt.expectedErrorMsg) > 0 { | |
errQuery := fmt.Sprintf(query, fmt.Sprintf("(%s)", tt.filter)) | |
result := graphqlhelper.ErrorGraphQL(t, helper.RootAuth, errQuery) | |
assert.Len(t, result, 1) | |
errMsg := result[0].Message | |
assert.Equal(t, tt.expectedErrorMsg, errMsg) | |
} else { | |
parseResults := func(t *testing.T, cities []interface{}) []strfmt.UUID { | |
var ids []strfmt.UUID | |
for _, city := range cities { | |
id, ok := city.(map[string]interface{})["_additional"].(map[string]interface{})["id"] | |
require.True(t, ok) | |
idString, ok := id.(string) | |
require.True(t, ok) | |
ids = append(ids, strfmt.UUID(idString)) | |
} | |
return ids | |
} | |
// use cursor api | |
cursorSearch := func(t *testing.T, className, after string, limit int) []strfmt.UUID { | |
cursor := fmt.Sprintf(`(limit: %v after: "%s")`, limit, after) | |
result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, fmt.Sprintf(query, cursor)) | |
cities := result.Get("Get", className).AsSlice() | |
return parseResults(t, cities) | |
} | |
var cursorIDs []strfmt.UUID | |
after, limit := tt.after, tt.limit | |
for { | |
result := cursorSearch(t, tt.className, after, limit) | |
cursorIDs = append(cursorIDs, result...) | |
if len(result) == 0 { | |
break | |
} | |
after = result[len(result)-1].String() | |
} | |
assert.ElementsMatch(t, tt.expectedIDs, cursorIDs) | |
require.Equal(t, len(tt.expectedIDs), len(cursorIDs)) | |
for i := range tt.expectedIDs { | |
assert.Equal(t, tt.expectedIDs[i], cursorIDs[i]) | |
} | |
} | |
}) | |
} | |
}) | |
} | |