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  }