github.com/weaviate/weaviate@v1.24.6/test/acceptance/graphql_resolvers/local_get_cursor_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package test 13 14 import ( 15 "fmt" 16 "testing" 17 18 "github.com/go-openapi/strfmt" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 "github.com/weaviate/weaviate/test/helper" 22 graphqlhelper "github.com/weaviate/weaviate/test/helper/graphql" 23 "github.com/weaviate/weaviate/test/helper/sample-schema/multishard" 24 ) 25 26 func getWithCursorSearch(t *testing.T) { 27 t.Run("listing objects using cursor api", func(t *testing.T) { 28 tests := []struct { 29 name string 30 className string 31 after string 32 limit int 33 filter string 34 expectedIDs []strfmt.UUID 35 expectedErrorMsg string 36 }{ 37 { 38 name: `cursor with after: "" limit: 2`, 39 className: "CursorClass", 40 after: "", 41 limit: 2, 42 expectedIDs: []strfmt.UUID{ 43 cursorClassID1, 44 cursorClassID2, 45 cursorClassID3, 46 cursorClassID4, 47 cursorClassID5, 48 cursorClassID6, 49 cursorClassID7, 50 }, 51 }, 52 { 53 name: fmt.Sprintf("cursor with after: \"%s\" limit: 1", cursorClassID4), 54 className: "CursorClass", 55 after: cursorClassID4.String(), 56 limit: 1, 57 expectedIDs: []strfmt.UUID{ 58 cursorClassID5, 59 cursorClassID6, 60 cursorClassID7, 61 }, 62 }, 63 { 64 name: "error with offset", 65 className: "CursorClass", 66 filter: `limit: 1 after: "" offset: 1`, 67 expectedErrorMsg: "cursor api: invalid 'after' parameter: offset cannot be set with after and limit parameters", 68 }, 69 { 70 name: "error with nearObject", 71 className: "CursorClass", 72 filter: fmt.Sprintf("limit: 1 after: \"\" nearObject:{id:\"%s\"}", cursorClassID1), 73 expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", 74 }, 75 { 76 name: "error with nearVector", 77 className: "CursorClass", 78 filter: `limit: 1 after: "" nearVector:{vector:[0.1, 0.2]}`, 79 expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", 80 }, 81 { 82 name: "error with hybrid", 83 className: "CursorClass", 84 filter: `limit: 1 after: "" hybrid:{query:"cursor api"}`, 85 expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", 86 }, 87 { 88 name: "error with bm25", 89 className: "CursorClass", 90 filter: `limit: 1 after: "" bm25:{query:"cursor api"}`, 91 expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", 92 }, 93 { 94 name: "error with sort", 95 className: "CursorClass", 96 filter: `limit: 1 after: "" sort:{path:"name"}`, 97 expectedErrorMsg: "cursor api: invalid 'after' parameter: sort cannot be set with after and limit parameters", 98 }, 99 { 100 name: "error with where", 101 className: "CursorClass", 102 filter: `limit: 1 after: "" where:{path:"id" operator:Like valueText:"*"}`, 103 expectedErrorMsg: "cursor api: invalid 'after' parameter: where cannot be set with after and limit parameters", 104 }, 105 { 106 name: "error with bm25, hybrid and offset", 107 className: "CursorClass", 108 filter: `limit: 1 after: "" bm25:{query:"cursor api"} hybrid:{query:"cursor api"} offset:1`, 109 expectedErrorMsg: "cursor api: invalid 'after' parameter: other params cannot be set with after and limit parameters", 110 }, 111 { 112 name: "error with no limit set", 113 className: "CursorClass", 114 filter: `after:"00000000-0000-0000-0000-000000000000"`, 115 expectedErrorMsg: "cursor api: invalid 'after' parameter: limit parameter must be set", 116 }, 117 // multi shard 118 { 119 name: `multi shard cursor with after: "" limit: 1`, 120 className: "MultiShard", 121 after: "", 122 limit: 1, 123 expectedIDs: []strfmt.UUID{ 124 multishard.MultiShardID1, 125 multishard.MultiShardID2, 126 multishard.MultiShardID3, 127 }, 128 }, 129 } 130 for _, tt := range tests { 131 t.Run(tt.name, func(t *testing.T) { 132 query := "{ Get { " + tt.className + " %s { _additional { id } } } }" 133 if len(tt.expectedErrorMsg) > 0 { 134 errQuery := fmt.Sprintf(query, fmt.Sprintf("(%s)", tt.filter)) 135 result := graphqlhelper.ErrorGraphQL(t, helper.RootAuth, errQuery) 136 assert.Len(t, result, 1) 137 138 errMsg := result[0].Message 139 assert.Equal(t, tt.expectedErrorMsg, errMsg) 140 } else { 141 parseResults := func(t *testing.T, cities []interface{}) []strfmt.UUID { 142 var ids []strfmt.UUID 143 for _, city := range cities { 144 id, ok := city.(map[string]interface{})["_additional"].(map[string]interface{})["id"] 145 require.True(t, ok) 146 147 idString, ok := id.(string) 148 require.True(t, ok) 149 150 ids = append(ids, strfmt.UUID(idString)) 151 } 152 return ids 153 } 154 // use cursor api 155 cursorSearch := func(t *testing.T, className, after string, limit int) []strfmt.UUID { 156 cursor := fmt.Sprintf(`(limit: %v after: "%s")`, limit, after) 157 result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, fmt.Sprintf(query, cursor)) 158 cities := result.Get("Get", className).AsSlice() 159 return parseResults(t, cities) 160 } 161 162 var cursorIDs []strfmt.UUID 163 after, limit := tt.after, tt.limit 164 for { 165 result := cursorSearch(t, tt.className, after, limit) 166 cursorIDs = append(cursorIDs, result...) 167 if len(result) == 0 { 168 break 169 } 170 after = result[len(result)-1].String() 171 } 172 173 assert.ElementsMatch(t, tt.expectedIDs, cursorIDs) 174 require.Equal(t, len(tt.expectedIDs), len(cursorIDs)) 175 for i := range tt.expectedIDs { 176 assert.Equal(t, tt.expectedIDs[i], cursorIDs[i]) 177 } 178 } 179 }) 180 } 181 }) 182 }