github.com/weaviate/weaviate@v1.24.6/test/acceptance/actions/object_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 "encoding/json" 16 "errors" 17 "fmt" 18 "testing" 19 "time" 20 21 "github.com/go-openapi/strfmt" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 "github.com/weaviate/weaviate/client/batch" 25 "github.com/weaviate/weaviate/client/objects" 26 "github.com/weaviate/weaviate/entities/models" 27 "github.com/weaviate/weaviate/entities/schema" 28 "github.com/weaviate/weaviate/entities/schema/crossref" 29 "github.com/weaviate/weaviate/test/helper" 30 ) 31 32 func TestFindObject(t *testing.T) { 33 t.Parallel() 34 var ( 35 cls = "TestObjectHTTPGet" 36 first_friend = "TestObjectHTTPGetFriendFirst" 37 second_friend = "TestObjectHTTPGetFriendSecond" 38 ) 39 40 // test setup 41 first_uuid := helper.AssertCreateObject(t, first_friend, map[string]interface{}{}) 42 defer helper.DeleteClassObject(t, first_friend) 43 second_uuid := helper.AssertCreateObject(t, second_friend, map[string]interface{}{}) 44 defer helper.DeleteClassObject(t, second_friend) 45 46 helper.AssertCreateObjectClass(t, &models.Class{ 47 Class: cls, 48 Vectorizer: "none", 49 Properties: []*models.Property{ 50 { 51 Name: "name", 52 DataType: schema.DataTypeText.PropString(), 53 Tokenization: models.PropertyTokenizationWhitespace, 54 }, 55 { 56 Name: "friend", 57 DataType: []string{first_friend, second_friend}, 58 }, 59 }, 60 }) 61 // tear down 62 defer helper.DeleteClassObject(t, cls) 63 link1 := map[string]interface{}{ 64 "beacon": crossref.NewLocalhost(first_friend, first_uuid).String(), 65 "href": fmt.Sprintf("/v1/objects/%s/%s", first_friend, first_uuid), 66 } 67 link2 := map[string]interface{}{ 68 "beacon": crossref.NewLocalhost(second_friend, second_uuid).String(), 69 "href": fmt.Sprintf("/v1/objects/%s/%s", second_friend, second_uuid), 70 } 71 expected := map[string]interface{}{ 72 "number": json.Number("2"), 73 "friend": []interface{}{link1, link2}, 74 } 75 76 uuid := helper.AssertCreateObject(t, cls, expected) 77 78 r := objects.NewObjectsClassGetParams().WithID(uuid).WithClassName(cls) 79 resp, err := helper.Client(t).Objects.ObjectsClassGet(r, nil) 80 helper.AssertRequestOk(t, resp, err, nil) 81 assert.Equal(t, expected, resp.Payload.Properties.(map[string]interface{})) 82 83 // check for an object which doesn't exist 84 unknown_uuid := strfmt.UUID("11110000-0000-0000-0000-000011110000") 85 r = objects.NewObjectsClassGetParams().WithID(unknown_uuid).WithClassName(cls) 86 resp, err = helper.Client(t).Objects.ObjectsClassGet(r, nil) 87 helper.AssertRequestFail(t, resp, err, nil) 88 } 89 90 func TestHeadObject(t *testing.T) { 91 t.Parallel() 92 cls := "TestObjectHTTPHead" 93 // test setup 94 helper.AssertCreateObjectClass(t, &models.Class{ 95 Class: cls, 96 Vectorizer: "none", 97 Properties: []*models.Property{ 98 { 99 Name: "name", 100 DataType: schema.DataTypeText.PropString(), 101 Tokenization: models.PropertyTokenizationWhitespace, 102 }, 103 }, 104 }) 105 // tear down 106 defer helper.DeleteClassObject(t, cls) 107 108 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 109 "name": "John", 110 }) 111 112 r := objects.NewObjectsClassHeadParams().WithID(uuid).WithClassName(cls) 113 resp, err := helper.Client(t).Objects.ObjectsClassHead(r, nil) 114 helper.AssertRequestOk(t, resp, err, nil) 115 116 // check for an object which doesn't exist 117 unknown_uuid := strfmt.UUID("11110000-0000-0000-0000-000011110000") 118 r = objects.NewObjectsClassHeadParams().WithID(unknown_uuid).WithClassName(cls) 119 resp, err = helper.Client(t).Objects.ObjectsClassHead(r, nil) 120 helper.AssertRequestFail(t, resp, err, nil) 121 } 122 123 func TestPutObject(t *testing.T) { 124 t.Parallel() 125 var ( 126 cls = "TestObjectHTTPUpdate" 127 friend_cls = "TestObjectHTTPUpdateFriend" 128 ) 129 130 // test setup 131 friend_uuid := helper.AssertCreateObject(t, friend_cls, map[string]interface{}{}) 132 defer helper.DeleteClassObject(t, friend_cls) 133 134 helper.AssertCreateObjectClass(t, &models.Class{ 135 Class: cls, 136 ModuleConfig: map[string]interface{}{ 137 "text2vec-contextionary": map[string]interface{}{ 138 "vectorizeClassName": true, 139 }, 140 }, 141 Properties: []*models.Property{ 142 { 143 Name: "testString", 144 DataType: schema.DataTypeText.PropString(), 145 Tokenization: models.PropertyTokenizationWhitespace, 146 }, 147 { 148 Name: "testWholeNumber", 149 DataType: []string{"int"}, 150 }, 151 { 152 Name: "testNumber", 153 DataType: []string{"number"}, 154 }, 155 { 156 Name: "testDateTime", 157 DataType: []string{"date"}, 158 }, 159 { 160 Name: "testTrueFalse", 161 DataType: []string{"boolean"}, 162 }, 163 { 164 Name: "friend", 165 DataType: []string{friend_cls}, 166 }, 167 }, 168 }) 169 // tear down 170 defer helper.DeleteClassObject(t, cls) 171 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 172 "testWholeNumber": 2.0, 173 "testDateTime": time.Now(), 174 "testString": "wibbly", 175 }) 176 177 link1 := map[string]interface{}{ 178 "beacon": crossref.NewLocalhost(friend_cls, friend_uuid).String(), 179 "href": fmt.Sprintf("/v1/objects/%s/%s", friend_cls, friend_uuid), 180 } 181 link2 := map[string]interface{}{ 182 "beacon": crossref.NewLocalhost(friend_cls, friend_uuid).String(), 183 "href": fmt.Sprintf("/v1/objects/%s/%s", friend_cls, friend_uuid), 184 } 185 expected := map[string]interface{}{ 186 "testNumber": json.Number("2"), 187 "testTrueFalse": true, 188 "testString": "wibbly wobbly", 189 "friend": []interface{}{link1, link2}, 190 } 191 update := models.Object{ 192 Class: cls, 193 Properties: models.PropertySchema(expected), 194 ID: uuid, 195 } 196 params := objects.NewObjectsClassPutParams().WithID(uuid).WithBody(&update) 197 updateResp, err := helper.Client(t).Objects.ObjectsClassPut(params, nil) 198 helper.AssertRequestOk(t, updateResp, err, nil) 199 actual := helper.AssertGetObject(t, cls, uuid).Properties.(map[string]interface{}) 200 assert.Equal(t, expected, actual) 201 } 202 203 func TestPatchObject(t *testing.T) { 204 t.Parallel() 205 var ( 206 cls = "TestObjectHTTPPatch" 207 friend_cls = "TestObjectHTTPPatchFriend" 208 mconfig = map[string]interface{}{ 209 "text2vec-contextionary": map[string]interface{}{ 210 "vectorizeClassName": true, 211 }, 212 } 213 ) 214 // test setup 215 helper.AssertCreateObjectClass(t, &models.Class{ // friend 216 Class: friend_cls, 217 ModuleConfig: mconfig, 218 Properties: []*models.Property{}, 219 }) 220 defer helper.DeleteClassObject(t, friend_cls) 221 helper.AssertCreateObjectClass(t, &models.Class{ // class 222 Class: cls, 223 ModuleConfig: mconfig, 224 Properties: []*models.Property{ 225 { 226 Name: "string1", 227 DataType: schema.DataTypeText.PropString(), 228 Tokenization: models.PropertyTokenizationWhitespace, 229 }, 230 { 231 Name: "integer1", 232 DataType: []string{"int"}, 233 }, 234 { 235 Name: "number1", 236 DataType: []string{"number"}, 237 }, 238 { 239 Name: "friend", 240 DataType: []string{friend_cls}, 241 }, 242 { 243 Name: "boolean1", 244 DataType: []string{"boolean"}, 245 }, 246 }, 247 }) 248 defer helper.DeleteClassObject(t, cls) 249 250 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 251 "integer1": 2.0, 252 "string1": "wibbly", 253 }) 254 friendID := helper.AssertCreateObject(t, friend_cls, nil) 255 link1 := map[string]interface{}{ 256 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", friend_cls, friendID), 257 "href": fmt.Sprintf("/v1/objects/%s/%s", friend_cls, friendID), 258 } 259 link2 := map[string]interface{}{ 260 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", friend_cls, friendID), 261 "href": fmt.Sprintf("/v1/objects/%s/%s", friend_cls, friendID), 262 } 263 expected := map[string]interface{}{ 264 "integer1": json.Number("2"), 265 "number1": json.Number("3"), 266 "boolean1": true, 267 "string1": "wibbly wobbly", 268 "friend": []interface{}{link1, link2}, 269 } 270 update := map[string]interface{}{ 271 "number1": 3.0, 272 "boolean1": true, 273 "string1": "wibbly wobbly", 274 "friend": []interface{}{ 275 map[string]interface{}{ 276 "beacon": link1["beacon"], 277 }, map[string]interface{}{ 278 "beacon": link2["beacon"], 279 }, 280 }, 281 } 282 updateObj := models.Object{ 283 Properties: models.PropertySchema(update), 284 } 285 params := objects.NewObjectsClassPatchParams().WithClassName(cls) 286 params.WithID(uuid).WithBody(&updateObj) 287 updateResp, err := helper.Client(t).Objects.ObjectsClassPatch(params, nil) 288 helper.AssertRequestOk(t, updateResp, err, nil) 289 actual := func() interface{} { 290 obj := helper.AssertGetObject(t, cls, uuid) 291 props := obj.Properties.(map[string]interface{}) 292 return props 293 } 294 helper.AssertEventuallyEqual(t, expected, actual) 295 296 params.WithID(strfmt.UUID("e5be1f32-0001-0000-0000-ebb25dfc811f")) 297 _, err = helper.Client(t).Objects.ObjectsClassPatch(params, nil) 298 if err == nil { 299 t.Errorf("must return an error for non existing object") 300 } 301 } 302 303 func TestDeleteObject(t *testing.T) { 304 t.Parallel() 305 var ( 306 id = strfmt.UUID("21111111-1111-1111-1111-111111111111") 307 classA = "TestObjectHTTPDeleteA" 308 classB = "TestObjectHTTPDeleteB" 309 props = []*models.Property{ 310 { 311 Name: "text", 312 DataType: []string{"text"}, 313 }, 314 } 315 ) 316 // test setup 317 helper.AssertCreateObjectClass(t, &models.Class{ 318 Class: classA, 319 Vectorizer: "none", 320 Properties: props, 321 }) 322 defer helper.DeleteClassObject(t, classA) 323 324 helper.AssertCreateObjectClass(t, &models.Class{ 325 Class: classB, 326 Vectorizer: "none", 327 Properties: props, 328 }) 329 330 defer helper.DeleteClassObject(t, classB) 331 332 object1 := &models.Object{ 333 Class: classA, 334 ID: id, 335 Properties: map[string]interface{}{ 336 "text": "string 1", 337 }, 338 } 339 object2 := &models.Object{ 340 Class: classB, 341 ID: id, 342 Properties: map[string]interface{}{ 343 "text": "string 2", 344 }, 345 } 346 347 // create objects 348 returnedFields := "ALL" 349 params := batch.NewBatchObjectsCreateParams().WithBody( 350 batch.BatchObjectsCreateBody{ 351 Objects: []*models.Object{object1, object2}, 352 Fields: []*string{&returnedFields}, 353 }) 354 355 resp, err := helper.BatchClient(t).BatchObjectsCreate(params, nil) 356 357 // ensure that the response is OK 358 helper.AssertRequestOk(t, resp, err, func() { 359 objectsCreateResponse := resp.Payload 360 361 // check if the batch response contains two batched responses 362 assert.Equal(t, 2, len(objectsCreateResponse)) 363 364 for _, elem := range resp.Payload { 365 assert.Nil(t, elem.Result.Errors) 366 } 367 }) 368 369 { // "delete object from first class 370 params := objects.NewObjectsClassDeleteParams().WithClassName(classA).WithID(id) 371 resp, err := helper.Client(t).Objects.ObjectsClassDelete(params, nil) 372 if err != nil { 373 t.Errorf("cannot delete existing object err: %v", err) 374 } 375 assert.Equal(t, &objects.ObjectsClassDeleteNoContent{}, resp) 376 } 377 { // check if object still exit 378 params := objects.NewObjectsClassGetParams().WithClassName(classA).WithID(id) 379 _, err := helper.Client(t).Objects.ObjectsClassGet(params, nil) 380 werr := &objects.ObjectsClassGetNotFound{} 381 if !errors.As(err, &werr) { 382 t.Errorf("Get deleted object error got: %v want %v", err, werr) 383 } 384 } 385 { // object with a different class must exist 386 params := objects.NewObjectsClassGetParams().WithClassName(classB).WithID(id) 387 resp, err := helper.Client(t).Objects.ObjectsClassGet(params, nil) 388 if err != nil { 389 t.Errorf("object must exist err: %v", err) 390 } 391 if resp.Payload == nil { 392 t.Errorf("payload of an existing object cannot be empty") 393 } 394 } 395 396 { // "delete object again from first class 397 params := objects.NewObjectsClassDeleteParams().WithClassName(classA).WithID(id) 398 _, err := helper.Client(t).Objects.ObjectsClassDelete(params, nil) 399 werr := &objects.ObjectsClassDeleteNotFound{} 400 if !errors.As(err, &werr) { 401 t.Errorf("Get deleted object error got: %v want %v", err, werr) 402 } 403 } 404 } 405 406 func TestPostReference(t *testing.T) { 407 t.Parallel() 408 var ( 409 cls = "TestObjectHTTPAddReference" 410 friend_cls = "TestObjectHTTPAddReferenceFriend" 411 mconfig = map[string]interface{}{ 412 "text2vec-contextionary": map[string]interface{}{ 413 "vectorizeClassName": true, 414 }, 415 } 416 ) 417 418 // test setup 419 helper.AssertCreateObjectClass(t, &models.Class{ 420 Class: friend_cls, 421 ModuleConfig: mconfig, 422 Properties: []*models.Property{}, 423 }) 424 defer helper.DeleteClassObject(t, friend_cls) 425 helper.AssertCreateObjectClass(t, &models.Class{ 426 Class: cls, 427 ModuleConfig: mconfig, 428 Properties: []*models.Property{ 429 { 430 Name: "number", 431 DataType: []string{"number"}, 432 }, 433 { 434 Name: "friend", 435 DataType: []string{friend_cls}, 436 }, 437 }, 438 }) 439 defer helper.DeleteClassObject(t, cls) 440 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 441 "number": 2.0, 442 }) 443 friendID := helper.AssertCreateObject(t, friend_cls, nil) 444 expected := map[string]interface{}{ 445 "number": json.Number("2"), 446 "friend": []interface{}{ 447 map[string]interface{}{ 448 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", friend_cls, friendID), 449 "href": fmt.Sprintf("/v1/objects/%s/%s", friend_cls, friendID), 450 }, 451 }, 452 } 453 updateObj := crossref.NewLocalhost(friend_cls, friendID).SingleRef() 454 params := objects.NewObjectsClassReferencesCreateParams().WithClassName(cls) 455 params.WithID(uuid).WithBody(updateObj).WithPropertyName("friend") 456 resp, err := helper.Client(t).Objects.ObjectsClassReferencesCreate(params, nil) 457 helper.AssertRequestOk(t, resp, err, nil) 458 obj := helper.AssertGetObject(t, cls, uuid) 459 actual := obj.Properties.(map[string]interface{}) 460 assert.Equal(t, expected, actual) 461 462 params.WithPropertyName("unknown") 463 _, err = helper.Client(t).Objects.ObjectsClassReferencesCreate(params, nil) 464 if _, ok := err.(*objects.ObjectsClassReferencesCreateUnprocessableEntity); !ok { 465 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesCreateUnprocessableEntity{}, err) 466 } 467 468 params.WithPropertyName("friend") 469 params.WithID("e7cd261a-0000-0000-0000-d7b8e7b5c9ea") 470 _, err = helper.Client(t).Objects.ObjectsClassReferencesCreate(params, nil) 471 if _, ok := err.(*objects.ObjectsClassReferencesCreateNotFound); !ok { 472 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesCreateNotFound{}, err) 473 } 474 } 475 476 func TestPutReferences(t *testing.T) { 477 t.Parallel() 478 var ( 479 cls = "TestObjectHTTPUpdateReferences" 480 first_friend = "TestObjectHTTPUpdateReferencesFriendFirst" 481 second_friend = "TestObjectHTTPUpdateReferencesFriendSecond" 482 mconfig = map[string]interface{}{ 483 "text2vec-contextionary": map[string]interface{}{ 484 "vectorizeClassName": true, 485 }, 486 } 487 ) 488 // test setup 489 helper.AssertCreateObjectClass(t, &models.Class{ 490 Class: first_friend, 491 ModuleConfig: mconfig, 492 Properties: []*models.Property{}, 493 }) 494 defer helper.DeleteClassObject(t, first_friend) 495 496 helper.AssertCreateObjectClass(t, &models.Class{ 497 Class: second_friend, 498 ModuleConfig: mconfig, 499 Properties: []*models.Property{}, 500 }) 501 defer helper.DeleteClassObject(t, second_friend) 502 503 helper.AssertCreateObjectClass(t, &models.Class{ 504 Class: cls, 505 ModuleConfig: mconfig, 506 Properties: []*models.Property{ 507 { 508 Name: "number", 509 DataType: []string{"number"}, 510 }, 511 { 512 Name: "friend", 513 DataType: []string{first_friend, second_friend}, 514 }, 515 }, 516 }) 517 defer helper.DeleteClassObject(t, cls) 518 519 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 520 "number": 2.0, 521 }) 522 first_friendID := helper.AssertCreateObject(t, first_friend, nil) 523 second_friendID := helper.AssertCreateObject(t, second_friend, nil) 524 525 expected := map[string]interface{}{ 526 "number": json.Number("2"), 527 "friend": []interface{}{ 528 map[string]interface{}{ 529 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", first_friend, first_friendID), 530 "href": fmt.Sprintf("/v1/objects/%s/%s", first_friend, first_friendID), 531 }, 532 map[string]interface{}{ 533 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", second_friend, second_friendID), 534 "href": fmt.Sprintf("/v1/objects/%s/%s", second_friend, second_friendID), 535 }, 536 }, 537 } 538 updateObj := models.MultipleRef{ 539 crossref.NewLocalhost(first_friend, first_friendID).SingleRef(), 540 crossref.NewLocalhost(second_friend, second_friendID).SingleRef(), 541 } 542 // add two references 543 params := objects.NewObjectsClassReferencesPutParams().WithClassName(cls) 544 params.WithID(uuid).WithBody(updateObj).WithPropertyName("friend") 545 resp, err := helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 546 helper.AssertRequestOk(t, resp, err, nil) 547 obj := helper.AssertGetObject(t, cls, uuid) 548 actual := obj.Properties.(map[string]interface{}) 549 assert.Equal(t, expected, actual) 550 551 // exclude one reference 552 params.WithID(uuid).WithBody(updateObj[:1]).WithPropertyName("friend") 553 resp, err = helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 554 helper.AssertRequestOk(t, resp, err, nil) 555 obj = helper.AssertGetObject(t, cls, uuid) 556 actual = obj.Properties.(map[string]interface{}) 557 expected["friend"] = expected["friend"].([]interface{})[:1] 558 assert.Equal(t, expected, actual) 559 560 params.WithPropertyName("unknown") 561 _, err = helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 562 if _, ok := err.(*objects.ObjectsClassReferencesPutUnprocessableEntity); !ok { 563 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesPutUnprocessableEntity{}, err) 564 } 565 params.WithPropertyName("friend") 566 567 params.WithID("e7cd261a-0000-0000-0000-d7b8e7b5c9ea") 568 _, err = helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 569 if _, ok := err.(*objects.ObjectsClassReferencesPutNotFound); !ok { 570 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesPutNotFound{}, err) 571 } 572 params.WithID(uuid) 573 574 // exclude all 575 params.WithBody(models.MultipleRef{}).WithPropertyName("friend") 576 resp, err = helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 577 helper.AssertRequestOk(t, resp, err, nil) 578 obj = helper.AssertGetObject(t, cls, uuid) 579 actual = obj.Properties.(map[string]interface{}) 580 expected["friend"] = expected["friend"].([]interface{})[1:] 581 assert.Equal(t, expected, actual) 582 583 // bad request since body is required 584 params.WithID(uuid).WithBody(nil).WithPropertyName("friend") 585 _, err = helper.Client(t).Objects.ObjectsClassReferencesPut(params, nil) 586 if _, ok := err.(*objects.ObjectsClassReferencesPutUnprocessableEntity); !ok { 587 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesPutUnprocessableEntity{}, err) 588 } 589 } 590 591 func TestDeleteReference(t *testing.T) { 592 t.Parallel() 593 var ( 594 cls = "TestObjectHTTPDeleteReference" 595 first_friend = "TestObjectHTTPDeleteReferenceFriendFirst" 596 second_friend = "TestObjectHTTPDeleteReferenceFriendSecond" 597 mconfig = map[string]interface{}{ 598 "text2vec-contextionary": map[string]interface{}{ 599 "vectorizeClassName": true, 600 }, 601 } 602 ) 603 // test setup 604 helper.AssertCreateObjectClass(t, &models.Class{ 605 Class: first_friend, 606 ModuleConfig: mconfig, 607 Properties: []*models.Property{}, 608 }) 609 defer helper.DeleteClassObject(t, first_friend) 610 611 helper.AssertCreateObjectClass(t, &models.Class{ 612 Class: second_friend, 613 ModuleConfig: mconfig, 614 Properties: []*models.Property{}, 615 }) 616 defer helper.DeleteClassObject(t, second_friend) 617 618 helper.AssertCreateObjectClass(t, &models.Class{ 619 Class: cls, 620 ModuleConfig: mconfig, 621 Properties: []*models.Property{ 622 { 623 Name: "number", 624 DataType: []string{"number"}, 625 }, 626 { 627 Name: "friend", 628 DataType: []string{first_friend, second_friend}, 629 }, 630 }, 631 }) 632 defer helper.DeleteClassObject(t, cls) 633 634 first_friendID := helper.AssertCreateObject(t, first_friend, nil) 635 second_friendID := helper.AssertCreateObject(t, second_friend, nil) 636 uuid := helper.AssertCreateObject(t, cls, map[string]interface{}{ 637 "number": 2.0, 638 "friend": []interface{}{ 639 map[string]interface{}{ 640 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", first_friend, first_friendID), 641 "href": fmt.Sprintf("/v1/objects/%s/%s", first_friend, first_friendID), 642 }, 643 map[string]interface{}{ 644 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", second_friend, second_friendID), 645 "href": fmt.Sprintf("/v1/objects/%s/%s", second_friend, second_friendID), 646 }, 647 }, 648 }) 649 expected := map[string]interface{}{ 650 "number": json.Number("2"), 651 "friend": []interface{}{ 652 map[string]interface{}{ 653 "beacon": fmt.Sprintf("weaviate://localhost/%s/%s", first_friend, first_friendID), 654 "href": fmt.Sprintf("/v1/objects/%s/%s", first_friend, first_friendID), 655 }, 656 }, 657 } 658 659 updateObj := crossref.NewLocalhost(second_friend, second_friendID).SingleRef() 660 // delete second reference 661 params := objects.NewObjectsClassReferencesDeleteParams().WithClassName(cls) 662 params.WithID(uuid).WithBody(updateObj).WithPropertyName("friend") 663 resp, err := helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 664 helper.AssertRequestOk(t, resp, err, nil) 665 obj := helper.AssertGetObject(t, cls, uuid) 666 actual := obj.Properties.(map[string]interface{}) 667 assert.Equal(t, expected, actual) 668 669 // delete same reference again 670 resp, err = helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 671 helper.AssertRequestOk(t, resp, err, nil) 672 obj = helper.AssertGetObject(t, cls, uuid) 673 actual = obj.Properties.(map[string]interface{}) 674 assert.Equal(t, expected, actual) 675 676 // delete last reference 677 expected = map[string]interface{}{ 678 "number": json.Number("2"), 679 "friend": []interface{}{}, 680 } 681 updateObj = crossref.NewLocalhost(first_friend, first_friendID).SingleRef() 682 params.WithID(uuid).WithBody(updateObj).WithPropertyName("friend") 683 resp, err = helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 684 helper.AssertRequestOk(t, resp, err, nil) 685 obj = helper.AssertGetObject(t, cls, uuid) 686 actual = obj.Properties.(map[string]interface{}) 687 assert.Equal(t, expected, actual) 688 689 // property is not part of the schema 690 params.WithPropertyName("unknown") 691 _, err = helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 692 if _, ok := err.(*objects.ObjectsClassReferencesDeleteUnprocessableEntity); !ok { 693 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesDeleteUnprocessableEntity{}, err) 694 } 695 params.WithPropertyName("friend") 696 697 // This ID doesn't exist 698 params.WithID("e7cd261a-0000-0000-0000-d7b8e7b5c9ea") 699 _, err = helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 700 if _, ok := err.(*objects.ObjectsClassReferencesDeleteNotFound); !ok { 701 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesDeleteNotFound{}, err) 702 } 703 params.WithID(uuid) 704 705 // bad request since body is required 706 params.WithID(uuid).WithBody(nil).WithPropertyName("friend") 707 _, err = helper.Client(t).Objects.ObjectsClassReferencesDelete(params, nil) 708 if _, ok := err.(*objects.ObjectsClassReferencesDeleteUnprocessableEntity); !ok { 709 t.Errorf("error type expected: %T, got %T", objects.ObjectsClassReferencesDeleteUnprocessableEntity{}, err) 710 } 711 } 712 713 func TestQuery(t *testing.T) { 714 t.Parallel() 715 var ( 716 cls = "TestObjectHTTPQuery" 717 first_friend = "TestObjectHTTPQueryFriend" 718 ) 719 // test setup 720 helper.AssertCreateObject(t, first_friend, map[string]interface{}{}) 721 defer helper.DeleteClassObject(t, first_friend) 722 helper.AssertCreateObjectClass(t, &models.Class{ 723 Class: cls, 724 Vectorizer: "none", 725 Properties: []*models.Property{ 726 { 727 Name: "count", 728 DataType: []string{"int"}, 729 }, 730 }, 731 }) 732 defer helper.DeleteClassObject(t, cls) 733 helper.AssertCreateObject(t, cls, map[string]interface{}{"count": 1}) 734 helper.AssertCreateObject(t, cls, map[string]interface{}{"count": 1}) 735 736 listParams := objects.NewObjectsListParams() 737 listParams.Class = &cls 738 resp, err := helper.Client(t).Objects.ObjectsList(listParams, nil) 739 require.Nil(t, err, "unexpected error", resp) 740 741 if n := len(resp.Payload.Objects); n != 2 { 742 t.Errorf("Number of object got:%v want %v", n, 2) 743 } 744 var count int64 745 for _, x := range resp.Payload.Objects { 746 if x.Class != cls { 747 t.Errorf("Class got:%v want:%v", x.Class, cls) 748 } 749 m, ok := x.Properties.(map[string]interface{}) 750 if !ok { 751 t.Error("wrong property type") 752 } 753 n, _ := m["count"].(json.Number).Int64() 754 count += n 755 } 756 if count != 2 { 757 t.Errorf("Count got:%v want:%v", count, 2) 758 } 759 760 listParams.Class = &first_friend 761 resp, err = helper.Client(t).Objects.ObjectsList(listParams, nil) 762 require.Nil(t, err, "unexpected error", resp) 763 if n := len(resp.Payload.Objects); n != 1 { 764 t.Errorf("Number of friend objects got:%v want %v", n, 2) 765 } 766 767 unknown_cls := "unknow" 768 listParams.Class = &unknown_cls 769 _, err = helper.Client(t).Objects.ObjectsList(listParams, nil) 770 if _, ok := err.(*objects.ObjectsListNotFound); !ok { 771 t.Errorf("error type expected: %T, got %T", objects.ObjectsListNotFound{}, err) 772 } 773 }